]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Update to iD v2.20.2
[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         var check = function (it) {
6           return it && it.Math == Math && it;
7         };
8
9         // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
10         var global$F =
11           // eslint-disable-next-line es/no-global-this -- safe
12           check(typeof globalThis == 'object' && globalThis) ||
13           check(typeof window == 'object' && window) ||
14           // eslint-disable-next-line no-restricted-globals -- safe
15           check(typeof self == 'object' && self) ||
16           check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
17           // eslint-disable-next-line no-new-func -- fallback
18           (function () { return this; })() || Function('return this')();
19
20         var objectGetOwnPropertyDescriptor = {};
21
22         var fails$N = function (exec) {
23           try {
24             return !!exec();
25           } catch (error) {
26             return true;
27           }
28         };
29
30         var fails$M = fails$N;
31
32         // Detect IE8's incomplete defineProperty implementation
33         var descriptors = !fails$M(function () {
34           // eslint-disable-next-line es/no-object-defineproperty -- required for testing
35           return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
36         });
37
38         var objectPropertyIsEnumerable = {};
39
40         var $propertyIsEnumerable$1 = {}.propertyIsEnumerable;
41         // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
42         var getOwnPropertyDescriptor$5 = Object.getOwnPropertyDescriptor;
43
44         // Nashorn ~ JDK8 bug
45         var NASHORN_BUG = getOwnPropertyDescriptor$5 && !$propertyIsEnumerable$1.call({ 1: 2 }, 1);
46
47         // `Object.prototype.propertyIsEnumerable` method implementation
48         // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
49         objectPropertyIsEnumerable.f = NASHORN_BUG ? function propertyIsEnumerable(V) {
50           var descriptor = getOwnPropertyDescriptor$5(this, V);
51           return !!descriptor && descriptor.enumerable;
52         } : $propertyIsEnumerable$1;
53
54         var createPropertyDescriptor$7 = function (bitmap, value) {
55           return {
56             enumerable: !(bitmap & 1),
57             configurable: !(bitmap & 2),
58             writable: !(bitmap & 4),
59             value: value
60           };
61         };
62
63         var toString$2 = {}.toString;
64
65         var classofRaw$1 = function (it) {
66           return toString$2.call(it).slice(8, -1);
67         };
68
69         var fails$L = fails$N;
70         var classof$c = classofRaw$1;
71
72         var split$1 = ''.split;
73
74         // fallback for non-array-like ES3 and non-enumerable old V8 strings
75         var indexedObject = fails$L(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 classof$c(it) == 'String' ? split$1.call(it, '') : Object(it);
81         } : Object;
82
83         // `RequireObjectCoercible` abstract operation
84         // https://tc39.es/ecma262/#sec-requireobjectcoercible
85         var requireObjectCoercible$e = 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         var IndexedObject$4 = indexedObject;
92         var requireObjectCoercible$d = requireObjectCoercible$e;
93
94         var toIndexedObject$b = function (it) {
95           return IndexedObject$4(requireObjectCoercible$d(it));
96         };
97
98         var isObject$r = function (it) {
99           return typeof it === 'object' ? it !== null : typeof it === 'function';
100         };
101
102         var isObject$q = isObject$r;
103
104         // `ToPrimitive` abstract operation
105         // https://tc39.es/ecma262/#sec-toprimitive
106         // instead of the ES6 spec version, we didn't implement @@toPrimitive case
107         // and the second argument - flag - preferred type is a string
108         var toPrimitive$7 = function (input, PREFERRED_STRING) {
109           if (!isObject$q(input)) return input;
110           var fn, val;
111           if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject$q(val = fn.call(input))) return val;
112           if (typeof (fn = input.valueOf) == 'function' && !isObject$q(val = fn.call(input))) return val;
113           if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject$q(val = fn.call(input))) return val;
114           throw TypeError("Can't convert object to primitive value");
115         };
116
117         var requireObjectCoercible$c = requireObjectCoercible$e;
118
119         // `ToObject` abstract operation
120         // https://tc39.es/ecma262/#sec-toobject
121         var toObject$i = function (argument) {
122           return Object(requireObjectCoercible$c(argument));
123         };
124
125         var toObject$h = toObject$i;
126
127         var hasOwnProperty$3 = {}.hasOwnProperty;
128
129         var has$j = Object.hasOwn || function hasOwn(it, key) {
130           return hasOwnProperty$3.call(toObject$h(it), key);
131         };
132
133         var global$E = global$F;
134         var isObject$p = isObject$r;
135
136         var document$3 = global$E.document;
137         // typeof document.createElement is 'object' in old IE
138         var EXISTS = isObject$p(document$3) && isObject$p(document$3.createElement);
139
140         var documentCreateElement$1 = function (it) {
141           return EXISTS ? document$3.createElement(it) : {};
142         };
143
144         var DESCRIPTORS$m = descriptors;
145         var fails$K = fails$N;
146         var createElement$1 = documentCreateElement$1;
147
148         // Thank's IE8 for his funny defineProperty
149         var ie8DomDefine = !DESCRIPTORS$m && !fails$K(function () {
150           // eslint-disable-next-line es/no-object-defineproperty -- requied for testing
151           return Object.defineProperty(createElement$1('div'), 'a', {
152             get: function () { return 7; }
153           }).a != 7;
154         });
155
156         var DESCRIPTORS$l = descriptors;
157         var propertyIsEnumerableModule$2 = objectPropertyIsEnumerable;
158         var createPropertyDescriptor$6 = createPropertyDescriptor$7;
159         var toIndexedObject$a = toIndexedObject$b;
160         var toPrimitive$6 = toPrimitive$7;
161         var has$i = has$j;
162         var IE8_DOM_DEFINE$1 = ie8DomDefine;
163
164         // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
165         var $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
166
167         // `Object.getOwnPropertyDescriptor` method
168         // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
169         objectGetOwnPropertyDescriptor.f = DESCRIPTORS$l ? $getOwnPropertyDescriptor$1 : function getOwnPropertyDescriptor(O, P) {
170           O = toIndexedObject$a(O);
171           P = toPrimitive$6(P, true);
172           if (IE8_DOM_DEFINE$1) try {
173             return $getOwnPropertyDescriptor$1(O, P);
174           } catch (error) { /* empty */ }
175           if (has$i(O, P)) return createPropertyDescriptor$6(!propertyIsEnumerableModule$2.f.call(O, P), O[P]);
176         };
177
178         var objectDefineProperty = {};
179
180         var isObject$o = isObject$r;
181
182         var anObject$m = function (it) {
183           if (!isObject$o(it)) {
184             throw TypeError(String(it) + ' is not an object');
185           } return it;
186         };
187
188         var DESCRIPTORS$k = descriptors;
189         var IE8_DOM_DEFINE = ie8DomDefine;
190         var anObject$l = anObject$m;
191         var toPrimitive$5 = toPrimitive$7;
192
193         // eslint-disable-next-line es/no-object-defineproperty -- safe
194         var $defineProperty$1 = Object.defineProperty;
195
196         // `Object.defineProperty` method
197         // https://tc39.es/ecma262/#sec-object.defineproperty
198         objectDefineProperty.f = DESCRIPTORS$k ? $defineProperty$1 : function defineProperty(O, P, Attributes) {
199           anObject$l(O);
200           P = toPrimitive$5(P, true);
201           anObject$l(Attributes);
202           if (IE8_DOM_DEFINE) try {
203             return $defineProperty$1(O, P, Attributes);
204           } catch (error) { /* empty */ }
205           if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
206           if ('value' in Attributes) O[P] = Attributes.value;
207           return O;
208         };
209
210         var DESCRIPTORS$j = descriptors;
211         var definePropertyModule$7 = objectDefineProperty;
212         var createPropertyDescriptor$5 = createPropertyDescriptor$7;
213
214         var createNonEnumerableProperty$e = DESCRIPTORS$j ? function (object, key, value) {
215           return definePropertyModule$7.f(object, key, createPropertyDescriptor$5(1, value));
216         } : function (object, key, value) {
217           object[key] = value;
218           return object;
219         };
220
221         var redefine$g = {exports: {}};
222
223         var global$D = global$F;
224         var createNonEnumerableProperty$d = createNonEnumerableProperty$e;
225
226         var setGlobal$3 = function (key, value) {
227           try {
228             createNonEnumerableProperty$d(global$D, key, value);
229           } catch (error) {
230             global$D[key] = value;
231           } return value;
232         };
233
234         var global$C = global$F;
235         var setGlobal$2 = setGlobal$3;
236
237         var SHARED = '__core-js_shared__';
238         var store$4 = global$C[SHARED] || setGlobal$2(SHARED, {});
239
240         var sharedStore = store$4;
241
242         var store$3 = sharedStore;
243
244         var functionToString = Function.toString;
245
246         // this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
247         if (typeof store$3.inspectSource != 'function') {
248           store$3.inspectSource = function (it) {
249             return functionToString.call(it);
250           };
251         }
252
253         var inspectSource$3 = store$3.inspectSource;
254
255         var global$B = global$F;
256         var inspectSource$2 = inspectSource$3;
257
258         var WeakMap$1 = global$B.WeakMap;
259
260         var nativeWeakMap = typeof WeakMap$1 === 'function' && /native code/.test(inspectSource$2(WeakMap$1));
261
262         var shared$5 = {exports: {}};
263
264         var isPure = false;
265
266         var store$2 = sharedStore;
267
268         (shared$5.exports = function (key, value) {
269           return store$2[key] || (store$2[key] = value !== undefined ? value : {});
270         })('versions', []).push({
271           version: '3.15.0',
272           mode: 'global',
273           copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
274         });
275
276         var id$2 = 0;
277         var postfix = Math.random();
278
279         var uid$5 = function (key) {
280           return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id$2 + postfix).toString(36);
281         };
282
283         var shared$4 = shared$5.exports;
284         var uid$4 = uid$5;
285
286         var keys$3 = shared$4('keys');
287
288         var sharedKey$4 = function (key) {
289           return keys$3[key] || (keys$3[key] = uid$4(key));
290         };
291
292         var hiddenKeys$6 = {};
293
294         var NATIVE_WEAK_MAP = nativeWeakMap;
295         var global$A = global$F;
296         var isObject$n = isObject$r;
297         var createNonEnumerableProperty$c = createNonEnumerableProperty$e;
298         var objectHas = has$j;
299         var shared$3 = sharedStore;
300         var sharedKey$3 = sharedKey$4;
301         var hiddenKeys$5 = hiddenKeys$6;
302
303         var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
304         var WeakMap = global$A.WeakMap;
305         var set$4, get$5, has$h;
306
307         var enforce = function (it) {
308           return has$h(it) ? get$5(it) : set$4(it, {});
309         };
310
311         var getterFor = function (TYPE) {
312           return function (it) {
313             var state;
314             if (!isObject$n(it) || (state = get$5(it)).type !== TYPE) {
315               throw TypeError('Incompatible receiver, ' + TYPE + ' required');
316             } return state;
317           };
318         };
319
320         if (NATIVE_WEAK_MAP || shared$3.state) {
321           var store$1 = shared$3.state || (shared$3.state = new WeakMap());
322           var wmget = store$1.get;
323           var wmhas = store$1.has;
324           var wmset = store$1.set;
325           set$4 = function (it, metadata) {
326             if (wmhas.call(store$1, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
327             metadata.facade = it;
328             wmset.call(store$1, it, metadata);
329             return metadata;
330           };
331           get$5 = function (it) {
332             return wmget.call(store$1, it) || {};
333           };
334           has$h = function (it) {
335             return wmhas.call(store$1, it);
336           };
337         } else {
338           var STATE = sharedKey$3('state');
339           hiddenKeys$5[STATE] = true;
340           set$4 = function (it, metadata) {
341             if (objectHas(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
342             metadata.facade = it;
343             createNonEnumerableProperty$c(it, STATE, metadata);
344             return metadata;
345           };
346           get$5 = function (it) {
347             return objectHas(it, STATE) ? it[STATE] : {};
348           };
349           has$h = function (it) {
350             return objectHas(it, STATE);
351           };
352         }
353
354         var internalState = {
355           set: set$4,
356           get: get$5,
357           has: has$h,
358           enforce: enforce,
359           getterFor: getterFor
360         };
361
362         var global$z = global$F;
363         var createNonEnumerableProperty$b = createNonEnumerableProperty$e;
364         var has$g = has$j;
365         var setGlobal$1 = setGlobal$3;
366         var inspectSource$1 = inspectSource$3;
367         var InternalStateModule$9 = internalState;
368
369         var getInternalState$7 = InternalStateModule$9.get;
370         var enforceInternalState$1 = InternalStateModule$9.enforce;
371         var TEMPLATE = String(String).split('String');
372
373         (redefine$g.exports = function (O, key, value, options) {
374           var unsafe = options ? !!options.unsafe : false;
375           var simple = options ? !!options.enumerable : false;
376           var noTargetGet = options ? !!options.noTargetGet : false;
377           var state;
378           if (typeof value == 'function') {
379             if (typeof key == 'string' && !has$g(value, 'name')) {
380               createNonEnumerableProperty$b(value, 'name', key);
381             }
382             state = enforceInternalState$1(value);
383             if (!state.source) {
384               state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
385             }
386           }
387           if (O === global$z) {
388             if (simple) O[key] = value;
389             else setGlobal$1(key, value);
390             return;
391           } else if (!unsafe) {
392             delete O[key];
393           } else if (!noTargetGet && O[key]) {
394             simple = true;
395           }
396           if (simple) O[key] = value;
397           else createNonEnumerableProperty$b(O, key, value);
398         // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
399         })(Function.prototype, 'toString', function toString() {
400           return typeof this == 'function' && getInternalState$7(this).source || inspectSource$1(this);
401         });
402
403         var global$y = global$F;
404
405         var path$2 = global$y;
406
407         var path$1 = path$2;
408         var global$x = global$F;
409
410         var aFunction$a = function (variable) {
411           return typeof variable == 'function' ? variable : undefined;
412         };
413
414         var getBuiltIn$9 = function (namespace, method) {
415           return arguments.length < 2 ? aFunction$a(path$1[namespace]) || aFunction$a(global$x[namespace])
416             : path$1[namespace] && path$1[namespace][method] || global$x[namespace] && global$x[namespace][method];
417         };
418
419         var objectGetOwnPropertyNames = {};
420
421         var ceil$1 = Math.ceil;
422         var floor$7 = Math.floor;
423
424         // `ToInteger` abstract operation
425         // https://tc39.es/ecma262/#sec-tointeger
426         var toInteger$b = function (argument) {
427           return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor$7 : ceil$1)(argument);
428         };
429
430         var toInteger$a = toInteger$b;
431
432         var min$9 = Math.min;
433
434         // `ToLength` abstract operation
435         // https://tc39.es/ecma262/#sec-tolength
436         var toLength$q = function (argument) {
437           return argument > 0 ? min$9(toInteger$a(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
438         };
439
440         var toInteger$9 = toInteger$b;
441
442         var max$4 = Math.max;
443         var min$8 = Math.min;
444
445         // Helper for a popular repeating case of the spec:
446         // Let integer be ? ToInteger(index).
447         // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
448         var toAbsoluteIndex$8 = function (index, length) {
449           var integer = toInteger$9(index);
450           return integer < 0 ? max$4(integer + length, 0) : min$8(integer, length);
451         };
452
453         var toIndexedObject$9 = toIndexedObject$b;
454         var toLength$p = toLength$q;
455         var toAbsoluteIndex$7 = toAbsoluteIndex$8;
456
457         // `Array.prototype.{ indexOf, includes }` methods implementation
458         var createMethod$6 = function (IS_INCLUDES) {
459           return function ($this, el, fromIndex) {
460             var O = toIndexedObject$9($this);
461             var length = toLength$p(O.length);
462             var index = toAbsoluteIndex$7(fromIndex, length);
463             var value;
464             // Array#includes uses SameValueZero equality algorithm
465             // eslint-disable-next-line no-self-compare -- NaN check
466             if (IS_INCLUDES && el != el) while (length > index) {
467               value = O[index++];
468               // eslint-disable-next-line no-self-compare -- NaN check
469               if (value != value) return true;
470             // Array#indexOf ignores holes, Array#includes - not
471             } else for (;length > index; index++) {
472               if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
473             } return !IS_INCLUDES && -1;
474           };
475         };
476
477         var arrayIncludes = {
478           // `Array.prototype.includes` method
479           // https://tc39.es/ecma262/#sec-array.prototype.includes
480           includes: createMethod$6(true),
481           // `Array.prototype.indexOf` method
482           // https://tc39.es/ecma262/#sec-array.prototype.indexof
483           indexOf: createMethod$6(false)
484         };
485
486         var has$f = has$j;
487         var toIndexedObject$8 = toIndexedObject$b;
488         var indexOf = arrayIncludes.indexOf;
489         var hiddenKeys$4 = hiddenKeys$6;
490
491         var objectKeysInternal = function (object, names) {
492           var O = toIndexedObject$8(object);
493           var i = 0;
494           var result = [];
495           var key;
496           for (key in O) !has$f(hiddenKeys$4, key) && has$f(O, key) && result.push(key);
497           // Don't enum bug & hidden keys
498           while (names.length > i) if (has$f(O, key = names[i++])) {
499             ~indexOf(result, key) || result.push(key);
500           }
501           return result;
502         };
503
504         // IE8- don't enum bug keys
505         var enumBugKeys$3 = [
506           'constructor',
507           'hasOwnProperty',
508           'isPrototypeOf',
509           'propertyIsEnumerable',
510           'toLocaleString',
511           'toString',
512           'valueOf'
513         ];
514
515         var internalObjectKeys$1 = objectKeysInternal;
516         var enumBugKeys$2 = enumBugKeys$3;
517
518         var hiddenKeys$3 = enumBugKeys$2.concat('length', 'prototype');
519
520         // `Object.getOwnPropertyNames` method
521         // https://tc39.es/ecma262/#sec-object.getownpropertynames
522         // eslint-disable-next-line es/no-object-getownpropertynames -- safe
523         objectGetOwnPropertyNames.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
524           return internalObjectKeys$1(O, hiddenKeys$3);
525         };
526
527         var objectGetOwnPropertySymbols = {};
528
529         // eslint-disable-next-line es/no-object-getownpropertysymbols -- safe
530         objectGetOwnPropertySymbols.f = Object.getOwnPropertySymbols;
531
532         var getBuiltIn$8 = getBuiltIn$9;
533         var getOwnPropertyNamesModule$1 = objectGetOwnPropertyNames;
534         var getOwnPropertySymbolsModule$2 = objectGetOwnPropertySymbols;
535         var anObject$k = anObject$m;
536
537         // all object keys, includes non-enumerable and symbols
538         var ownKeys$1 = getBuiltIn$8('Reflect', 'ownKeys') || function ownKeys(it) {
539           var keys = getOwnPropertyNamesModule$1.f(anObject$k(it));
540           var getOwnPropertySymbols = getOwnPropertySymbolsModule$2.f;
541           return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
542         };
543
544         var has$e = has$j;
545         var ownKeys = ownKeys$1;
546         var getOwnPropertyDescriptorModule$3 = objectGetOwnPropertyDescriptor;
547         var definePropertyModule$6 = objectDefineProperty;
548
549         var copyConstructorProperties$2 = function (target, source) {
550           var keys = ownKeys(source);
551           var defineProperty = definePropertyModule$6.f;
552           var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule$3.f;
553           for (var i = 0; i < keys.length; i++) {
554             var key = keys[i];
555             if (!has$e(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
556           }
557         };
558
559         var fails$J = fails$N;
560
561         var replacement = /#|\.prototype\./;
562
563         var isForced$5 = function (feature, detection) {
564           var value = data[normalize$1(feature)];
565           return value == POLYFILL ? true
566             : value == NATIVE ? false
567             : typeof detection == 'function' ? fails$J(detection)
568             : !!detection;
569         };
570
571         var normalize$1 = isForced$5.normalize = function (string) {
572           return String(string).replace(replacement, '.').toLowerCase();
573         };
574
575         var data = isForced$5.data = {};
576         var NATIVE = isForced$5.NATIVE = 'N';
577         var POLYFILL = isForced$5.POLYFILL = 'P';
578
579         var isForced_1 = isForced$5;
580
581         var global$w = global$F;
582         var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
583         var createNonEnumerableProperty$a = createNonEnumerableProperty$e;
584         var redefine$f = redefine$g.exports;
585         var setGlobal = setGlobal$3;
586         var copyConstructorProperties$1 = copyConstructorProperties$2;
587         var isForced$4 = isForced_1;
588
589         /*
590           options.target      - name of the target object
591           options.global      - target is the global object
592           options.stat        - export as static methods of target
593           options.proto       - export as prototype methods of target
594           options.real        - real prototype method for the `pure` version
595           options.forced      - export even if the native feature is available
596           options.bind        - bind methods to the target, required for the `pure` version
597           options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
598           options.unsafe      - use the simple assignment of property instead of delete + defineProperty
599           options.sham        - add a flag to not completely full polyfills
600           options.enumerable  - export as enumerable property
601           options.noTargetGet - prevent calling a getter on target
602         */
603         var _export = function (options, source) {
604           var TARGET = options.target;
605           var GLOBAL = options.global;
606           var STATIC = options.stat;
607           var FORCED, target, key, targetProperty, sourceProperty, descriptor;
608           if (GLOBAL) {
609             target = global$w;
610           } else if (STATIC) {
611             target = global$w[TARGET] || setGlobal(TARGET, {});
612           } else {
613             target = (global$w[TARGET] || {}).prototype;
614           }
615           if (target) for (key in source) {
616             sourceProperty = source[key];
617             if (options.noTargetGet) {
618               descriptor = getOwnPropertyDescriptor$4(target, key);
619               targetProperty = descriptor && descriptor.value;
620             } else targetProperty = target[key];
621             FORCED = isForced$4(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
622             // contained in target
623             if (!FORCED && targetProperty !== undefined) {
624               if (typeof sourceProperty === typeof targetProperty) continue;
625               copyConstructorProperties$1(sourceProperty, targetProperty);
626             }
627             // add a flag to not completely full polyfills
628             if (options.sham || (targetProperty && targetProperty.sham)) {
629               createNonEnumerableProperty$a(sourceProperty, 'sham', true);
630             }
631             // extend global
632             redefine$f(target, key, sourceProperty, options);
633           }
634         };
635
636         var $$16 = _export;
637
638         // `Date.now` method
639         // https://tc39.es/ecma262/#sec-date.now
640         $$16({ target: 'Date', stat: true }, {
641           now: function now() {
642             return new Date().getTime();
643           }
644         });
645
646         var redefine$e = redefine$g.exports;
647
648         var DatePrototype$1 = Date.prototype;
649         var INVALID_DATE = 'Invalid Date';
650         var TO_STRING$1 = 'toString';
651         var nativeDateToString = DatePrototype$1[TO_STRING$1];
652         var getTime$1 = DatePrototype$1.getTime;
653
654         // `Date.prototype.toString` method
655         // https://tc39.es/ecma262/#sec-date.prototype.tostring
656         if (new Date(NaN) + '' != INVALID_DATE) {
657           redefine$e(DatePrototype$1, TO_STRING$1, function toString() {
658             var value = getTime$1.call(this);
659             // eslint-disable-next-line no-self-compare -- NaN check
660             return value === value ? nativeDateToString.call(this) : INVALID_DATE;
661           });
662         }
663
664         function _typeof(obj) {
665           "@babel/helpers - typeof";
666
667           if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
668             _typeof = function (obj) {
669               return typeof obj;
670             };
671           } else {
672             _typeof = function (obj) {
673               return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
674             };
675           }
676
677           return _typeof(obj);
678         }
679
680         function _classCallCheck$1(instance, Constructor) {
681           if (!(instance instanceof Constructor)) {
682             throw new TypeError("Cannot call a class as a function");
683           }
684         }
685
686         function _defineProperties$1(target, props) {
687           for (var i = 0; i < props.length; i++) {
688             var descriptor = props[i];
689             descriptor.enumerable = descriptor.enumerable || false;
690             descriptor.configurable = true;
691             if ("value" in descriptor) descriptor.writable = true;
692             Object.defineProperty(target, descriptor.key, descriptor);
693           }
694         }
695
696         function _createClass$1(Constructor, protoProps, staticProps) {
697           if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
698           if (staticProps) _defineProperties$1(Constructor, staticProps);
699           return Constructor;
700         }
701
702         function _defineProperty(obj, key, value) {
703           if (key in obj) {
704             Object.defineProperty(obj, key, {
705               value: value,
706               enumerable: true,
707               configurable: true,
708               writable: true
709             });
710           } else {
711             obj[key] = value;
712           }
713
714           return obj;
715         }
716
717         function _slicedToArray(arr, i) {
718           return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
719         }
720
721         function _toConsumableArray(arr) {
722           return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
723         }
724
725         function _arrayWithoutHoles(arr) {
726           if (Array.isArray(arr)) return _arrayLikeToArray(arr);
727         }
728
729         function _arrayWithHoles(arr) {
730           if (Array.isArray(arr)) return arr;
731         }
732
733         function _iterableToArray(iter) {
734           if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
735         }
736
737         function _iterableToArrayLimit(arr, i) {
738           var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
739
740           if (_i == null) return;
741           var _arr = [];
742           var _n = true;
743           var _d = false;
744
745           var _s, _e;
746
747           try {
748             for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
749               _arr.push(_s.value);
750
751               if (i && _arr.length === i) break;
752             }
753           } catch (err) {
754             _d = true;
755             _e = err;
756           } finally {
757             try {
758               if (!_n && _i["return"] != null) _i["return"]();
759             } finally {
760               if (_d) throw _e;
761             }
762           }
763
764           return _arr;
765         }
766
767         function _unsupportedIterableToArray(o, minLen) {
768           if (!o) return;
769           if (typeof o === "string") return _arrayLikeToArray(o, minLen);
770           var n = Object.prototype.toString.call(o).slice(8, -1);
771           if (n === "Object" && o.constructor) n = o.constructor.name;
772           if (n === "Map" || n === "Set") return Array.from(o);
773           if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
774         }
775
776         function _arrayLikeToArray(arr, len) {
777           if (len == null || len > arr.length) len = arr.length;
778
779           for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
780
781           return arr2;
782         }
783
784         function _nonIterableSpread() {
785           throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
786         }
787
788         function _nonIterableRest() {
789           throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
790         }
791
792         function _createForOfIteratorHelper(o, allowArrayLike) {
793           var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
794
795           if (!it) {
796             if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
797               if (it) o = it;
798               var i = 0;
799
800               var F = function () {};
801
802               return {
803                 s: F,
804                 n: function () {
805                   if (i >= o.length) return {
806                     done: true
807                   };
808                   return {
809                     done: false,
810                     value: o[i++]
811                   };
812                 },
813                 e: function (e) {
814                   throw e;
815                 },
816                 f: F
817               };
818             }
819
820             throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
821           }
822
823           var normalCompletion = true,
824               didErr = false,
825               err;
826           return {
827             s: function () {
828               it = it.call(o);
829             },
830             n: function () {
831               var step = it.next();
832               normalCompletion = step.done;
833               return step;
834             },
835             e: function (e) {
836               didErr = true;
837               err = e;
838             },
839             f: function () {
840               try {
841                 if (!normalCompletion && it.return != null) it.return();
842               } finally {
843                 if (didErr) throw err;
844               }
845             }
846           };
847         }
848
849         var wellKnownSymbolWrapped = {};
850
851         var getBuiltIn$7 = getBuiltIn$9;
852
853         var engineUserAgent = getBuiltIn$7('navigator', 'userAgent') || '';
854
855         var global$v = global$F;
856         var userAgent$5 = engineUserAgent;
857
858         var process$4 = global$v.process;
859         var versions = process$4 && process$4.versions;
860         var v8 = versions && versions.v8;
861         var match, version$1;
862
863         if (v8) {
864           match = v8.split('.');
865           version$1 = match[0] < 4 ? 1 : match[0] + match[1];
866         } else if (userAgent$5) {
867           match = userAgent$5.match(/Edge\/(\d+)/);
868           if (!match || match[1] >= 74) {
869             match = userAgent$5.match(/Chrome\/(\d+)/);
870             if (match) version$1 = match[1];
871           }
872         }
873
874         var engineV8Version = version$1 && +version$1;
875
876         /* eslint-disable es/no-symbol -- required for testing */
877
878         var V8_VERSION$3 = engineV8Version;
879         var fails$I = fails$N;
880
881         // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
882         var nativeSymbol = !!Object.getOwnPropertySymbols && !fails$I(function () {
883           var symbol = Symbol();
884           // Chrome 38 Symbol has incorrect toString conversion
885           // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
886           return !String(symbol) || !(Object(symbol) instanceof Symbol) ||
887             // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
888             !Symbol.sham && V8_VERSION$3 && V8_VERSION$3 < 41;
889         });
890
891         /* eslint-disable es/no-symbol -- required for testing */
892
893         var NATIVE_SYMBOL$2 = nativeSymbol;
894
895         var useSymbolAsUid = NATIVE_SYMBOL$2
896           && !Symbol.sham
897           && typeof Symbol.iterator == 'symbol';
898
899         var global$u = global$F;
900         var shared$2 = shared$5.exports;
901         var has$d = has$j;
902         var uid$3 = uid$5;
903         var NATIVE_SYMBOL$1 = nativeSymbol;
904         var USE_SYMBOL_AS_UID$1 = useSymbolAsUid;
905
906         var WellKnownSymbolsStore$1 = shared$2('wks');
907         var Symbol$1 = global$u.Symbol;
908         var createWellKnownSymbol = USE_SYMBOL_AS_UID$1 ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid$3;
909
910         var wellKnownSymbol$s = function (name) {
911           if (!has$d(WellKnownSymbolsStore$1, name) || !(NATIVE_SYMBOL$1 || typeof WellKnownSymbolsStore$1[name] == 'string')) {
912             if (NATIVE_SYMBOL$1 && has$d(Symbol$1, name)) {
913               WellKnownSymbolsStore$1[name] = Symbol$1[name];
914             } else {
915               WellKnownSymbolsStore$1[name] = createWellKnownSymbol('Symbol.' + name);
916             }
917           } return WellKnownSymbolsStore$1[name];
918         };
919
920         var wellKnownSymbol$r = wellKnownSymbol$s;
921
922         wellKnownSymbolWrapped.f = wellKnownSymbol$r;
923
924         var path = path$2;
925         var has$c = has$j;
926         var wrappedWellKnownSymbolModule$1 = wellKnownSymbolWrapped;
927         var defineProperty$a = objectDefineProperty.f;
928
929         var defineWellKnownSymbol$4 = function (NAME) {
930           var Symbol = path.Symbol || (path.Symbol = {});
931           if (!has$c(Symbol, NAME)) defineProperty$a(Symbol, NAME, {
932             value: wrappedWellKnownSymbolModule$1.f(NAME)
933           });
934         };
935
936         var defineWellKnownSymbol$3 = defineWellKnownSymbol$4;
937
938         // `Symbol.iterator` well-known symbol
939         // https://tc39.es/ecma262/#sec-symbol.iterator
940         defineWellKnownSymbol$3('iterator');
941
942         var internalObjectKeys = objectKeysInternal;
943         var enumBugKeys$1 = enumBugKeys$3;
944
945         // `Object.keys` method
946         // https://tc39.es/ecma262/#sec-object.keys
947         // eslint-disable-next-line es/no-object-keys -- safe
948         var objectKeys$4 = Object.keys || function keys(O) {
949           return internalObjectKeys(O, enumBugKeys$1);
950         };
951
952         var DESCRIPTORS$i = descriptors;
953         var definePropertyModule$5 = objectDefineProperty;
954         var anObject$j = anObject$m;
955         var objectKeys$3 = objectKeys$4;
956
957         // `Object.defineProperties` method
958         // https://tc39.es/ecma262/#sec-object.defineproperties
959         // eslint-disable-next-line es/no-object-defineproperties -- safe
960         var objectDefineProperties = DESCRIPTORS$i ? Object.defineProperties : function defineProperties(O, Properties) {
961           anObject$j(O);
962           var keys = objectKeys$3(Properties);
963           var length = keys.length;
964           var index = 0;
965           var key;
966           while (length > index) definePropertyModule$5.f(O, key = keys[index++], Properties[key]);
967           return O;
968         };
969
970         var getBuiltIn$6 = getBuiltIn$9;
971
972         var html$2 = getBuiltIn$6('document', 'documentElement');
973
974         var anObject$i = anObject$m;
975         var defineProperties$2 = objectDefineProperties;
976         var enumBugKeys = enumBugKeys$3;
977         var hiddenKeys$2 = hiddenKeys$6;
978         var html$1 = html$2;
979         var documentCreateElement = documentCreateElement$1;
980         var sharedKey$2 = sharedKey$4;
981
982         var GT = '>';
983         var LT = '<';
984         var PROTOTYPE$2 = 'prototype';
985         var SCRIPT = 'script';
986         var IE_PROTO$1 = sharedKey$2('IE_PROTO');
987
988         var EmptyConstructor = function () { /* empty */ };
989
990         var scriptTag = function (content) {
991           return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
992         };
993
994         // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
995         var NullProtoObjectViaActiveX = function (activeXDocument) {
996           activeXDocument.write(scriptTag(''));
997           activeXDocument.close();
998           var temp = activeXDocument.parentWindow.Object;
999           activeXDocument = null; // avoid memory leak
1000           return temp;
1001         };
1002
1003         // Create object with fake `null` prototype: use iframe Object with cleared prototype
1004         var NullProtoObjectViaIFrame = function () {
1005           // Thrash, waste and sodomy: IE GC bug
1006           var iframe = documentCreateElement('iframe');
1007           var JS = 'java' + SCRIPT + ':';
1008           var iframeDocument;
1009           iframe.style.display = 'none';
1010           html$1.appendChild(iframe);
1011           // https://github.com/zloirock/core-js/issues/475
1012           iframe.src = String(JS);
1013           iframeDocument = iframe.contentWindow.document;
1014           iframeDocument.open();
1015           iframeDocument.write(scriptTag('document.F=Object'));
1016           iframeDocument.close();
1017           return iframeDocument.F;
1018         };
1019
1020         // Check for document.domain and active x support
1021         // No need to use active x approach when document.domain is not set
1022         // see https://github.com/es-shims/es5-shim/issues/150
1023         // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
1024         // avoid IE GC bug
1025         var activeXDocument;
1026         var NullProtoObject = function () {
1027           try {
1028             /* global ActiveXObject -- old IE */
1029             activeXDocument = document.domain && new ActiveXObject('htmlfile');
1030           } catch (error) { /* ignore */ }
1031           NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
1032           var length = enumBugKeys.length;
1033           while (length--) delete NullProtoObject[PROTOTYPE$2][enumBugKeys[length]];
1034           return NullProtoObject();
1035         };
1036
1037         hiddenKeys$2[IE_PROTO$1] = true;
1038
1039         // `Object.create` method
1040         // https://tc39.es/ecma262/#sec-object.create
1041         var objectCreate = Object.create || function create(O, Properties) {
1042           var result;
1043           if (O !== null) {
1044             EmptyConstructor[PROTOTYPE$2] = anObject$i(O);
1045             result = new EmptyConstructor();
1046             EmptyConstructor[PROTOTYPE$2] = null;
1047             // add "__proto__" for Object.getPrototypeOf polyfill
1048             result[IE_PROTO$1] = O;
1049           } else result = NullProtoObject();
1050           return Properties === undefined ? result : defineProperties$2(result, Properties);
1051         };
1052
1053         var wellKnownSymbol$q = wellKnownSymbol$s;
1054         var create$b = objectCreate;
1055         var definePropertyModule$4 = objectDefineProperty;
1056
1057         var UNSCOPABLES = wellKnownSymbol$q('unscopables');
1058         var ArrayPrototype$1 = Array.prototype;
1059
1060         // Array.prototype[@@unscopables]
1061         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1062         if (ArrayPrototype$1[UNSCOPABLES] == undefined) {
1063           definePropertyModule$4.f(ArrayPrototype$1, UNSCOPABLES, {
1064             configurable: true,
1065             value: create$b(null)
1066           });
1067         }
1068
1069         // add a key to Array.prototype[@@unscopables]
1070         var addToUnscopables$5 = function (key) {
1071           ArrayPrototype$1[UNSCOPABLES][key] = true;
1072         };
1073
1074         var iterators = {};
1075
1076         var fails$H = fails$N;
1077
1078         var correctPrototypeGetter = !fails$H(function () {
1079           function F() { /* empty */ }
1080           F.prototype.constructor = null;
1081           // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
1082           return Object.getPrototypeOf(new F()) !== F.prototype;
1083         });
1084
1085         var has$b = has$j;
1086         var toObject$g = toObject$i;
1087         var sharedKey$1 = sharedKey$4;
1088         var CORRECT_PROTOTYPE_GETTER$1 = correctPrototypeGetter;
1089
1090         var IE_PROTO = sharedKey$1('IE_PROTO');
1091         var ObjectPrototype$3 = Object.prototype;
1092
1093         // `Object.getPrototypeOf` method
1094         // https://tc39.es/ecma262/#sec-object.getprototypeof
1095         // eslint-disable-next-line es/no-object-getprototypeof -- safe
1096         var objectGetPrototypeOf = CORRECT_PROTOTYPE_GETTER$1 ? Object.getPrototypeOf : function (O) {
1097           O = toObject$g(O);
1098           if (has$b(O, IE_PROTO)) return O[IE_PROTO];
1099           if (typeof O.constructor == 'function' && O instanceof O.constructor) {
1100             return O.constructor.prototype;
1101           } return O instanceof Object ? ObjectPrototype$3 : null;
1102         };
1103
1104         var fails$G = fails$N;
1105         var getPrototypeOf$4 = objectGetPrototypeOf;
1106         var createNonEnumerableProperty$9 = createNonEnumerableProperty$e;
1107         var has$a = has$j;
1108         var wellKnownSymbol$p = wellKnownSymbol$s;
1109
1110         var ITERATOR$8 = wellKnownSymbol$p('iterator');
1111         var BUGGY_SAFARI_ITERATORS$1 = false;
1112
1113         var returnThis$2 = function () { return this; };
1114
1115         // `%IteratorPrototype%` object
1116         // https://tc39.es/ecma262/#sec-%iteratorprototype%-object
1117         var IteratorPrototype$2, PrototypeOfArrayIteratorPrototype, arrayIterator;
1118
1119         /* eslint-disable es/no-array-prototype-keys -- safe */
1120         if ([].keys) {
1121           arrayIterator = [].keys();
1122           // Safari 8 has buggy iterators w/o `next`
1123           if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS$1 = true;
1124           else {
1125             PrototypeOfArrayIteratorPrototype = getPrototypeOf$4(getPrototypeOf$4(arrayIterator));
1126             if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$2 = PrototypeOfArrayIteratorPrototype;
1127           }
1128         }
1129
1130         var NEW_ITERATOR_PROTOTYPE = IteratorPrototype$2 == undefined || fails$G(function () {
1131           var test = {};
1132           // FF44- legacy iterators case
1133           return IteratorPrototype$2[ITERATOR$8].call(test) !== test;
1134         });
1135
1136         if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype$2 = {};
1137
1138         // `%IteratorPrototype%[@@iterator]()` method
1139         // https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
1140         if (!has$a(IteratorPrototype$2, ITERATOR$8)) {
1141           createNonEnumerableProperty$9(IteratorPrototype$2, ITERATOR$8, returnThis$2);
1142         }
1143
1144         var iteratorsCore = {
1145           IteratorPrototype: IteratorPrototype$2,
1146           BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS$1
1147         };
1148
1149         var defineProperty$9 = objectDefineProperty.f;
1150         var has$9 = has$j;
1151         var wellKnownSymbol$o = wellKnownSymbol$s;
1152
1153         var TO_STRING_TAG$4 = wellKnownSymbol$o('toStringTag');
1154
1155         var setToStringTag$a = function (it, TAG, STATIC) {
1156           if (it && !has$9(it = STATIC ? it : it.prototype, TO_STRING_TAG$4)) {
1157             defineProperty$9(it, TO_STRING_TAG$4, { configurable: true, value: TAG });
1158           }
1159         };
1160
1161         var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1162         var create$a = objectCreate;
1163         var createPropertyDescriptor$4 = createPropertyDescriptor$7;
1164         var setToStringTag$9 = setToStringTag$a;
1165         var Iterators$4 = iterators;
1166
1167         var returnThis$1 = function () { return this; };
1168
1169         var createIteratorConstructor$2 = function (IteratorConstructor, NAME, next) {
1170           var TO_STRING_TAG = NAME + ' Iterator';
1171           IteratorConstructor.prototype = create$a(IteratorPrototype$1, { next: createPropertyDescriptor$4(1, next) });
1172           setToStringTag$9(IteratorConstructor, TO_STRING_TAG, false);
1173           Iterators$4[TO_STRING_TAG] = returnThis$1;
1174           return IteratorConstructor;
1175         };
1176
1177         var isObject$m = isObject$r;
1178
1179         var aPossiblePrototype$1 = function (it) {
1180           if (!isObject$m(it) && it !== null) {
1181             throw TypeError("Can't set " + String(it) + ' as a prototype');
1182           } return it;
1183         };
1184
1185         /* eslint-disable no-proto -- safe */
1186
1187         var anObject$h = anObject$m;
1188         var aPossiblePrototype = aPossiblePrototype$1;
1189
1190         // `Object.setPrototypeOf` method
1191         // https://tc39.es/ecma262/#sec-object.setprototypeof
1192         // Works with __proto__ only. Old v8 can't work with null proto objects.
1193         // eslint-disable-next-line es/no-object-setprototypeof -- safe
1194         var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1195           var CORRECT_SETTER = false;
1196           var test = {};
1197           var setter;
1198           try {
1199             // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
1200             setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1201             setter.call(test, []);
1202             CORRECT_SETTER = test instanceof Array;
1203           } catch (error) { /* empty */ }
1204           return function setPrototypeOf(O, proto) {
1205             anObject$h(O);
1206             aPossiblePrototype(proto);
1207             if (CORRECT_SETTER) setter.call(O, proto);
1208             else O.__proto__ = proto;
1209             return O;
1210           };
1211         }() : undefined);
1212
1213         var $$15 = _export;
1214         var createIteratorConstructor$1 = createIteratorConstructor$2;
1215         var getPrototypeOf$3 = objectGetPrototypeOf;
1216         var setPrototypeOf$6 = objectSetPrototypeOf;
1217         var setToStringTag$8 = setToStringTag$a;
1218         var createNonEnumerableProperty$8 = createNonEnumerableProperty$e;
1219         var redefine$d = redefine$g.exports;
1220         var wellKnownSymbol$n = wellKnownSymbol$s;
1221         var Iterators$3 = iterators;
1222         var IteratorsCore = iteratorsCore;
1223
1224         var IteratorPrototype = IteratorsCore.IteratorPrototype;
1225         var BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS;
1226         var ITERATOR$7 = wellKnownSymbol$n('iterator');
1227         var KEYS = 'keys';
1228         var VALUES = 'values';
1229         var ENTRIES = 'entries';
1230
1231         var returnThis = function () { return this; };
1232
1233         var defineIterator$3 = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1234           createIteratorConstructor$1(IteratorConstructor, NAME, next);
1235
1236           var getIterationMethod = function (KIND) {
1237             if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1238             if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];
1239             switch (KIND) {
1240               case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
1241               case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
1242               case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
1243             } return function () { return new IteratorConstructor(this); };
1244           };
1245
1246           var TO_STRING_TAG = NAME + ' Iterator';
1247           var INCORRECT_VALUES_NAME = false;
1248           var IterablePrototype = Iterable.prototype;
1249           var nativeIterator = IterablePrototype[ITERATOR$7]
1250             || IterablePrototype['@@iterator']
1251             || DEFAULT && IterablePrototype[DEFAULT];
1252           var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);
1253           var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1254           var CurrentIteratorPrototype, methods, KEY;
1255
1256           // fix native
1257           if (anyNativeIterator) {
1258             CurrentIteratorPrototype = getPrototypeOf$3(anyNativeIterator.call(new Iterable()));
1259             if (IteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {
1260               if (getPrototypeOf$3(CurrentIteratorPrototype) !== IteratorPrototype) {
1261                 if (setPrototypeOf$6) {
1262                   setPrototypeOf$6(CurrentIteratorPrototype, IteratorPrototype);
1263                 } else if (typeof CurrentIteratorPrototype[ITERATOR$7] != 'function') {
1264                   createNonEnumerableProperty$8(CurrentIteratorPrototype, ITERATOR$7, returnThis);
1265                 }
1266               }
1267               // Set @@toStringTag to native iterators
1268               setToStringTag$8(CurrentIteratorPrototype, TO_STRING_TAG, true);
1269             }
1270           }
1271
1272           // fix Array.prototype.{ values, @@iterator }.name in V8 / FF
1273           if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1274             INCORRECT_VALUES_NAME = true;
1275             defaultIterator = function values() { return nativeIterator.call(this); };
1276           }
1277
1278           // define iterator
1279           if (IterablePrototype[ITERATOR$7] !== defaultIterator) {
1280             createNonEnumerableProperty$8(IterablePrototype, ITERATOR$7, defaultIterator);
1281           }
1282           Iterators$3[NAME] = defaultIterator;
1283
1284           // export additional methods
1285           if (DEFAULT) {
1286             methods = {
1287               values: getIterationMethod(VALUES),
1288               keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1289               entries: getIterationMethod(ENTRIES)
1290             };
1291             if (FORCED) for (KEY in methods) {
1292               if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1293                 redefine$d(IterablePrototype, KEY, methods[KEY]);
1294               }
1295             } else $$15({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);
1296           }
1297
1298           return methods;
1299         };
1300
1301         var toIndexedObject$7 = toIndexedObject$b;
1302         var addToUnscopables$4 = addToUnscopables$5;
1303         var Iterators$2 = iterators;
1304         var InternalStateModule$8 = internalState;
1305         var defineIterator$2 = defineIterator$3;
1306
1307         var ARRAY_ITERATOR = 'Array Iterator';
1308         var setInternalState$8 = InternalStateModule$8.set;
1309         var getInternalState$6 = InternalStateModule$8.getterFor(ARRAY_ITERATOR);
1310
1311         // `Array.prototype.entries` method
1312         // https://tc39.es/ecma262/#sec-array.prototype.entries
1313         // `Array.prototype.keys` method
1314         // https://tc39.es/ecma262/#sec-array.prototype.keys
1315         // `Array.prototype.values` method
1316         // https://tc39.es/ecma262/#sec-array.prototype.values
1317         // `Array.prototype[@@iterator]` method
1318         // https://tc39.es/ecma262/#sec-array.prototype-@@iterator
1319         // `CreateArrayIterator` internal method
1320         // https://tc39.es/ecma262/#sec-createarrayiterator
1321         var es_array_iterator = defineIterator$2(Array, 'Array', function (iterated, kind) {
1322           setInternalState$8(this, {
1323             type: ARRAY_ITERATOR,
1324             target: toIndexedObject$7(iterated), // target
1325             index: 0,                          // next index
1326             kind: kind                         // kind
1327           });
1328         // `%ArrayIteratorPrototype%.next` method
1329         // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
1330         }, function () {
1331           var state = getInternalState$6(this);
1332           var target = state.target;
1333           var kind = state.kind;
1334           var index = state.index++;
1335           if (!target || index >= target.length) {
1336             state.target = undefined;
1337             return { value: undefined, done: true };
1338           }
1339           if (kind == 'keys') return { value: index, done: false };
1340           if (kind == 'values') return { value: target[index], done: false };
1341           return { value: [index, target[index]], done: false };
1342         }, 'values');
1343
1344         // argumentsList[@@iterator] is %ArrayProto_values%
1345         // https://tc39.es/ecma262/#sec-createunmappedargumentsobject
1346         // https://tc39.es/ecma262/#sec-createmappedargumentsobject
1347         Iterators$2.Arguments = Iterators$2.Array;
1348
1349         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1350         addToUnscopables$4('keys');
1351         addToUnscopables$4('values');
1352         addToUnscopables$4('entries');
1353
1354         var wellKnownSymbol$m = wellKnownSymbol$s;
1355
1356         var TO_STRING_TAG$3 = wellKnownSymbol$m('toStringTag');
1357         var test$2 = {};
1358
1359         test$2[TO_STRING_TAG$3] = 'z';
1360
1361         var toStringTagSupport = String(test$2) === '[object z]';
1362
1363         var TO_STRING_TAG_SUPPORT$2 = toStringTagSupport;
1364         var classofRaw = classofRaw$1;
1365         var wellKnownSymbol$l = wellKnownSymbol$s;
1366
1367         var TO_STRING_TAG$2 = wellKnownSymbol$l('toStringTag');
1368         // ES3 wrong here
1369         var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
1370
1371         // fallback for IE11 Script Access Denied error
1372         var tryGet = function (it, key) {
1373           try {
1374             return it[key];
1375           } catch (error) { /* empty */ }
1376         };
1377
1378         // getting tag from ES6+ `Object.prototype.toString`
1379         var classof$b = TO_STRING_TAG_SUPPORT$2 ? classofRaw : function (it) {
1380           var O, tag, result;
1381           return it === undefined ? 'Undefined' : it === null ? 'Null'
1382             // @@toStringTag case
1383             : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag
1384             // builtinTag case
1385             : CORRECT_ARGUMENTS ? classofRaw(O)
1386             // ES3 arguments fallback
1387             : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
1388         };
1389
1390         var TO_STRING_TAG_SUPPORT$1 = toStringTagSupport;
1391         var classof$a = classof$b;
1392
1393         // `Object.prototype.toString` method implementation
1394         // https://tc39.es/ecma262/#sec-object.prototype.tostring
1395         var objectToString$1 = TO_STRING_TAG_SUPPORT$1 ? {}.toString : function toString() {
1396           return '[object ' + classof$a(this) + ']';
1397         };
1398
1399         var TO_STRING_TAG_SUPPORT = toStringTagSupport;
1400         var redefine$c = redefine$g.exports;
1401         var toString$1 = objectToString$1;
1402
1403         // `Object.prototype.toString` method
1404         // https://tc39.es/ecma262/#sec-object.prototype.tostring
1405         if (!TO_STRING_TAG_SUPPORT) {
1406           redefine$c(Object.prototype, 'toString', toString$1, { unsafe: true });
1407         }
1408
1409         var toInteger$8 = toInteger$b;
1410         var requireObjectCoercible$b = requireObjectCoercible$e;
1411
1412         // `String.prototype.{ codePointAt, at }` methods implementation
1413         var createMethod$5 = function (CONVERT_TO_STRING) {
1414           return function ($this, pos) {
1415             var S = String(requireObjectCoercible$b($this));
1416             var position = toInteger$8(pos);
1417             var size = S.length;
1418             var first, second;
1419             if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
1420             first = S.charCodeAt(position);
1421             return first < 0xD800 || first > 0xDBFF || position + 1 === size
1422               || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
1423                 ? CONVERT_TO_STRING ? S.charAt(position) : first
1424                 : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
1425           };
1426         };
1427
1428         var stringMultibyte = {
1429           // `String.prototype.codePointAt` method
1430           // https://tc39.es/ecma262/#sec-string.prototype.codepointat
1431           codeAt: createMethod$5(false),
1432           // `String.prototype.at` method
1433           // https://github.com/mathiasbynens/String.prototype.at
1434           charAt: createMethod$5(true)
1435         };
1436
1437         var charAt$1 = stringMultibyte.charAt;
1438         var InternalStateModule$7 = internalState;
1439         var defineIterator$1 = defineIterator$3;
1440
1441         var STRING_ITERATOR = 'String Iterator';
1442         var setInternalState$7 = InternalStateModule$7.set;
1443         var getInternalState$5 = InternalStateModule$7.getterFor(STRING_ITERATOR);
1444
1445         // `String.prototype[@@iterator]` method
1446         // https://tc39.es/ecma262/#sec-string.prototype-@@iterator
1447         defineIterator$1(String, 'String', function (iterated) {
1448           setInternalState$7(this, {
1449             type: STRING_ITERATOR,
1450             string: String(iterated),
1451             index: 0
1452           });
1453         // `%StringIteratorPrototype%.next` method
1454         // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
1455         }, function next() {
1456           var state = getInternalState$5(this);
1457           var string = state.string;
1458           var index = state.index;
1459           var point;
1460           if (index >= string.length) return { value: undefined, done: true };
1461           point = charAt$1(string, index);
1462           state.index += point.length;
1463           return { value: point, done: false };
1464         });
1465
1466         // iterable DOM collections
1467         // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
1468         var domIterables = {
1469           CSSRuleList: 0,
1470           CSSStyleDeclaration: 0,
1471           CSSValueList: 0,
1472           ClientRectList: 0,
1473           DOMRectList: 0,
1474           DOMStringList: 0,
1475           DOMTokenList: 1,
1476           DataTransferItemList: 0,
1477           FileList: 0,
1478           HTMLAllCollection: 0,
1479           HTMLCollection: 0,
1480           HTMLFormElement: 0,
1481           HTMLSelectElement: 0,
1482           MediaList: 0,
1483           MimeTypeArray: 0,
1484           NamedNodeMap: 0,
1485           NodeList: 1,
1486           PaintRequestList: 0,
1487           Plugin: 0,
1488           PluginArray: 0,
1489           SVGLengthList: 0,
1490           SVGNumberList: 0,
1491           SVGPathSegList: 0,
1492           SVGPointList: 0,
1493           SVGStringList: 0,
1494           SVGTransformList: 0,
1495           SourceBufferList: 0,
1496           StyleSheetList: 0,
1497           TextTrackCueList: 0,
1498           TextTrackList: 0,
1499           TouchList: 0
1500         };
1501
1502         var global$t = global$F;
1503         var DOMIterables$1 = domIterables;
1504         var ArrayIteratorMethods = es_array_iterator;
1505         var createNonEnumerableProperty$7 = createNonEnumerableProperty$e;
1506         var wellKnownSymbol$k = wellKnownSymbol$s;
1507
1508         var ITERATOR$6 = wellKnownSymbol$k('iterator');
1509         var TO_STRING_TAG$1 = wellKnownSymbol$k('toStringTag');
1510         var ArrayValues = ArrayIteratorMethods.values;
1511
1512         for (var COLLECTION_NAME$1 in DOMIterables$1) {
1513           var Collection$1 = global$t[COLLECTION_NAME$1];
1514           var CollectionPrototype$1 = Collection$1 && Collection$1.prototype;
1515           if (CollectionPrototype$1) {
1516             // some Chrome versions have non-configurable methods on DOMTokenList
1517             if (CollectionPrototype$1[ITERATOR$6] !== ArrayValues) try {
1518               createNonEnumerableProperty$7(CollectionPrototype$1, ITERATOR$6, ArrayValues);
1519             } catch (error) {
1520               CollectionPrototype$1[ITERATOR$6] = ArrayValues;
1521             }
1522             if (!CollectionPrototype$1[TO_STRING_TAG$1]) {
1523               createNonEnumerableProperty$7(CollectionPrototype$1, TO_STRING_TAG$1, COLLECTION_NAME$1);
1524             }
1525             if (DOMIterables$1[COLLECTION_NAME$1]) for (var METHOD_NAME in ArrayIteratorMethods) {
1526               // some Chrome versions have non-configurable methods on DOMTokenList
1527               if (CollectionPrototype$1[METHOD_NAME] !== ArrayIteratorMethods[METHOD_NAME]) try {
1528                 createNonEnumerableProperty$7(CollectionPrototype$1, METHOD_NAME, ArrayIteratorMethods[METHOD_NAME]);
1529               } catch (error) {
1530                 CollectionPrototype$1[METHOD_NAME] = ArrayIteratorMethods[METHOD_NAME];
1531               }
1532             }
1533           }
1534         }
1535
1536         var classof$9 = classofRaw$1;
1537
1538         // `IsArray` abstract operation
1539         // https://tc39.es/ecma262/#sec-isarray
1540         // eslint-disable-next-line es/no-array-isarray -- safe
1541         var isArray$6 = Array.isArray || function isArray(arg) {
1542           return classof$9(arg) == 'Array';
1543         };
1544
1545         var objectGetOwnPropertyNamesExternal = {};
1546
1547         /* eslint-disable es/no-object-getownpropertynames -- safe */
1548
1549         var toIndexedObject$6 = toIndexedObject$b;
1550         var $getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
1551
1552         var toString = {}.toString;
1553
1554         var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames
1555           ? Object.getOwnPropertyNames(window) : [];
1556
1557         var getWindowNames = function (it) {
1558           try {
1559             return $getOwnPropertyNames$1(it);
1560           } catch (error) {
1561             return windowNames.slice();
1562           }
1563         };
1564
1565         // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
1566         objectGetOwnPropertyNamesExternal.f = function getOwnPropertyNames(it) {
1567           return windowNames && toString.call(it) == '[object Window]'
1568             ? getWindowNames(it)
1569             : $getOwnPropertyNames$1(toIndexedObject$6(it));
1570         };
1571
1572         var aFunction$9 = function (it) {
1573           if (typeof it != 'function') {
1574             throw TypeError(String(it) + ' is not a function');
1575           } return it;
1576         };
1577
1578         var aFunction$8 = aFunction$9;
1579
1580         // optional / simple context binding
1581         var functionBindContext = function (fn, that, length) {
1582           aFunction$8(fn);
1583           if (that === undefined) return fn;
1584           switch (length) {
1585             case 0: return function () {
1586               return fn.call(that);
1587             };
1588             case 1: return function (a) {
1589               return fn.call(that, a);
1590             };
1591             case 2: return function (a, b) {
1592               return fn.call(that, a, b);
1593             };
1594             case 3: return function (a, b, c) {
1595               return fn.call(that, a, b, c);
1596             };
1597           }
1598           return function (/* ...args */) {
1599             return fn.apply(that, arguments);
1600           };
1601         };
1602
1603         var isObject$l = isObject$r;
1604         var isArray$5 = isArray$6;
1605         var wellKnownSymbol$j = wellKnownSymbol$s;
1606
1607         var SPECIES$6 = wellKnownSymbol$j('species');
1608
1609         // `ArraySpeciesCreate` abstract operation
1610         // https://tc39.es/ecma262/#sec-arrayspeciescreate
1611         var arraySpeciesCreate$3 = function (originalArray, length) {
1612           var C;
1613           if (isArray$5(originalArray)) {
1614             C = originalArray.constructor;
1615             // cross-realm fallback
1616             if (typeof C == 'function' && (C === Array || isArray$5(C.prototype))) C = undefined;
1617             else if (isObject$l(C)) {
1618               C = C[SPECIES$6];
1619               if (C === null) C = undefined;
1620             }
1621           } return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
1622         };
1623
1624         var bind$b = functionBindContext;
1625         var IndexedObject$3 = indexedObject;
1626         var toObject$f = toObject$i;
1627         var toLength$o = toLength$q;
1628         var arraySpeciesCreate$2 = arraySpeciesCreate$3;
1629
1630         var push = [].push;
1631
1632         // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterOut }` methods implementation
1633         var createMethod$4 = function (TYPE) {
1634           var IS_MAP = TYPE == 1;
1635           var IS_FILTER = TYPE == 2;
1636           var IS_SOME = TYPE == 3;
1637           var IS_EVERY = TYPE == 4;
1638           var IS_FIND_INDEX = TYPE == 6;
1639           var IS_FILTER_OUT = TYPE == 7;
1640           var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
1641           return function ($this, callbackfn, that, specificCreate) {
1642             var O = toObject$f($this);
1643             var self = IndexedObject$3(O);
1644             var boundFunction = bind$b(callbackfn, that, 3);
1645             var length = toLength$o(self.length);
1646             var index = 0;
1647             var create = specificCreate || arraySpeciesCreate$2;
1648             var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_OUT ? create($this, 0) : undefined;
1649             var value, result;
1650             for (;length > index; index++) if (NO_HOLES || index in self) {
1651               value = self[index];
1652               result = boundFunction(value, index, O);
1653               if (TYPE) {
1654                 if (IS_MAP) target[index] = result; // map
1655                 else if (result) switch (TYPE) {
1656                   case 3: return true;              // some
1657                   case 5: return value;             // find
1658                   case 6: return index;             // findIndex
1659                   case 2: push.call(target, value); // filter
1660                 } else switch (TYPE) {
1661                   case 4: return false;             // every
1662                   case 7: push.call(target, value); // filterOut
1663                 }
1664               }
1665             }
1666             return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
1667           };
1668         };
1669
1670         var arrayIteration = {
1671           // `Array.prototype.forEach` method
1672           // https://tc39.es/ecma262/#sec-array.prototype.foreach
1673           forEach: createMethod$4(0),
1674           // `Array.prototype.map` method
1675           // https://tc39.es/ecma262/#sec-array.prototype.map
1676           map: createMethod$4(1),
1677           // `Array.prototype.filter` method
1678           // https://tc39.es/ecma262/#sec-array.prototype.filter
1679           filter: createMethod$4(2),
1680           // `Array.prototype.some` method
1681           // https://tc39.es/ecma262/#sec-array.prototype.some
1682           some: createMethod$4(3),
1683           // `Array.prototype.every` method
1684           // https://tc39.es/ecma262/#sec-array.prototype.every
1685           every: createMethod$4(4),
1686           // `Array.prototype.find` method
1687           // https://tc39.es/ecma262/#sec-array.prototype.find
1688           find: createMethod$4(5),
1689           // `Array.prototype.findIndex` method
1690           // https://tc39.es/ecma262/#sec-array.prototype.findIndex
1691           findIndex: createMethod$4(6),
1692           // `Array.prototype.filterOut` method
1693           // https://github.com/tc39/proposal-array-filtering
1694           filterOut: createMethod$4(7)
1695         };
1696
1697         var $$14 = _export;
1698         var global$s = global$F;
1699         var getBuiltIn$5 = getBuiltIn$9;
1700         var DESCRIPTORS$h = descriptors;
1701         var NATIVE_SYMBOL = nativeSymbol;
1702         var USE_SYMBOL_AS_UID = useSymbolAsUid;
1703         var fails$F = fails$N;
1704         var has$8 = has$j;
1705         var isArray$4 = isArray$6;
1706         var isObject$k = isObject$r;
1707         var anObject$g = anObject$m;
1708         var toObject$e = toObject$i;
1709         var toIndexedObject$5 = toIndexedObject$b;
1710         var toPrimitive$4 = toPrimitive$7;
1711         var createPropertyDescriptor$3 = createPropertyDescriptor$7;
1712         var nativeObjectCreate = objectCreate;
1713         var objectKeys$2 = objectKeys$4;
1714         var getOwnPropertyNamesModule = objectGetOwnPropertyNames;
1715         var getOwnPropertyNamesExternal = objectGetOwnPropertyNamesExternal;
1716         var getOwnPropertySymbolsModule$1 = objectGetOwnPropertySymbols;
1717         var getOwnPropertyDescriptorModule$2 = objectGetOwnPropertyDescriptor;
1718         var definePropertyModule$3 = objectDefineProperty;
1719         var propertyIsEnumerableModule$1 = objectPropertyIsEnumerable;
1720         var createNonEnumerableProperty$6 = createNonEnumerableProperty$e;
1721         var redefine$b = redefine$g.exports;
1722         var shared$1 = shared$5.exports;
1723         var sharedKey = sharedKey$4;
1724         var hiddenKeys$1 = hiddenKeys$6;
1725         var uid$2 = uid$5;
1726         var wellKnownSymbol$i = wellKnownSymbol$s;
1727         var wrappedWellKnownSymbolModule = wellKnownSymbolWrapped;
1728         var defineWellKnownSymbol$2 = defineWellKnownSymbol$4;
1729         var setToStringTag$7 = setToStringTag$a;
1730         var InternalStateModule$6 = internalState;
1731         var $forEach$2 = arrayIteration.forEach;
1732
1733         var HIDDEN = sharedKey('hidden');
1734         var SYMBOL = 'Symbol';
1735         var PROTOTYPE$1 = 'prototype';
1736         var TO_PRIMITIVE = wellKnownSymbol$i('toPrimitive');
1737         var setInternalState$6 = InternalStateModule$6.set;
1738         var getInternalState$4 = InternalStateModule$6.getterFor(SYMBOL);
1739         var ObjectPrototype$2 = Object[PROTOTYPE$1];
1740         var $Symbol = global$s.Symbol;
1741         var $stringify = getBuiltIn$5('JSON', 'stringify');
1742         var nativeGetOwnPropertyDescriptor$2 = getOwnPropertyDescriptorModule$2.f;
1743         var nativeDefineProperty$1 = definePropertyModule$3.f;
1744         var nativeGetOwnPropertyNames = getOwnPropertyNamesExternal.f;
1745         var nativePropertyIsEnumerable = propertyIsEnumerableModule$1.f;
1746         var AllSymbols = shared$1('symbols');
1747         var ObjectPrototypeSymbols = shared$1('op-symbols');
1748         var StringToSymbolRegistry = shared$1('string-to-symbol-registry');
1749         var SymbolToStringRegistry = shared$1('symbol-to-string-registry');
1750         var WellKnownSymbolsStore = shared$1('wks');
1751         var QObject = global$s.QObject;
1752         // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
1753         var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild;
1754
1755         // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
1756         var setSymbolDescriptor = DESCRIPTORS$h && fails$F(function () {
1757           return nativeObjectCreate(nativeDefineProperty$1({}, 'a', {
1758             get: function () { return nativeDefineProperty$1(this, 'a', { value: 7 }).a; }
1759           })).a != 7;
1760         }) ? function (O, P, Attributes) {
1761           var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$2(ObjectPrototype$2, P);
1762           if (ObjectPrototypeDescriptor) delete ObjectPrototype$2[P];
1763           nativeDefineProperty$1(O, P, Attributes);
1764           if (ObjectPrototypeDescriptor && O !== ObjectPrototype$2) {
1765             nativeDefineProperty$1(ObjectPrototype$2, P, ObjectPrototypeDescriptor);
1766           }
1767         } : nativeDefineProperty$1;
1768
1769         var wrap$2 = function (tag, description) {
1770           var symbol = AllSymbols[tag] = nativeObjectCreate($Symbol[PROTOTYPE$1]);
1771           setInternalState$6(symbol, {
1772             type: SYMBOL,
1773             tag: tag,
1774             description: description
1775           });
1776           if (!DESCRIPTORS$h) symbol.description = description;
1777           return symbol;
1778         };
1779
1780         var isSymbol$1 = USE_SYMBOL_AS_UID ? function (it) {
1781           return typeof it == 'symbol';
1782         } : function (it) {
1783           return Object(it) instanceof $Symbol;
1784         };
1785
1786         var $defineProperty = function defineProperty(O, P, Attributes) {
1787           if (O === ObjectPrototype$2) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
1788           anObject$g(O);
1789           var key = toPrimitive$4(P, true);
1790           anObject$g(Attributes);
1791           if (has$8(AllSymbols, key)) {
1792             if (!Attributes.enumerable) {
1793               if (!has$8(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor$3(1, {}));
1794               O[HIDDEN][key] = true;
1795             } else {
1796               if (has$8(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
1797               Attributes = nativeObjectCreate(Attributes, { enumerable: createPropertyDescriptor$3(0, false) });
1798             } return setSymbolDescriptor(O, key, Attributes);
1799           } return nativeDefineProperty$1(O, key, Attributes);
1800         };
1801
1802         var $defineProperties = function defineProperties(O, Properties) {
1803           anObject$g(O);
1804           var properties = toIndexedObject$5(Properties);
1805           var keys = objectKeys$2(properties).concat($getOwnPropertySymbols(properties));
1806           $forEach$2(keys, function (key) {
1807             if (!DESCRIPTORS$h || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
1808           });
1809           return O;
1810         };
1811
1812         var $create = function create(O, Properties) {
1813           return Properties === undefined ? nativeObjectCreate(O) : $defineProperties(nativeObjectCreate(O), Properties);
1814         };
1815
1816         var $propertyIsEnumerable = function propertyIsEnumerable(V) {
1817           var P = toPrimitive$4(V, true);
1818           var enumerable = nativePropertyIsEnumerable.call(this, P);
1819           if (this === ObjectPrototype$2 && has$8(AllSymbols, P) && !has$8(ObjectPrototypeSymbols, P)) return false;
1820           return enumerable || !has$8(this, P) || !has$8(AllSymbols, P) || has$8(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
1821         };
1822
1823         var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
1824           var it = toIndexedObject$5(O);
1825           var key = toPrimitive$4(P, true);
1826           if (it === ObjectPrototype$2 && has$8(AllSymbols, key) && !has$8(ObjectPrototypeSymbols, key)) return;
1827           var descriptor = nativeGetOwnPropertyDescriptor$2(it, key);
1828           if (descriptor && has$8(AllSymbols, key) && !(has$8(it, HIDDEN) && it[HIDDEN][key])) {
1829             descriptor.enumerable = true;
1830           }
1831           return descriptor;
1832         };
1833
1834         var $getOwnPropertyNames = function getOwnPropertyNames(O) {
1835           var names = nativeGetOwnPropertyNames(toIndexedObject$5(O));
1836           var result = [];
1837           $forEach$2(names, function (key) {
1838             if (!has$8(AllSymbols, key) && !has$8(hiddenKeys$1, key)) result.push(key);
1839           });
1840           return result;
1841         };
1842
1843         var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
1844           var IS_OBJECT_PROTOTYPE = O === ObjectPrototype$2;
1845           var names = nativeGetOwnPropertyNames(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject$5(O));
1846           var result = [];
1847           $forEach$2(names, function (key) {
1848             if (has$8(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has$8(ObjectPrototype$2, key))) {
1849               result.push(AllSymbols[key]);
1850             }
1851           });
1852           return result;
1853         };
1854
1855         // `Symbol` constructor
1856         // https://tc39.es/ecma262/#sec-symbol-constructor
1857         if (!NATIVE_SYMBOL) {
1858           $Symbol = function Symbol() {
1859             if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
1860             var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
1861             var tag = uid$2(description);
1862             var setter = function (value) {
1863               if (this === ObjectPrototype$2) setter.call(ObjectPrototypeSymbols, value);
1864               if (has$8(this, HIDDEN) && has$8(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
1865               setSymbolDescriptor(this, tag, createPropertyDescriptor$3(1, value));
1866             };
1867             if (DESCRIPTORS$h && USE_SETTER) setSymbolDescriptor(ObjectPrototype$2, tag, { configurable: true, set: setter });
1868             return wrap$2(tag, description);
1869           };
1870
1871           redefine$b($Symbol[PROTOTYPE$1], 'toString', function toString() {
1872             return getInternalState$4(this).tag;
1873           });
1874
1875           redefine$b($Symbol, 'withoutSetter', function (description) {
1876             return wrap$2(uid$2(description), description);
1877           });
1878
1879           propertyIsEnumerableModule$1.f = $propertyIsEnumerable;
1880           definePropertyModule$3.f = $defineProperty;
1881           getOwnPropertyDescriptorModule$2.f = $getOwnPropertyDescriptor;
1882           getOwnPropertyNamesModule.f = getOwnPropertyNamesExternal.f = $getOwnPropertyNames;
1883           getOwnPropertySymbolsModule$1.f = $getOwnPropertySymbols;
1884
1885           wrappedWellKnownSymbolModule.f = function (name) {
1886             return wrap$2(wellKnownSymbol$i(name), name);
1887           };
1888
1889           if (DESCRIPTORS$h) {
1890             // https://github.com/tc39/proposal-Symbol-description
1891             nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', {
1892               configurable: true,
1893               get: function description() {
1894                 return getInternalState$4(this).description;
1895               }
1896             });
1897             {
1898               redefine$b(ObjectPrototype$2, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true });
1899             }
1900           }
1901         }
1902
1903         $$14({ global: true, wrap: true, forced: !NATIVE_SYMBOL, sham: !NATIVE_SYMBOL }, {
1904           Symbol: $Symbol
1905         });
1906
1907         $forEach$2(objectKeys$2(WellKnownSymbolsStore), function (name) {
1908           defineWellKnownSymbol$2(name);
1909         });
1910
1911         $$14({ target: SYMBOL, stat: true, forced: !NATIVE_SYMBOL }, {
1912           // `Symbol.for` method
1913           // https://tc39.es/ecma262/#sec-symbol.for
1914           'for': function (key) {
1915             var string = String(key);
1916             if (has$8(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
1917             var symbol = $Symbol(string);
1918             StringToSymbolRegistry[string] = symbol;
1919             SymbolToStringRegistry[symbol] = string;
1920             return symbol;
1921           },
1922           // `Symbol.keyFor` method
1923           // https://tc39.es/ecma262/#sec-symbol.keyfor
1924           keyFor: function keyFor(sym) {
1925             if (!isSymbol$1(sym)) throw TypeError(sym + ' is not a symbol');
1926             if (has$8(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
1927           },
1928           useSetter: function () { USE_SETTER = true; },
1929           useSimple: function () { USE_SETTER = false; }
1930         });
1931
1932         $$14({ target: 'Object', stat: true, forced: !NATIVE_SYMBOL, sham: !DESCRIPTORS$h }, {
1933           // `Object.create` method
1934           // https://tc39.es/ecma262/#sec-object.create
1935           create: $create,
1936           // `Object.defineProperty` method
1937           // https://tc39.es/ecma262/#sec-object.defineproperty
1938           defineProperty: $defineProperty,
1939           // `Object.defineProperties` method
1940           // https://tc39.es/ecma262/#sec-object.defineproperties
1941           defineProperties: $defineProperties,
1942           // `Object.getOwnPropertyDescriptor` method
1943           // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
1944           getOwnPropertyDescriptor: $getOwnPropertyDescriptor
1945         });
1946
1947         $$14({ target: 'Object', stat: true, forced: !NATIVE_SYMBOL }, {
1948           // `Object.getOwnPropertyNames` method
1949           // https://tc39.es/ecma262/#sec-object.getownpropertynames
1950           getOwnPropertyNames: $getOwnPropertyNames,
1951           // `Object.getOwnPropertySymbols` method
1952           // https://tc39.es/ecma262/#sec-object.getownpropertysymbols
1953           getOwnPropertySymbols: $getOwnPropertySymbols
1954         });
1955
1956         // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
1957         // https://bugs.chromium.org/p/v8/issues/detail?id=3443
1958         $$14({ target: 'Object', stat: true, forced: fails$F(function () { getOwnPropertySymbolsModule$1.f(1); }) }, {
1959           getOwnPropertySymbols: function getOwnPropertySymbols(it) {
1960             return getOwnPropertySymbolsModule$1.f(toObject$e(it));
1961           }
1962         });
1963
1964         // `JSON.stringify` method behavior with symbols
1965         // https://tc39.es/ecma262/#sec-json.stringify
1966         if ($stringify) {
1967           var FORCED_JSON_STRINGIFY = !NATIVE_SYMBOL || fails$F(function () {
1968             var symbol = $Symbol();
1969             // MS Edge converts symbol values to JSON as {}
1970             return $stringify([symbol]) != '[null]'
1971               // WebKit converts symbol values to JSON as null
1972               || $stringify({ a: symbol }) != '{}'
1973               // V8 throws on boxed symbols
1974               || $stringify(Object(symbol)) != '{}';
1975           });
1976
1977           $$14({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, {
1978             // eslint-disable-next-line no-unused-vars -- required for `.length`
1979             stringify: function stringify(it, replacer, space) {
1980               var args = [it];
1981               var index = 1;
1982               var $replacer;
1983               while (arguments.length > index) args.push(arguments[index++]);
1984               $replacer = replacer;
1985               if (!isObject$k(replacer) && it === undefined || isSymbol$1(it)) return; // IE8 returns string on undefined
1986               if (!isArray$4(replacer)) replacer = function (key, value) {
1987                 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
1988                 if (!isSymbol$1(value)) return value;
1989               };
1990               args[1] = replacer;
1991               return $stringify.apply(null, args);
1992             }
1993           });
1994         }
1995
1996         // `Symbol.prototype[@@toPrimitive]` method
1997         // https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
1998         if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
1999           createNonEnumerableProperty$6($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
2000         }
2001         // `Symbol.prototype[@@toStringTag]` property
2002         // https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
2003         setToStringTag$7($Symbol, SYMBOL);
2004
2005         hiddenKeys$1[HIDDEN] = true;
2006
2007         var $$13 = _export;
2008         var DESCRIPTORS$g = descriptors;
2009         var global$r = global$F;
2010         var has$7 = has$j;
2011         var isObject$j = isObject$r;
2012         var defineProperty$8 = objectDefineProperty.f;
2013         var copyConstructorProperties = copyConstructorProperties$2;
2014
2015         var NativeSymbol = global$r.Symbol;
2016
2017         if (DESCRIPTORS$g && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) ||
2018           // Safari 12 bug
2019           NativeSymbol().description !== undefined
2020         )) {
2021           var EmptyStringDescriptionStore = {};
2022           // wrap Symbol constructor for correct work with undefined description
2023           var SymbolWrapper = function Symbol() {
2024             var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
2025             var result = this instanceof SymbolWrapper
2026               ? new NativeSymbol(description)
2027               // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
2028               : description === undefined ? NativeSymbol() : NativeSymbol(description);
2029             if (description === '') EmptyStringDescriptionStore[result] = true;
2030             return result;
2031           };
2032           copyConstructorProperties(SymbolWrapper, NativeSymbol);
2033           var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
2034           symbolPrototype.constructor = SymbolWrapper;
2035
2036           var symbolToString = symbolPrototype.toString;
2037           var native = String(NativeSymbol('test')) == 'Symbol(test)';
2038           var regexp = /^Symbol\((.*)\)[^)]+$/;
2039           defineProperty$8(symbolPrototype, 'description', {
2040             configurable: true,
2041             get: function description() {
2042               var symbol = isObject$j(this) ? this.valueOf() : this;
2043               var string = symbolToString.call(symbol);
2044               if (has$7(EmptyStringDescriptionStore, symbol)) return '';
2045               var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
2046               return desc === '' ? undefined : desc;
2047             }
2048           });
2049
2050           $$13({ global: true, forced: true }, {
2051             Symbol: SymbolWrapper
2052           });
2053         }
2054
2055         // eslint-disable-next-line es/no-typed-arrays -- safe
2056         var arrayBufferNative = typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined';
2057
2058         var redefine$a = redefine$g.exports;
2059
2060         var redefineAll$4 = function (target, src, options) {
2061           for (var key in src) redefine$a(target, key, src[key], options);
2062           return target;
2063         };
2064
2065         var anInstance$7 = function (it, Constructor, name) {
2066           if (!(it instanceof Constructor)) {
2067             throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
2068           } return it;
2069         };
2070
2071         var toInteger$7 = toInteger$b;
2072         var toLength$n = toLength$q;
2073
2074         // `ToIndex` abstract operation
2075         // https://tc39.es/ecma262/#sec-toindex
2076         var toIndex$2 = function (it) {
2077           if (it === undefined) return 0;
2078           var number = toInteger$7(it);
2079           var length = toLength$n(number);
2080           if (number !== length) throw RangeError('Wrong length or index');
2081           return length;
2082         };
2083
2084         // IEEE754 conversions based on https://github.com/feross/ieee754
2085         var abs$4 = Math.abs;
2086         var pow$2 = Math.pow;
2087         var floor$6 = Math.floor;
2088         var log$2 = Math.log;
2089         var LN2 = Math.LN2;
2090
2091         var pack = function (number, mantissaLength, bytes) {
2092           var buffer = new Array(bytes);
2093           var exponentLength = bytes * 8 - mantissaLength - 1;
2094           var eMax = (1 << exponentLength) - 1;
2095           var eBias = eMax >> 1;
2096           var rt = mantissaLength === 23 ? pow$2(2, -24) - pow$2(2, -77) : 0;
2097           var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
2098           var index = 0;
2099           var exponent, mantissa, c;
2100           number = abs$4(number);
2101           // eslint-disable-next-line no-self-compare -- NaN check
2102           if (number != number || number === Infinity) {
2103             // eslint-disable-next-line no-self-compare -- NaN check
2104             mantissa = number != number ? 1 : 0;
2105             exponent = eMax;
2106           } else {
2107             exponent = floor$6(log$2(number) / LN2);
2108             if (number * (c = pow$2(2, -exponent)) < 1) {
2109               exponent--;
2110               c *= 2;
2111             }
2112             if (exponent + eBias >= 1) {
2113               number += rt / c;
2114             } else {
2115               number += rt * pow$2(2, 1 - eBias);
2116             }
2117             if (number * c >= 2) {
2118               exponent++;
2119               c /= 2;
2120             }
2121             if (exponent + eBias >= eMax) {
2122               mantissa = 0;
2123               exponent = eMax;
2124             } else if (exponent + eBias >= 1) {
2125               mantissa = (number * c - 1) * pow$2(2, mantissaLength);
2126               exponent = exponent + eBias;
2127             } else {
2128               mantissa = number * pow$2(2, eBias - 1) * pow$2(2, mantissaLength);
2129               exponent = 0;
2130             }
2131           }
2132           for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);
2133           exponent = exponent << mantissaLength | mantissa;
2134           exponentLength += mantissaLength;
2135           for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);
2136           buffer[--index] |= sign * 128;
2137           return buffer;
2138         };
2139
2140         var unpack = function (buffer, mantissaLength) {
2141           var bytes = buffer.length;
2142           var exponentLength = bytes * 8 - mantissaLength - 1;
2143           var eMax = (1 << exponentLength) - 1;
2144           var eBias = eMax >> 1;
2145           var nBits = exponentLength - 7;
2146           var index = bytes - 1;
2147           var sign = buffer[index--];
2148           var exponent = sign & 127;
2149           var mantissa;
2150           sign >>= 7;
2151           for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);
2152           mantissa = exponent & (1 << -nBits) - 1;
2153           exponent >>= -nBits;
2154           nBits += mantissaLength;
2155           for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);
2156           if (exponent === 0) {
2157             exponent = 1 - eBias;
2158           } else if (exponent === eMax) {
2159             return mantissa ? NaN : sign ? -Infinity : Infinity;
2160           } else {
2161             mantissa = mantissa + pow$2(2, mantissaLength);
2162             exponent = exponent - eBias;
2163           } return (sign ? -1 : 1) * mantissa * pow$2(2, exponent - mantissaLength);
2164         };
2165
2166         var ieee754$2 = {
2167           pack: pack,
2168           unpack: unpack
2169         };
2170
2171         var toObject$d = toObject$i;
2172         var toAbsoluteIndex$6 = toAbsoluteIndex$8;
2173         var toLength$m = toLength$q;
2174
2175         // `Array.prototype.fill` method implementation
2176         // https://tc39.es/ecma262/#sec-array.prototype.fill
2177         var arrayFill$1 = function fill(value /* , start = 0, end = @length */) {
2178           var O = toObject$d(this);
2179           var length = toLength$m(O.length);
2180           var argumentsLength = arguments.length;
2181           var index = toAbsoluteIndex$6(argumentsLength > 1 ? arguments[1] : undefined, length);
2182           var end = argumentsLength > 2 ? arguments[2] : undefined;
2183           var endPos = end === undefined ? length : toAbsoluteIndex$6(end, length);
2184           while (endPos > index) O[index++] = value;
2185           return O;
2186         };
2187
2188         var global$q = global$F;
2189         var DESCRIPTORS$f = descriptors;
2190         var NATIVE_ARRAY_BUFFER$2 = arrayBufferNative;
2191         var createNonEnumerableProperty$5 = createNonEnumerableProperty$e;
2192         var redefineAll$3 = redefineAll$4;
2193         var fails$E = fails$N;
2194         var anInstance$6 = anInstance$7;
2195         var toInteger$6 = toInteger$b;
2196         var toLength$l = toLength$q;
2197         var toIndex$1 = toIndex$2;
2198         var IEEE754 = ieee754$2;
2199         var getPrototypeOf$2 = objectGetPrototypeOf;
2200         var setPrototypeOf$5 = objectSetPrototypeOf;
2201         var getOwnPropertyNames$4 = objectGetOwnPropertyNames.f;
2202         var defineProperty$7 = objectDefineProperty.f;
2203         var arrayFill = arrayFill$1;
2204         var setToStringTag$6 = setToStringTag$a;
2205         var InternalStateModule$5 = internalState;
2206
2207         var getInternalState$3 = InternalStateModule$5.get;
2208         var setInternalState$5 = InternalStateModule$5.set;
2209         var ARRAY_BUFFER$1 = 'ArrayBuffer';
2210         var DATA_VIEW = 'DataView';
2211         var PROTOTYPE = 'prototype';
2212         var WRONG_LENGTH$1 = 'Wrong length';
2213         var WRONG_INDEX = 'Wrong index';
2214         var NativeArrayBuffer$1 = global$q[ARRAY_BUFFER$1];
2215         var $ArrayBuffer = NativeArrayBuffer$1;
2216         var $DataView = global$q[DATA_VIEW];
2217         var $DataViewPrototype = $DataView && $DataView[PROTOTYPE];
2218         var ObjectPrototype$1 = Object.prototype;
2219         var RangeError$2 = global$q.RangeError;
2220
2221         var packIEEE754 = IEEE754.pack;
2222         var unpackIEEE754 = IEEE754.unpack;
2223
2224         var packInt8 = function (number) {
2225           return [number & 0xFF];
2226         };
2227
2228         var packInt16 = function (number) {
2229           return [number & 0xFF, number >> 8 & 0xFF];
2230         };
2231
2232         var packInt32 = function (number) {
2233           return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
2234         };
2235
2236         var unpackInt32 = function (buffer) {
2237           return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
2238         };
2239
2240         var packFloat32 = function (number) {
2241           return packIEEE754(number, 23, 4);
2242         };
2243
2244         var packFloat64 = function (number) {
2245           return packIEEE754(number, 52, 8);
2246         };
2247
2248         var addGetter$1 = function (Constructor, key) {
2249           defineProperty$7(Constructor[PROTOTYPE], key, { get: function () { return getInternalState$3(this)[key]; } });
2250         };
2251
2252         var get$4 = function (view, count, index, isLittleEndian) {
2253           var intIndex = toIndex$1(index);
2254           var store = getInternalState$3(view);
2255           if (intIndex + count > store.byteLength) throw RangeError$2(WRONG_INDEX);
2256           var bytes = getInternalState$3(store.buffer).bytes;
2257           var start = intIndex + store.byteOffset;
2258           var pack = bytes.slice(start, start + count);
2259           return isLittleEndian ? pack : pack.reverse();
2260         };
2261
2262         var set$3 = function (view, count, index, conversion, value, isLittleEndian) {
2263           var intIndex = toIndex$1(index);
2264           var store = getInternalState$3(view);
2265           if (intIndex + count > store.byteLength) throw RangeError$2(WRONG_INDEX);
2266           var bytes = getInternalState$3(store.buffer).bytes;
2267           var start = intIndex + store.byteOffset;
2268           var pack = conversion(+value);
2269           for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
2270         };
2271
2272         if (!NATIVE_ARRAY_BUFFER$2) {
2273           $ArrayBuffer = function ArrayBuffer(length) {
2274             anInstance$6(this, $ArrayBuffer, ARRAY_BUFFER$1);
2275             var byteLength = toIndex$1(length);
2276             setInternalState$5(this, {
2277               bytes: arrayFill.call(new Array(byteLength), 0),
2278               byteLength: byteLength
2279             });
2280             if (!DESCRIPTORS$f) this.byteLength = byteLength;
2281           };
2282
2283           $DataView = function DataView(buffer, byteOffset, byteLength) {
2284             anInstance$6(this, $DataView, DATA_VIEW);
2285             anInstance$6(buffer, $ArrayBuffer, DATA_VIEW);
2286             var bufferLength = getInternalState$3(buffer).byteLength;
2287             var offset = toInteger$6(byteOffset);
2288             if (offset < 0 || offset > bufferLength) throw RangeError$2('Wrong offset');
2289             byteLength = byteLength === undefined ? bufferLength - offset : toLength$l(byteLength);
2290             if (offset + byteLength > bufferLength) throw RangeError$2(WRONG_LENGTH$1);
2291             setInternalState$5(this, {
2292               buffer: buffer,
2293               byteLength: byteLength,
2294               byteOffset: offset
2295             });
2296             if (!DESCRIPTORS$f) {
2297               this.buffer = buffer;
2298               this.byteLength = byteLength;
2299               this.byteOffset = offset;
2300             }
2301           };
2302
2303           if (DESCRIPTORS$f) {
2304             addGetter$1($ArrayBuffer, 'byteLength');
2305             addGetter$1($DataView, 'buffer');
2306             addGetter$1($DataView, 'byteLength');
2307             addGetter$1($DataView, 'byteOffset');
2308           }
2309
2310           redefineAll$3($DataView[PROTOTYPE], {
2311             getInt8: function getInt8(byteOffset) {
2312               return get$4(this, 1, byteOffset)[0] << 24 >> 24;
2313             },
2314             getUint8: function getUint8(byteOffset) {
2315               return get$4(this, 1, byteOffset)[0];
2316             },
2317             getInt16: function getInt16(byteOffset /* , littleEndian */) {
2318               var bytes = get$4(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2319               return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
2320             },
2321             getUint16: function getUint16(byteOffset /* , littleEndian */) {
2322               var bytes = get$4(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2323               return bytes[1] << 8 | bytes[0];
2324             },
2325             getInt32: function getInt32(byteOffset /* , littleEndian */) {
2326               return unpackInt32(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
2327             },
2328             getUint32: function getUint32(byteOffset /* , littleEndian */) {
2329               return unpackInt32(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
2330             },
2331             getFloat32: function getFloat32(byteOffset /* , littleEndian */) {
2332               return unpackIEEE754(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
2333             },
2334             getFloat64: function getFloat64(byteOffset /* , littleEndian */) {
2335               return unpackIEEE754(get$4(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
2336             },
2337             setInt8: function setInt8(byteOffset, value) {
2338               set$3(this, 1, byteOffset, packInt8, value);
2339             },
2340             setUint8: function setUint8(byteOffset, value) {
2341               set$3(this, 1, byteOffset, packInt8, value);
2342             },
2343             setInt16: function setInt16(byteOffset, value /* , littleEndian */) {
2344               set$3(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2345             },
2346             setUint16: function setUint16(byteOffset, value /* , littleEndian */) {
2347               set$3(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2348             },
2349             setInt32: function setInt32(byteOffset, value /* , littleEndian */) {
2350               set$3(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2351             },
2352             setUint32: function setUint32(byteOffset, value /* , littleEndian */) {
2353               set$3(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2354             },
2355             setFloat32: function setFloat32(byteOffset, value /* , littleEndian */) {
2356               set$3(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
2357             },
2358             setFloat64: function setFloat64(byteOffset, value /* , littleEndian */) {
2359               set$3(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
2360             }
2361           });
2362         } else {
2363           /* eslint-disable no-new -- required for testing */
2364           if (!fails$E(function () {
2365             NativeArrayBuffer$1(1);
2366           }) || !fails$E(function () {
2367             new NativeArrayBuffer$1(-1);
2368           }) || fails$E(function () {
2369             new NativeArrayBuffer$1();
2370             new NativeArrayBuffer$1(1.5);
2371             new NativeArrayBuffer$1(NaN);
2372             return NativeArrayBuffer$1.name != ARRAY_BUFFER$1;
2373           })) {
2374           /* eslint-enable no-new -- required for testing */
2375             $ArrayBuffer = function ArrayBuffer(length) {
2376               anInstance$6(this, $ArrayBuffer);
2377               return new NativeArrayBuffer$1(toIndex$1(length));
2378             };
2379             var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE] = NativeArrayBuffer$1[PROTOTYPE];
2380             for (var keys$2 = getOwnPropertyNames$4(NativeArrayBuffer$1), j$2 = 0, key$1; keys$2.length > j$2;) {
2381               if (!((key$1 = keys$2[j$2++]) in $ArrayBuffer)) {
2382                 createNonEnumerableProperty$5($ArrayBuffer, key$1, NativeArrayBuffer$1[key$1]);
2383               }
2384             }
2385             ArrayBufferPrototype.constructor = $ArrayBuffer;
2386           }
2387
2388           // WebKit bug - the same parent prototype for typed arrays and data view
2389           if (setPrototypeOf$5 && getPrototypeOf$2($DataViewPrototype) !== ObjectPrototype$1) {
2390             setPrototypeOf$5($DataViewPrototype, ObjectPrototype$1);
2391           }
2392
2393           // iOS Safari 7.x bug
2394           var testView = new $DataView(new $ArrayBuffer(2));
2395           var $setInt8 = $DataViewPrototype.setInt8;
2396           testView.setInt8(0, 2147483648);
2397           testView.setInt8(1, 2147483649);
2398           if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll$3($DataViewPrototype, {
2399             setInt8: function setInt8(byteOffset, value) {
2400               $setInt8.call(this, byteOffset, value << 24 >> 24);
2401             },
2402             setUint8: function setUint8(byteOffset, value) {
2403               $setInt8.call(this, byteOffset, value << 24 >> 24);
2404             }
2405           }, { unsafe: true });
2406         }
2407
2408         setToStringTag$6($ArrayBuffer, ARRAY_BUFFER$1);
2409         setToStringTag$6($DataView, DATA_VIEW);
2410
2411         var arrayBuffer = {
2412           ArrayBuffer: $ArrayBuffer,
2413           DataView: $DataView
2414         };
2415
2416         var anObject$f = anObject$m;
2417         var aFunction$7 = aFunction$9;
2418         var wellKnownSymbol$h = wellKnownSymbol$s;
2419
2420         var SPECIES$5 = wellKnownSymbol$h('species');
2421
2422         // `SpeciesConstructor` abstract operation
2423         // https://tc39.es/ecma262/#sec-speciesconstructor
2424         var speciesConstructor$8 = function (O, defaultConstructor) {
2425           var C = anObject$f(O).constructor;
2426           var S;
2427           return C === undefined || (S = anObject$f(C)[SPECIES$5]) == undefined ? defaultConstructor : aFunction$7(S);
2428         };
2429
2430         var $$12 = _export;
2431         var fails$D = fails$N;
2432         var ArrayBufferModule$2 = arrayBuffer;
2433         var anObject$e = anObject$m;
2434         var toAbsoluteIndex$5 = toAbsoluteIndex$8;
2435         var toLength$k = toLength$q;
2436         var speciesConstructor$7 = speciesConstructor$8;
2437
2438         var ArrayBuffer$4 = ArrayBufferModule$2.ArrayBuffer;
2439         var DataView$2 = ArrayBufferModule$2.DataView;
2440         var nativeArrayBufferSlice = ArrayBuffer$4.prototype.slice;
2441
2442         var INCORRECT_SLICE = fails$D(function () {
2443           return !new ArrayBuffer$4(2).slice(1, undefined).byteLength;
2444         });
2445
2446         // `ArrayBuffer.prototype.slice` method
2447         // https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
2448         $$12({ target: 'ArrayBuffer', proto: true, unsafe: true, forced: INCORRECT_SLICE }, {
2449           slice: function slice(start, end) {
2450             if (nativeArrayBufferSlice !== undefined && end === undefined) {
2451               return nativeArrayBufferSlice.call(anObject$e(this), start); // FF fix
2452             }
2453             var length = anObject$e(this).byteLength;
2454             var first = toAbsoluteIndex$5(start, length);
2455             var fin = toAbsoluteIndex$5(end === undefined ? length : end, length);
2456             var result = new (speciesConstructor$7(this, ArrayBuffer$4))(toLength$k(fin - first));
2457             var viewSource = new DataView$2(this);
2458             var viewTarget = new DataView$2(result);
2459             var index = 0;
2460             while (first < fin) {
2461               viewTarget.setUint8(index++, viewSource.getUint8(first++));
2462             } return result;
2463           }
2464         });
2465
2466         var $$11 = _export;
2467         var ArrayBufferModule$1 = arrayBuffer;
2468         var NATIVE_ARRAY_BUFFER$1 = arrayBufferNative;
2469
2470         // `DataView` constructor
2471         // https://tc39.es/ecma262/#sec-dataview-constructor
2472         $$11({ global: true, forced: !NATIVE_ARRAY_BUFFER$1 }, {
2473           DataView: ArrayBufferModule$1.DataView
2474         });
2475
2476         var NATIVE_ARRAY_BUFFER = arrayBufferNative;
2477         var DESCRIPTORS$e = descriptors;
2478         var global$p = global$F;
2479         var isObject$i = isObject$r;
2480         var has$6 = has$j;
2481         var classof$8 = classof$b;
2482         var createNonEnumerableProperty$4 = createNonEnumerableProperty$e;
2483         var redefine$9 = redefine$g.exports;
2484         var defineProperty$6 = objectDefineProperty.f;
2485         var getPrototypeOf$1 = objectGetPrototypeOf;
2486         var setPrototypeOf$4 = objectSetPrototypeOf;
2487         var wellKnownSymbol$g = wellKnownSymbol$s;
2488         var uid$1 = uid$5;
2489
2490         var Int8Array$3 = global$p.Int8Array;
2491         var Int8ArrayPrototype = Int8Array$3 && Int8Array$3.prototype;
2492         var Uint8ClampedArray = global$p.Uint8ClampedArray;
2493         var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
2494         var TypedArray$1 = Int8Array$3 && getPrototypeOf$1(Int8Array$3);
2495         var TypedArrayPrototype$1 = Int8ArrayPrototype && getPrototypeOf$1(Int8ArrayPrototype);
2496         var ObjectPrototype = Object.prototype;
2497         var isPrototypeOf = ObjectPrototype.isPrototypeOf;
2498
2499         var TO_STRING_TAG = wellKnownSymbol$g('toStringTag');
2500         var TYPED_ARRAY_TAG$1 = uid$1('TYPED_ARRAY_TAG');
2501         // Fixing native typed arrays in Opera Presto crashes the browser, see #595
2502         var NATIVE_ARRAY_BUFFER_VIEWS$3 = NATIVE_ARRAY_BUFFER && !!setPrototypeOf$4 && classof$8(global$p.opera) !== 'Opera';
2503         var TYPED_ARRAY_TAG_REQIRED = false;
2504         var NAME$1;
2505
2506         var TypedArrayConstructorsList = {
2507           Int8Array: 1,
2508           Uint8Array: 1,
2509           Uint8ClampedArray: 1,
2510           Int16Array: 2,
2511           Uint16Array: 2,
2512           Int32Array: 4,
2513           Uint32Array: 4,
2514           Float32Array: 4,
2515           Float64Array: 8
2516         };
2517
2518         var BigIntArrayConstructorsList = {
2519           BigInt64Array: 8,
2520           BigUint64Array: 8
2521         };
2522
2523         var isView = function isView(it) {
2524           if (!isObject$i(it)) return false;
2525           var klass = classof$8(it);
2526           return klass === 'DataView'
2527             || has$6(TypedArrayConstructorsList, klass)
2528             || has$6(BigIntArrayConstructorsList, klass);
2529         };
2530
2531         var isTypedArray$1 = function (it) {
2532           if (!isObject$i(it)) return false;
2533           var klass = classof$8(it);
2534           return has$6(TypedArrayConstructorsList, klass)
2535             || has$6(BigIntArrayConstructorsList, klass);
2536         };
2537
2538         var aTypedArray$m = function (it) {
2539           if (isTypedArray$1(it)) return it;
2540           throw TypeError('Target is not a typed array');
2541         };
2542
2543         var aTypedArrayConstructor$5 = function (C) {
2544           if (setPrototypeOf$4) {
2545             if (isPrototypeOf.call(TypedArray$1, C)) return C;
2546           } else for (var ARRAY in TypedArrayConstructorsList) if (has$6(TypedArrayConstructorsList, NAME$1)) {
2547             var TypedArrayConstructor = global$p[ARRAY];
2548             if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
2549               return C;
2550             }
2551           } throw TypeError('Target is not a typed array constructor');
2552         };
2553
2554         var exportTypedArrayMethod$n = function (KEY, property, forced) {
2555           if (!DESCRIPTORS$e) return;
2556           if (forced) for (var ARRAY in TypedArrayConstructorsList) {
2557             var TypedArrayConstructor = global$p[ARRAY];
2558             if (TypedArrayConstructor && has$6(TypedArrayConstructor.prototype, KEY)) try {
2559               delete TypedArrayConstructor.prototype[KEY];
2560             } catch (error) { /* empty */ }
2561           }
2562           if (!TypedArrayPrototype$1[KEY] || forced) {
2563             redefine$9(TypedArrayPrototype$1, KEY, forced ? property
2564               : NATIVE_ARRAY_BUFFER_VIEWS$3 && Int8ArrayPrototype[KEY] || property);
2565           }
2566         };
2567
2568         var exportTypedArrayStaticMethod$1 = function (KEY, property, forced) {
2569           var ARRAY, TypedArrayConstructor;
2570           if (!DESCRIPTORS$e) return;
2571           if (setPrototypeOf$4) {
2572             if (forced) for (ARRAY in TypedArrayConstructorsList) {
2573               TypedArrayConstructor = global$p[ARRAY];
2574               if (TypedArrayConstructor && has$6(TypedArrayConstructor, KEY)) try {
2575                 delete TypedArrayConstructor[KEY];
2576               } catch (error) { /* empty */ }
2577             }
2578             if (!TypedArray$1[KEY] || forced) {
2579               // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
2580               try {
2581                 return redefine$9(TypedArray$1, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS$3 && TypedArray$1[KEY] || property);
2582               } catch (error) { /* empty */ }
2583             } else return;
2584           }
2585           for (ARRAY in TypedArrayConstructorsList) {
2586             TypedArrayConstructor = global$p[ARRAY];
2587             if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
2588               redefine$9(TypedArrayConstructor, KEY, property);
2589             }
2590           }
2591         };
2592
2593         for (NAME$1 in TypedArrayConstructorsList) {
2594           if (!global$p[NAME$1]) NATIVE_ARRAY_BUFFER_VIEWS$3 = false;
2595         }
2596
2597         // WebKit bug - typed arrays constructors prototype is Object.prototype
2598         if (!NATIVE_ARRAY_BUFFER_VIEWS$3 || typeof TypedArray$1 != 'function' || TypedArray$1 === Function.prototype) {
2599           // eslint-disable-next-line no-shadow -- safe
2600           TypedArray$1 = function TypedArray() {
2601             throw TypeError('Incorrect invocation');
2602           };
2603           if (NATIVE_ARRAY_BUFFER_VIEWS$3) for (NAME$1 in TypedArrayConstructorsList) {
2604             if (global$p[NAME$1]) setPrototypeOf$4(global$p[NAME$1], TypedArray$1);
2605           }
2606         }
2607
2608         if (!NATIVE_ARRAY_BUFFER_VIEWS$3 || !TypedArrayPrototype$1 || TypedArrayPrototype$1 === ObjectPrototype) {
2609           TypedArrayPrototype$1 = TypedArray$1.prototype;
2610           if (NATIVE_ARRAY_BUFFER_VIEWS$3) for (NAME$1 in TypedArrayConstructorsList) {
2611             if (global$p[NAME$1]) setPrototypeOf$4(global$p[NAME$1].prototype, TypedArrayPrototype$1);
2612           }
2613         }
2614
2615         // WebKit bug - one more object in Uint8ClampedArray prototype chain
2616         if (NATIVE_ARRAY_BUFFER_VIEWS$3 && getPrototypeOf$1(Uint8ClampedArrayPrototype) !== TypedArrayPrototype$1) {
2617           setPrototypeOf$4(Uint8ClampedArrayPrototype, TypedArrayPrototype$1);
2618         }
2619
2620         if (DESCRIPTORS$e && !has$6(TypedArrayPrototype$1, TO_STRING_TAG)) {
2621           TYPED_ARRAY_TAG_REQIRED = true;
2622           defineProperty$6(TypedArrayPrototype$1, TO_STRING_TAG, { get: function () {
2623             return isObject$i(this) ? this[TYPED_ARRAY_TAG$1] : undefined;
2624           } });
2625           for (NAME$1 in TypedArrayConstructorsList) if (global$p[NAME$1]) {
2626             createNonEnumerableProperty$4(global$p[NAME$1], TYPED_ARRAY_TAG$1, NAME$1);
2627           }
2628         }
2629
2630         var arrayBufferViewCore = {
2631           NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS$3,
2632           TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG$1,
2633           aTypedArray: aTypedArray$m,
2634           aTypedArrayConstructor: aTypedArrayConstructor$5,
2635           exportTypedArrayMethod: exportTypedArrayMethod$n,
2636           exportTypedArrayStaticMethod: exportTypedArrayStaticMethod$1,
2637           isView: isView,
2638           isTypedArray: isTypedArray$1,
2639           TypedArray: TypedArray$1,
2640           TypedArrayPrototype: TypedArrayPrototype$1
2641         };
2642
2643         var $$10 = _export;
2644         var ArrayBufferViewCore$n = arrayBufferViewCore;
2645
2646         var NATIVE_ARRAY_BUFFER_VIEWS$2 = ArrayBufferViewCore$n.NATIVE_ARRAY_BUFFER_VIEWS;
2647
2648         // `ArrayBuffer.isView` method
2649         // https://tc39.es/ecma262/#sec-arraybuffer.isview
2650         $$10({ target: 'ArrayBuffer', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS$2 }, {
2651           isView: ArrayBufferViewCore$n.isView
2652         });
2653
2654         var getBuiltIn$4 = getBuiltIn$9;
2655         var definePropertyModule$2 = objectDefineProperty;
2656         var wellKnownSymbol$f = wellKnownSymbol$s;
2657         var DESCRIPTORS$d = descriptors;
2658
2659         var SPECIES$4 = wellKnownSymbol$f('species');
2660
2661         var setSpecies$5 = function (CONSTRUCTOR_NAME) {
2662           var Constructor = getBuiltIn$4(CONSTRUCTOR_NAME);
2663           var defineProperty = definePropertyModule$2.f;
2664
2665           if (DESCRIPTORS$d && Constructor && !Constructor[SPECIES$4]) {
2666             defineProperty(Constructor, SPECIES$4, {
2667               configurable: true,
2668               get: function () { return this; }
2669             });
2670           }
2671         };
2672
2673         var $$$ = _export;
2674         var global$o = global$F;
2675         var arrayBufferModule = arrayBuffer;
2676         var setSpecies$4 = setSpecies$5;
2677
2678         var ARRAY_BUFFER = 'ArrayBuffer';
2679         var ArrayBuffer$3 = arrayBufferModule[ARRAY_BUFFER];
2680         var NativeArrayBuffer = global$o[ARRAY_BUFFER];
2681
2682         // `ArrayBuffer` constructor
2683         // https://tc39.es/ecma262/#sec-arraybuffer-constructor
2684         $$$({ global: true, forced: NativeArrayBuffer !== ArrayBuffer$3 }, {
2685           ArrayBuffer: ArrayBuffer$3
2686         });
2687
2688         setSpecies$4(ARRAY_BUFFER);
2689
2690         var fails$C = fails$N;
2691
2692         var arrayMethodIsStrict$8 = function (METHOD_NAME, argument) {
2693           var method = [][METHOD_NAME];
2694           return !!method && fails$C(function () {
2695             // eslint-disable-next-line no-useless-call,no-throw-literal -- required for testing
2696             method.call(null, argument || function () { throw 1; }, 1);
2697           });
2698         };
2699
2700         /* eslint-disable es/no-array-prototype-indexof -- required for testing */
2701         var $$_ = _export;
2702         var $indexOf$1 = arrayIncludes.indexOf;
2703         var arrayMethodIsStrict$7 = arrayMethodIsStrict$8;
2704
2705         var nativeIndexOf = [].indexOf;
2706
2707         var NEGATIVE_ZERO$1 = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
2708         var STRICT_METHOD$7 = arrayMethodIsStrict$7('indexOf');
2709
2710         // `Array.prototype.indexOf` method
2711         // https://tc39.es/ecma262/#sec-array.prototype.indexof
2712         $$_({ target: 'Array', proto: true, forced: NEGATIVE_ZERO$1 || !STRICT_METHOD$7 }, {
2713           indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
2714             return NEGATIVE_ZERO$1
2715               // convert -0 to +0
2716               ? nativeIndexOf.apply(this, arguments) || 0
2717               : $indexOf$1(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
2718           }
2719         });
2720
2721         var fails$B = fails$N;
2722         var wellKnownSymbol$e = wellKnownSymbol$s;
2723         var V8_VERSION$2 = engineV8Version;
2724
2725         var SPECIES$3 = wellKnownSymbol$e('species');
2726
2727         var arrayMethodHasSpeciesSupport$5 = function (METHOD_NAME) {
2728           // We can't use this feature detection in V8 since it causes
2729           // deoptimization and serious performance degradation
2730           // https://github.com/zloirock/core-js/issues/677
2731           return V8_VERSION$2 >= 51 || !fails$B(function () {
2732             var array = [];
2733             var constructor = array.constructor = {};
2734             constructor[SPECIES$3] = function () {
2735               return { foo: 1 };
2736             };
2737             return array[METHOD_NAME](Boolean).foo !== 1;
2738           });
2739         };
2740
2741         var $$Z = _export;
2742         var $map$1 = arrayIteration.map;
2743         var arrayMethodHasSpeciesSupport$4 = arrayMethodHasSpeciesSupport$5;
2744
2745         var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport$4('map');
2746
2747         // `Array.prototype.map` method
2748         // https://tc39.es/ecma262/#sec-array.prototype.map
2749         // with adding support of @@species
2750         $$Z({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$3 }, {
2751           map: function map(callbackfn /* , thisArg */) {
2752             return $map$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2753           }
2754         });
2755
2756         var $forEach$1 = arrayIteration.forEach;
2757         var arrayMethodIsStrict$6 = arrayMethodIsStrict$8;
2758
2759         var STRICT_METHOD$6 = arrayMethodIsStrict$6('forEach');
2760
2761         // `Array.prototype.forEach` method implementation
2762         // https://tc39.es/ecma262/#sec-array.prototype.foreach
2763         var arrayForEach = !STRICT_METHOD$6 ? function forEach(callbackfn /* , thisArg */) {
2764           return $forEach$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2765         // eslint-disable-next-line es/no-array-prototype-foreach -- safe
2766         } : [].forEach;
2767
2768         var $$Y = _export;
2769         var forEach$3 = arrayForEach;
2770
2771         // `Array.prototype.forEach` method
2772         // https://tc39.es/ecma262/#sec-array.prototype.foreach
2773         // eslint-disable-next-line es/no-array-prototype-foreach -- safe
2774         $$Y({ target: 'Array', proto: true, forced: [].forEach != forEach$3 }, {
2775           forEach: forEach$3
2776         });
2777
2778         var global$n = global$F;
2779         var DOMIterables = domIterables;
2780         var forEach$2 = arrayForEach;
2781         var createNonEnumerableProperty$3 = createNonEnumerableProperty$e;
2782
2783         for (var COLLECTION_NAME in DOMIterables) {
2784           var Collection = global$n[COLLECTION_NAME];
2785           var CollectionPrototype = Collection && Collection.prototype;
2786           // some Chrome versions have non-configurable methods on DOMTokenList
2787           if (CollectionPrototype && CollectionPrototype.forEach !== forEach$2) try {
2788             createNonEnumerableProperty$3(CollectionPrototype, 'forEach', forEach$2);
2789           } catch (error) {
2790             CollectionPrototype.forEach = forEach$2;
2791           }
2792         }
2793
2794         var $$X = _export;
2795         var isArray$3 = isArray$6;
2796
2797         // `Array.isArray` method
2798         // https://tc39.es/ecma262/#sec-array.isarray
2799         $$X({ target: 'Array', stat: true }, {
2800           isArray: isArray$3
2801         });
2802
2803         var $$W = _export;
2804         var fails$A = fails$N;
2805         var getOwnPropertyNames$3 = objectGetOwnPropertyNamesExternal.f;
2806
2807         // eslint-disable-next-line es/no-object-getownpropertynames -- required for testing
2808         var FAILS_ON_PRIMITIVES$4 = fails$A(function () { return !Object.getOwnPropertyNames(1); });
2809
2810         // `Object.getOwnPropertyNames` method
2811         // https://tc39.es/ecma262/#sec-object.getownpropertynames
2812         $$W({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$4 }, {
2813           getOwnPropertyNames: getOwnPropertyNames$3
2814         });
2815
2816         var global$m = global$F;
2817
2818         var nativePromiseConstructor = global$m.Promise;
2819
2820         var wellKnownSymbol$d = wellKnownSymbol$s;
2821         var Iterators$1 = iterators;
2822
2823         var ITERATOR$5 = wellKnownSymbol$d('iterator');
2824         var ArrayPrototype = Array.prototype;
2825
2826         // check on default Array iterator
2827         var isArrayIteratorMethod$3 = function (it) {
2828           return it !== undefined && (Iterators$1.Array === it || ArrayPrototype[ITERATOR$5] === it);
2829         };
2830
2831         var classof$7 = classof$b;
2832         var Iterators = iterators;
2833         var wellKnownSymbol$c = wellKnownSymbol$s;
2834
2835         var ITERATOR$4 = wellKnownSymbol$c('iterator');
2836
2837         var getIteratorMethod$5 = function (it) {
2838           if (it != undefined) return it[ITERATOR$4]
2839             || it['@@iterator']
2840             || Iterators[classof$7(it)];
2841         };
2842
2843         var anObject$d = anObject$m;
2844
2845         var iteratorClose$2 = function (iterator) {
2846           var returnMethod = iterator['return'];
2847           if (returnMethod !== undefined) {
2848             return anObject$d(returnMethod.call(iterator)).value;
2849           }
2850         };
2851
2852         var anObject$c = anObject$m;
2853         var isArrayIteratorMethod$2 = isArrayIteratorMethod$3;
2854         var toLength$j = toLength$q;
2855         var bind$a = functionBindContext;
2856         var getIteratorMethod$4 = getIteratorMethod$5;
2857         var iteratorClose$1 = iteratorClose$2;
2858
2859         var Result = function (stopped, result) {
2860           this.stopped = stopped;
2861           this.result = result;
2862         };
2863
2864         var iterate$3 = function (iterable, unboundFunction, options) {
2865           var that = options && options.that;
2866           var AS_ENTRIES = !!(options && options.AS_ENTRIES);
2867           var IS_ITERATOR = !!(options && options.IS_ITERATOR);
2868           var INTERRUPTED = !!(options && options.INTERRUPTED);
2869           var fn = bind$a(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
2870           var iterator, iterFn, index, length, result, next, step;
2871
2872           var stop = function (condition) {
2873             if (iterator) iteratorClose$1(iterator);
2874             return new Result(true, condition);
2875           };
2876
2877           var callFn = function (value) {
2878             if (AS_ENTRIES) {
2879               anObject$c(value);
2880               return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
2881             } return INTERRUPTED ? fn(value, stop) : fn(value);
2882           };
2883
2884           if (IS_ITERATOR) {
2885             iterator = iterable;
2886           } else {
2887             iterFn = getIteratorMethod$4(iterable);
2888             if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
2889             // optimisation for array iterators
2890             if (isArrayIteratorMethod$2(iterFn)) {
2891               for (index = 0, length = toLength$j(iterable.length); length > index; index++) {
2892                 result = callFn(iterable[index]);
2893                 if (result && result instanceof Result) return result;
2894               } return new Result(false);
2895             }
2896             iterator = iterFn.call(iterable);
2897           }
2898
2899           next = iterator.next;
2900           while (!(step = next.call(iterator)).done) {
2901             try {
2902               result = callFn(step.value);
2903             } catch (error) {
2904               iteratorClose$1(iterator);
2905               throw error;
2906             }
2907             if (typeof result == 'object' && result && result instanceof Result) return result;
2908           } return new Result(false);
2909         };
2910
2911         var wellKnownSymbol$b = wellKnownSymbol$s;
2912
2913         var ITERATOR$3 = wellKnownSymbol$b('iterator');
2914         var SAFE_CLOSING = false;
2915
2916         try {
2917           var called = 0;
2918           var iteratorWithReturn = {
2919             next: function () {
2920               return { done: !!called++ };
2921             },
2922             'return': function () {
2923               SAFE_CLOSING = true;
2924             }
2925           };
2926           iteratorWithReturn[ITERATOR$3] = function () {
2927             return this;
2928           };
2929           // eslint-disable-next-line es/no-array-from, no-throw-literal -- required for testing
2930           Array.from(iteratorWithReturn, function () { throw 2; });
2931         } catch (error) { /* empty */ }
2932
2933         var checkCorrectnessOfIteration$4 = function (exec, SKIP_CLOSING) {
2934           if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2935           var ITERATION_SUPPORT = false;
2936           try {
2937             var object = {};
2938             object[ITERATOR$3] = function () {
2939               return {
2940                 next: function () {
2941                   return { done: ITERATION_SUPPORT = true };
2942                 }
2943               };
2944             };
2945             exec(object);
2946           } catch (error) { /* empty */ }
2947           return ITERATION_SUPPORT;
2948         };
2949
2950         var userAgent$4 = engineUserAgent;
2951
2952         var engineIsIos = /(?:iphone|ipod|ipad).*applewebkit/i.test(userAgent$4);
2953
2954         var classof$6 = classofRaw$1;
2955         var global$l = global$F;
2956
2957         var engineIsNode = classof$6(global$l.process) == 'process';
2958
2959         var global$k = global$F;
2960         var fails$z = fails$N;
2961         var bind$9 = functionBindContext;
2962         var html = html$2;
2963         var createElement = documentCreateElement$1;
2964         var IS_IOS$1 = engineIsIos;
2965         var IS_NODE$3 = engineIsNode;
2966
2967         var location$1 = global$k.location;
2968         var set$2 = global$k.setImmediate;
2969         var clear = global$k.clearImmediate;
2970         var process$3 = global$k.process;
2971         var MessageChannel = global$k.MessageChannel;
2972         var Dispatch$1 = global$k.Dispatch;
2973         var counter = 0;
2974         var queue = {};
2975         var ONREADYSTATECHANGE = 'onreadystatechange';
2976         var defer, channel, port;
2977
2978         var run = function (id) {
2979           // eslint-disable-next-line no-prototype-builtins -- safe
2980           if (queue.hasOwnProperty(id)) {
2981             var fn = queue[id];
2982             delete queue[id];
2983             fn();
2984           }
2985         };
2986
2987         var runner = function (id) {
2988           return function () {
2989             run(id);
2990           };
2991         };
2992
2993         var listener = function (event) {
2994           run(event.data);
2995         };
2996
2997         var post = function (id) {
2998           // old engines have not location.origin
2999           global$k.postMessage(id + '', location$1.protocol + '//' + location$1.host);
3000         };
3001
3002         // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
3003         if (!set$2 || !clear) {
3004           set$2 = function setImmediate(fn) {
3005             var args = [];
3006             var i = 1;
3007             while (arguments.length > i) args.push(arguments[i++]);
3008             queue[++counter] = function () {
3009               // eslint-disable-next-line no-new-func -- spec requirement
3010               (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
3011             };
3012             defer(counter);
3013             return counter;
3014           };
3015           clear = function clearImmediate(id) {
3016             delete queue[id];
3017           };
3018           // Node.js 0.8-
3019           if (IS_NODE$3) {
3020             defer = function (id) {
3021               process$3.nextTick(runner(id));
3022             };
3023           // Sphere (JS game engine) Dispatch API
3024           } else if (Dispatch$1 && Dispatch$1.now) {
3025             defer = function (id) {
3026               Dispatch$1.now(runner(id));
3027             };
3028           // Browsers with MessageChannel, includes WebWorkers
3029           // except iOS - https://github.com/zloirock/core-js/issues/624
3030           } else if (MessageChannel && !IS_IOS$1) {
3031             channel = new MessageChannel();
3032             port = channel.port2;
3033             channel.port1.onmessage = listener;
3034             defer = bind$9(port.postMessage, port, 1);
3035           // Browsers with postMessage, skip WebWorkers
3036           // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
3037           } else if (
3038             global$k.addEventListener &&
3039             typeof postMessage == 'function' &&
3040             !global$k.importScripts &&
3041             location$1 && location$1.protocol !== 'file:' &&
3042             !fails$z(post)
3043           ) {
3044             defer = post;
3045             global$k.addEventListener('message', listener, false);
3046           // IE8-
3047           } else if (ONREADYSTATECHANGE in createElement('script')) {
3048             defer = function (id) {
3049               html.appendChild(createElement('script'))[ONREADYSTATECHANGE] = function () {
3050                 html.removeChild(this);
3051                 run(id);
3052               };
3053             };
3054           // Rest old browsers
3055           } else {
3056             defer = function (id) {
3057               setTimeout(runner(id), 0);
3058             };
3059           }
3060         }
3061
3062         var task$1 = {
3063           set: set$2,
3064           clear: clear
3065         };
3066
3067         var userAgent$3 = engineUserAgent;
3068
3069         var engineIsWebosWebkit = /web0s(?!.*chrome)/i.test(userAgent$3);
3070
3071         var global$j = global$F;
3072         var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
3073         var macrotask = task$1.set;
3074         var IS_IOS = engineIsIos;
3075         var IS_WEBOS_WEBKIT = engineIsWebosWebkit;
3076         var IS_NODE$2 = engineIsNode;
3077
3078         var MutationObserver = global$j.MutationObserver || global$j.WebKitMutationObserver;
3079         var document$2 = global$j.document;
3080         var process$2 = global$j.process;
3081         var Promise$1 = global$j.Promise;
3082         // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
3083         var queueMicrotaskDescriptor = getOwnPropertyDescriptor$3(global$j, 'queueMicrotask');
3084         var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
3085
3086         var flush, head, last, notify$1, toggle, node, promise, then;
3087
3088         // modern engines have queueMicrotask method
3089         if (!queueMicrotask) {
3090           flush = function () {
3091             var parent, fn;
3092             if (IS_NODE$2 && (parent = process$2.domain)) parent.exit();
3093             while (head) {
3094               fn = head.fn;
3095               head = head.next;
3096               try {
3097                 fn();
3098               } catch (error) {
3099                 if (head) notify$1();
3100                 else last = undefined;
3101                 throw error;
3102               }
3103             } last = undefined;
3104             if (parent) parent.enter();
3105           };
3106
3107           // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
3108           // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898
3109           if (!IS_IOS && !IS_NODE$2 && !IS_WEBOS_WEBKIT && MutationObserver && document$2) {
3110             toggle = true;
3111             node = document$2.createTextNode('');
3112             new MutationObserver(flush).observe(node, { characterData: true });
3113             notify$1 = function () {
3114               node.data = toggle = !toggle;
3115             };
3116           // environments with maybe non-completely correct, but existent Promise
3117           } else if (Promise$1 && Promise$1.resolve) {
3118             // Promise.resolve without an argument throws an error in LG WebOS 2
3119             promise = Promise$1.resolve(undefined);
3120             // workaround of WebKit ~ iOS Safari 10.1 bug
3121             promise.constructor = Promise$1;
3122             then = promise.then;
3123             notify$1 = function () {
3124               then.call(promise, flush);
3125             };
3126           // Node.js without promises
3127           } else if (IS_NODE$2) {
3128             notify$1 = function () {
3129               process$2.nextTick(flush);
3130             };
3131           // for other environments - macrotask based on:
3132           // - setImmediate
3133           // - MessageChannel
3134           // - window.postMessag
3135           // - onreadystatechange
3136           // - setTimeout
3137           } else {
3138             notify$1 = function () {
3139               // strange IE + webpack dev server bug - use .call(global)
3140               macrotask.call(global$j, flush);
3141             };
3142           }
3143         }
3144
3145         var microtask$1 = queueMicrotask || function (fn) {
3146           var task = { fn: fn, next: undefined };
3147           if (last) last.next = task;
3148           if (!head) {
3149             head = task;
3150             notify$1();
3151           } last = task;
3152         };
3153
3154         var newPromiseCapability$2 = {};
3155
3156         var aFunction$6 = aFunction$9;
3157
3158         var PromiseCapability = function (C) {
3159           var resolve, reject;
3160           this.promise = new C(function ($$resolve, $$reject) {
3161             if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
3162             resolve = $$resolve;
3163             reject = $$reject;
3164           });
3165           this.resolve = aFunction$6(resolve);
3166           this.reject = aFunction$6(reject);
3167         };
3168
3169         // `NewPromiseCapability` abstract operation
3170         // https://tc39.es/ecma262/#sec-newpromisecapability
3171         newPromiseCapability$2.f = function (C) {
3172           return new PromiseCapability(C);
3173         };
3174
3175         var anObject$b = anObject$m;
3176         var isObject$h = isObject$r;
3177         var newPromiseCapability$1 = newPromiseCapability$2;
3178
3179         var promiseResolve$2 = function (C, x) {
3180           anObject$b(C);
3181           if (isObject$h(x) && x.constructor === C) return x;
3182           var promiseCapability = newPromiseCapability$1.f(C);
3183           var resolve = promiseCapability.resolve;
3184           resolve(x);
3185           return promiseCapability.promise;
3186         };
3187
3188         var global$i = global$F;
3189
3190         var hostReportErrors$1 = function (a, b) {
3191           var console = global$i.console;
3192           if (console && console.error) {
3193             arguments.length === 1 ? console.error(a) : console.error(a, b);
3194           }
3195         };
3196
3197         var perform$1 = function (exec) {
3198           try {
3199             return { error: false, value: exec() };
3200           } catch (error) {
3201             return { error: true, value: error };
3202           }
3203         };
3204
3205         var engineIsBrowser = typeof window == 'object';
3206
3207         var $$V = _export;
3208         var global$h = global$F;
3209         var getBuiltIn$3 = getBuiltIn$9;
3210         var NativePromise$1 = nativePromiseConstructor;
3211         var redefine$8 = redefine$g.exports;
3212         var redefineAll$2 = redefineAll$4;
3213         var setPrototypeOf$3 = objectSetPrototypeOf;
3214         var setToStringTag$5 = setToStringTag$a;
3215         var setSpecies$3 = setSpecies$5;
3216         var isObject$g = isObject$r;
3217         var aFunction$5 = aFunction$9;
3218         var anInstance$5 = anInstance$7;
3219         var inspectSource = inspectSource$3;
3220         var iterate$2 = iterate$3;
3221         var checkCorrectnessOfIteration$3 = checkCorrectnessOfIteration$4;
3222         var speciesConstructor$6 = speciesConstructor$8;
3223         var task = task$1.set;
3224         var microtask = microtask$1;
3225         var promiseResolve$1 = promiseResolve$2;
3226         var hostReportErrors = hostReportErrors$1;
3227         var newPromiseCapabilityModule = newPromiseCapability$2;
3228         var perform = perform$1;
3229         var InternalStateModule$4 = internalState;
3230         var isForced$3 = isForced_1;
3231         var wellKnownSymbol$a = wellKnownSymbol$s;
3232         var IS_BROWSER = engineIsBrowser;
3233         var IS_NODE$1 = engineIsNode;
3234         var V8_VERSION$1 = engineV8Version;
3235
3236         var SPECIES$2 = wellKnownSymbol$a('species');
3237         var PROMISE = 'Promise';
3238         var getInternalState$2 = InternalStateModule$4.get;
3239         var setInternalState$4 = InternalStateModule$4.set;
3240         var getInternalPromiseState = InternalStateModule$4.getterFor(PROMISE);
3241         var NativePromisePrototype = NativePromise$1 && NativePromise$1.prototype;
3242         var PromiseConstructor = NativePromise$1;
3243         var PromiseConstructorPrototype = NativePromisePrototype;
3244         var TypeError$1 = global$h.TypeError;
3245         var document$1 = global$h.document;
3246         var process$1 = global$h.process;
3247         var newPromiseCapability = newPromiseCapabilityModule.f;
3248         var newGenericPromiseCapability = newPromiseCapability;
3249         var DISPATCH_EVENT = !!(document$1 && document$1.createEvent && global$h.dispatchEvent);
3250         var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
3251         var UNHANDLED_REJECTION = 'unhandledrejection';
3252         var REJECTION_HANDLED = 'rejectionhandled';
3253         var PENDING = 0;
3254         var FULFILLED = 1;
3255         var REJECTED = 2;
3256         var HANDLED = 1;
3257         var UNHANDLED = 2;
3258         var SUBCLASSING = false;
3259         var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
3260
3261         var FORCED$f = isForced$3(PROMISE, function () {
3262           var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);
3263           // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
3264           // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
3265           // We can't detect it synchronously, so just check versions
3266           if (!GLOBAL_CORE_JS_PROMISE && V8_VERSION$1 === 66) return true;
3267           // We can't use @@species feature detection in V8 since it causes
3268           // deoptimization and performance degradation
3269           // https://github.com/zloirock/core-js/issues/679
3270           if (V8_VERSION$1 >= 51 && /native code/.test(PromiseConstructor)) return false;
3271           // Detect correctness of subclassing with @@species support
3272           var promise = new PromiseConstructor(function (resolve) { resolve(1); });
3273           var FakePromise = function (exec) {
3274             exec(function () { /* empty */ }, function () { /* empty */ });
3275           };
3276           var constructor = promise.constructor = {};
3277           constructor[SPECIES$2] = FakePromise;
3278           SUBCLASSING = promise.then(function () { /* empty */ }) instanceof FakePromise;
3279           if (!SUBCLASSING) return true;
3280           // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
3281           return !GLOBAL_CORE_JS_PROMISE && IS_BROWSER && !NATIVE_REJECTION_EVENT;
3282         });
3283
3284         var INCORRECT_ITERATION$1 = FORCED$f || !checkCorrectnessOfIteration$3(function (iterable) {
3285           PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
3286         });
3287
3288         // helpers
3289         var isThenable = function (it) {
3290           var then;
3291           return isObject$g(it) && typeof (then = it.then) == 'function' ? then : false;
3292         };
3293
3294         var notify = function (state, isReject) {
3295           if (state.notified) return;
3296           state.notified = true;
3297           var chain = state.reactions;
3298           microtask(function () {
3299             var value = state.value;
3300             var ok = state.state == FULFILLED;
3301             var index = 0;
3302             // variable length - can't use forEach
3303             while (chain.length > index) {
3304               var reaction = chain[index++];
3305               var handler = ok ? reaction.ok : reaction.fail;
3306               var resolve = reaction.resolve;
3307               var reject = reaction.reject;
3308               var domain = reaction.domain;
3309               var result, then, exited;
3310               try {
3311                 if (handler) {
3312                   if (!ok) {
3313                     if (state.rejection === UNHANDLED) onHandleUnhandled(state);
3314                     state.rejection = HANDLED;
3315                   }
3316                   if (handler === true) result = value;
3317                   else {
3318                     if (domain) domain.enter();
3319                     result = handler(value); // can throw
3320                     if (domain) {
3321                       domain.exit();
3322                       exited = true;
3323                     }
3324                   }
3325                   if (result === reaction.promise) {
3326                     reject(TypeError$1('Promise-chain cycle'));
3327                   } else if (then = isThenable(result)) {
3328                     then.call(result, resolve, reject);
3329                   } else resolve(result);
3330                 } else reject(value);
3331               } catch (error) {
3332                 if (domain && !exited) domain.exit();
3333                 reject(error);
3334               }
3335             }
3336             state.reactions = [];
3337             state.notified = false;
3338             if (isReject && !state.rejection) onUnhandled(state);
3339           });
3340         };
3341
3342         var dispatchEvent$1 = function (name, promise, reason) {
3343           var event, handler;
3344           if (DISPATCH_EVENT) {
3345             event = document$1.createEvent('Event');
3346             event.promise = promise;
3347             event.reason = reason;
3348             event.initEvent(name, false, true);
3349             global$h.dispatchEvent(event);
3350           } else event = { promise: promise, reason: reason };
3351           if (!NATIVE_REJECTION_EVENT && (handler = global$h['on' + name])) handler(event);
3352           else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
3353         };
3354
3355         var onUnhandled = function (state) {
3356           task.call(global$h, function () {
3357             var promise = state.facade;
3358             var value = state.value;
3359             var IS_UNHANDLED = isUnhandled(state);
3360             var result;
3361             if (IS_UNHANDLED) {
3362               result = perform(function () {
3363                 if (IS_NODE$1) {
3364                   process$1.emit('unhandledRejection', value, promise);
3365                 } else dispatchEvent$1(UNHANDLED_REJECTION, promise, value);
3366               });
3367               // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
3368               state.rejection = IS_NODE$1 || isUnhandled(state) ? UNHANDLED : HANDLED;
3369               if (result.error) throw result.value;
3370             }
3371           });
3372         };
3373
3374         var isUnhandled = function (state) {
3375           return state.rejection !== HANDLED && !state.parent;
3376         };
3377
3378         var onHandleUnhandled = function (state) {
3379           task.call(global$h, function () {
3380             var promise = state.facade;
3381             if (IS_NODE$1) {
3382               process$1.emit('rejectionHandled', promise);
3383             } else dispatchEvent$1(REJECTION_HANDLED, promise, state.value);
3384           });
3385         };
3386
3387         var bind$8 = function (fn, state, unwrap) {
3388           return function (value) {
3389             fn(state, value, unwrap);
3390           };
3391         };
3392
3393         var internalReject = function (state, value, unwrap) {
3394           if (state.done) return;
3395           state.done = true;
3396           if (unwrap) state = unwrap;
3397           state.value = value;
3398           state.state = REJECTED;
3399           notify(state, true);
3400         };
3401
3402         var internalResolve = function (state, value, unwrap) {
3403           if (state.done) return;
3404           state.done = true;
3405           if (unwrap) state = unwrap;
3406           try {
3407             if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
3408             var then = isThenable(value);
3409             if (then) {
3410               microtask(function () {
3411                 var wrapper = { done: false };
3412                 try {
3413                   then.call(value,
3414                     bind$8(internalResolve, wrapper, state),
3415                     bind$8(internalReject, wrapper, state)
3416                   );
3417                 } catch (error) {
3418                   internalReject(wrapper, error, state);
3419                 }
3420               });
3421             } else {
3422               state.value = value;
3423               state.state = FULFILLED;
3424               notify(state, false);
3425             }
3426           } catch (error) {
3427             internalReject({ done: false }, error, state);
3428           }
3429         };
3430
3431         // constructor polyfill
3432         if (FORCED$f) {
3433           // 25.4.3.1 Promise(executor)
3434           PromiseConstructor = function Promise(executor) {
3435             anInstance$5(this, PromiseConstructor, PROMISE);
3436             aFunction$5(executor);
3437             Internal.call(this);
3438             var state = getInternalState$2(this);
3439             try {
3440               executor(bind$8(internalResolve, state), bind$8(internalReject, state));
3441             } catch (error) {
3442               internalReject(state, error);
3443             }
3444           };
3445           PromiseConstructorPrototype = PromiseConstructor.prototype;
3446           // eslint-disable-next-line no-unused-vars -- required for `.length`
3447           Internal = function Promise(executor) {
3448             setInternalState$4(this, {
3449               type: PROMISE,
3450               done: false,
3451               notified: false,
3452               parent: false,
3453               reactions: [],
3454               rejection: false,
3455               state: PENDING,
3456               value: undefined
3457             });
3458           };
3459           Internal.prototype = redefineAll$2(PromiseConstructorPrototype, {
3460             // `Promise.prototype.then` method
3461             // https://tc39.es/ecma262/#sec-promise.prototype.then
3462             then: function then(onFulfilled, onRejected) {
3463               var state = getInternalPromiseState(this);
3464               var reaction = newPromiseCapability(speciesConstructor$6(this, PromiseConstructor));
3465               reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
3466               reaction.fail = typeof onRejected == 'function' && onRejected;
3467               reaction.domain = IS_NODE$1 ? process$1.domain : undefined;
3468               state.parent = true;
3469               state.reactions.push(reaction);
3470               if (state.state != PENDING) notify(state, false);
3471               return reaction.promise;
3472             },
3473             // `Promise.prototype.catch` method
3474             // https://tc39.es/ecma262/#sec-promise.prototype.catch
3475             'catch': function (onRejected) {
3476               return this.then(undefined, onRejected);
3477             }
3478           });
3479           OwnPromiseCapability = function () {
3480             var promise = new Internal();
3481             var state = getInternalState$2(promise);
3482             this.promise = promise;
3483             this.resolve = bind$8(internalResolve, state);
3484             this.reject = bind$8(internalReject, state);
3485           };
3486           newPromiseCapabilityModule.f = newPromiseCapability = function (C) {
3487             return C === PromiseConstructor || C === PromiseWrapper
3488               ? new OwnPromiseCapability(C)
3489               : newGenericPromiseCapability(C);
3490           };
3491
3492           if (typeof NativePromise$1 == 'function' && NativePromisePrototype !== Object.prototype) {
3493             nativeThen = NativePromisePrototype.then;
3494
3495             if (!SUBCLASSING) {
3496               // make `Promise#then` return a polyfilled `Promise` for native promise-based APIs
3497               redefine$8(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) {
3498                 var that = this;
3499                 return new PromiseConstructor(function (resolve, reject) {
3500                   nativeThen.call(that, resolve, reject);
3501                 }).then(onFulfilled, onRejected);
3502               // https://github.com/zloirock/core-js/issues/640
3503               }, { unsafe: true });
3504
3505               // makes sure that native promise-based APIs `Promise#catch` properly works with patched `Promise#then`
3506               redefine$8(NativePromisePrototype, 'catch', PromiseConstructorPrototype['catch'], { unsafe: true });
3507             }
3508
3509             // make `.constructor === Promise` work for native promise-based APIs
3510             try {
3511               delete NativePromisePrototype.constructor;
3512             } catch (error) { /* empty */ }
3513
3514             // make `instanceof Promise` work for native promise-based APIs
3515             if (setPrototypeOf$3) {
3516               setPrototypeOf$3(NativePromisePrototype, PromiseConstructorPrototype);
3517             }
3518           }
3519         }
3520
3521         $$V({ global: true, wrap: true, forced: FORCED$f }, {
3522           Promise: PromiseConstructor
3523         });
3524
3525         setToStringTag$5(PromiseConstructor, PROMISE, false);
3526         setSpecies$3(PROMISE);
3527
3528         PromiseWrapper = getBuiltIn$3(PROMISE);
3529
3530         // statics
3531         $$V({ target: PROMISE, stat: true, forced: FORCED$f }, {
3532           // `Promise.reject` method
3533           // https://tc39.es/ecma262/#sec-promise.reject
3534           reject: function reject(r) {
3535             var capability = newPromiseCapability(this);
3536             capability.reject.call(undefined, r);
3537             return capability.promise;
3538           }
3539         });
3540
3541         $$V({ target: PROMISE, stat: true, forced: FORCED$f }, {
3542           // `Promise.resolve` method
3543           // https://tc39.es/ecma262/#sec-promise.resolve
3544           resolve: function resolve(x) {
3545             return promiseResolve$1(this, x);
3546           }
3547         });
3548
3549         $$V({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION$1 }, {
3550           // `Promise.all` method
3551           // https://tc39.es/ecma262/#sec-promise.all
3552           all: function all(iterable) {
3553             var C = this;
3554             var capability = newPromiseCapability(C);
3555             var resolve = capability.resolve;
3556             var reject = capability.reject;
3557             var result = perform(function () {
3558               var $promiseResolve = aFunction$5(C.resolve);
3559               var values = [];
3560               var counter = 0;
3561               var remaining = 1;
3562               iterate$2(iterable, function (promise) {
3563                 var index = counter++;
3564                 var alreadyCalled = false;
3565                 values.push(undefined);
3566                 remaining++;
3567                 $promiseResolve.call(C, promise).then(function (value) {
3568                   if (alreadyCalled) return;
3569                   alreadyCalled = true;
3570                   values[index] = value;
3571                   --remaining || resolve(values);
3572                 }, reject);
3573               });
3574               --remaining || resolve(values);
3575             });
3576             if (result.error) reject(result.value);
3577             return capability.promise;
3578           },
3579           // `Promise.race` method
3580           // https://tc39.es/ecma262/#sec-promise.race
3581           race: function race(iterable) {
3582             var C = this;
3583             var capability = newPromiseCapability(C);
3584             var reject = capability.reject;
3585             var result = perform(function () {
3586               var $promiseResolve = aFunction$5(C.resolve);
3587               iterate$2(iterable, function (promise) {
3588                 $promiseResolve.call(C, promise).then(capability.resolve, reject);
3589               });
3590             });
3591             if (result.error) reject(result.value);
3592             return capability.promise;
3593           }
3594         });
3595
3596         var typedArrayConstructor = {exports: {}};
3597
3598         /* eslint-disable no-new -- required for testing */
3599
3600         var global$g = global$F;
3601         var fails$y = fails$N;
3602         var checkCorrectnessOfIteration$2 = checkCorrectnessOfIteration$4;
3603         var NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3604
3605         var ArrayBuffer$2 = global$g.ArrayBuffer;
3606         var Int8Array$2 = global$g.Int8Array;
3607
3608         var typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS$1 || !fails$y(function () {
3609           Int8Array$2(1);
3610         }) || !fails$y(function () {
3611           new Int8Array$2(-1);
3612         }) || !checkCorrectnessOfIteration$2(function (iterable) {
3613           new Int8Array$2();
3614           new Int8Array$2(null);
3615           new Int8Array$2(1.5);
3616           new Int8Array$2(iterable);
3617         }, true) || fails$y(function () {
3618           // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill
3619           return new Int8Array$2(new ArrayBuffer$2(2), 1, undefined).length !== 1;
3620         });
3621
3622         var toInteger$5 = toInteger$b;
3623
3624         var toPositiveInteger$1 = function (it) {
3625           var result = toInteger$5(it);
3626           if (result < 0) throw RangeError("The argument can't be less than 0");
3627           return result;
3628         };
3629
3630         var toPositiveInteger = toPositiveInteger$1;
3631
3632         var toOffset$2 = function (it, BYTES) {
3633           var offset = toPositiveInteger(it);
3634           if (offset % BYTES) throw RangeError('Wrong offset');
3635           return offset;
3636         };
3637
3638         var toObject$c = toObject$i;
3639         var toLength$i = toLength$q;
3640         var getIteratorMethod$3 = getIteratorMethod$5;
3641         var isArrayIteratorMethod$1 = isArrayIteratorMethod$3;
3642         var bind$7 = functionBindContext;
3643         var aTypedArrayConstructor$4 = arrayBufferViewCore.aTypedArrayConstructor;
3644
3645         var typedArrayFrom$2 = function from(source /* , mapfn, thisArg */) {
3646           var O = toObject$c(source);
3647           var argumentsLength = arguments.length;
3648           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
3649           var mapping = mapfn !== undefined;
3650           var iteratorMethod = getIteratorMethod$3(O);
3651           var i, length, result, step, iterator, next;
3652           if (iteratorMethod != undefined && !isArrayIteratorMethod$1(iteratorMethod)) {
3653             iterator = iteratorMethod.call(O);
3654             next = iterator.next;
3655             O = [];
3656             while (!(step = next.call(iterator)).done) {
3657               O.push(step.value);
3658             }
3659           }
3660           if (mapping && argumentsLength > 2) {
3661             mapfn = bind$7(mapfn, arguments[2], 2);
3662           }
3663           length = toLength$i(O.length);
3664           result = new (aTypedArrayConstructor$4(this))(length);
3665           for (i = 0; length > i; i++) {
3666             result[i] = mapping ? mapfn(O[i], i) : O[i];
3667           }
3668           return result;
3669         };
3670
3671         var isObject$f = isObject$r;
3672         var setPrototypeOf$2 = objectSetPrototypeOf;
3673
3674         // makes subclassing work correct for wrapped built-ins
3675         var inheritIfRequired$4 = function ($this, dummy, Wrapper) {
3676           var NewTarget, NewTargetPrototype;
3677           if (
3678             // it can work only with native `setPrototypeOf`
3679             setPrototypeOf$2 &&
3680             // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
3681             typeof (NewTarget = dummy.constructor) == 'function' &&
3682             NewTarget !== Wrapper &&
3683             isObject$f(NewTargetPrototype = NewTarget.prototype) &&
3684             NewTargetPrototype !== Wrapper.prototype
3685           ) setPrototypeOf$2($this, NewTargetPrototype);
3686           return $this;
3687         };
3688
3689         var $$U = _export;
3690         var global$f = global$F;
3691         var DESCRIPTORS$c = descriptors;
3692         var TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS$1 = typedArrayConstructorsRequireWrappers;
3693         var ArrayBufferViewCore$m = arrayBufferViewCore;
3694         var ArrayBufferModule = arrayBuffer;
3695         var anInstance$4 = anInstance$7;
3696         var createPropertyDescriptor$2 = createPropertyDescriptor$7;
3697         var createNonEnumerableProperty$2 = createNonEnumerableProperty$e;
3698         var toLength$h = toLength$q;
3699         var toIndex = toIndex$2;
3700         var toOffset$1 = toOffset$2;
3701         var toPrimitive$3 = toPrimitive$7;
3702         var has$5 = has$j;
3703         var classof$5 = classof$b;
3704         var isObject$e = isObject$r;
3705         var create$9 = objectCreate;
3706         var setPrototypeOf$1 = objectSetPrototypeOf;
3707         var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
3708         var typedArrayFrom$1 = typedArrayFrom$2;
3709         var forEach$1 = arrayIteration.forEach;
3710         var setSpecies$2 = setSpecies$5;
3711         var definePropertyModule$1 = objectDefineProperty;
3712         var getOwnPropertyDescriptorModule$1 = objectGetOwnPropertyDescriptor;
3713         var InternalStateModule$3 = internalState;
3714         var inheritIfRequired$3 = inheritIfRequired$4;
3715
3716         var getInternalState$1 = InternalStateModule$3.get;
3717         var setInternalState$3 = InternalStateModule$3.set;
3718         var nativeDefineProperty = definePropertyModule$1.f;
3719         var nativeGetOwnPropertyDescriptor$1 = getOwnPropertyDescriptorModule$1.f;
3720         var round = Math.round;
3721         var RangeError$1 = global$f.RangeError;
3722         var ArrayBuffer$1 = ArrayBufferModule.ArrayBuffer;
3723         var DataView$1 = ArrayBufferModule.DataView;
3724         var NATIVE_ARRAY_BUFFER_VIEWS = ArrayBufferViewCore$m.NATIVE_ARRAY_BUFFER_VIEWS;
3725         var TYPED_ARRAY_TAG = ArrayBufferViewCore$m.TYPED_ARRAY_TAG;
3726         var TypedArray = ArrayBufferViewCore$m.TypedArray;
3727         var TypedArrayPrototype = ArrayBufferViewCore$m.TypedArrayPrototype;
3728         var aTypedArrayConstructor$3 = ArrayBufferViewCore$m.aTypedArrayConstructor;
3729         var isTypedArray = ArrayBufferViewCore$m.isTypedArray;
3730         var BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';
3731         var WRONG_LENGTH = 'Wrong length';
3732
3733         var fromList = function (C, list) {
3734           var index = 0;
3735           var length = list.length;
3736           var result = new (aTypedArrayConstructor$3(C))(length);
3737           while (length > index) result[index] = list[index++];
3738           return result;
3739         };
3740
3741         var addGetter = function (it, key) {
3742           nativeDefineProperty(it, key, { get: function () {
3743             return getInternalState$1(this)[key];
3744           } });
3745         };
3746
3747         var isArrayBuffer = function (it) {
3748           var klass;
3749           return it instanceof ArrayBuffer$1 || (klass = classof$5(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';
3750         };
3751
3752         var isTypedArrayIndex = function (target, key) {
3753           return isTypedArray(target)
3754             && typeof key != 'symbol'
3755             && key in target
3756             && String(+key) == String(key);
3757         };
3758
3759         var wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {
3760           return isTypedArrayIndex(target, key = toPrimitive$3(key, true))
3761             ? createPropertyDescriptor$2(2, target[key])
3762             : nativeGetOwnPropertyDescriptor$1(target, key);
3763         };
3764
3765         var wrappedDefineProperty = function defineProperty(target, key, descriptor) {
3766           if (isTypedArrayIndex(target, key = toPrimitive$3(key, true))
3767             && isObject$e(descriptor)
3768             && has$5(descriptor, 'value')
3769             && !has$5(descriptor, 'get')
3770             && !has$5(descriptor, 'set')
3771             // TODO: add validation descriptor w/o calling accessors
3772             && !descriptor.configurable
3773             && (!has$5(descriptor, 'writable') || descriptor.writable)
3774             && (!has$5(descriptor, 'enumerable') || descriptor.enumerable)
3775           ) {
3776             target[key] = descriptor.value;
3777             return target;
3778           } return nativeDefineProperty(target, key, descriptor);
3779         };
3780
3781         if (DESCRIPTORS$c) {
3782           if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3783             getOwnPropertyDescriptorModule$1.f = wrappedGetOwnPropertyDescriptor;
3784             definePropertyModule$1.f = wrappedDefineProperty;
3785             addGetter(TypedArrayPrototype, 'buffer');
3786             addGetter(TypedArrayPrototype, 'byteOffset');
3787             addGetter(TypedArrayPrototype, 'byteLength');
3788             addGetter(TypedArrayPrototype, 'length');
3789           }
3790
3791           $$U({ target: 'Object', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS }, {
3792             getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,
3793             defineProperty: wrappedDefineProperty
3794           });
3795
3796           typedArrayConstructor.exports = function (TYPE, wrapper, CLAMPED) {
3797             var BYTES = TYPE.match(/\d+$/)[0] / 8;
3798             var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';
3799             var GETTER = 'get' + TYPE;
3800             var SETTER = 'set' + TYPE;
3801             var NativeTypedArrayConstructor = global$f[CONSTRUCTOR_NAME];
3802             var TypedArrayConstructor = NativeTypedArrayConstructor;
3803             var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;
3804             var exported = {};
3805
3806             var getter = function (that, index) {
3807               var data = getInternalState$1(that);
3808               return data.view[GETTER](index * BYTES + data.byteOffset, true);
3809             };
3810
3811             var setter = function (that, index, value) {
3812               var data = getInternalState$1(that);
3813               if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;
3814               data.view[SETTER](index * BYTES + data.byteOffset, value, true);
3815             };
3816
3817             var addElement = function (that, index) {
3818               nativeDefineProperty(that, index, {
3819                 get: function () {
3820                   return getter(this, index);
3821                 },
3822                 set: function (value) {
3823                   return setter(this, index, value);
3824                 },
3825                 enumerable: true
3826               });
3827             };
3828
3829             if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3830               TypedArrayConstructor = wrapper(function (that, data, offset, $length) {
3831                 anInstance$4(that, TypedArrayConstructor, CONSTRUCTOR_NAME);
3832                 var index = 0;
3833                 var byteOffset = 0;
3834                 var buffer, byteLength, length;
3835                 if (!isObject$e(data)) {
3836                   length = toIndex(data);
3837                   byteLength = length * BYTES;
3838                   buffer = new ArrayBuffer$1(byteLength);
3839                 } else if (isArrayBuffer(data)) {
3840                   buffer = data;
3841                   byteOffset = toOffset$1(offset, BYTES);
3842                   var $len = data.byteLength;
3843                   if ($length === undefined) {
3844                     if ($len % BYTES) throw RangeError$1(WRONG_LENGTH);
3845                     byteLength = $len - byteOffset;
3846                     if (byteLength < 0) throw RangeError$1(WRONG_LENGTH);
3847                   } else {
3848                     byteLength = toLength$h($length) * BYTES;
3849                     if (byteLength + byteOffset > $len) throw RangeError$1(WRONG_LENGTH);
3850                   }
3851                   length = byteLength / BYTES;
3852                 } else if (isTypedArray(data)) {
3853                   return fromList(TypedArrayConstructor, data);
3854                 } else {
3855                   return typedArrayFrom$1.call(TypedArrayConstructor, data);
3856                 }
3857                 setInternalState$3(that, {
3858                   buffer: buffer,
3859                   byteOffset: byteOffset,
3860                   byteLength: byteLength,
3861                   length: length,
3862                   view: new DataView$1(buffer)
3863                 });
3864                 while (index < length) addElement(that, index++);
3865               });
3866
3867               if (setPrototypeOf$1) setPrototypeOf$1(TypedArrayConstructor, TypedArray);
3868               TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = create$9(TypedArrayPrototype);
3869             } else if (TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS$1) {
3870               TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {
3871                 anInstance$4(dummy, TypedArrayConstructor, CONSTRUCTOR_NAME);
3872                 return inheritIfRequired$3(function () {
3873                   if (!isObject$e(data)) return new NativeTypedArrayConstructor(toIndex(data));
3874                   if (isArrayBuffer(data)) return $length !== undefined
3875                     ? new NativeTypedArrayConstructor(data, toOffset$1(typedArrayOffset, BYTES), $length)
3876                     : typedArrayOffset !== undefined
3877                       ? new NativeTypedArrayConstructor(data, toOffset$1(typedArrayOffset, BYTES))
3878                       : new NativeTypedArrayConstructor(data);
3879                   if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);
3880                   return typedArrayFrom$1.call(TypedArrayConstructor, data);
3881                 }(), dummy, TypedArrayConstructor);
3882               });
3883
3884               if (setPrototypeOf$1) setPrototypeOf$1(TypedArrayConstructor, TypedArray);
3885               forEach$1(getOwnPropertyNames$2(NativeTypedArrayConstructor), function (key) {
3886                 if (!(key in TypedArrayConstructor)) {
3887                   createNonEnumerableProperty$2(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);
3888                 }
3889               });
3890               TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;
3891             }
3892
3893             if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {
3894               createNonEnumerableProperty$2(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);
3895             }
3896
3897             if (TYPED_ARRAY_TAG) {
3898               createNonEnumerableProperty$2(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);
3899             }
3900
3901             exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;
3902
3903             $$U({
3904               global: true, forced: TypedArrayConstructor != NativeTypedArrayConstructor, sham: !NATIVE_ARRAY_BUFFER_VIEWS
3905             }, exported);
3906
3907             if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {
3908               createNonEnumerableProperty$2(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);
3909             }
3910
3911             if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {
3912               createNonEnumerableProperty$2(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);
3913             }
3914
3915             setSpecies$2(CONSTRUCTOR_NAME);
3916           };
3917         } else typedArrayConstructor.exports = function () { /* empty */ };
3918
3919         var createTypedArrayConstructor$1 = typedArrayConstructor.exports;
3920
3921         // `Uint8Array` constructor
3922         // https://tc39.es/ecma262/#sec-typedarray-objects
3923         createTypedArrayConstructor$1('Uint8', function (init) {
3924           return function Uint8Array(data, byteOffset, length) {
3925             return init(this, data, byteOffset, length);
3926           };
3927         });
3928
3929         var toObject$b = toObject$i;
3930         var toAbsoluteIndex$4 = toAbsoluteIndex$8;
3931         var toLength$g = toLength$q;
3932
3933         var min$7 = Math.min;
3934
3935         // `Array.prototype.copyWithin` method implementation
3936         // https://tc39.es/ecma262/#sec-array.prototype.copywithin
3937         // eslint-disable-next-line es/no-array-prototype-copywithin -- safe
3938         var arrayCopyWithin = [].copyWithin || function copyWithin(target /* = 0 */, start /* = 0, end = @length */) {
3939           var O = toObject$b(this);
3940           var len = toLength$g(O.length);
3941           var to = toAbsoluteIndex$4(target, len);
3942           var from = toAbsoluteIndex$4(start, len);
3943           var end = arguments.length > 2 ? arguments[2] : undefined;
3944           var count = min$7((end === undefined ? len : toAbsoluteIndex$4(end, len)) - from, len - to);
3945           var inc = 1;
3946           if (from < to && to < from + count) {
3947             inc = -1;
3948             from += count - 1;
3949             to += count - 1;
3950           }
3951           while (count-- > 0) {
3952             if (from in O) O[to] = O[from];
3953             else delete O[to];
3954             to += inc;
3955             from += inc;
3956           } return O;
3957         };
3958
3959         var ArrayBufferViewCore$l = arrayBufferViewCore;
3960         var $copyWithin = arrayCopyWithin;
3961
3962         var aTypedArray$l = ArrayBufferViewCore$l.aTypedArray;
3963         var exportTypedArrayMethod$m = ArrayBufferViewCore$l.exportTypedArrayMethod;
3964
3965         // `%TypedArray%.prototype.copyWithin` method
3966         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.copywithin
3967         exportTypedArrayMethod$m('copyWithin', function copyWithin(target, start /* , end */) {
3968           return $copyWithin.call(aTypedArray$l(this), target, start, arguments.length > 2 ? arguments[2] : undefined);
3969         });
3970
3971         var ArrayBufferViewCore$k = arrayBufferViewCore;
3972         var $every$1 = arrayIteration.every;
3973
3974         var aTypedArray$k = ArrayBufferViewCore$k.aTypedArray;
3975         var exportTypedArrayMethod$l = ArrayBufferViewCore$k.exportTypedArrayMethod;
3976
3977         // `%TypedArray%.prototype.every` method
3978         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.every
3979         exportTypedArrayMethod$l('every', function every(callbackfn /* , thisArg */) {
3980           return $every$1(aTypedArray$k(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3981         });
3982
3983         var ArrayBufferViewCore$j = arrayBufferViewCore;
3984         var $fill = arrayFill$1;
3985
3986         var aTypedArray$j = ArrayBufferViewCore$j.aTypedArray;
3987         var exportTypedArrayMethod$k = ArrayBufferViewCore$j.exportTypedArrayMethod;
3988
3989         // `%TypedArray%.prototype.fill` method
3990         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill
3991         // eslint-disable-next-line no-unused-vars -- required for `.length`
3992         exportTypedArrayMethod$k('fill', function fill(value /* , start, end */) {
3993           return $fill.apply(aTypedArray$j(this), arguments);
3994         });
3995
3996         var aTypedArrayConstructor$2 = arrayBufferViewCore.aTypedArrayConstructor;
3997         var speciesConstructor$5 = speciesConstructor$8;
3998
3999         var typedArrayFromSpeciesAndList = function (instance, list) {
4000           var C = speciesConstructor$5(instance, instance.constructor);
4001           var index = 0;
4002           var length = list.length;
4003           var result = new (aTypedArrayConstructor$2(C))(length);
4004           while (length > index) result[index] = list[index++];
4005           return result;
4006         };
4007
4008         var ArrayBufferViewCore$i = arrayBufferViewCore;
4009         var $filter$1 = arrayIteration.filter;
4010         var fromSpeciesAndList = typedArrayFromSpeciesAndList;
4011
4012         var aTypedArray$i = ArrayBufferViewCore$i.aTypedArray;
4013         var exportTypedArrayMethod$j = ArrayBufferViewCore$i.exportTypedArrayMethod;
4014
4015         // `%TypedArray%.prototype.filter` method
4016         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter
4017         exportTypedArrayMethod$j('filter', function filter(callbackfn /* , thisArg */) {
4018           var list = $filter$1(aTypedArray$i(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4019           return fromSpeciesAndList(this, list);
4020         });
4021
4022         var ArrayBufferViewCore$h = arrayBufferViewCore;
4023         var $find$1 = arrayIteration.find;
4024
4025         var aTypedArray$h = ArrayBufferViewCore$h.aTypedArray;
4026         var exportTypedArrayMethod$i = ArrayBufferViewCore$h.exportTypedArrayMethod;
4027
4028         // `%TypedArray%.prototype.find` method
4029         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.find
4030         exportTypedArrayMethod$i('find', function find(predicate /* , thisArg */) {
4031           return $find$1(aTypedArray$h(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
4032         });
4033
4034         var ArrayBufferViewCore$g = arrayBufferViewCore;
4035         var $findIndex$1 = arrayIteration.findIndex;
4036
4037         var aTypedArray$g = ArrayBufferViewCore$g.aTypedArray;
4038         var exportTypedArrayMethod$h = ArrayBufferViewCore$g.exportTypedArrayMethod;
4039
4040         // `%TypedArray%.prototype.findIndex` method
4041         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.findindex
4042         exportTypedArrayMethod$h('findIndex', function findIndex(predicate /* , thisArg */) {
4043           return $findIndex$1(aTypedArray$g(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
4044         });
4045
4046         var ArrayBufferViewCore$f = arrayBufferViewCore;
4047         var $forEach = arrayIteration.forEach;
4048
4049         var aTypedArray$f = ArrayBufferViewCore$f.aTypedArray;
4050         var exportTypedArrayMethod$g = ArrayBufferViewCore$f.exportTypedArrayMethod;
4051
4052         // `%TypedArray%.prototype.forEach` method
4053         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.foreach
4054         exportTypedArrayMethod$g('forEach', function forEach(callbackfn /* , thisArg */) {
4055           $forEach(aTypedArray$f(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4056         });
4057
4058         var ArrayBufferViewCore$e = arrayBufferViewCore;
4059         var $includes$1 = arrayIncludes.includes;
4060
4061         var aTypedArray$e = ArrayBufferViewCore$e.aTypedArray;
4062         var exportTypedArrayMethod$f = ArrayBufferViewCore$e.exportTypedArrayMethod;
4063
4064         // `%TypedArray%.prototype.includes` method
4065         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.includes
4066         exportTypedArrayMethod$f('includes', function includes(searchElement /* , fromIndex */) {
4067           return $includes$1(aTypedArray$e(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4068         });
4069
4070         var ArrayBufferViewCore$d = arrayBufferViewCore;
4071         var $indexOf = arrayIncludes.indexOf;
4072
4073         var aTypedArray$d = ArrayBufferViewCore$d.aTypedArray;
4074         var exportTypedArrayMethod$e = ArrayBufferViewCore$d.exportTypedArrayMethod;
4075
4076         // `%TypedArray%.prototype.indexOf` method
4077         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.indexof
4078         exportTypedArrayMethod$e('indexOf', function indexOf(searchElement /* , fromIndex */) {
4079           return $indexOf(aTypedArray$d(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4080         });
4081
4082         var global$e = global$F;
4083         var ArrayBufferViewCore$c = arrayBufferViewCore;
4084         var ArrayIterators = es_array_iterator;
4085         var wellKnownSymbol$9 = wellKnownSymbol$s;
4086
4087         var ITERATOR$2 = wellKnownSymbol$9('iterator');
4088         var Uint8Array$2 = global$e.Uint8Array;
4089         var arrayValues = ArrayIterators.values;
4090         var arrayKeys = ArrayIterators.keys;
4091         var arrayEntries = ArrayIterators.entries;
4092         var aTypedArray$c = ArrayBufferViewCore$c.aTypedArray;
4093         var exportTypedArrayMethod$d = ArrayBufferViewCore$c.exportTypedArrayMethod;
4094         var nativeTypedArrayIterator = Uint8Array$2 && Uint8Array$2.prototype[ITERATOR$2];
4095
4096         var CORRECT_ITER_NAME = !!nativeTypedArrayIterator
4097           && (nativeTypedArrayIterator.name == 'values' || nativeTypedArrayIterator.name == undefined);
4098
4099         var typedArrayValues = function values() {
4100           return arrayValues.call(aTypedArray$c(this));
4101         };
4102
4103         // `%TypedArray%.prototype.entries` method
4104         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries
4105         exportTypedArrayMethod$d('entries', function entries() {
4106           return arrayEntries.call(aTypedArray$c(this));
4107         });
4108         // `%TypedArray%.prototype.keys` method
4109         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.keys
4110         exportTypedArrayMethod$d('keys', function keys() {
4111           return arrayKeys.call(aTypedArray$c(this));
4112         });
4113         // `%TypedArray%.prototype.values` method
4114         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.values
4115         exportTypedArrayMethod$d('values', typedArrayValues, !CORRECT_ITER_NAME);
4116         // `%TypedArray%.prototype[@@iterator]` method
4117         // https://tc39.es/ecma262/#sec-%typedarray%.prototype-@@iterator
4118         exportTypedArrayMethod$d(ITERATOR$2, typedArrayValues, !CORRECT_ITER_NAME);
4119
4120         var ArrayBufferViewCore$b = arrayBufferViewCore;
4121
4122         var aTypedArray$b = ArrayBufferViewCore$b.aTypedArray;
4123         var exportTypedArrayMethod$c = ArrayBufferViewCore$b.exportTypedArrayMethod;
4124         var $join = [].join;
4125
4126         // `%TypedArray%.prototype.join` method
4127         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.join
4128         // eslint-disable-next-line no-unused-vars -- required for `.length`
4129         exportTypedArrayMethod$c('join', function join(separator) {
4130           return $join.apply(aTypedArray$b(this), arguments);
4131         });
4132
4133         /* eslint-disable es/no-array-prototype-lastindexof -- safe */
4134         var toIndexedObject$4 = toIndexedObject$b;
4135         var toInteger$4 = toInteger$b;
4136         var toLength$f = toLength$q;
4137         var arrayMethodIsStrict$5 = arrayMethodIsStrict$8;
4138
4139         var min$6 = Math.min;
4140         var $lastIndexOf$1 = [].lastIndexOf;
4141         var NEGATIVE_ZERO = !!$lastIndexOf$1 && 1 / [1].lastIndexOf(1, -0) < 0;
4142         var STRICT_METHOD$5 = arrayMethodIsStrict$5('lastIndexOf');
4143         var FORCED$e = NEGATIVE_ZERO || !STRICT_METHOD$5;
4144
4145         // `Array.prototype.lastIndexOf` method implementation
4146         // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
4147         var arrayLastIndexOf = FORCED$e ? function lastIndexOf(searchElement /* , fromIndex = @[*-1] */) {
4148           // convert -0 to +0
4149           if (NEGATIVE_ZERO) return $lastIndexOf$1.apply(this, arguments) || 0;
4150           var O = toIndexedObject$4(this);
4151           var length = toLength$f(O.length);
4152           var index = length - 1;
4153           if (arguments.length > 1) index = min$6(index, toInteger$4(arguments[1]));
4154           if (index < 0) index = length + index;
4155           for (;index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;
4156           return -1;
4157         } : $lastIndexOf$1;
4158
4159         var ArrayBufferViewCore$a = arrayBufferViewCore;
4160         var $lastIndexOf = arrayLastIndexOf;
4161
4162         var aTypedArray$a = ArrayBufferViewCore$a.aTypedArray;
4163         var exportTypedArrayMethod$b = ArrayBufferViewCore$a.exportTypedArrayMethod;
4164
4165         // `%TypedArray%.prototype.lastIndexOf` method
4166         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof
4167         // eslint-disable-next-line no-unused-vars -- required for `.length`
4168         exportTypedArrayMethod$b('lastIndexOf', function lastIndexOf(searchElement /* , fromIndex */) {
4169           return $lastIndexOf.apply(aTypedArray$a(this), arguments);
4170         });
4171
4172         var ArrayBufferViewCore$9 = arrayBufferViewCore;
4173         var $map = arrayIteration.map;
4174         var speciesConstructor$4 = speciesConstructor$8;
4175
4176         var aTypedArray$9 = ArrayBufferViewCore$9.aTypedArray;
4177         var aTypedArrayConstructor$1 = ArrayBufferViewCore$9.aTypedArrayConstructor;
4178         var exportTypedArrayMethod$a = ArrayBufferViewCore$9.exportTypedArrayMethod;
4179
4180         // `%TypedArray%.prototype.map` method
4181         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.map
4182         exportTypedArrayMethod$a('map', function map(mapfn /* , thisArg */) {
4183           return $map(aTypedArray$9(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {
4184             return new (aTypedArrayConstructor$1(speciesConstructor$4(O, O.constructor)))(length);
4185           });
4186         });
4187
4188         var aFunction$4 = aFunction$9;
4189         var toObject$a = toObject$i;
4190         var IndexedObject$2 = indexedObject;
4191         var toLength$e = toLength$q;
4192
4193         // `Array.prototype.{ reduce, reduceRight }` methods implementation
4194         var createMethod$3 = function (IS_RIGHT) {
4195           return function (that, callbackfn, argumentsLength, memo) {
4196             aFunction$4(callbackfn);
4197             var O = toObject$a(that);
4198             var self = IndexedObject$2(O);
4199             var length = toLength$e(O.length);
4200             var index = IS_RIGHT ? length - 1 : 0;
4201             var i = IS_RIGHT ? -1 : 1;
4202             if (argumentsLength < 2) while (true) {
4203               if (index in self) {
4204                 memo = self[index];
4205                 index += i;
4206                 break;
4207               }
4208               index += i;
4209               if (IS_RIGHT ? index < 0 : length <= index) {
4210                 throw TypeError('Reduce of empty array with no initial value');
4211               }
4212             }
4213             for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
4214               memo = callbackfn(memo, self[index], index, O);
4215             }
4216             return memo;
4217           };
4218         };
4219
4220         var arrayReduce = {
4221           // `Array.prototype.reduce` method
4222           // https://tc39.es/ecma262/#sec-array.prototype.reduce
4223           left: createMethod$3(false),
4224           // `Array.prototype.reduceRight` method
4225           // https://tc39.es/ecma262/#sec-array.prototype.reduceright
4226           right: createMethod$3(true)
4227         };
4228
4229         var ArrayBufferViewCore$8 = arrayBufferViewCore;
4230         var $reduce$1 = arrayReduce.left;
4231
4232         var aTypedArray$8 = ArrayBufferViewCore$8.aTypedArray;
4233         var exportTypedArrayMethod$9 = ArrayBufferViewCore$8.exportTypedArrayMethod;
4234
4235         // `%TypedArray%.prototype.reduce` method
4236         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduce
4237         exportTypedArrayMethod$9('reduce', function reduce(callbackfn /* , initialValue */) {
4238           return $reduce$1(aTypedArray$8(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4239         });
4240
4241         var ArrayBufferViewCore$7 = arrayBufferViewCore;
4242         var $reduceRight = arrayReduce.right;
4243
4244         var aTypedArray$7 = ArrayBufferViewCore$7.aTypedArray;
4245         var exportTypedArrayMethod$8 = ArrayBufferViewCore$7.exportTypedArrayMethod;
4246
4247         // `%TypedArray%.prototype.reduceRicht` method
4248         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduceright
4249         exportTypedArrayMethod$8('reduceRight', function reduceRight(callbackfn /* , initialValue */) {
4250           return $reduceRight(aTypedArray$7(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4251         });
4252
4253         var ArrayBufferViewCore$6 = arrayBufferViewCore;
4254
4255         var aTypedArray$6 = ArrayBufferViewCore$6.aTypedArray;
4256         var exportTypedArrayMethod$7 = ArrayBufferViewCore$6.exportTypedArrayMethod;
4257         var floor$5 = Math.floor;
4258
4259         // `%TypedArray%.prototype.reverse` method
4260         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse
4261         exportTypedArrayMethod$7('reverse', function reverse() {
4262           var that = this;
4263           var length = aTypedArray$6(that).length;
4264           var middle = floor$5(length / 2);
4265           var index = 0;
4266           var value;
4267           while (index < middle) {
4268             value = that[index];
4269             that[index++] = that[--length];
4270             that[length] = value;
4271           } return that;
4272         });
4273
4274         var ArrayBufferViewCore$5 = arrayBufferViewCore;
4275         var toLength$d = toLength$q;
4276         var toOffset = toOffset$2;
4277         var toObject$9 = toObject$i;
4278         var fails$x = fails$N;
4279
4280         var aTypedArray$5 = ArrayBufferViewCore$5.aTypedArray;
4281         var exportTypedArrayMethod$6 = ArrayBufferViewCore$5.exportTypedArrayMethod;
4282
4283         var FORCED$d = fails$x(function () {
4284           // eslint-disable-next-line es/no-typed-arrays -- required for testing
4285           new Int8Array(1).set({});
4286         });
4287
4288         // `%TypedArray%.prototype.set` method
4289         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
4290         exportTypedArrayMethod$6('set', function set(arrayLike /* , offset */) {
4291           aTypedArray$5(this);
4292           var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
4293           var length = this.length;
4294           var src = toObject$9(arrayLike);
4295           var len = toLength$d(src.length);
4296           var index = 0;
4297           if (len + offset > length) throw RangeError('Wrong length');
4298           while (index < len) this[offset + index] = src[index++];
4299         }, FORCED$d);
4300
4301         var ArrayBufferViewCore$4 = arrayBufferViewCore;
4302         var speciesConstructor$3 = speciesConstructor$8;
4303         var fails$w = fails$N;
4304
4305         var aTypedArray$4 = ArrayBufferViewCore$4.aTypedArray;
4306         var aTypedArrayConstructor = ArrayBufferViewCore$4.aTypedArrayConstructor;
4307         var exportTypedArrayMethod$5 = ArrayBufferViewCore$4.exportTypedArrayMethod;
4308         var $slice$1 = [].slice;
4309
4310         var FORCED$c = fails$w(function () {
4311           // eslint-disable-next-line es/no-typed-arrays -- required for testing
4312           new Int8Array(1).slice();
4313         });
4314
4315         // `%TypedArray%.prototype.slice` method
4316         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice
4317         exportTypedArrayMethod$5('slice', function slice(start, end) {
4318           var list = $slice$1.call(aTypedArray$4(this), start, end);
4319           var C = speciesConstructor$3(this, this.constructor);
4320           var index = 0;
4321           var length = list.length;
4322           var result = new (aTypedArrayConstructor(C))(length);
4323           while (length > index) result[index] = list[index++];
4324           return result;
4325         }, FORCED$c);
4326
4327         var ArrayBufferViewCore$3 = arrayBufferViewCore;
4328         var $some$1 = arrayIteration.some;
4329
4330         var aTypedArray$3 = ArrayBufferViewCore$3.aTypedArray;
4331         var exportTypedArrayMethod$4 = ArrayBufferViewCore$3.exportTypedArrayMethod;
4332
4333         // `%TypedArray%.prototype.some` method
4334         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.some
4335         exportTypedArrayMethod$4('some', function some(callbackfn /* , thisArg */) {
4336           return $some$1(aTypedArray$3(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4337         });
4338
4339         // TODO: use something more complex like timsort?
4340         var floor$4 = Math.floor;
4341
4342         var mergeSort = function (array, comparefn) {
4343           var length = array.length;
4344           var middle = floor$4(length / 2);
4345           return length < 8 ? insertionSort(array, comparefn) : merge$5(
4346             mergeSort(array.slice(0, middle), comparefn),
4347             mergeSort(array.slice(middle), comparefn),
4348             comparefn
4349           );
4350         };
4351
4352         var insertionSort = function (array, comparefn) {
4353           var length = array.length;
4354           var i = 1;
4355           var element, j;
4356
4357           while (i < length) {
4358             j = i;
4359             element = array[i];
4360             while (j && comparefn(array[j - 1], element) > 0) {
4361               array[j] = array[--j];
4362             }
4363             if (j !== i++) array[j] = element;
4364           } return array;
4365         };
4366
4367         var merge$5 = function (left, right, comparefn) {
4368           var llength = left.length;
4369           var rlength = right.length;
4370           var lindex = 0;
4371           var rindex = 0;
4372           var result = [];
4373
4374           while (lindex < llength || rindex < rlength) {
4375             if (lindex < llength && rindex < rlength) {
4376               result.push(comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++]);
4377             } else {
4378               result.push(lindex < llength ? left[lindex++] : right[rindex++]);
4379             }
4380           } return result;
4381         };
4382
4383         var arraySort = mergeSort;
4384
4385         var userAgent$2 = engineUserAgent;
4386
4387         var firefox = userAgent$2.match(/firefox\/(\d+)/i);
4388
4389         var engineFfVersion = !!firefox && +firefox[1];
4390
4391         var UA = engineUserAgent;
4392
4393         var engineIsIeOrEdge = /MSIE|Trident/.test(UA);
4394
4395         var userAgent$1 = engineUserAgent;
4396
4397         var webkit = userAgent$1.match(/AppleWebKit\/(\d+)\./);
4398
4399         var engineWebkitVersion = !!webkit && +webkit[1];
4400
4401         var ArrayBufferViewCore$2 = arrayBufferViewCore;
4402         var global$d = global$F;
4403         var fails$v = fails$N;
4404         var aFunction$3 = aFunction$9;
4405         var toLength$c = toLength$q;
4406         var internalSort$1 = arraySort;
4407         var FF$1 = engineFfVersion;
4408         var IE_OR_EDGE$1 = engineIsIeOrEdge;
4409         var V8$1 = engineV8Version;
4410         var WEBKIT$1 = engineWebkitVersion;
4411
4412         var aTypedArray$2 = ArrayBufferViewCore$2.aTypedArray;
4413         var exportTypedArrayMethod$3 = ArrayBufferViewCore$2.exportTypedArrayMethod;
4414         var Uint16Array = global$d.Uint16Array;
4415         var nativeSort$1 = Uint16Array && Uint16Array.prototype.sort;
4416
4417         // WebKit
4418         var ACCEPT_INCORRECT_ARGUMENTS = !!nativeSort$1 && !fails$v(function () {
4419           var array = new Uint16Array(2);
4420           array.sort(null);
4421           array.sort({});
4422         });
4423
4424         var STABLE_SORT$1 = !!nativeSort$1 && !fails$v(function () {
4425           // feature detection can be too slow, so check engines versions
4426           if (V8$1) return V8$1 < 74;
4427           if (FF$1) return FF$1 < 67;
4428           if (IE_OR_EDGE$1) return true;
4429           if (WEBKIT$1) return WEBKIT$1 < 602;
4430
4431           var array = new Uint16Array(516);
4432           var expected = Array(516);
4433           var index, mod;
4434
4435           for (index = 0; index < 516; index++) {
4436             mod = index % 4;
4437             array[index] = 515 - index;
4438             expected[index] = index - 2 * mod + 3;
4439           }
4440
4441           array.sort(function (a, b) {
4442             return (a / 4 | 0) - (b / 4 | 0);
4443           });
4444
4445           for (index = 0; index < 516; index++) {
4446             if (array[index] !== expected[index]) return true;
4447           }
4448         });
4449
4450         var getSortCompare$1 = function (comparefn) {
4451           return function (x, y) {
4452             if (comparefn !== undefined) return +comparefn(x, y) || 0;
4453             // eslint-disable-next-line no-self-compare -- NaN check
4454             if (y !== y) return -1;
4455             // eslint-disable-next-line no-self-compare -- NaN check
4456             if (x !== x) return 1;
4457             if (x === 0 && y === 0) return 1 / x > 0 && 1 / y < 0 ? 1 : -1;
4458             return x > y;
4459           };
4460         };
4461
4462         // `%TypedArray%.prototype.sort` method
4463         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.sort
4464         exportTypedArrayMethod$3('sort', function sort(comparefn) {
4465           var array = this;
4466           if (comparefn !== undefined) aFunction$3(comparefn);
4467           if (STABLE_SORT$1) return nativeSort$1.call(array, comparefn);
4468
4469           aTypedArray$2(array);
4470           var arrayLength = toLength$c(array.length);
4471           var items = Array(arrayLength);
4472           var index;
4473
4474           for (index = 0; index < arrayLength; index++) {
4475             items[index] = array[index];
4476           }
4477
4478           items = internalSort$1(array, getSortCompare$1(comparefn));
4479
4480           for (index = 0; index < arrayLength; index++) {
4481             array[index] = items[index];
4482           }
4483
4484           return array;
4485         }, !STABLE_SORT$1 || ACCEPT_INCORRECT_ARGUMENTS);
4486
4487         var ArrayBufferViewCore$1 = arrayBufferViewCore;
4488         var toLength$b = toLength$q;
4489         var toAbsoluteIndex$3 = toAbsoluteIndex$8;
4490         var speciesConstructor$2 = speciesConstructor$8;
4491
4492         var aTypedArray$1 = ArrayBufferViewCore$1.aTypedArray;
4493         var exportTypedArrayMethod$2 = ArrayBufferViewCore$1.exportTypedArrayMethod;
4494
4495         // `%TypedArray%.prototype.subarray` method
4496         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray
4497         exportTypedArrayMethod$2('subarray', function subarray(begin, end) {
4498           var O = aTypedArray$1(this);
4499           var length = O.length;
4500           var beginIndex = toAbsoluteIndex$3(begin, length);
4501           return new (speciesConstructor$2(O, O.constructor))(
4502             O.buffer,
4503             O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT,
4504             toLength$b((end === undefined ? length : toAbsoluteIndex$3(end, length)) - beginIndex)
4505           );
4506         });
4507
4508         var global$c = global$F;
4509         var ArrayBufferViewCore = arrayBufferViewCore;
4510         var fails$u = fails$N;
4511
4512         var Int8Array$1 = global$c.Int8Array;
4513         var aTypedArray = ArrayBufferViewCore.aTypedArray;
4514         var exportTypedArrayMethod$1 = ArrayBufferViewCore.exportTypedArrayMethod;
4515         var $toLocaleString = [].toLocaleString;
4516         var $slice = [].slice;
4517
4518         // iOS Safari 6.x fails here
4519         var TO_LOCALE_STRING_BUG = !!Int8Array$1 && fails$u(function () {
4520           $toLocaleString.call(new Int8Array$1(1));
4521         });
4522
4523         var FORCED$b = fails$u(function () {
4524           return [1, 2].toLocaleString() != new Int8Array$1([1, 2]).toLocaleString();
4525         }) || !fails$u(function () {
4526           Int8Array$1.prototype.toLocaleString.call([1, 2]);
4527         });
4528
4529         // `%TypedArray%.prototype.toLocaleString` method
4530         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tolocalestring
4531         exportTypedArrayMethod$1('toLocaleString', function toLocaleString() {
4532           return $toLocaleString.apply(TO_LOCALE_STRING_BUG ? $slice.call(aTypedArray(this)) : aTypedArray(this), arguments);
4533         }, FORCED$b);
4534
4535         var exportTypedArrayMethod = arrayBufferViewCore.exportTypedArrayMethod;
4536         var fails$t = fails$N;
4537         var global$b = global$F;
4538
4539         var Uint8Array$1 = global$b.Uint8Array;
4540         var Uint8ArrayPrototype = Uint8Array$1 && Uint8Array$1.prototype || {};
4541         var arrayToString = [].toString;
4542         var arrayJoin = [].join;
4543
4544         if (fails$t(function () { arrayToString.call({}); })) {
4545           arrayToString = function toString() {
4546             return arrayJoin.call(this);
4547           };
4548         }
4549
4550         var IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString;
4551
4552         // `%TypedArray%.prototype.toString` method
4553         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tostring
4554         exportTypedArrayMethod('toString', arrayToString, IS_NOT_ARRAY_METHOD);
4555
4556         var $$T = _export;
4557         var IndexedObject$1 = indexedObject;
4558         var toIndexedObject$3 = toIndexedObject$b;
4559         var arrayMethodIsStrict$4 = arrayMethodIsStrict$8;
4560
4561         var nativeJoin = [].join;
4562
4563         var ES3_STRINGS = IndexedObject$1 != Object;
4564         var STRICT_METHOD$4 = arrayMethodIsStrict$4('join', ',');
4565
4566         // `Array.prototype.join` method
4567         // https://tc39.es/ecma262/#sec-array.prototype.join
4568         $$T({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$4 }, {
4569           join: function join(separator) {
4570             return nativeJoin.call(toIndexedObject$3(this), separator === undefined ? ',' : separator);
4571           }
4572         });
4573
4574         var toPrimitive$2 = toPrimitive$7;
4575         var definePropertyModule = objectDefineProperty;
4576         var createPropertyDescriptor$1 = createPropertyDescriptor$7;
4577
4578         var createProperty$4 = function (object, key, value) {
4579           var propertyKey = toPrimitive$2(key);
4580           if (propertyKey in object) definePropertyModule.f(object, propertyKey, createPropertyDescriptor$1(0, value));
4581           else object[propertyKey] = value;
4582         };
4583
4584         var $$S = _export;
4585         var isObject$d = isObject$r;
4586         var isArray$2 = isArray$6;
4587         var toAbsoluteIndex$2 = toAbsoluteIndex$8;
4588         var toLength$a = toLength$q;
4589         var toIndexedObject$2 = toIndexedObject$b;
4590         var createProperty$3 = createProperty$4;
4591         var wellKnownSymbol$8 = wellKnownSymbol$s;
4592         var arrayMethodHasSpeciesSupport$3 = arrayMethodHasSpeciesSupport$5;
4593
4594         var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport$3('slice');
4595
4596         var SPECIES$1 = wellKnownSymbol$8('species');
4597         var nativeSlice = [].slice;
4598         var max$3 = Math.max;
4599
4600         // `Array.prototype.slice` method
4601         // https://tc39.es/ecma262/#sec-array.prototype.slice
4602         // fallback for not array-like ES3 strings and DOM objects
4603         $$S({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 }, {
4604           slice: function slice(start, end) {
4605             var O = toIndexedObject$2(this);
4606             var length = toLength$a(O.length);
4607             var k = toAbsoluteIndex$2(start, length);
4608             var fin = toAbsoluteIndex$2(end === undefined ? length : end, length);
4609             // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
4610             var Constructor, result, n;
4611             if (isArray$2(O)) {
4612               Constructor = O.constructor;
4613               // cross-realm fallback
4614               if (typeof Constructor == 'function' && (Constructor === Array || isArray$2(Constructor.prototype))) {
4615                 Constructor = undefined;
4616               } else if (isObject$d(Constructor)) {
4617                 Constructor = Constructor[SPECIES$1];
4618                 if (Constructor === null) Constructor = undefined;
4619               }
4620               if (Constructor === Array || Constructor === undefined) {
4621                 return nativeSlice.call(O, k, fin);
4622               }
4623             }
4624             result = new (Constructor === undefined ? Array : Constructor)(max$3(fin - k, 0));
4625             for (n = 0; k < fin; k++, n++) if (k in O) createProperty$3(result, n, O[k]);
4626             result.length = n;
4627             return result;
4628           }
4629         });
4630
4631         var fails$s = fails$N;
4632         var wellKnownSymbol$7 = wellKnownSymbol$s;
4633         var IS_PURE = isPure;
4634
4635         var ITERATOR$1 = wellKnownSymbol$7('iterator');
4636
4637         var nativeUrl = !fails$s(function () {
4638           var url = new URL('b?a=1&b=2&c=3', 'http://a');
4639           var searchParams = url.searchParams;
4640           var result = '';
4641           url.pathname = 'c%20d';
4642           searchParams.forEach(function (value, key) {
4643             searchParams['delete']('b');
4644             result += key + value;
4645           });
4646           return (IS_PURE && !url.toJSON)
4647             || !searchParams.sort
4648             || url.href !== 'http://a/c%20d?a=1&c=3'
4649             || searchParams.get('c') !== '3'
4650             || String(new URLSearchParams('?a=1')) !== 'a=1'
4651             || !searchParams[ITERATOR$1]
4652             // throws in Edge
4653             || new URL('https://a@b').username !== 'a'
4654             || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b'
4655             // not punycoded in Edge
4656             || new URL('http://тест').host !== 'xn--e1aybc'
4657             // not escaped in Chrome 62-
4658             || new URL('http://a#б').hash !== '#%D0%B1'
4659             // fails in Chrome 66-
4660             || result !== 'a1c3'
4661             // throws in Safari
4662             || new URL('http://x', undefined).host !== 'x';
4663         });
4664
4665         var DESCRIPTORS$b = descriptors;
4666         var fails$r = fails$N;
4667         var objectKeys$1 = objectKeys$4;
4668         var getOwnPropertySymbolsModule = objectGetOwnPropertySymbols;
4669         var propertyIsEnumerableModule = objectPropertyIsEnumerable;
4670         var toObject$8 = toObject$i;
4671         var IndexedObject = indexedObject;
4672
4673         // eslint-disable-next-line es/no-object-assign -- safe
4674         var $assign = Object.assign;
4675         // eslint-disable-next-line es/no-object-defineproperty -- required for testing
4676         var defineProperty$5 = Object.defineProperty;
4677
4678         // `Object.assign` method
4679         // https://tc39.es/ecma262/#sec-object.assign
4680         var objectAssign = !$assign || fails$r(function () {
4681           // should have correct order of operations (Edge bug)
4682           if (DESCRIPTORS$b && $assign({ b: 1 }, $assign(defineProperty$5({}, 'a', {
4683             enumerable: true,
4684             get: function () {
4685               defineProperty$5(this, 'b', {
4686                 value: 3,
4687                 enumerable: false
4688               });
4689             }
4690           }), { b: 2 })).b !== 1) return true;
4691           // should work with symbols and should have deterministic property order (V8 bug)
4692           var A = {};
4693           var B = {};
4694           // eslint-disable-next-line es/no-symbol -- safe
4695           var symbol = Symbol();
4696           var alphabet = 'abcdefghijklmnopqrst';
4697           A[symbol] = 7;
4698           alphabet.split('').forEach(function (chr) { B[chr] = chr; });
4699           return $assign({}, A)[symbol] != 7 || objectKeys$1($assign({}, B)).join('') != alphabet;
4700         }) ? function assign(target, source) { // eslint-disable-line no-unused-vars -- required for `.length`
4701           var T = toObject$8(target);
4702           var argumentsLength = arguments.length;
4703           var index = 1;
4704           var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;
4705           var propertyIsEnumerable = propertyIsEnumerableModule.f;
4706           while (argumentsLength > index) {
4707             var S = IndexedObject(arguments[index++]);
4708             var keys = getOwnPropertySymbols ? objectKeys$1(S).concat(getOwnPropertySymbols(S)) : objectKeys$1(S);
4709             var length = keys.length;
4710             var j = 0;
4711             var key;
4712             while (length > j) {
4713               key = keys[j++];
4714               if (!DESCRIPTORS$b || propertyIsEnumerable.call(S, key)) T[key] = S[key];
4715             }
4716           } return T;
4717         } : $assign;
4718
4719         var anObject$a = anObject$m;
4720         var iteratorClose = iteratorClose$2;
4721
4722         // call something on iterator step with safe closing on error
4723         var callWithSafeIterationClosing$1 = function (iterator, fn, value, ENTRIES) {
4724           try {
4725             return ENTRIES ? fn(anObject$a(value)[0], value[1]) : fn(value);
4726           } catch (error) {
4727             iteratorClose(iterator);
4728             throw error;
4729           }
4730         };
4731
4732         var bind$6 = functionBindContext;
4733         var toObject$7 = toObject$i;
4734         var callWithSafeIterationClosing = callWithSafeIterationClosing$1;
4735         var isArrayIteratorMethod = isArrayIteratorMethod$3;
4736         var toLength$9 = toLength$q;
4737         var createProperty$2 = createProperty$4;
4738         var getIteratorMethod$2 = getIteratorMethod$5;
4739
4740         // `Array.from` method implementation
4741         // https://tc39.es/ecma262/#sec-array.from
4742         var arrayFrom$1 = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {
4743           var O = toObject$7(arrayLike);
4744           var C = typeof this == 'function' ? this : Array;
4745           var argumentsLength = arguments.length;
4746           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
4747           var mapping = mapfn !== undefined;
4748           var iteratorMethod = getIteratorMethod$2(O);
4749           var index = 0;
4750           var length, result, step, iterator, next, value;
4751           if (mapping) mapfn = bind$6(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
4752           // if the target is not iterable or it's an array with the default iterator - use a simple case
4753           if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
4754             iterator = iteratorMethod.call(O);
4755             next = iterator.next;
4756             result = new C();
4757             for (;!(step = next.call(iterator)).done; index++) {
4758               value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
4759               createProperty$2(result, index, value);
4760             }
4761           } else {
4762             length = toLength$9(O.length);
4763             result = new C(length);
4764             for (;length > index; index++) {
4765               value = mapping ? mapfn(O[index], index) : O[index];
4766               createProperty$2(result, index, value);
4767             }
4768           }
4769           result.length = index;
4770           return result;
4771         };
4772
4773         // based on https://github.com/bestiejs/punycode.js/blob/master/punycode.js
4774         var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
4775         var base = 36;
4776         var tMin = 1;
4777         var tMax = 26;
4778         var skew = 38;
4779         var damp = 700;
4780         var initialBias = 72;
4781         var initialN = 128; // 0x80
4782         var delimiter = '-'; // '\x2D'
4783         var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars
4784         var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
4785         var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
4786         var baseMinusTMin = base - tMin;
4787         var floor$3 = Math.floor;
4788         var stringFromCharCode = String.fromCharCode;
4789
4790         /**
4791          * Creates an array containing the numeric code points of each Unicode
4792          * character in the string. While JavaScript uses UCS-2 internally,
4793          * this function will convert a pair of surrogate halves (each of which
4794          * UCS-2 exposes as separate characters) into a single code point,
4795          * matching UTF-16.
4796          */
4797         var ucs2decode = function (string) {
4798           var output = [];
4799           var counter = 0;
4800           var length = string.length;
4801           while (counter < length) {
4802             var value = string.charCodeAt(counter++);
4803             if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
4804               // It's a high surrogate, and there is a next character.
4805               var extra = string.charCodeAt(counter++);
4806               if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
4807                 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
4808               } else {
4809                 // It's an unmatched surrogate; only append this code unit, in case the
4810                 // next code unit is the high surrogate of a surrogate pair.
4811                 output.push(value);
4812                 counter--;
4813               }
4814             } else {
4815               output.push(value);
4816             }
4817           }
4818           return output;
4819         };
4820
4821         /**
4822          * Converts a digit/integer into a basic code point.
4823          */
4824         var digitToBasic = function (digit) {
4825           //  0..25 map to ASCII a..z or A..Z
4826           // 26..35 map to ASCII 0..9
4827           return digit + 22 + 75 * (digit < 26);
4828         };
4829
4830         /**
4831          * Bias adaptation function as per section 3.4 of RFC 3492.
4832          * https://tools.ietf.org/html/rfc3492#section-3.4
4833          */
4834         var adapt = function (delta, numPoints, firstTime) {
4835           var k = 0;
4836           delta = firstTime ? floor$3(delta / damp) : delta >> 1;
4837           delta += floor$3(delta / numPoints);
4838           for (; delta > baseMinusTMin * tMax >> 1; k += base) {
4839             delta = floor$3(delta / baseMinusTMin);
4840           }
4841           return floor$3(k + (baseMinusTMin + 1) * delta / (delta + skew));
4842         };
4843
4844         /**
4845          * Converts a string of Unicode symbols (e.g. a domain name label) to a
4846          * Punycode string of ASCII-only symbols.
4847          */
4848         // eslint-disable-next-line max-statements -- TODO
4849         var encode = function (input) {
4850           var output = [];
4851
4852           // Convert the input in UCS-2 to an array of Unicode code points.
4853           input = ucs2decode(input);
4854
4855           // Cache the length.
4856           var inputLength = input.length;
4857
4858           // Initialize the state.
4859           var n = initialN;
4860           var delta = 0;
4861           var bias = initialBias;
4862           var i, currentValue;
4863
4864           // Handle the basic code points.
4865           for (i = 0; i < input.length; i++) {
4866             currentValue = input[i];
4867             if (currentValue < 0x80) {
4868               output.push(stringFromCharCode(currentValue));
4869             }
4870           }
4871
4872           var basicLength = output.length; // number of basic code points.
4873           var handledCPCount = basicLength; // number of code points that have been handled;
4874
4875           // Finish the basic string with a delimiter unless it's empty.
4876           if (basicLength) {
4877             output.push(delimiter);
4878           }
4879
4880           // Main encoding loop:
4881           while (handledCPCount < inputLength) {
4882             // All non-basic code points < n have been handled already. Find the next larger one:
4883             var m = maxInt;
4884             for (i = 0; i < input.length; i++) {
4885               currentValue = input[i];
4886               if (currentValue >= n && currentValue < m) {
4887                 m = currentValue;
4888               }
4889             }
4890
4891             // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.
4892             var handledCPCountPlusOne = handledCPCount + 1;
4893             if (m - n > floor$3((maxInt - delta) / handledCPCountPlusOne)) {
4894               throw RangeError(OVERFLOW_ERROR);
4895             }
4896
4897             delta += (m - n) * handledCPCountPlusOne;
4898             n = m;
4899
4900             for (i = 0; i < input.length; i++) {
4901               currentValue = input[i];
4902               if (currentValue < n && ++delta > maxInt) {
4903                 throw RangeError(OVERFLOW_ERROR);
4904               }
4905               if (currentValue == n) {
4906                 // Represent delta as a generalized variable-length integer.
4907                 var q = delta;
4908                 for (var k = base; /* no condition */; k += base) {
4909                   var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
4910                   if (q < t) break;
4911                   var qMinusT = q - t;
4912                   var baseMinusT = base - t;
4913                   output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
4914                   q = floor$3(qMinusT / baseMinusT);
4915                 }
4916
4917                 output.push(stringFromCharCode(digitToBasic(q)));
4918                 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
4919                 delta = 0;
4920                 ++handledCPCount;
4921               }
4922             }
4923
4924             ++delta;
4925             ++n;
4926           }
4927           return output.join('');
4928         };
4929
4930         var stringPunycodeToAscii = function (input) {
4931           var encoded = [];
4932           var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
4933           var i, label;
4934           for (i = 0; i < labels.length; i++) {
4935             label = labels[i];
4936             encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
4937           }
4938           return encoded.join('.');
4939         };
4940
4941         var anObject$9 = anObject$m;
4942         var getIteratorMethod$1 = getIteratorMethod$5;
4943
4944         var getIterator$1 = function (it) {
4945           var iteratorMethod = getIteratorMethod$1(it);
4946           if (typeof iteratorMethod != 'function') {
4947             throw TypeError(String(it) + ' is not iterable');
4948           } return anObject$9(iteratorMethod.call(it));
4949         };
4950
4951         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4952
4953         var $$R = _export;
4954         var getBuiltIn$2 = getBuiltIn$9;
4955         var USE_NATIVE_URL$1 = nativeUrl;
4956         var redefine$7 = redefine$g.exports;
4957         var redefineAll$1 = redefineAll$4;
4958         var setToStringTag$4 = setToStringTag$a;
4959         var createIteratorConstructor = createIteratorConstructor$2;
4960         var InternalStateModule$2 = internalState;
4961         var anInstance$3 = anInstance$7;
4962         var hasOwn = has$j;
4963         var bind$5 = functionBindContext;
4964         var classof$4 = classof$b;
4965         var anObject$8 = anObject$m;
4966         var isObject$c = isObject$r;
4967         var create$8 = objectCreate;
4968         var createPropertyDescriptor = createPropertyDescriptor$7;
4969         var getIterator = getIterator$1;
4970         var getIteratorMethod = getIteratorMethod$5;
4971         var wellKnownSymbol$6 = wellKnownSymbol$s;
4972
4973         var $fetch = getBuiltIn$2('fetch');
4974         var Headers$1 = getBuiltIn$2('Headers');
4975         var ITERATOR = wellKnownSymbol$6('iterator');
4976         var URL_SEARCH_PARAMS = 'URLSearchParams';
4977         var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
4978         var setInternalState$2 = InternalStateModule$2.set;
4979         var getInternalParamsState = InternalStateModule$2.getterFor(URL_SEARCH_PARAMS);
4980         var getInternalIteratorState = InternalStateModule$2.getterFor(URL_SEARCH_PARAMS_ITERATOR);
4981
4982         var plus = /\+/g;
4983         var sequences = Array(4);
4984
4985         var percentSequence = function (bytes) {
4986           return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
4987         };
4988
4989         var percentDecode = function (sequence) {
4990           try {
4991             return decodeURIComponent(sequence);
4992           } catch (error) {
4993             return sequence;
4994           }
4995         };
4996
4997         var deserialize = function (it) {
4998           var result = it.replace(plus, ' ');
4999           var bytes = 4;
5000           try {
5001             return decodeURIComponent(result);
5002           } catch (error) {
5003             while (bytes) {
5004               result = result.replace(percentSequence(bytes--), percentDecode);
5005             }
5006             return result;
5007           }
5008         };
5009
5010         var find$1 = /[!'()~]|%20/g;
5011
5012         var replace$1 = {
5013           '!': '%21',
5014           "'": '%27',
5015           '(': '%28',
5016           ')': '%29',
5017           '~': '%7E',
5018           '%20': '+'
5019         };
5020
5021         var replacer = function (match) {
5022           return replace$1[match];
5023         };
5024
5025         var serialize = function (it) {
5026           return encodeURIComponent(it).replace(find$1, replacer);
5027         };
5028
5029         var parseSearchParams = function (result, query) {
5030           if (query) {
5031             var attributes = query.split('&');
5032             var index = 0;
5033             var attribute, entry;
5034             while (index < attributes.length) {
5035               attribute = attributes[index++];
5036               if (attribute.length) {
5037                 entry = attribute.split('=');
5038                 result.push({
5039                   key: deserialize(entry.shift()),
5040                   value: deserialize(entry.join('='))
5041                 });
5042               }
5043             }
5044           }
5045         };
5046
5047         var updateSearchParams = function (query) {
5048           this.entries.length = 0;
5049           parseSearchParams(this.entries, query);
5050         };
5051
5052         var validateArgumentsLength = function (passed, required) {
5053           if (passed < required) throw TypeError('Not enough arguments');
5054         };
5055
5056         var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
5057           setInternalState$2(this, {
5058             type: URL_SEARCH_PARAMS_ITERATOR,
5059             iterator: getIterator(getInternalParamsState(params).entries),
5060             kind: kind
5061           });
5062         }, 'Iterator', function next() {
5063           var state = getInternalIteratorState(this);
5064           var kind = state.kind;
5065           var step = state.iterator.next();
5066           var entry = step.value;
5067           if (!step.done) {
5068             step.value = kind === 'keys' ? entry.key : kind === 'values' ? entry.value : [entry.key, entry.value];
5069           } return step;
5070         });
5071
5072         // `URLSearchParams` constructor
5073         // https://url.spec.whatwg.org/#interface-urlsearchparams
5074         var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
5075           anInstance$3(this, URLSearchParamsConstructor, URL_SEARCH_PARAMS);
5076           var init = arguments.length > 0 ? arguments[0] : undefined;
5077           var that = this;
5078           var entries = [];
5079           var iteratorMethod, iterator, next, step, entryIterator, entryNext, first, second, key;
5080
5081           setInternalState$2(that, {
5082             type: URL_SEARCH_PARAMS,
5083             entries: entries,
5084             updateURL: function () { /* empty */ },
5085             updateSearchParams: updateSearchParams
5086           });
5087
5088           if (init !== undefined) {
5089             if (isObject$c(init)) {
5090               iteratorMethod = getIteratorMethod(init);
5091               if (typeof iteratorMethod === 'function') {
5092                 iterator = iteratorMethod.call(init);
5093                 next = iterator.next;
5094                 while (!(step = next.call(iterator)).done) {
5095                   entryIterator = getIterator(anObject$8(step.value));
5096                   entryNext = entryIterator.next;
5097                   if (
5098                     (first = entryNext.call(entryIterator)).done ||
5099                     (second = entryNext.call(entryIterator)).done ||
5100                     !entryNext.call(entryIterator).done
5101                   ) throw TypeError('Expected sequence with length 2');
5102                   entries.push({ key: first.value + '', value: second.value + '' });
5103                 }
5104               } else for (key in init) if (hasOwn(init, key)) entries.push({ key: key, value: init[key] + '' });
5105             } else {
5106               parseSearchParams(entries, typeof init === 'string' ? init.charAt(0) === '?' ? init.slice(1) : init : init + '');
5107             }
5108           }
5109         };
5110
5111         var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
5112
5113         redefineAll$1(URLSearchParamsPrototype, {
5114           // `URLSearchParams.prototype.append` method
5115           // https://url.spec.whatwg.org/#dom-urlsearchparams-append
5116           append: function append(name, value) {
5117             validateArgumentsLength(arguments.length, 2);
5118             var state = getInternalParamsState(this);
5119             state.entries.push({ key: name + '', value: value + '' });
5120             state.updateURL();
5121           },
5122           // `URLSearchParams.prototype.delete` method
5123           // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
5124           'delete': function (name) {
5125             validateArgumentsLength(arguments.length, 1);
5126             var state = getInternalParamsState(this);
5127             var entries = state.entries;
5128             var key = name + '';
5129             var index = 0;
5130             while (index < entries.length) {
5131               if (entries[index].key === key) entries.splice(index, 1);
5132               else index++;
5133             }
5134             state.updateURL();
5135           },
5136           // `URLSearchParams.prototype.get` method
5137           // https://url.spec.whatwg.org/#dom-urlsearchparams-get
5138           get: function get(name) {
5139             validateArgumentsLength(arguments.length, 1);
5140             var entries = getInternalParamsState(this).entries;
5141             var key = name + '';
5142             var index = 0;
5143             for (; index < entries.length; index++) {
5144               if (entries[index].key === key) return entries[index].value;
5145             }
5146             return null;
5147           },
5148           // `URLSearchParams.prototype.getAll` method
5149           // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
5150           getAll: function getAll(name) {
5151             validateArgumentsLength(arguments.length, 1);
5152             var entries = getInternalParamsState(this).entries;
5153             var key = name + '';
5154             var result = [];
5155             var index = 0;
5156             for (; index < entries.length; index++) {
5157               if (entries[index].key === key) result.push(entries[index].value);
5158             }
5159             return result;
5160           },
5161           // `URLSearchParams.prototype.has` method
5162           // https://url.spec.whatwg.org/#dom-urlsearchparams-has
5163           has: function has(name) {
5164             validateArgumentsLength(arguments.length, 1);
5165             var entries = getInternalParamsState(this).entries;
5166             var key = name + '';
5167             var index = 0;
5168             while (index < entries.length) {
5169               if (entries[index++].key === key) return true;
5170             }
5171             return false;
5172           },
5173           // `URLSearchParams.prototype.set` method
5174           // https://url.spec.whatwg.org/#dom-urlsearchparams-set
5175           set: function set(name, value) {
5176             validateArgumentsLength(arguments.length, 1);
5177             var state = getInternalParamsState(this);
5178             var entries = state.entries;
5179             var found = false;
5180             var key = name + '';
5181             var val = value + '';
5182             var index = 0;
5183             var entry;
5184             for (; index < entries.length; index++) {
5185               entry = entries[index];
5186               if (entry.key === key) {
5187                 if (found) entries.splice(index--, 1);
5188                 else {
5189                   found = true;
5190                   entry.value = val;
5191                 }
5192               }
5193             }
5194             if (!found) entries.push({ key: key, value: val });
5195             state.updateURL();
5196           },
5197           // `URLSearchParams.prototype.sort` method
5198           // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
5199           sort: function sort() {
5200             var state = getInternalParamsState(this);
5201             var entries = state.entries;
5202             // Array#sort is not stable in some engines
5203             var slice = entries.slice();
5204             var entry, entriesIndex, sliceIndex;
5205             entries.length = 0;
5206             for (sliceIndex = 0; sliceIndex < slice.length; sliceIndex++) {
5207               entry = slice[sliceIndex];
5208               for (entriesIndex = 0; entriesIndex < sliceIndex; entriesIndex++) {
5209                 if (entries[entriesIndex].key > entry.key) {
5210                   entries.splice(entriesIndex, 0, entry);
5211                   break;
5212                 }
5213               }
5214               if (entriesIndex === sliceIndex) entries.push(entry);
5215             }
5216             state.updateURL();
5217           },
5218           // `URLSearchParams.prototype.forEach` method
5219           forEach: function forEach(callback /* , thisArg */) {
5220             var entries = getInternalParamsState(this).entries;
5221             var boundFunction = bind$5(callback, arguments.length > 1 ? arguments[1] : undefined, 3);
5222             var index = 0;
5223             var entry;
5224             while (index < entries.length) {
5225               entry = entries[index++];
5226               boundFunction(entry.value, entry.key, this);
5227             }
5228           },
5229           // `URLSearchParams.prototype.keys` method
5230           keys: function keys() {
5231             return new URLSearchParamsIterator(this, 'keys');
5232           },
5233           // `URLSearchParams.prototype.values` method
5234           values: function values() {
5235             return new URLSearchParamsIterator(this, 'values');
5236           },
5237           // `URLSearchParams.prototype.entries` method
5238           entries: function entries() {
5239             return new URLSearchParamsIterator(this, 'entries');
5240           }
5241         }, { enumerable: true });
5242
5243         // `URLSearchParams.prototype[@@iterator]` method
5244         redefine$7(URLSearchParamsPrototype, ITERATOR, URLSearchParamsPrototype.entries);
5245
5246         // `URLSearchParams.prototype.toString` method
5247         // https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
5248         redefine$7(URLSearchParamsPrototype, 'toString', function toString() {
5249           var entries = getInternalParamsState(this).entries;
5250           var result = [];
5251           var index = 0;
5252           var entry;
5253           while (index < entries.length) {
5254             entry = entries[index++];
5255             result.push(serialize(entry.key) + '=' + serialize(entry.value));
5256           } return result.join('&');
5257         }, { enumerable: true });
5258
5259         setToStringTag$4(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
5260
5261         $$R({ global: true, forced: !USE_NATIVE_URL$1 }, {
5262           URLSearchParams: URLSearchParamsConstructor
5263         });
5264
5265         // Wrap `fetch` for correct work with polyfilled `URLSearchParams`
5266         // https://github.com/zloirock/core-js/issues/674
5267         if (!USE_NATIVE_URL$1 && typeof $fetch == 'function' && typeof Headers$1 == 'function') {
5268           $$R({ global: true, enumerable: true, forced: true }, {
5269             fetch: function fetch(input /* , init */) {
5270               var args = [input];
5271               var init, body, headers;
5272               if (arguments.length > 1) {
5273                 init = arguments[1];
5274                 if (isObject$c(init)) {
5275                   body = init.body;
5276                   if (classof$4(body) === URL_SEARCH_PARAMS) {
5277                     headers = init.headers ? new Headers$1(init.headers) : new Headers$1();
5278                     if (!headers.has('content-type')) {
5279                       headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
5280                     }
5281                     init = create$8(init, {
5282                       body: createPropertyDescriptor(0, String(body)),
5283                       headers: createPropertyDescriptor(0, headers)
5284                     });
5285                   }
5286                 }
5287                 args.push(init);
5288               } return $fetch.apply(this, args);
5289             }
5290           });
5291         }
5292
5293         var web_urlSearchParams = {
5294           URLSearchParams: URLSearchParamsConstructor,
5295           getState: getInternalParamsState
5296         };
5297
5298         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
5299
5300         var $$Q = _export;
5301         var DESCRIPTORS$a = descriptors;
5302         var USE_NATIVE_URL = nativeUrl;
5303         var global$a = global$F;
5304         var defineProperties$1 = objectDefineProperties;
5305         var redefine$6 = redefine$g.exports;
5306         var anInstance$2 = anInstance$7;
5307         var has$4 = has$j;
5308         var assign$2 = objectAssign;
5309         var arrayFrom = arrayFrom$1;
5310         var codeAt = stringMultibyte.codeAt;
5311         var toASCII = stringPunycodeToAscii;
5312         var setToStringTag$3 = setToStringTag$a;
5313         var URLSearchParamsModule = web_urlSearchParams;
5314         var InternalStateModule$1 = internalState;
5315
5316         var NativeURL = global$a.URL;
5317         var URLSearchParams$1 = URLSearchParamsModule.URLSearchParams;
5318         var getInternalSearchParamsState = URLSearchParamsModule.getState;
5319         var setInternalState$1 = InternalStateModule$1.set;
5320         var getInternalURLState = InternalStateModule$1.getterFor('URL');
5321         var floor$2 = Math.floor;
5322         var pow$1 = Math.pow;
5323
5324         var INVALID_AUTHORITY = 'Invalid authority';
5325         var INVALID_SCHEME = 'Invalid scheme';
5326         var INVALID_HOST = 'Invalid host';
5327         var INVALID_PORT = 'Invalid port';
5328
5329         var ALPHA = /[A-Za-z]/;
5330         // eslint-disable-next-line regexp/no-obscure-range -- safe
5331         var ALPHANUMERIC = /[\d+-.A-Za-z]/;
5332         var DIGIT = /\d/;
5333         var HEX_START = /^0x/i;
5334         var OCT = /^[0-7]+$/;
5335         var DEC = /^\d+$/;
5336         var HEX = /^[\dA-Fa-f]+$/;
5337         /* eslint-disable no-control-regex -- safe */
5338         var FORBIDDEN_HOST_CODE_POINT = /[\0\t\n\r #%/:<>?@[\\\]^|]/;
5339         var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\0\t\n\r #/:<>?@[\\\]^|]/;
5340         var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
5341         var TAB_AND_NEW_LINE = /[\t\n\r]/g;
5342         /* eslint-enable no-control-regex -- safe */
5343         var EOF;
5344
5345         var parseHost = function (url, input) {
5346           var result, codePoints, index;
5347           if (input.charAt(0) == '[') {
5348             if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
5349             result = parseIPv6(input.slice(1, -1));
5350             if (!result) return INVALID_HOST;
5351             url.host = result;
5352           // opaque host
5353           } else if (!isSpecial(url)) {
5354             if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
5355             result = '';
5356             codePoints = arrayFrom(input);
5357             for (index = 0; index < codePoints.length; index++) {
5358               result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
5359             }
5360             url.host = result;
5361           } else {
5362             input = toASCII(input);
5363             if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
5364             result = parseIPv4(input);
5365             if (result === null) return INVALID_HOST;
5366             url.host = result;
5367           }
5368         };
5369
5370         var parseIPv4 = function (input) {
5371           var parts = input.split('.');
5372           var partsLength, numbers, index, part, radix, number, ipv4;
5373           if (parts.length && parts[parts.length - 1] == '') {
5374             parts.pop();
5375           }
5376           partsLength = parts.length;
5377           if (partsLength > 4) return input;
5378           numbers = [];
5379           for (index = 0; index < partsLength; index++) {
5380             part = parts[index];
5381             if (part == '') return input;
5382             radix = 10;
5383             if (part.length > 1 && part.charAt(0) == '0') {
5384               radix = HEX_START.test(part) ? 16 : 8;
5385               part = part.slice(radix == 8 ? 1 : 2);
5386             }
5387             if (part === '') {
5388               number = 0;
5389             } else {
5390               if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
5391               number = parseInt(part, radix);
5392             }
5393             numbers.push(number);
5394           }
5395           for (index = 0; index < partsLength; index++) {
5396             number = numbers[index];
5397             if (index == partsLength - 1) {
5398               if (number >= pow$1(256, 5 - partsLength)) return null;
5399             } else if (number > 255) return null;
5400           }
5401           ipv4 = numbers.pop();
5402           for (index = 0; index < numbers.length; index++) {
5403             ipv4 += numbers[index] * pow$1(256, 3 - index);
5404           }
5405           return ipv4;
5406         };
5407
5408         // eslint-disable-next-line max-statements -- TODO
5409         var parseIPv6 = function (input) {
5410           var address = [0, 0, 0, 0, 0, 0, 0, 0];
5411           var pieceIndex = 0;
5412           var compress = null;
5413           var pointer = 0;
5414           var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
5415
5416           var char = function () {
5417             return input.charAt(pointer);
5418           };
5419
5420           if (char() == ':') {
5421             if (input.charAt(1) != ':') return;
5422             pointer += 2;
5423             pieceIndex++;
5424             compress = pieceIndex;
5425           }
5426           while (char()) {
5427             if (pieceIndex == 8) return;
5428             if (char() == ':') {
5429               if (compress !== null) return;
5430               pointer++;
5431               pieceIndex++;
5432               compress = pieceIndex;
5433               continue;
5434             }
5435             value = length = 0;
5436             while (length < 4 && HEX.test(char())) {
5437               value = value * 16 + parseInt(char(), 16);
5438               pointer++;
5439               length++;
5440             }
5441             if (char() == '.') {
5442               if (length == 0) return;
5443               pointer -= length;
5444               if (pieceIndex > 6) return;
5445               numbersSeen = 0;
5446               while (char()) {
5447                 ipv4Piece = null;
5448                 if (numbersSeen > 0) {
5449                   if (char() == '.' && numbersSeen < 4) pointer++;
5450                   else return;
5451                 }
5452                 if (!DIGIT.test(char())) return;
5453                 while (DIGIT.test(char())) {
5454                   number = parseInt(char(), 10);
5455                   if (ipv4Piece === null) ipv4Piece = number;
5456                   else if (ipv4Piece == 0) return;
5457                   else ipv4Piece = ipv4Piece * 10 + number;
5458                   if (ipv4Piece > 255) return;
5459                   pointer++;
5460                 }
5461                 address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
5462                 numbersSeen++;
5463                 if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
5464               }
5465               if (numbersSeen != 4) return;
5466               break;
5467             } else if (char() == ':') {
5468               pointer++;
5469               if (!char()) return;
5470             } else if (char()) return;
5471             address[pieceIndex++] = value;
5472           }
5473           if (compress !== null) {
5474             swaps = pieceIndex - compress;
5475             pieceIndex = 7;
5476             while (pieceIndex != 0 && swaps > 0) {
5477               swap = address[pieceIndex];
5478               address[pieceIndex--] = address[compress + swaps - 1];
5479               address[compress + --swaps] = swap;
5480             }
5481           } else if (pieceIndex != 8) return;
5482           return address;
5483         };
5484
5485         var findLongestZeroSequence = function (ipv6) {
5486           var maxIndex = null;
5487           var maxLength = 1;
5488           var currStart = null;
5489           var currLength = 0;
5490           var index = 0;
5491           for (; index < 8; index++) {
5492             if (ipv6[index] !== 0) {
5493               if (currLength > maxLength) {
5494                 maxIndex = currStart;
5495                 maxLength = currLength;
5496               }
5497               currStart = null;
5498               currLength = 0;
5499             } else {
5500               if (currStart === null) currStart = index;
5501               ++currLength;
5502             }
5503           }
5504           if (currLength > maxLength) {
5505             maxIndex = currStart;
5506             maxLength = currLength;
5507           }
5508           return maxIndex;
5509         };
5510
5511         var serializeHost = function (host) {
5512           var result, index, compress, ignore0;
5513           // ipv4
5514           if (typeof host == 'number') {
5515             result = [];
5516             for (index = 0; index < 4; index++) {
5517               result.unshift(host % 256);
5518               host = floor$2(host / 256);
5519             } return result.join('.');
5520           // ipv6
5521           } else if (typeof host == 'object') {
5522             result = '';
5523             compress = findLongestZeroSequence(host);
5524             for (index = 0; index < 8; index++) {
5525               if (ignore0 && host[index] === 0) continue;
5526               if (ignore0) ignore0 = false;
5527               if (compress === index) {
5528                 result += index ? ':' : '::';
5529                 ignore0 = true;
5530               } else {
5531                 result += host[index].toString(16);
5532                 if (index < 7) result += ':';
5533               }
5534             }
5535             return '[' + result + ']';
5536           } return host;
5537         };
5538
5539         var C0ControlPercentEncodeSet = {};
5540         var fragmentPercentEncodeSet = assign$2({}, C0ControlPercentEncodeSet, {
5541           ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
5542         });
5543         var pathPercentEncodeSet = assign$2({}, fragmentPercentEncodeSet, {
5544           '#': 1, '?': 1, '{': 1, '}': 1
5545         });
5546         var userinfoPercentEncodeSet = assign$2({}, pathPercentEncodeSet, {
5547           '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
5548         });
5549
5550         var percentEncode = function (char, set) {
5551           var code = codeAt(char, 0);
5552           return code > 0x20 && code < 0x7F && !has$4(set, char) ? char : encodeURIComponent(char);
5553         };
5554
5555         var specialSchemes = {
5556           ftp: 21,
5557           file: null,
5558           http: 80,
5559           https: 443,
5560           ws: 80,
5561           wss: 443
5562         };
5563
5564         var isSpecial = function (url) {
5565           return has$4(specialSchemes, url.scheme);
5566         };
5567
5568         var includesCredentials = function (url) {
5569           return url.username != '' || url.password != '';
5570         };
5571
5572         var cannotHaveUsernamePasswordPort = function (url) {
5573           return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
5574         };
5575
5576         var isWindowsDriveLetter = function (string, normalized) {
5577           var second;
5578           return string.length == 2 && ALPHA.test(string.charAt(0))
5579             && ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
5580         };
5581
5582         var startsWithWindowsDriveLetter = function (string) {
5583           var third;
5584           return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
5585             string.length == 2 ||
5586             ((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
5587           );
5588         };
5589
5590         var shortenURLsPath = function (url) {
5591           var path = url.path;
5592           var pathSize = path.length;
5593           if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
5594             path.pop();
5595           }
5596         };
5597
5598         var isSingleDot = function (segment) {
5599           return segment === '.' || segment.toLowerCase() === '%2e';
5600         };
5601
5602         var isDoubleDot = function (segment) {
5603           segment = segment.toLowerCase();
5604           return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
5605         };
5606
5607         // States:
5608         var SCHEME_START = {};
5609         var SCHEME = {};
5610         var NO_SCHEME = {};
5611         var SPECIAL_RELATIVE_OR_AUTHORITY = {};
5612         var PATH_OR_AUTHORITY = {};
5613         var RELATIVE = {};
5614         var RELATIVE_SLASH = {};
5615         var SPECIAL_AUTHORITY_SLASHES = {};
5616         var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
5617         var AUTHORITY = {};
5618         var HOST = {};
5619         var HOSTNAME = {};
5620         var PORT = {};
5621         var FILE = {};
5622         var FILE_SLASH = {};
5623         var FILE_HOST = {};
5624         var PATH_START = {};
5625         var PATH = {};
5626         var CANNOT_BE_A_BASE_URL_PATH = {};
5627         var QUERY = {};
5628         var FRAGMENT = {};
5629
5630         // eslint-disable-next-line max-statements -- TODO
5631         var parseURL = function (url, input, stateOverride, base) {
5632           var state = stateOverride || SCHEME_START;
5633           var pointer = 0;
5634           var buffer = '';
5635           var seenAt = false;
5636           var seenBracket = false;
5637           var seenPasswordToken = false;
5638           var codePoints, char, bufferCodePoints, failure;
5639
5640           if (!stateOverride) {
5641             url.scheme = '';
5642             url.username = '';
5643             url.password = '';
5644             url.host = null;
5645             url.port = null;
5646             url.path = [];
5647             url.query = null;
5648             url.fragment = null;
5649             url.cannotBeABaseURL = false;
5650             input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
5651           }
5652
5653           input = input.replace(TAB_AND_NEW_LINE, '');
5654
5655           codePoints = arrayFrom(input);
5656
5657           while (pointer <= codePoints.length) {
5658             char = codePoints[pointer];
5659             switch (state) {
5660               case SCHEME_START:
5661                 if (char && ALPHA.test(char)) {
5662                   buffer += char.toLowerCase();
5663                   state = SCHEME;
5664                 } else if (!stateOverride) {
5665                   state = NO_SCHEME;
5666                   continue;
5667                 } else return INVALID_SCHEME;
5668                 break;
5669
5670               case SCHEME:
5671                 if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
5672                   buffer += char.toLowerCase();
5673                 } else if (char == ':') {
5674                   if (stateOverride && (
5675                     (isSpecial(url) != has$4(specialSchemes, buffer)) ||
5676                     (buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
5677                     (url.scheme == 'file' && !url.host)
5678                   )) return;
5679                   url.scheme = buffer;
5680                   if (stateOverride) {
5681                     if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
5682                     return;
5683                   }
5684                   buffer = '';
5685                   if (url.scheme == 'file') {
5686                     state = FILE;
5687                   } else if (isSpecial(url) && base && base.scheme == url.scheme) {
5688                     state = SPECIAL_RELATIVE_OR_AUTHORITY;
5689                   } else if (isSpecial(url)) {
5690                     state = SPECIAL_AUTHORITY_SLASHES;
5691                   } else if (codePoints[pointer + 1] == '/') {
5692                     state = PATH_OR_AUTHORITY;
5693                     pointer++;
5694                   } else {
5695                     url.cannotBeABaseURL = true;
5696                     url.path.push('');
5697                     state = CANNOT_BE_A_BASE_URL_PATH;
5698                   }
5699                 } else if (!stateOverride) {
5700                   buffer = '';
5701                   state = NO_SCHEME;
5702                   pointer = 0;
5703                   continue;
5704                 } else return INVALID_SCHEME;
5705                 break;
5706
5707               case NO_SCHEME:
5708                 if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
5709                 if (base.cannotBeABaseURL && char == '#') {
5710                   url.scheme = base.scheme;
5711                   url.path = base.path.slice();
5712                   url.query = base.query;
5713                   url.fragment = '';
5714                   url.cannotBeABaseURL = true;
5715                   state = FRAGMENT;
5716                   break;
5717                 }
5718                 state = base.scheme == 'file' ? FILE : RELATIVE;
5719                 continue;
5720
5721               case SPECIAL_RELATIVE_OR_AUTHORITY:
5722                 if (char == '/' && codePoints[pointer + 1] == '/') {
5723                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5724                   pointer++;
5725                 } else {
5726                   state = RELATIVE;
5727                   continue;
5728                 } break;
5729
5730               case PATH_OR_AUTHORITY:
5731                 if (char == '/') {
5732                   state = AUTHORITY;
5733                   break;
5734                 } else {
5735                   state = PATH;
5736                   continue;
5737                 }
5738
5739               case RELATIVE:
5740                 url.scheme = base.scheme;
5741                 if (char == EOF) {
5742                   url.username = base.username;
5743                   url.password = base.password;
5744                   url.host = base.host;
5745                   url.port = base.port;
5746                   url.path = base.path.slice();
5747                   url.query = base.query;
5748                 } else if (char == '/' || (char == '\\' && isSpecial(url))) {
5749                   state = RELATIVE_SLASH;
5750                 } else if (char == '?') {
5751                   url.username = base.username;
5752                   url.password = base.password;
5753                   url.host = base.host;
5754                   url.port = base.port;
5755                   url.path = base.path.slice();
5756                   url.query = '';
5757                   state = QUERY;
5758                 } else if (char == '#') {
5759                   url.username = base.username;
5760                   url.password = base.password;
5761                   url.host = base.host;
5762                   url.port = base.port;
5763                   url.path = base.path.slice();
5764                   url.query = base.query;
5765                   url.fragment = '';
5766                   state = FRAGMENT;
5767                 } else {
5768                   url.username = base.username;
5769                   url.password = base.password;
5770                   url.host = base.host;
5771                   url.port = base.port;
5772                   url.path = base.path.slice();
5773                   url.path.pop();
5774                   state = PATH;
5775                   continue;
5776                 } break;
5777
5778               case RELATIVE_SLASH:
5779                 if (isSpecial(url) && (char == '/' || char == '\\')) {
5780                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5781                 } else if (char == '/') {
5782                   state = AUTHORITY;
5783                 } else {
5784                   url.username = base.username;
5785                   url.password = base.password;
5786                   url.host = base.host;
5787                   url.port = base.port;
5788                   state = PATH;
5789                   continue;
5790                 } break;
5791
5792               case SPECIAL_AUTHORITY_SLASHES:
5793                 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5794                 if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
5795                 pointer++;
5796                 break;
5797
5798               case SPECIAL_AUTHORITY_IGNORE_SLASHES:
5799                 if (char != '/' && char != '\\') {
5800                   state = AUTHORITY;
5801                   continue;
5802                 } break;
5803
5804               case AUTHORITY:
5805                 if (char == '@') {
5806                   if (seenAt) buffer = '%40' + buffer;
5807                   seenAt = true;
5808                   bufferCodePoints = arrayFrom(buffer);
5809                   for (var i = 0; i < bufferCodePoints.length; i++) {
5810                     var codePoint = bufferCodePoints[i];
5811                     if (codePoint == ':' && !seenPasswordToken) {
5812                       seenPasswordToken = true;
5813                       continue;
5814                     }
5815                     var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
5816                     if (seenPasswordToken) url.password += encodedCodePoints;
5817                     else url.username += encodedCodePoints;
5818                   }
5819                   buffer = '';
5820                 } else if (
5821                   char == EOF || char == '/' || char == '?' || char == '#' ||
5822                   (char == '\\' && isSpecial(url))
5823                 ) {
5824                   if (seenAt && buffer == '') return INVALID_AUTHORITY;
5825                   pointer -= arrayFrom(buffer).length + 1;
5826                   buffer = '';
5827                   state = HOST;
5828                 } else buffer += char;
5829                 break;
5830
5831               case HOST:
5832               case HOSTNAME:
5833                 if (stateOverride && url.scheme == 'file') {
5834                   state = FILE_HOST;
5835                   continue;
5836                 } else if (char == ':' && !seenBracket) {
5837                   if (buffer == '') return INVALID_HOST;
5838                   failure = parseHost(url, buffer);
5839                   if (failure) return failure;
5840                   buffer = '';
5841                   state = PORT;
5842                   if (stateOverride == HOSTNAME) return;
5843                 } else if (
5844                   char == EOF || char == '/' || char == '?' || char == '#' ||
5845                   (char == '\\' && isSpecial(url))
5846                 ) {
5847                   if (isSpecial(url) && buffer == '') return INVALID_HOST;
5848                   if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
5849                   failure = parseHost(url, buffer);
5850                   if (failure) return failure;
5851                   buffer = '';
5852                   state = PATH_START;
5853                   if (stateOverride) return;
5854                   continue;
5855                 } else {
5856                   if (char == '[') seenBracket = true;
5857                   else if (char == ']') seenBracket = false;
5858                   buffer += char;
5859                 } break;
5860
5861               case PORT:
5862                 if (DIGIT.test(char)) {
5863                   buffer += char;
5864                 } else if (
5865                   char == EOF || char == '/' || char == '?' || char == '#' ||
5866                   (char == '\\' && isSpecial(url)) ||
5867                   stateOverride
5868                 ) {
5869                   if (buffer != '') {
5870                     var port = parseInt(buffer, 10);
5871                     if (port > 0xFFFF) return INVALID_PORT;
5872                     url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
5873                     buffer = '';
5874                   }
5875                   if (stateOverride) return;
5876                   state = PATH_START;
5877                   continue;
5878                 } else return INVALID_PORT;
5879                 break;
5880
5881               case FILE:
5882                 url.scheme = 'file';
5883                 if (char == '/' || char == '\\') state = FILE_SLASH;
5884                 else if (base && base.scheme == 'file') {
5885                   if (char == EOF) {
5886                     url.host = base.host;
5887                     url.path = base.path.slice();
5888                     url.query = base.query;
5889                   } else if (char == '?') {
5890                     url.host = base.host;
5891                     url.path = base.path.slice();
5892                     url.query = '';
5893                     state = QUERY;
5894                   } else if (char == '#') {
5895                     url.host = base.host;
5896                     url.path = base.path.slice();
5897                     url.query = base.query;
5898                     url.fragment = '';
5899                     state = FRAGMENT;
5900                   } else {
5901                     if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5902                       url.host = base.host;
5903                       url.path = base.path.slice();
5904                       shortenURLsPath(url);
5905                     }
5906                     state = PATH;
5907                     continue;
5908                   }
5909                 } else {
5910                   state = PATH;
5911                   continue;
5912                 } break;
5913
5914               case FILE_SLASH:
5915                 if (char == '/' || char == '\\') {
5916                   state = FILE_HOST;
5917                   break;
5918                 }
5919                 if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5920                   if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
5921                   else url.host = base.host;
5922                 }
5923                 state = PATH;
5924                 continue;
5925
5926               case FILE_HOST:
5927                 if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
5928                   if (!stateOverride && isWindowsDriveLetter(buffer)) {
5929                     state = PATH;
5930                   } else if (buffer == '') {
5931                     url.host = '';
5932                     if (stateOverride) return;
5933                     state = PATH_START;
5934                   } else {
5935                     failure = parseHost(url, buffer);
5936                     if (failure) return failure;
5937                     if (url.host == 'localhost') url.host = '';
5938                     if (stateOverride) return;
5939                     buffer = '';
5940                     state = PATH_START;
5941                   } continue;
5942                 } else buffer += char;
5943                 break;
5944
5945               case PATH_START:
5946                 if (isSpecial(url)) {
5947                   state = PATH;
5948                   if (char != '/' && char != '\\') continue;
5949                 } else if (!stateOverride && char == '?') {
5950                   url.query = '';
5951                   state = QUERY;
5952                 } else if (!stateOverride && char == '#') {
5953                   url.fragment = '';
5954                   state = FRAGMENT;
5955                 } else if (char != EOF) {
5956                   state = PATH;
5957                   if (char != '/') continue;
5958                 } break;
5959
5960               case PATH:
5961                 if (
5962                   char == EOF || char == '/' ||
5963                   (char == '\\' && isSpecial(url)) ||
5964                   (!stateOverride && (char == '?' || char == '#'))
5965                 ) {
5966                   if (isDoubleDot(buffer)) {
5967                     shortenURLsPath(url);
5968                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5969                       url.path.push('');
5970                     }
5971                   } else if (isSingleDot(buffer)) {
5972                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5973                       url.path.push('');
5974                     }
5975                   } else {
5976                     if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
5977                       if (url.host) url.host = '';
5978                       buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
5979                     }
5980                     url.path.push(buffer);
5981                   }
5982                   buffer = '';
5983                   if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
5984                     while (url.path.length > 1 && url.path[0] === '') {
5985                       url.path.shift();
5986                     }
5987                   }
5988                   if (char == '?') {
5989                     url.query = '';
5990                     state = QUERY;
5991                   } else if (char == '#') {
5992                     url.fragment = '';
5993                     state = FRAGMENT;
5994                   }
5995                 } else {
5996                   buffer += percentEncode(char, pathPercentEncodeSet);
5997                 } break;
5998
5999               case CANNOT_BE_A_BASE_URL_PATH:
6000                 if (char == '?') {
6001                   url.query = '';
6002                   state = QUERY;
6003                 } else if (char == '#') {
6004                   url.fragment = '';
6005                   state = FRAGMENT;
6006                 } else if (char != EOF) {
6007                   url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
6008                 } break;
6009
6010               case QUERY:
6011                 if (!stateOverride && char == '#') {
6012                   url.fragment = '';
6013                   state = FRAGMENT;
6014                 } else if (char != EOF) {
6015                   if (char == "'" && isSpecial(url)) url.query += '%27';
6016                   else if (char == '#') url.query += '%23';
6017                   else url.query += percentEncode(char, C0ControlPercentEncodeSet);
6018                 } break;
6019
6020               case FRAGMENT:
6021                 if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
6022                 break;
6023             }
6024
6025             pointer++;
6026           }
6027         };
6028
6029         // `URL` constructor
6030         // https://url.spec.whatwg.org/#url-class
6031         var URLConstructor = function URL(url /* , base */) {
6032           var that = anInstance$2(this, URLConstructor, 'URL');
6033           var base = arguments.length > 1 ? arguments[1] : undefined;
6034           var urlString = String(url);
6035           var state = setInternalState$1(that, { type: 'URL' });
6036           var baseState, failure;
6037           if (base !== undefined) {
6038             if (base instanceof URLConstructor) baseState = getInternalURLState(base);
6039             else {
6040               failure = parseURL(baseState = {}, String(base));
6041               if (failure) throw TypeError(failure);
6042             }
6043           }
6044           failure = parseURL(state, urlString, null, baseState);
6045           if (failure) throw TypeError(failure);
6046           var searchParams = state.searchParams = new URLSearchParams$1();
6047           var searchParamsState = getInternalSearchParamsState(searchParams);
6048           searchParamsState.updateSearchParams(state.query);
6049           searchParamsState.updateURL = function () {
6050             state.query = String(searchParams) || null;
6051           };
6052           if (!DESCRIPTORS$a) {
6053             that.href = serializeURL.call(that);
6054             that.origin = getOrigin.call(that);
6055             that.protocol = getProtocol.call(that);
6056             that.username = getUsername.call(that);
6057             that.password = getPassword.call(that);
6058             that.host = getHost.call(that);
6059             that.hostname = getHostname.call(that);
6060             that.port = getPort.call(that);
6061             that.pathname = getPathname.call(that);
6062             that.search = getSearch.call(that);
6063             that.searchParams = getSearchParams.call(that);
6064             that.hash = getHash.call(that);
6065           }
6066         };
6067
6068         var URLPrototype = URLConstructor.prototype;
6069
6070         var serializeURL = function () {
6071           var url = getInternalURLState(this);
6072           var scheme = url.scheme;
6073           var username = url.username;
6074           var password = url.password;
6075           var host = url.host;
6076           var port = url.port;
6077           var path = url.path;
6078           var query = url.query;
6079           var fragment = url.fragment;
6080           var output = scheme + ':';
6081           if (host !== null) {
6082             output += '//';
6083             if (includesCredentials(url)) {
6084               output += username + (password ? ':' + password : '') + '@';
6085             }
6086             output += serializeHost(host);
6087             if (port !== null) output += ':' + port;
6088           } else if (scheme == 'file') output += '//';
6089           output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
6090           if (query !== null) output += '?' + query;
6091           if (fragment !== null) output += '#' + fragment;
6092           return output;
6093         };
6094
6095         var getOrigin = function () {
6096           var url = getInternalURLState(this);
6097           var scheme = url.scheme;
6098           var port = url.port;
6099           if (scheme == 'blob') try {
6100             return new URLConstructor(scheme.path[0]).origin;
6101           } catch (error) {
6102             return 'null';
6103           }
6104           if (scheme == 'file' || !isSpecial(url)) return 'null';
6105           return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
6106         };
6107
6108         var getProtocol = function () {
6109           return getInternalURLState(this).scheme + ':';
6110         };
6111
6112         var getUsername = function () {
6113           return getInternalURLState(this).username;
6114         };
6115
6116         var getPassword = function () {
6117           return getInternalURLState(this).password;
6118         };
6119
6120         var getHost = function () {
6121           var url = getInternalURLState(this);
6122           var host = url.host;
6123           var port = url.port;
6124           return host === null ? ''
6125             : port === null ? serializeHost(host)
6126             : serializeHost(host) + ':' + port;
6127         };
6128
6129         var getHostname = function () {
6130           var host = getInternalURLState(this).host;
6131           return host === null ? '' : serializeHost(host);
6132         };
6133
6134         var getPort = function () {
6135           var port = getInternalURLState(this).port;
6136           return port === null ? '' : String(port);
6137         };
6138
6139         var getPathname = function () {
6140           var url = getInternalURLState(this);
6141           var path = url.path;
6142           return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
6143         };
6144
6145         var getSearch = function () {
6146           var query = getInternalURLState(this).query;
6147           return query ? '?' + query : '';
6148         };
6149
6150         var getSearchParams = function () {
6151           return getInternalURLState(this).searchParams;
6152         };
6153
6154         var getHash = function () {
6155           var fragment = getInternalURLState(this).fragment;
6156           return fragment ? '#' + fragment : '';
6157         };
6158
6159         var accessorDescriptor = function (getter, setter) {
6160           return { get: getter, set: setter, configurable: true, enumerable: true };
6161         };
6162
6163         if (DESCRIPTORS$a) {
6164           defineProperties$1(URLPrototype, {
6165             // `URL.prototype.href` accessors pair
6166             // https://url.spec.whatwg.org/#dom-url-href
6167             href: accessorDescriptor(serializeURL, function (href) {
6168               var url = getInternalURLState(this);
6169               var urlString = String(href);
6170               var failure = parseURL(url, urlString);
6171               if (failure) throw TypeError(failure);
6172               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
6173             }),
6174             // `URL.prototype.origin` getter
6175             // https://url.spec.whatwg.org/#dom-url-origin
6176             origin: accessorDescriptor(getOrigin),
6177             // `URL.prototype.protocol` accessors pair
6178             // https://url.spec.whatwg.org/#dom-url-protocol
6179             protocol: accessorDescriptor(getProtocol, function (protocol) {
6180               var url = getInternalURLState(this);
6181               parseURL(url, String(protocol) + ':', SCHEME_START);
6182             }),
6183             // `URL.prototype.username` accessors pair
6184             // https://url.spec.whatwg.org/#dom-url-username
6185             username: accessorDescriptor(getUsername, function (username) {
6186               var url = getInternalURLState(this);
6187               var codePoints = arrayFrom(String(username));
6188               if (cannotHaveUsernamePasswordPort(url)) return;
6189               url.username = '';
6190               for (var i = 0; i < codePoints.length; i++) {
6191                 url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
6192               }
6193             }),
6194             // `URL.prototype.password` accessors pair
6195             // https://url.spec.whatwg.org/#dom-url-password
6196             password: accessorDescriptor(getPassword, function (password) {
6197               var url = getInternalURLState(this);
6198               var codePoints = arrayFrom(String(password));
6199               if (cannotHaveUsernamePasswordPort(url)) return;
6200               url.password = '';
6201               for (var i = 0; i < codePoints.length; i++) {
6202                 url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
6203               }
6204             }),
6205             // `URL.prototype.host` accessors pair
6206             // https://url.spec.whatwg.org/#dom-url-host
6207             host: accessorDescriptor(getHost, function (host) {
6208               var url = getInternalURLState(this);
6209               if (url.cannotBeABaseURL) return;
6210               parseURL(url, String(host), HOST);
6211             }),
6212             // `URL.prototype.hostname` accessors pair
6213             // https://url.spec.whatwg.org/#dom-url-hostname
6214             hostname: accessorDescriptor(getHostname, function (hostname) {
6215               var url = getInternalURLState(this);
6216               if (url.cannotBeABaseURL) return;
6217               parseURL(url, String(hostname), HOSTNAME);
6218             }),
6219             // `URL.prototype.port` accessors pair
6220             // https://url.spec.whatwg.org/#dom-url-port
6221             port: accessorDescriptor(getPort, function (port) {
6222               var url = getInternalURLState(this);
6223               if (cannotHaveUsernamePasswordPort(url)) return;
6224               port = String(port);
6225               if (port == '') url.port = null;
6226               else parseURL(url, port, PORT);
6227             }),
6228             // `URL.prototype.pathname` accessors pair
6229             // https://url.spec.whatwg.org/#dom-url-pathname
6230             pathname: accessorDescriptor(getPathname, function (pathname) {
6231               var url = getInternalURLState(this);
6232               if (url.cannotBeABaseURL) return;
6233               url.path = [];
6234               parseURL(url, pathname + '', PATH_START);
6235             }),
6236             // `URL.prototype.search` accessors pair
6237             // https://url.spec.whatwg.org/#dom-url-search
6238             search: accessorDescriptor(getSearch, function (search) {
6239               var url = getInternalURLState(this);
6240               search = String(search);
6241               if (search == '') {
6242                 url.query = null;
6243               } else {
6244                 if ('?' == search.charAt(0)) search = search.slice(1);
6245                 url.query = '';
6246                 parseURL(url, search, QUERY);
6247               }
6248               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
6249             }),
6250             // `URL.prototype.searchParams` getter
6251             // https://url.spec.whatwg.org/#dom-url-searchparams
6252             searchParams: accessorDescriptor(getSearchParams),
6253             // `URL.prototype.hash` accessors pair
6254             // https://url.spec.whatwg.org/#dom-url-hash
6255             hash: accessorDescriptor(getHash, function (hash) {
6256               var url = getInternalURLState(this);
6257               hash = String(hash);
6258               if (hash == '') {
6259                 url.fragment = null;
6260                 return;
6261               }
6262               if ('#' == hash.charAt(0)) hash = hash.slice(1);
6263               url.fragment = '';
6264               parseURL(url, hash, FRAGMENT);
6265             })
6266           });
6267         }
6268
6269         // `URL.prototype.toJSON` method
6270         // https://url.spec.whatwg.org/#dom-url-tojson
6271         redefine$6(URLPrototype, 'toJSON', function toJSON() {
6272           return serializeURL.call(this);
6273         }, { enumerable: true });
6274
6275         // `URL.prototype.toString` method
6276         // https://url.spec.whatwg.org/#URL-stringification-behavior
6277         redefine$6(URLPrototype, 'toString', function toString() {
6278           return serializeURL.call(this);
6279         }, { enumerable: true });
6280
6281         if (NativeURL) {
6282           var nativeCreateObjectURL = NativeURL.createObjectURL;
6283           var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
6284           // `URL.createObjectURL` method
6285           // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
6286           // eslint-disable-next-line no-unused-vars -- required for `.length`
6287           if (nativeCreateObjectURL) redefine$6(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
6288             return nativeCreateObjectURL.apply(NativeURL, arguments);
6289           });
6290           // `URL.revokeObjectURL` method
6291           // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
6292           // eslint-disable-next-line no-unused-vars -- required for `.length`
6293           if (nativeRevokeObjectURL) redefine$6(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
6294             return nativeRevokeObjectURL.apply(NativeURL, arguments);
6295           });
6296         }
6297
6298         setToStringTag$3(URLConstructor, 'URL');
6299
6300         $$Q({ global: true, forced: !USE_NATIVE_URL, sham: !DESCRIPTORS$a }, {
6301           URL: URLConstructor
6302         });
6303
6304         var anObject$7 = anObject$m;
6305
6306         // `RegExp.prototype.flags` getter implementation
6307         // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
6308         var regexpFlags$1 = function () {
6309           var that = anObject$7(this);
6310           var result = '';
6311           if (that.global) result += 'g';
6312           if (that.ignoreCase) result += 'i';
6313           if (that.multiline) result += 'm';
6314           if (that.dotAll) result += 's';
6315           if (that.unicode) result += 'u';
6316           if (that.sticky) result += 'y';
6317           return result;
6318         };
6319
6320         var redefine$5 = redefine$g.exports;
6321         var anObject$6 = anObject$m;
6322         var fails$q = fails$N;
6323         var flags = regexpFlags$1;
6324
6325         var TO_STRING = 'toString';
6326         var RegExpPrototype$2 = RegExp.prototype;
6327         var nativeToString = RegExpPrototype$2[TO_STRING];
6328
6329         var NOT_GENERIC = fails$q(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });
6330         // FF44- RegExp#toString has a wrong name
6331         var INCORRECT_NAME = nativeToString.name != TO_STRING;
6332
6333         // `RegExp.prototype.toString` method
6334         // https://tc39.es/ecma262/#sec-regexp.prototype.tostring
6335         if (NOT_GENERIC || INCORRECT_NAME) {
6336           redefine$5(RegExp.prototype, TO_STRING, function toString() {
6337             var R = anObject$6(this);
6338             var p = String(R.source);
6339             var rf = R.flags;
6340             var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype$2) ? flags.call(R) : rf);
6341             return '/' + p + '/' + f;
6342           }, { unsafe: true });
6343         }
6344
6345         var regexpStickyHelpers = {};
6346
6347         var fails$p = fails$N;
6348
6349         // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
6350         var RE = function (s, f) {
6351           return RegExp(s, f);
6352         };
6353
6354         regexpStickyHelpers.UNSUPPORTED_Y = fails$p(function () {
6355           var re = RE('a', 'y');
6356           re.lastIndex = 2;
6357           return re.exec('abcd') != null;
6358         });
6359
6360         regexpStickyHelpers.BROKEN_CARET = fails$p(function () {
6361           // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
6362           var re = RE('^r', 'gy');
6363           re.lastIndex = 2;
6364           return re.exec('str') != null;
6365         });
6366
6367         var fails$o = fails$N;
6368
6369         var regexpUnsupportedDotAll = fails$o(function () {
6370           // babel-minify transpiles RegExp('.', 's') -> /./s and it causes SyntaxError
6371           var re = RegExp('.', (typeof '').charAt(0));
6372           return !(re.dotAll && re.exec('\n') && re.flags === 's');
6373         });
6374
6375         var fails$n = fails$N;
6376
6377         var regexpUnsupportedNcg = fails$n(function () {
6378           // babel-minify transpiles RegExp('.', 'g') -> /./g and it causes SyntaxError
6379           var re = RegExp('(?<a>b)', (typeof '').charAt(5));
6380           return re.exec('b').groups.a !== 'b' ||
6381             'b'.replace(re, '$<a>c') !== 'bc';
6382         });
6383
6384         /* eslint-disable regexp/no-assertion-capturing-group, regexp/no-empty-group, regexp/no-lazy-ends -- testing */
6385         /* eslint-disable regexp/no-useless-quantifier -- testing */
6386         var regexpFlags = regexpFlags$1;
6387         var stickyHelpers$2 = regexpStickyHelpers;
6388         var shared = shared$5.exports;
6389         var create$7 = objectCreate;
6390         var getInternalState = internalState.get;
6391         var UNSUPPORTED_DOT_ALL$1 = regexpUnsupportedDotAll;
6392         var UNSUPPORTED_NCG$1 = regexpUnsupportedNcg;
6393
6394         var nativeExec = RegExp.prototype.exec;
6395         var nativeReplace = shared('native-string-replace', String.prototype.replace);
6396
6397         var patchedExec = nativeExec;
6398
6399         var UPDATES_LAST_INDEX_WRONG = (function () {
6400           var re1 = /a/;
6401           var re2 = /b*/g;
6402           nativeExec.call(re1, 'a');
6403           nativeExec.call(re2, 'a');
6404           return re1.lastIndex !== 0 || re2.lastIndex !== 0;
6405         })();
6406
6407         var UNSUPPORTED_Y$2 = stickyHelpers$2.UNSUPPORTED_Y || stickyHelpers$2.BROKEN_CARET;
6408
6409         // nonparticipating capturing group, copied from es5-shim's String#split patch.
6410         var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
6411
6412         var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$2 || UNSUPPORTED_DOT_ALL$1 || UNSUPPORTED_NCG$1;
6413
6414         if (PATCH) {
6415           // eslint-disable-next-line max-statements -- TODO
6416           patchedExec = function exec(str) {
6417             var re = this;
6418             var state = getInternalState(re);
6419             var raw = state.raw;
6420             var result, reCopy, lastIndex, match, i, object, group;
6421
6422             if (raw) {
6423               raw.lastIndex = re.lastIndex;
6424               result = patchedExec.call(raw, str);
6425               re.lastIndex = raw.lastIndex;
6426               return result;
6427             }
6428
6429             var groups = state.groups;
6430             var sticky = UNSUPPORTED_Y$2 && re.sticky;
6431             var flags = regexpFlags.call(re);
6432             var source = re.source;
6433             var charsAdded = 0;
6434             var strCopy = str;
6435
6436             if (sticky) {
6437               flags = flags.replace('y', '');
6438               if (flags.indexOf('g') === -1) {
6439                 flags += 'g';
6440               }
6441
6442               strCopy = String(str).slice(re.lastIndex);
6443               // Support anchored sticky behavior.
6444               if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
6445                 source = '(?: ' + source + ')';
6446                 strCopy = ' ' + strCopy;
6447                 charsAdded++;
6448               }
6449               // ^(? + rx + ) is needed, in combination with some str slicing, to
6450               // simulate the 'y' flag.
6451               reCopy = new RegExp('^(?:' + source + ')', flags);
6452             }
6453
6454             if (NPCG_INCLUDED) {
6455               reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
6456             }
6457             if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
6458
6459             match = nativeExec.call(sticky ? reCopy : re, strCopy);
6460
6461             if (sticky) {
6462               if (match) {
6463                 match.input = match.input.slice(charsAdded);
6464                 match[0] = match[0].slice(charsAdded);
6465                 match.index = re.lastIndex;
6466                 re.lastIndex += match[0].length;
6467               } else re.lastIndex = 0;
6468             } else if (UPDATES_LAST_INDEX_WRONG && match) {
6469               re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
6470             }
6471             if (NPCG_INCLUDED && match && match.length > 1) {
6472               // Fix browsers whose `exec` methods don't consistently return `undefined`
6473               // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
6474               nativeReplace.call(match[0], reCopy, function () {
6475                 for (i = 1; i < arguments.length - 2; i++) {
6476                   if (arguments[i] === undefined) match[i] = undefined;
6477                 }
6478               });
6479             }
6480
6481             if (match && groups) {
6482               match.groups = object = create$7(null);
6483               for (i = 0; i < groups.length; i++) {
6484                 group = groups[i];
6485                 object[group[0]] = match[group[1]];
6486               }
6487             }
6488
6489             return match;
6490           };
6491         }
6492
6493         var regexpExec$3 = patchedExec;
6494
6495         var $$P = _export;
6496         var exec = regexpExec$3;
6497
6498         // `RegExp.prototype.exec` method
6499         // https://tc39.es/ecma262/#sec-regexp.prototype.exec
6500         $$P({ target: 'RegExp', proto: true, forced: /./.exec !== exec }, {
6501           exec: exec
6502         });
6503
6504         // TODO: Remove from `core-js@4` since it's moved to entry points
6505
6506         var redefine$4 = redefine$g.exports;
6507         var regexpExec$2 = regexpExec$3;
6508         var fails$m = fails$N;
6509         var wellKnownSymbol$5 = wellKnownSymbol$s;
6510         var createNonEnumerableProperty$1 = createNonEnumerableProperty$e;
6511
6512         var SPECIES = wellKnownSymbol$5('species');
6513         var RegExpPrototype$1 = RegExp.prototype;
6514
6515         var fixRegexpWellKnownSymbolLogic = function (KEY, exec, FORCED, SHAM) {
6516           var SYMBOL = wellKnownSymbol$5(KEY);
6517
6518           var DELEGATES_TO_SYMBOL = !fails$m(function () {
6519             // String methods call symbol-named RegEp methods
6520             var O = {};
6521             O[SYMBOL] = function () { return 7; };
6522             return ''[KEY](O) != 7;
6523           });
6524
6525           var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails$m(function () {
6526             // Symbol-named RegExp methods call .exec
6527             var execCalled = false;
6528             var re = /a/;
6529
6530             if (KEY === 'split') {
6531               // We can't use real regex here since it causes deoptimization
6532               // and serious performance degradation in V8
6533               // https://github.com/zloirock/core-js/issues/306
6534               re = {};
6535               // RegExp[@@split] doesn't call the regex's exec method, but first creates
6536               // a new one. We need to return the patched regex when creating the new one.
6537               re.constructor = {};
6538               re.constructor[SPECIES] = function () { return re; };
6539               re.flags = '';
6540               re[SYMBOL] = /./[SYMBOL];
6541             }
6542
6543             re.exec = function () { execCalled = true; return null; };
6544
6545             re[SYMBOL]('');
6546             return !execCalled;
6547           });
6548
6549           if (
6550             !DELEGATES_TO_SYMBOL ||
6551             !DELEGATES_TO_EXEC ||
6552             FORCED
6553           ) {
6554             var nativeRegExpMethod = /./[SYMBOL];
6555             var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
6556               var $exec = regexp.exec;
6557               if ($exec === regexpExec$2 || $exec === RegExpPrototype$1.exec) {
6558                 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
6559                   // The native String method already delegates to @@method (this
6560                   // polyfilled function), leasing to infinite recursion.
6561                   // We avoid it by directly calling the native @@method method.
6562                   return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
6563                 }
6564                 return { done: true, value: nativeMethod.call(str, regexp, arg2) };
6565               }
6566               return { done: false };
6567             });
6568
6569             redefine$4(String.prototype, KEY, methods[0]);
6570             redefine$4(RegExpPrototype$1, SYMBOL, methods[1]);
6571           }
6572
6573           if (SHAM) createNonEnumerableProperty$1(RegExpPrototype$1[SYMBOL], 'sham', true);
6574         };
6575
6576         var charAt = stringMultibyte.charAt;
6577
6578         // `AdvanceStringIndex` abstract operation
6579         // https://tc39.es/ecma262/#sec-advancestringindex
6580         var advanceStringIndex$3 = function (S, index, unicode) {
6581           return index + (unicode ? charAt(S, index).length : 1);
6582         };
6583
6584         var toObject$6 = toObject$i;
6585
6586         var floor$1 = Math.floor;
6587         var replace = ''.replace;
6588         var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d{1,2}|<[^>]*>)/g;
6589         var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d{1,2})/g;
6590
6591         // `GetSubstitution` abstract operation
6592         // https://tc39.es/ecma262/#sec-getsubstitution
6593         var getSubstitution$1 = function (matched, str, position, captures, namedCaptures, replacement) {
6594           var tailPos = position + matched.length;
6595           var m = captures.length;
6596           var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
6597           if (namedCaptures !== undefined) {
6598             namedCaptures = toObject$6(namedCaptures);
6599             symbols = SUBSTITUTION_SYMBOLS;
6600           }
6601           return replace.call(replacement, symbols, function (match, ch) {
6602             var capture;
6603             switch (ch.charAt(0)) {
6604               case '$': return '$';
6605               case '&': return matched;
6606               case '`': return str.slice(0, position);
6607               case "'": return str.slice(tailPos);
6608               case '<':
6609                 capture = namedCaptures[ch.slice(1, -1)];
6610                 break;
6611               default: // \d\d?
6612                 var n = +ch;
6613                 if (n === 0) return match;
6614                 if (n > m) {
6615                   var f = floor$1(n / 10);
6616                   if (f === 0) return match;
6617                   if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
6618                   return match;
6619                 }
6620                 capture = captures[n - 1];
6621             }
6622             return capture === undefined ? '' : capture;
6623           });
6624         };
6625
6626         var classof$3 = classofRaw$1;
6627         var regexpExec$1 = regexpExec$3;
6628
6629         // `RegExpExec` abstract operation
6630         // https://tc39.es/ecma262/#sec-regexpexec
6631         var regexpExecAbstract = function (R, S) {
6632           var exec = R.exec;
6633           if (typeof exec === 'function') {
6634             var result = exec.call(R, S);
6635             if (typeof result !== 'object') {
6636               throw TypeError('RegExp exec method returned something other than an Object or null');
6637             }
6638             return result;
6639           }
6640
6641           if (classof$3(R) !== 'RegExp') {
6642             throw TypeError('RegExp#exec called on incompatible receiver');
6643           }
6644
6645           return regexpExec$1.call(R, S);
6646         };
6647
6648         var fixRegExpWellKnownSymbolLogic$3 = fixRegexpWellKnownSymbolLogic;
6649         var fails$l = fails$N;
6650         var anObject$5 = anObject$m;
6651         var toLength$8 = toLength$q;
6652         var toInteger$3 = toInteger$b;
6653         var requireObjectCoercible$a = requireObjectCoercible$e;
6654         var advanceStringIndex$2 = advanceStringIndex$3;
6655         var getSubstitution = getSubstitution$1;
6656         var regExpExec$2 = regexpExecAbstract;
6657         var wellKnownSymbol$4 = wellKnownSymbol$s;
6658
6659         var REPLACE = wellKnownSymbol$4('replace');
6660         var max$2 = Math.max;
6661         var min$5 = Math.min;
6662
6663         var maybeToString = function (it) {
6664           return it === undefined ? it : String(it);
6665         };
6666
6667         // IE <= 11 replaces $0 with the whole match, as if it was $&
6668         // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
6669         var REPLACE_KEEPS_$0 = (function () {
6670           // eslint-disable-next-line regexp/prefer-escape-replacement-dollar-char -- required for testing
6671           return 'a'.replace(/./, '$0') === '$0';
6672         })();
6673
6674         // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
6675         var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
6676           if (/./[REPLACE]) {
6677             return /./[REPLACE]('a', '$0') === '';
6678           }
6679           return false;
6680         })();
6681
6682         var REPLACE_SUPPORTS_NAMED_GROUPS = !fails$l(function () {
6683           var re = /./;
6684           re.exec = function () {
6685             var result = [];
6686             result.groups = { a: '7' };
6687             return result;
6688           };
6689           return ''.replace(re, '$<a>') !== '7';
6690         });
6691
6692         // @@replace logic
6693         fixRegExpWellKnownSymbolLogic$3('replace', function (_, nativeReplace, maybeCallNative) {
6694           var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
6695
6696           return [
6697             // `String.prototype.replace` method
6698             // https://tc39.es/ecma262/#sec-string.prototype.replace
6699             function replace(searchValue, replaceValue) {
6700               var O = requireObjectCoercible$a(this);
6701               var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
6702               return replacer !== undefined
6703                 ? replacer.call(searchValue, O, replaceValue)
6704                 : nativeReplace.call(String(O), searchValue, replaceValue);
6705             },
6706             // `RegExp.prototype[@@replace]` method
6707             // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
6708             function (string, replaceValue) {
6709               if (
6710                 typeof replaceValue === 'string' &&
6711                 replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1 &&
6712                 replaceValue.indexOf('$<') === -1
6713               ) {
6714                 var res = maybeCallNative(nativeReplace, this, string, replaceValue);
6715                 if (res.done) return res.value;
6716               }
6717
6718               var rx = anObject$5(this);
6719               var S = String(string);
6720
6721               var functionalReplace = typeof replaceValue === 'function';
6722               if (!functionalReplace) replaceValue = String(replaceValue);
6723
6724               var global = rx.global;
6725               if (global) {
6726                 var fullUnicode = rx.unicode;
6727                 rx.lastIndex = 0;
6728               }
6729               var results = [];
6730               while (true) {
6731                 var result = regExpExec$2(rx, S);
6732                 if (result === null) break;
6733
6734                 results.push(result);
6735                 if (!global) break;
6736
6737                 var matchStr = String(result[0]);
6738                 if (matchStr === '') rx.lastIndex = advanceStringIndex$2(S, toLength$8(rx.lastIndex), fullUnicode);
6739               }
6740
6741               var accumulatedResult = '';
6742               var nextSourcePosition = 0;
6743               for (var i = 0; i < results.length; i++) {
6744                 result = results[i];
6745
6746                 var matched = String(result[0]);
6747                 var position = max$2(min$5(toInteger$3(result.index), S.length), 0);
6748                 var captures = [];
6749                 // NOTE: This is equivalent to
6750                 //   captures = result.slice(1).map(maybeToString)
6751                 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
6752                 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
6753                 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
6754                 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
6755                 var namedCaptures = result.groups;
6756                 if (functionalReplace) {
6757                   var replacerArgs = [matched].concat(captures, position, S);
6758                   if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
6759                   var replacement = String(replaceValue.apply(undefined, replacerArgs));
6760                 } else {
6761                   replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
6762                 }
6763                 if (position >= nextSourcePosition) {
6764                   accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
6765                   nextSourcePosition = position + matched.length;
6766                 }
6767               }
6768               return accumulatedResult + S.slice(nextSourcePosition);
6769             }
6770           ];
6771         }, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);
6772
6773         var isObject$b = isObject$r;
6774         var classof$2 = classofRaw$1;
6775         var wellKnownSymbol$3 = wellKnownSymbol$s;
6776
6777         var MATCH$2 = wellKnownSymbol$3('match');
6778
6779         // `IsRegExp` abstract operation
6780         // https://tc39.es/ecma262/#sec-isregexp
6781         var isRegexp = function (it) {
6782           var isRegExp;
6783           return isObject$b(it) && ((isRegExp = it[MATCH$2]) !== undefined ? !!isRegExp : classof$2(it) == 'RegExp');
6784         };
6785
6786         var fixRegExpWellKnownSymbolLogic$2 = fixRegexpWellKnownSymbolLogic;
6787         var isRegExp$2 = isRegexp;
6788         var anObject$4 = anObject$m;
6789         var requireObjectCoercible$9 = requireObjectCoercible$e;
6790         var speciesConstructor$1 = speciesConstructor$8;
6791         var advanceStringIndex$1 = advanceStringIndex$3;
6792         var toLength$7 = toLength$q;
6793         var callRegExpExec = regexpExecAbstract;
6794         var regexpExec = regexpExec$3;
6795         var stickyHelpers$1 = regexpStickyHelpers;
6796         var fails$k = fails$N;
6797
6798         var UNSUPPORTED_Y$1 = stickyHelpers$1.UNSUPPORTED_Y;
6799         var arrayPush = [].push;
6800         var min$4 = Math.min;
6801         var MAX_UINT32 = 0xFFFFFFFF;
6802
6803         // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
6804         // Weex JS has frozen built-in prototypes, so use try / catch wrapper
6805         var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails$k(function () {
6806           // eslint-disable-next-line regexp/no-empty-group -- required for testing
6807           var re = /(?:)/;
6808           var originalExec = re.exec;
6809           re.exec = function () { return originalExec.apply(this, arguments); };
6810           var result = 'ab'.split(re);
6811           return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
6812         });
6813
6814         // @@split logic
6815         fixRegExpWellKnownSymbolLogic$2('split', function (SPLIT, nativeSplit, maybeCallNative) {
6816           var internalSplit;
6817           if (
6818             'abbc'.split(/(b)*/)[1] == 'c' ||
6819             // eslint-disable-next-line regexp/no-empty-group -- required for testing
6820             'test'.split(/(?:)/, -1).length != 4 ||
6821             'ab'.split(/(?:ab)*/).length != 2 ||
6822             '.'.split(/(.?)(.?)/).length != 4 ||
6823             // eslint-disable-next-line regexp/no-assertion-capturing-group, regexp/no-empty-group -- required for testing
6824             '.'.split(/()()/).length > 1 ||
6825             ''.split(/.?/).length
6826           ) {
6827             // based on es5-shim implementation, need to rework it
6828             internalSplit = function (separator, limit) {
6829               var string = String(requireObjectCoercible$9(this));
6830               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6831               if (lim === 0) return [];
6832               if (separator === undefined) return [string];
6833               // If `separator` is not a regex, use native split
6834               if (!isRegExp$2(separator)) {
6835                 return nativeSplit.call(string, separator, lim);
6836               }
6837               var output = [];
6838               var flags = (separator.ignoreCase ? 'i' : '') +
6839                           (separator.multiline ? 'm' : '') +
6840                           (separator.unicode ? 'u' : '') +
6841                           (separator.sticky ? 'y' : '');
6842               var lastLastIndex = 0;
6843               // Make `global` and avoid `lastIndex` issues by working with a copy
6844               var separatorCopy = new RegExp(separator.source, flags + 'g');
6845               var match, lastIndex, lastLength;
6846               while (match = regexpExec.call(separatorCopy, string)) {
6847                 lastIndex = separatorCopy.lastIndex;
6848                 if (lastIndex > lastLastIndex) {
6849                   output.push(string.slice(lastLastIndex, match.index));
6850                   if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
6851                   lastLength = match[0].length;
6852                   lastLastIndex = lastIndex;
6853                   if (output.length >= lim) break;
6854                 }
6855                 if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
6856               }
6857               if (lastLastIndex === string.length) {
6858                 if (lastLength || !separatorCopy.test('')) output.push('');
6859               } else output.push(string.slice(lastLastIndex));
6860               return output.length > lim ? output.slice(0, lim) : output;
6861             };
6862           // Chakra, V8
6863           } else if ('0'.split(undefined, 0).length) {
6864             internalSplit = function (separator, limit) {
6865               return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
6866             };
6867           } else internalSplit = nativeSplit;
6868
6869           return [
6870             // `String.prototype.split` method
6871             // https://tc39.es/ecma262/#sec-string.prototype.split
6872             function split(separator, limit) {
6873               var O = requireObjectCoercible$9(this);
6874               var splitter = separator == undefined ? undefined : separator[SPLIT];
6875               return splitter !== undefined
6876                 ? splitter.call(separator, O, limit)
6877                 : internalSplit.call(String(O), separator, limit);
6878             },
6879             // `RegExp.prototype[@@split]` method
6880             // https://tc39.es/ecma262/#sec-regexp.prototype-@@split
6881             //
6882             // NOTE: This cannot be properly polyfilled in engines that don't support
6883             // the 'y' flag.
6884             function (string, limit) {
6885               var res = maybeCallNative(internalSplit, this, string, limit, internalSplit !== nativeSplit);
6886               if (res.done) return res.value;
6887
6888               var rx = anObject$4(this);
6889               var S = String(string);
6890               var C = speciesConstructor$1(rx, RegExp);
6891
6892               var unicodeMatching = rx.unicode;
6893               var flags = (rx.ignoreCase ? 'i' : '') +
6894                           (rx.multiline ? 'm' : '') +
6895                           (rx.unicode ? 'u' : '') +
6896                           (UNSUPPORTED_Y$1 ? 'g' : 'y');
6897
6898               // ^(? + rx + ) is needed, in combination with some S slicing, to
6899               // simulate the 'y' flag.
6900               var splitter = new C(UNSUPPORTED_Y$1 ? '^(?:' + rx.source + ')' : rx, flags);
6901               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6902               if (lim === 0) return [];
6903               if (S.length === 0) return callRegExpExec(splitter, S) === null ? [S] : [];
6904               var p = 0;
6905               var q = 0;
6906               var A = [];
6907               while (q < S.length) {
6908                 splitter.lastIndex = UNSUPPORTED_Y$1 ? 0 : q;
6909                 var z = callRegExpExec(splitter, UNSUPPORTED_Y$1 ? S.slice(q) : S);
6910                 var e;
6911                 if (
6912                   z === null ||
6913                   (e = min$4(toLength$7(splitter.lastIndex + (UNSUPPORTED_Y$1 ? q : 0)), S.length)) === p
6914                 ) {
6915                   q = advanceStringIndex$1(S, q, unicodeMatching);
6916                 } else {
6917                   A.push(S.slice(p, q));
6918                   if (A.length === lim) return A;
6919                   for (var i = 1; i <= z.length - 1; i++) {
6920                     A.push(z[i]);
6921                     if (A.length === lim) return A;
6922                   }
6923                   q = p = e;
6924                 }
6925               }
6926               A.push(S.slice(p));
6927               return A;
6928             }
6929           ];
6930         }, !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC, UNSUPPORTED_Y$1);
6931
6932         // a string of all valid unicode whitespaces
6933         var whitespaces$4 = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002' +
6934           '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
6935
6936         var requireObjectCoercible$8 = requireObjectCoercible$e;
6937         var whitespaces$3 = whitespaces$4;
6938
6939         var whitespace = '[' + whitespaces$3 + ']';
6940         var ltrim = RegExp('^' + whitespace + whitespace + '*');
6941         var rtrim$2 = RegExp(whitespace + whitespace + '*$');
6942
6943         // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
6944         var createMethod$2 = function (TYPE) {
6945           return function ($this) {
6946             var string = String(requireObjectCoercible$8($this));
6947             if (TYPE & 1) string = string.replace(ltrim, '');
6948             if (TYPE & 2) string = string.replace(rtrim$2, '');
6949             return string;
6950           };
6951         };
6952
6953         var stringTrim = {
6954           // `String.prototype.{ trimLeft, trimStart }` methods
6955           // https://tc39.es/ecma262/#sec-string.prototype.trimstart
6956           start: createMethod$2(1),
6957           // `String.prototype.{ trimRight, trimEnd }` methods
6958           // https://tc39.es/ecma262/#sec-string.prototype.trimend
6959           end: createMethod$2(2),
6960           // `String.prototype.trim` method
6961           // https://tc39.es/ecma262/#sec-string.prototype.trim
6962           trim: createMethod$2(3)
6963         };
6964
6965         var fails$j = fails$N;
6966         var whitespaces$2 = whitespaces$4;
6967
6968         var non = '\u200B\u0085\u180E';
6969
6970         // check that a method works with the correct list
6971         // of whitespaces and has a correct name
6972         var stringTrimForced = function (METHOD_NAME) {
6973           return fails$j(function () {
6974             return !!whitespaces$2[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces$2[METHOD_NAME].name !== METHOD_NAME;
6975           });
6976         };
6977
6978         var $$O = _export;
6979         var $trim = stringTrim.trim;
6980         var forcedStringTrimMethod = stringTrimForced;
6981
6982         // `String.prototype.trim` method
6983         // https://tc39.es/ecma262/#sec-string.prototype.trim
6984         $$O({ target: 'String', proto: true, forced: forcedStringTrimMethod('trim') }, {
6985           trim: function trim() {
6986             return $trim(this);
6987           }
6988         });
6989
6990         var DESCRIPTORS$9 = descriptors;
6991         var defineProperty$4 = objectDefineProperty.f;
6992
6993         var FunctionPrototype = Function.prototype;
6994         var FunctionPrototypeToString = FunctionPrototype.toString;
6995         var nameRE = /^\s*function ([^ (]*)/;
6996         var NAME = 'name';
6997
6998         // Function instances `.name` property
6999         // https://tc39.es/ecma262/#sec-function-instances-name
7000         if (DESCRIPTORS$9 && !(NAME in FunctionPrototype)) {
7001           defineProperty$4(FunctionPrototype, NAME, {
7002             configurable: true,
7003             get: function () {
7004               try {
7005                 return FunctionPrototypeToString.call(this).match(nameRE)[1];
7006               } catch (error) {
7007                 return '';
7008               }
7009             }
7010           });
7011         }
7012
7013         var $$N = _export;
7014         var DESCRIPTORS$8 = descriptors;
7015         var create$6 = objectCreate;
7016
7017         // `Object.create` method
7018         // https://tc39.es/ecma262/#sec-object.create
7019         $$N({ target: 'Object', stat: true, sham: !DESCRIPTORS$8 }, {
7020           create: create$6
7021         });
7022
7023         var $$M = _export;
7024         var global$9 = global$F;
7025         var userAgent = engineUserAgent;
7026
7027         var slice$3 = [].slice;
7028         var MSIE = /MSIE .\./.test(userAgent); // <- dirty ie9- check
7029
7030         var wrap$1 = function (scheduler) {
7031           return function (handler, timeout /* , ...arguments */) {
7032             var boundArgs = arguments.length > 2;
7033             var args = boundArgs ? slice$3.call(arguments, 2) : undefined;
7034             return scheduler(boundArgs ? function () {
7035               // eslint-disable-next-line no-new-func -- spec requirement
7036               (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
7037             } : handler, timeout);
7038           };
7039         };
7040
7041         // ie9- setTimeout & setInterval additional parameters fix
7042         // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
7043         $$M({ global: true, bind: true, forced: MSIE }, {
7044           // `setTimeout` method
7045           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
7046           setTimeout: wrap$1(global$9.setTimeout),
7047           // `setInterval` method
7048           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
7049           setInterval: wrap$1(global$9.setInterval)
7050         });
7051
7052         var global$8 = typeof globalThis !== 'undefined' && globalThis || typeof self !== 'undefined' && self || typeof global$8 !== 'undefined' && global$8;
7053         var support = {
7054           searchParams: 'URLSearchParams' in global$8,
7055           iterable: 'Symbol' in global$8 && 'iterator' in Symbol,
7056           blob: 'FileReader' in global$8 && 'Blob' in global$8 && function () {
7057             try {
7058               new Blob();
7059               return true;
7060             } catch (e) {
7061               return false;
7062             }
7063           }(),
7064           formData: 'FormData' in global$8,
7065           arrayBuffer: 'ArrayBuffer' in global$8
7066         };
7067
7068         function isDataView(obj) {
7069           return obj && DataView.prototype.isPrototypeOf(obj);
7070         }
7071
7072         if (support.arrayBuffer) {
7073           var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];
7074
7075           var isArrayBufferView = ArrayBuffer.isView || function (obj) {
7076             return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
7077           };
7078         }
7079
7080         function normalizeName(name) {
7081           if (typeof name !== 'string') {
7082             name = String(name);
7083           }
7084
7085           if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
7086             throw new TypeError('Invalid character in header field name: "' + name + '"');
7087           }
7088
7089           return name.toLowerCase();
7090         }
7091
7092         function normalizeValue(value) {
7093           if (typeof value !== 'string') {
7094             value = String(value);
7095           }
7096
7097           return value;
7098         } // Build a destructive iterator for the value list
7099
7100
7101         function iteratorFor(items) {
7102           var iterator = {
7103             next: function next() {
7104               var value = items.shift();
7105               return {
7106                 done: value === undefined,
7107                 value: value
7108               };
7109             }
7110           };
7111
7112           if (support.iterable) {
7113             iterator[Symbol.iterator] = function () {
7114               return iterator;
7115             };
7116           }
7117
7118           return iterator;
7119         }
7120
7121         function Headers(headers) {
7122           this.map = {};
7123
7124           if (headers instanceof Headers) {
7125             headers.forEach(function (value, name) {
7126               this.append(name, value);
7127             }, this);
7128           } else if (Array.isArray(headers)) {
7129             headers.forEach(function (header) {
7130               this.append(header[0], header[1]);
7131             }, this);
7132           } else if (headers) {
7133             Object.getOwnPropertyNames(headers).forEach(function (name) {
7134               this.append(name, headers[name]);
7135             }, this);
7136           }
7137         }
7138
7139         Headers.prototype.append = function (name, value) {
7140           name = normalizeName(name);
7141           value = normalizeValue(value);
7142           var oldValue = this.map[name];
7143           this.map[name] = oldValue ? oldValue + ', ' + value : value;
7144         };
7145
7146         Headers.prototype['delete'] = function (name) {
7147           delete this.map[normalizeName(name)];
7148         };
7149
7150         Headers.prototype.get = function (name) {
7151           name = normalizeName(name);
7152           return this.has(name) ? this.map[name] : null;
7153         };
7154
7155         Headers.prototype.has = function (name) {
7156           return this.map.hasOwnProperty(normalizeName(name));
7157         };
7158
7159         Headers.prototype.set = function (name, value) {
7160           this.map[normalizeName(name)] = normalizeValue(value);
7161         };
7162
7163         Headers.prototype.forEach = function (callback, thisArg) {
7164           for (var name in this.map) {
7165             if (this.map.hasOwnProperty(name)) {
7166               callback.call(thisArg, this.map[name], name, this);
7167             }
7168           }
7169         };
7170
7171         Headers.prototype.keys = function () {
7172           var items = [];
7173           this.forEach(function (value, name) {
7174             items.push(name);
7175           });
7176           return iteratorFor(items);
7177         };
7178
7179         Headers.prototype.values = function () {
7180           var items = [];
7181           this.forEach(function (value) {
7182             items.push(value);
7183           });
7184           return iteratorFor(items);
7185         };
7186
7187         Headers.prototype.entries = function () {
7188           var items = [];
7189           this.forEach(function (value, name) {
7190             items.push([name, value]);
7191           });
7192           return iteratorFor(items);
7193         };
7194
7195         if (support.iterable) {
7196           Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
7197         }
7198
7199         function consumed(body) {
7200           if (body.bodyUsed) {
7201             return Promise.reject(new TypeError('Already read'));
7202           }
7203
7204           body.bodyUsed = true;
7205         }
7206
7207         function fileReaderReady(reader) {
7208           return new Promise(function (resolve, reject) {
7209             reader.onload = function () {
7210               resolve(reader.result);
7211             };
7212
7213             reader.onerror = function () {
7214               reject(reader.error);
7215             };
7216           });
7217         }
7218
7219         function readBlobAsArrayBuffer(blob) {
7220           var reader = new FileReader();
7221           var promise = fileReaderReady(reader);
7222           reader.readAsArrayBuffer(blob);
7223           return promise;
7224         }
7225
7226         function readBlobAsText(blob) {
7227           var reader = new FileReader();
7228           var promise = fileReaderReady(reader);
7229           reader.readAsText(blob);
7230           return promise;
7231         }
7232
7233         function readArrayBufferAsText(buf) {
7234           var view = new Uint8Array(buf);
7235           var chars = new Array(view.length);
7236
7237           for (var i = 0; i < view.length; i++) {
7238             chars[i] = String.fromCharCode(view[i]);
7239           }
7240
7241           return chars.join('');
7242         }
7243
7244         function bufferClone(buf) {
7245           if (buf.slice) {
7246             return buf.slice(0);
7247           } else {
7248             var view = new Uint8Array(buf.byteLength);
7249             view.set(new Uint8Array(buf));
7250             return view.buffer;
7251           }
7252         }
7253
7254         function Body() {
7255           this.bodyUsed = false;
7256
7257           this._initBody = function (body) {
7258             /*
7259               fetch-mock wraps the Response object in an ES6 Proxy to
7260               provide useful test harness features such as flush. However, on
7261               ES5 browsers without fetch or Proxy support pollyfills must be used;
7262               the proxy-pollyfill is unable to proxy an attribute unless it exists
7263               on the object before the Proxy is created. This change ensures
7264               Response.bodyUsed exists on the instance, while maintaining the
7265               semantic of setting Request.bodyUsed in the constructor before
7266               _initBody is called.
7267             */
7268             this.bodyUsed = this.bodyUsed;
7269             this._bodyInit = body;
7270
7271             if (!body) {
7272               this._bodyText = '';
7273             } else if (typeof body === 'string') {
7274               this._bodyText = body;
7275             } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
7276               this._bodyBlob = body;
7277             } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
7278               this._bodyFormData = body;
7279             } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
7280               this._bodyText = body.toString();
7281             } else if (support.arrayBuffer && support.blob && isDataView(body)) {
7282               this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.
7283
7284               this._bodyInit = new Blob([this._bodyArrayBuffer]);
7285             } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
7286               this._bodyArrayBuffer = bufferClone(body);
7287             } else {
7288               this._bodyText = body = Object.prototype.toString.call(body);
7289             }
7290
7291             if (!this.headers.get('content-type')) {
7292               if (typeof body === 'string') {
7293                 this.headers.set('content-type', 'text/plain;charset=UTF-8');
7294               } else if (this._bodyBlob && this._bodyBlob.type) {
7295                 this.headers.set('content-type', this._bodyBlob.type);
7296               } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
7297                 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
7298               }
7299             }
7300           };
7301
7302           if (support.blob) {
7303             this.blob = function () {
7304               var rejected = consumed(this);
7305
7306               if (rejected) {
7307                 return rejected;
7308               }
7309
7310               if (this._bodyBlob) {
7311                 return Promise.resolve(this._bodyBlob);
7312               } else if (this._bodyArrayBuffer) {
7313                 return Promise.resolve(new Blob([this._bodyArrayBuffer]));
7314               } else if (this._bodyFormData) {
7315                 throw new Error('could not read FormData body as blob');
7316               } else {
7317                 return Promise.resolve(new Blob([this._bodyText]));
7318               }
7319             };
7320
7321             this.arrayBuffer = function () {
7322               if (this._bodyArrayBuffer) {
7323                 var isConsumed = consumed(this);
7324
7325                 if (isConsumed) {
7326                   return isConsumed;
7327                 }
7328
7329                 if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
7330                   return Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset, this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength));
7331                 } else {
7332                   return Promise.resolve(this._bodyArrayBuffer);
7333                 }
7334               } else {
7335                 return this.blob().then(readBlobAsArrayBuffer);
7336               }
7337             };
7338           }
7339
7340           this.text = function () {
7341             var rejected = consumed(this);
7342
7343             if (rejected) {
7344               return rejected;
7345             }
7346
7347             if (this._bodyBlob) {
7348               return readBlobAsText(this._bodyBlob);
7349             } else if (this._bodyArrayBuffer) {
7350               return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
7351             } else if (this._bodyFormData) {
7352               throw new Error('could not read FormData body as text');
7353             } else {
7354               return Promise.resolve(this._bodyText);
7355             }
7356           };
7357
7358           if (support.formData) {
7359             this.formData = function () {
7360               return this.text().then(decode);
7361             };
7362           }
7363
7364           this.json = function () {
7365             return this.text().then(JSON.parse);
7366           };
7367
7368           return this;
7369         } // HTTP methods whose capitalization should be normalized
7370
7371
7372         var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
7373
7374         function normalizeMethod(method) {
7375           var upcased = method.toUpperCase();
7376           return methods.indexOf(upcased) > -1 ? upcased : method;
7377         }
7378
7379         function Request(input, options) {
7380           if (!(this instanceof Request)) {
7381             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
7382           }
7383
7384           options = options || {};
7385           var body = options.body;
7386
7387           if (input instanceof Request) {
7388             if (input.bodyUsed) {
7389               throw new TypeError('Already read');
7390             }
7391
7392             this.url = input.url;
7393             this.credentials = input.credentials;
7394
7395             if (!options.headers) {
7396               this.headers = new Headers(input.headers);
7397             }
7398
7399             this.method = input.method;
7400             this.mode = input.mode;
7401             this.signal = input.signal;
7402
7403             if (!body && input._bodyInit != null) {
7404               body = input._bodyInit;
7405               input.bodyUsed = true;
7406             }
7407           } else {
7408             this.url = String(input);
7409           }
7410
7411           this.credentials = options.credentials || this.credentials || 'same-origin';
7412
7413           if (options.headers || !this.headers) {
7414             this.headers = new Headers(options.headers);
7415           }
7416
7417           this.method = normalizeMethod(options.method || this.method || 'GET');
7418           this.mode = options.mode || this.mode || null;
7419           this.signal = options.signal || this.signal;
7420           this.referrer = null;
7421
7422           if ((this.method === 'GET' || this.method === 'HEAD') && body) {
7423             throw new TypeError('Body not allowed for GET or HEAD requests');
7424           }
7425
7426           this._initBody(body);
7427
7428           if (this.method === 'GET' || this.method === 'HEAD') {
7429             if (options.cache === 'no-store' || options.cache === 'no-cache') {
7430               // Search for a '_' parameter in the query string
7431               var reParamSearch = /([?&])_=[^&]*/;
7432
7433               if (reParamSearch.test(this.url)) {
7434                 // If it already exists then set the value with the current time
7435                 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
7436               } else {
7437                 // Otherwise add a new '_' parameter to the end with the current time
7438                 var reQueryString = /\?/;
7439                 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
7440               }
7441             }
7442           }
7443         }
7444
7445         Request.prototype.clone = function () {
7446           return new Request(this, {
7447             body: this._bodyInit
7448           });
7449         };
7450
7451         function decode(body) {
7452           var form = new FormData();
7453           body.trim().split('&').forEach(function (bytes) {
7454             if (bytes) {
7455               var split = bytes.split('=');
7456               var name = split.shift().replace(/\+/g, ' ');
7457               var value = split.join('=').replace(/\+/g, ' ');
7458               form.append(decodeURIComponent(name), decodeURIComponent(value));
7459             }
7460           });
7461           return form;
7462         }
7463
7464         function parseHeaders(rawHeaders) {
7465           var headers = new Headers(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
7466           // https://tools.ietf.org/html/rfc7230#section-3.2
7467
7468           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
7469           // https://github.com/github/fetch/issues/748
7470           // https://github.com/zloirock/core-js/issues/751
7471
7472           preProcessedHeaders.split('\r').map(function (header) {
7473             return header.indexOf('\n') === 0 ? header.substr(1, header.length) : header;
7474           }).forEach(function (line) {
7475             var parts = line.split(':');
7476             var key = parts.shift().trim();
7477
7478             if (key) {
7479               var value = parts.join(':').trim();
7480               headers.append(key, value);
7481             }
7482           });
7483           return headers;
7484         }
7485
7486         Body.call(Request.prototype);
7487         function Response(bodyInit, options) {
7488           if (!(this instanceof Response)) {
7489             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
7490           }
7491
7492           if (!options) {
7493             options = {};
7494           }
7495
7496           this.type = 'default';
7497           this.status = options.status === undefined ? 200 : options.status;
7498           this.ok = this.status >= 200 && this.status < 300;
7499           this.statusText = options.statusText === undefined ? '' : '' + options.statusText;
7500           this.headers = new Headers(options.headers);
7501           this.url = options.url || '';
7502
7503           this._initBody(bodyInit);
7504         }
7505         Body.call(Response.prototype);
7506
7507         Response.prototype.clone = function () {
7508           return new Response(this._bodyInit, {
7509             status: this.status,
7510             statusText: this.statusText,
7511             headers: new Headers(this.headers),
7512             url: this.url
7513           });
7514         };
7515
7516         Response.error = function () {
7517           var response = new Response(null, {
7518             status: 0,
7519             statusText: ''
7520           });
7521           response.type = 'error';
7522           return response;
7523         };
7524
7525         var redirectStatuses = [301, 302, 303, 307, 308];
7526
7527         Response.redirect = function (url, status) {
7528           if (redirectStatuses.indexOf(status) === -1) {
7529             throw new RangeError('Invalid status code');
7530           }
7531
7532           return new Response(null, {
7533             status: status,
7534             headers: {
7535               location: url
7536             }
7537           });
7538         };
7539
7540         var DOMException$1 = global$8.DOMException;
7541
7542         try {
7543           new DOMException$1();
7544         } catch (err) {
7545           DOMException$1 = function DOMException(message, name) {
7546             this.message = message;
7547             this.name = name;
7548             var error = Error(message);
7549             this.stack = error.stack;
7550           };
7551
7552           DOMException$1.prototype = Object.create(Error.prototype);
7553           DOMException$1.prototype.constructor = DOMException$1;
7554         }
7555
7556         function fetch$1(input, init) {
7557           return new Promise(function (resolve, reject) {
7558             var request = new Request(input, init);
7559
7560             if (request.signal && request.signal.aborted) {
7561               return reject(new DOMException$1('Aborted', 'AbortError'));
7562             }
7563
7564             var xhr = new XMLHttpRequest();
7565
7566             function abortXhr() {
7567               xhr.abort();
7568             }
7569
7570             xhr.onload = function () {
7571               var options = {
7572                 status: xhr.status,
7573                 statusText: xhr.statusText,
7574                 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
7575               };
7576               options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
7577               var body = 'response' in xhr ? xhr.response : xhr.responseText;
7578               setTimeout(function () {
7579                 resolve(new Response(body, options));
7580               }, 0);
7581             };
7582
7583             xhr.onerror = function () {
7584               setTimeout(function () {
7585                 reject(new TypeError('Network request failed'));
7586               }, 0);
7587             };
7588
7589             xhr.ontimeout = function () {
7590               setTimeout(function () {
7591                 reject(new TypeError('Network request failed'));
7592               }, 0);
7593             };
7594
7595             xhr.onabort = function () {
7596               setTimeout(function () {
7597                 reject(new DOMException$1('Aborted', 'AbortError'));
7598               }, 0);
7599             };
7600
7601             function fixUrl(url) {
7602               try {
7603                 return url === '' && global$8.location.href ? global$8.location.href : url;
7604               } catch (e) {
7605                 return url;
7606               }
7607             }
7608
7609             xhr.open(request.method, fixUrl(request.url), true);
7610
7611             if (request.credentials === 'include') {
7612               xhr.withCredentials = true;
7613             } else if (request.credentials === 'omit') {
7614               xhr.withCredentials = false;
7615             }
7616
7617             if ('responseType' in xhr) {
7618               if (support.blob) {
7619                 xhr.responseType = 'blob';
7620               } else if (support.arrayBuffer && request.headers.get('Content-Type') && request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1) {
7621                 xhr.responseType = 'arraybuffer';
7622               }
7623             }
7624
7625             if (init && _typeof(init.headers) === 'object' && !(init.headers instanceof Headers)) {
7626               Object.getOwnPropertyNames(init.headers).forEach(function (name) {
7627                 xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
7628               });
7629             } else {
7630               request.headers.forEach(function (value, name) {
7631                 xhr.setRequestHeader(name, value);
7632               });
7633             }
7634
7635             if (request.signal) {
7636               request.signal.addEventListener('abort', abortXhr);
7637
7638               xhr.onreadystatechange = function () {
7639                 // DONE (success or failure)
7640                 if (xhr.readyState === 4) {
7641                   request.signal.removeEventListener('abort', abortXhr);
7642                 }
7643               };
7644             }
7645
7646             xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
7647           });
7648         }
7649         fetch$1.polyfill = true;
7650
7651         if (!global$8.fetch) {
7652           global$8.fetch = fetch$1;
7653           global$8.Headers = Headers;
7654           global$8.Request = Request;
7655           global$8.Response = Response;
7656         }
7657
7658         var $$L = _export;
7659         var DESCRIPTORS$7 = descriptors;
7660         var objectDefinePropertyModile = objectDefineProperty;
7661
7662         // `Object.defineProperty` method
7663         // https://tc39.es/ecma262/#sec-object.defineproperty
7664         $$L({ target: 'Object', stat: true, forced: !DESCRIPTORS$7, sham: !DESCRIPTORS$7 }, {
7665           defineProperty: objectDefinePropertyModile.f
7666         });
7667
7668         var $$K = _export;
7669         var setPrototypeOf = objectSetPrototypeOf;
7670
7671         // `Object.setPrototypeOf` method
7672         // https://tc39.es/ecma262/#sec-object.setprototypeof
7673         $$K({ target: 'Object', stat: true }, {
7674           setPrototypeOf: setPrototypeOf
7675         });
7676
7677         var $$J = _export;
7678         var fails$i = fails$N;
7679         var toObject$5 = toObject$i;
7680         var nativeGetPrototypeOf = objectGetPrototypeOf;
7681         var CORRECT_PROTOTYPE_GETTER = correctPrototypeGetter;
7682
7683         var FAILS_ON_PRIMITIVES$3 = fails$i(function () { nativeGetPrototypeOf(1); });
7684
7685         // `Object.getPrototypeOf` method
7686         // https://tc39.es/ecma262/#sec-object.getprototypeof
7687         $$J({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$3, sham: !CORRECT_PROTOTYPE_GETTER }, {
7688           getPrototypeOf: function getPrototypeOf(it) {
7689             return nativeGetPrototypeOf(toObject$5(it));
7690           }
7691         });
7692
7693         var aFunction$2 = aFunction$9;
7694         var isObject$a = isObject$r;
7695
7696         var slice$2 = [].slice;
7697         var factories = {};
7698
7699         var construct = function (C, argsLength, args) {
7700           if (!(argsLength in factories)) {
7701             for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']';
7702             // eslint-disable-next-line no-new-func -- we have no proper alternatives, IE8- only
7703             factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
7704           } return factories[argsLength](C, args);
7705         };
7706
7707         // `Function.prototype.bind` method implementation
7708         // https://tc39.es/ecma262/#sec-function.prototype.bind
7709         var functionBind = Function.bind || function bind(that /* , ...args */) {
7710           var fn = aFunction$2(this);
7711           var partArgs = slice$2.call(arguments, 1);
7712           var boundFunction = function bound(/* args... */) {
7713             var args = partArgs.concat(slice$2.call(arguments));
7714             return this instanceof boundFunction ? construct(fn, args.length, args) : fn.apply(that, args);
7715           };
7716           if (isObject$a(fn.prototype)) boundFunction.prototype = fn.prototype;
7717           return boundFunction;
7718         };
7719
7720         var $$I = _export;
7721         var getBuiltIn$1 = getBuiltIn$9;
7722         var aFunction$1 = aFunction$9;
7723         var anObject$3 = anObject$m;
7724         var isObject$9 = isObject$r;
7725         var create$5 = objectCreate;
7726         var bind$4 = functionBind;
7727         var fails$h = fails$N;
7728
7729         var nativeConstruct = getBuiltIn$1('Reflect', 'construct');
7730
7731         // `Reflect.construct` method
7732         // https://tc39.es/ecma262/#sec-reflect.construct
7733         // MS Edge supports only 2 arguments and argumentsList argument is optional
7734         // FF Nightly sets third argument as `new.target`, but does not create `this` from it
7735         var NEW_TARGET_BUG = fails$h(function () {
7736           function F() { /* empty */ }
7737           return !(nativeConstruct(function () { /* empty */ }, [], F) instanceof F);
7738         });
7739         var ARGS_BUG = !fails$h(function () {
7740           nativeConstruct(function () { /* empty */ });
7741         });
7742         var FORCED$a = NEW_TARGET_BUG || ARGS_BUG;
7743
7744         $$I({ target: 'Reflect', stat: true, forced: FORCED$a, sham: FORCED$a }, {
7745           construct: function construct(Target, args /* , newTarget */) {
7746             aFunction$1(Target);
7747             anObject$3(args);
7748             var newTarget = arguments.length < 3 ? Target : aFunction$1(arguments[2]);
7749             if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
7750             if (Target == newTarget) {
7751               // w/o altered newTarget, optimization for 0-4 arguments
7752               switch (args.length) {
7753                 case 0: return new Target();
7754                 case 1: return new Target(args[0]);
7755                 case 2: return new Target(args[0], args[1]);
7756                 case 3: return new Target(args[0], args[1], args[2]);
7757                 case 4: return new Target(args[0], args[1], args[2], args[3]);
7758               }
7759               // w/o altered newTarget, lot of arguments case
7760               var $args = [null];
7761               $args.push.apply($args, args);
7762               return new (bind$4.apply(Target, $args))();
7763             }
7764             // with altered newTarget, not support built-in constructors
7765             var proto = newTarget.prototype;
7766             var instance = create$5(isObject$9(proto) ? proto : Object.prototype);
7767             var result = Function.apply.call(Target, instance, args);
7768             return isObject$9(result) ? result : instance;
7769           }
7770         });
7771
7772         var $$H = _export;
7773         var isObject$8 = isObject$r;
7774         var anObject$2 = anObject$m;
7775         var has$3 = has$j;
7776         var getOwnPropertyDescriptorModule = objectGetOwnPropertyDescriptor;
7777         var getPrototypeOf = objectGetPrototypeOf;
7778
7779         // `Reflect.get` method
7780         // https://tc39.es/ecma262/#sec-reflect.get
7781         function get$3(target, propertyKey /* , receiver */) {
7782           var receiver = arguments.length < 3 ? target : arguments[2];
7783           var descriptor, prototype;
7784           if (anObject$2(target) === receiver) return target[propertyKey];
7785           if (descriptor = getOwnPropertyDescriptorModule.f(target, propertyKey)) return has$3(descriptor, 'value')
7786             ? descriptor.value
7787             : descriptor.get === undefined
7788               ? undefined
7789               : descriptor.get.call(receiver);
7790           if (isObject$8(prototype = getPrototypeOf(target))) return get$3(prototype, propertyKey, receiver);
7791         }
7792
7793         $$H({ target: 'Reflect', stat: true }, {
7794           get: get$3
7795         });
7796
7797         var $$G = _export;
7798         var fails$g = fails$N;
7799         var toIndexedObject$1 = toIndexedObject$b;
7800         var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
7801         var DESCRIPTORS$6 = descriptors;
7802
7803         var FAILS_ON_PRIMITIVES$2 = fails$g(function () { nativeGetOwnPropertyDescriptor(1); });
7804         var FORCED$9 = !DESCRIPTORS$6 || FAILS_ON_PRIMITIVES$2;
7805
7806         // `Object.getOwnPropertyDescriptor` method
7807         // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
7808         $$G({ target: 'Object', stat: true, forced: FORCED$9, sham: !DESCRIPTORS$6 }, {
7809           getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
7810             return nativeGetOwnPropertyDescriptor(toIndexedObject$1(it), key);
7811           }
7812         });
7813
7814         var $$F = _export;
7815         var toAbsoluteIndex$1 = toAbsoluteIndex$8;
7816         var toInteger$2 = toInteger$b;
7817         var toLength$6 = toLength$q;
7818         var toObject$4 = toObject$i;
7819         var arraySpeciesCreate$1 = arraySpeciesCreate$3;
7820         var createProperty$1 = createProperty$4;
7821         var arrayMethodHasSpeciesSupport$2 = arrayMethodHasSpeciesSupport$5;
7822
7823         var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport$2('splice');
7824
7825         var max$1 = Math.max;
7826         var min$3 = Math.min;
7827         var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
7828         var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';
7829
7830         // `Array.prototype.splice` method
7831         // https://tc39.es/ecma262/#sec-array.prototype.splice
7832         // with adding support of @@species
7833         $$F({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 }, {
7834           splice: function splice(start, deleteCount /* , ...items */) {
7835             var O = toObject$4(this);
7836             var len = toLength$6(O.length);
7837             var actualStart = toAbsoluteIndex$1(start, len);
7838             var argumentsLength = arguments.length;
7839             var insertCount, actualDeleteCount, A, k, from, to;
7840             if (argumentsLength === 0) {
7841               insertCount = actualDeleteCount = 0;
7842             } else if (argumentsLength === 1) {
7843               insertCount = 0;
7844               actualDeleteCount = len - actualStart;
7845             } else {
7846               insertCount = argumentsLength - 2;
7847               actualDeleteCount = min$3(max$1(toInteger$2(deleteCount), 0), len - actualStart);
7848             }
7849             if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) {
7850               throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
7851             }
7852             A = arraySpeciesCreate$1(O, actualDeleteCount);
7853             for (k = 0; k < actualDeleteCount; k++) {
7854               from = actualStart + k;
7855               if (from in O) createProperty$1(A, k, O[from]);
7856             }
7857             A.length = actualDeleteCount;
7858             if (insertCount < actualDeleteCount) {
7859               for (k = actualStart; k < len - actualDeleteCount; k++) {
7860                 from = k + actualDeleteCount;
7861                 to = k + insertCount;
7862                 if (from in O) O[to] = O[from];
7863                 else delete O[to];
7864               }
7865               for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
7866             } else if (insertCount > actualDeleteCount) {
7867               for (k = len - actualDeleteCount; k > actualStart; k--) {
7868                 from = k + actualDeleteCount - 1;
7869                 to = k + insertCount - 1;
7870                 if (from in O) O[to] = O[from];
7871                 else delete O[to];
7872               }
7873             }
7874             for (k = 0; k < insertCount; k++) {
7875               O[k + actualStart] = arguments[k + 2];
7876             }
7877             O.length = len - actualDeleteCount + insertCount;
7878             return A;
7879           }
7880         });
7881
7882         var defineWellKnownSymbol$1 = defineWellKnownSymbol$4;
7883
7884         // `Symbol.toStringTag` well-known symbol
7885         // https://tc39.es/ecma262/#sec-symbol.tostringtag
7886         defineWellKnownSymbol$1('toStringTag');
7887
7888         var global$7 = global$F;
7889         var setToStringTag$2 = setToStringTag$a;
7890
7891         // JSON[@@toStringTag] property
7892         // https://tc39.es/ecma262/#sec-json-@@tostringtag
7893         setToStringTag$2(global$7.JSON, 'JSON', true);
7894
7895         var setToStringTag$1 = setToStringTag$a;
7896
7897         // Math[@@toStringTag] property
7898         // https://tc39.es/ecma262/#sec-math-@@tostringtag
7899         setToStringTag$1(Math, 'Math', true);
7900
7901         (function (factory) {
7902           factory();
7903         })(function () {
7904
7905           function _classCallCheck(instance, Constructor) {
7906             if (!(instance instanceof Constructor)) {
7907               throw new TypeError("Cannot call a class as a function");
7908             }
7909           }
7910
7911           function _defineProperties(target, props) {
7912             for (var i = 0; i < props.length; i++) {
7913               var descriptor = props[i];
7914               descriptor.enumerable = descriptor.enumerable || false;
7915               descriptor.configurable = true;
7916               if ("value" in descriptor) descriptor.writable = true;
7917               Object.defineProperty(target, descriptor.key, descriptor);
7918             }
7919           }
7920
7921           function _createClass(Constructor, protoProps, staticProps) {
7922             if (protoProps) _defineProperties(Constructor.prototype, protoProps);
7923             if (staticProps) _defineProperties(Constructor, staticProps);
7924             return Constructor;
7925           }
7926
7927           function _inherits(subClass, superClass) {
7928             if (typeof superClass !== "function" && superClass !== null) {
7929               throw new TypeError("Super expression must either be null or a function");
7930             }
7931
7932             subClass.prototype = Object.create(superClass && superClass.prototype, {
7933               constructor: {
7934                 value: subClass,
7935                 writable: true,
7936                 configurable: true
7937               }
7938             });
7939             if (superClass) _setPrototypeOf(subClass, superClass);
7940           }
7941
7942           function _getPrototypeOf(o) {
7943             _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
7944               return o.__proto__ || Object.getPrototypeOf(o);
7945             };
7946             return _getPrototypeOf(o);
7947           }
7948
7949           function _setPrototypeOf(o, p) {
7950             _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
7951               o.__proto__ = p;
7952               return o;
7953             };
7954
7955             return _setPrototypeOf(o, p);
7956           }
7957
7958           function _isNativeReflectConstruct() {
7959             if (typeof Reflect === "undefined" || !Reflect.construct) return false;
7960             if (Reflect.construct.sham) return false;
7961             if (typeof Proxy === "function") return true;
7962
7963             try {
7964               Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
7965               return true;
7966             } catch (e) {
7967               return false;
7968             }
7969           }
7970
7971           function _assertThisInitialized(self) {
7972             if (self === void 0) {
7973               throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
7974             }
7975
7976             return self;
7977           }
7978
7979           function _possibleConstructorReturn(self, call) {
7980             if (call && (_typeof(call) === "object" || typeof call === "function")) {
7981               return call;
7982             }
7983
7984             return _assertThisInitialized(self);
7985           }
7986
7987           function _createSuper(Derived) {
7988             var hasNativeReflectConstruct = _isNativeReflectConstruct();
7989
7990             return function _createSuperInternal() {
7991               var Super = _getPrototypeOf(Derived),
7992                   result;
7993
7994               if (hasNativeReflectConstruct) {
7995                 var NewTarget = _getPrototypeOf(this).constructor;
7996
7997                 result = Reflect.construct(Super, arguments, NewTarget);
7998               } else {
7999                 result = Super.apply(this, arguments);
8000               }
8001
8002               return _possibleConstructorReturn(this, result);
8003             };
8004           }
8005
8006           function _superPropBase(object, property) {
8007             while (!Object.prototype.hasOwnProperty.call(object, property)) {
8008               object = _getPrototypeOf(object);
8009               if (object === null) break;
8010             }
8011
8012             return object;
8013           }
8014
8015           function _get(target, property, receiver) {
8016             if (typeof Reflect !== "undefined" && Reflect.get) {
8017               _get = Reflect.get;
8018             } else {
8019               _get = function _get(target, property, receiver) {
8020                 var base = _superPropBase(target, property);
8021
8022                 if (!base) return;
8023                 var desc = Object.getOwnPropertyDescriptor(base, property);
8024
8025                 if (desc.get) {
8026                   return desc.get.call(receiver);
8027                 }
8028
8029                 return desc.value;
8030               };
8031             }
8032
8033             return _get(target, property, receiver || target);
8034           }
8035
8036           var Emitter = /*#__PURE__*/function () {
8037             function Emitter() {
8038               _classCallCheck(this, Emitter);
8039
8040               Object.defineProperty(this, 'listeners', {
8041                 value: {},
8042                 writable: true,
8043                 configurable: true
8044               });
8045             }
8046
8047             _createClass(Emitter, [{
8048               key: "addEventListener",
8049               value: function addEventListener(type, callback, options) {
8050                 if (!(type in this.listeners)) {
8051                   this.listeners[type] = [];
8052                 }
8053
8054                 this.listeners[type].push({
8055                   callback: callback,
8056                   options: options
8057                 });
8058               }
8059             }, {
8060               key: "removeEventListener",
8061               value: function removeEventListener(type, callback) {
8062                 if (!(type in this.listeners)) {
8063                   return;
8064                 }
8065
8066                 var stack = this.listeners[type];
8067
8068                 for (var i = 0, l = stack.length; i < l; i++) {
8069                   if (stack[i].callback === callback) {
8070                     stack.splice(i, 1);
8071                     return;
8072                   }
8073                 }
8074               }
8075             }, {
8076               key: "dispatchEvent",
8077               value: function dispatchEvent(event) {
8078                 if (!(event.type in this.listeners)) {
8079                   return;
8080                 }
8081
8082                 var stack = this.listeners[event.type];
8083                 var stackToCall = stack.slice();
8084
8085                 for (var i = 0, l = stackToCall.length; i < l; i++) {
8086                   var listener = stackToCall[i];
8087
8088                   try {
8089                     listener.callback.call(this, event);
8090                   } catch (e) {
8091                     Promise.resolve().then(function () {
8092                       throw e;
8093                     });
8094                   }
8095
8096                   if (listener.options && listener.options.once) {
8097                     this.removeEventListener(event.type, listener.callback);
8098                   }
8099                 }
8100
8101                 return !event.defaultPrevented;
8102               }
8103             }]);
8104
8105             return Emitter;
8106           }();
8107
8108           var AbortSignal = /*#__PURE__*/function (_Emitter) {
8109             _inherits(AbortSignal, _Emitter);
8110
8111             var _super = _createSuper(AbortSignal);
8112
8113             function AbortSignal() {
8114               var _this;
8115
8116               _classCallCheck(this, AbortSignal);
8117
8118               _this = _super.call(this); // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
8119               // constructor has failed to run, then "this.listeners" will still be undefined and then we call
8120               // the parent constructor directly instead as a workaround. For general details, see babel bug:
8121               // https://github.com/babel/babel/issues/3041
8122               // This hack was added as a fix for the issue described here:
8123               // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
8124
8125               if (!_this.listeners) {
8126                 Emitter.call(_assertThisInitialized(_this));
8127               } // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
8128               // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
8129
8130
8131               Object.defineProperty(_assertThisInitialized(_this), 'aborted', {
8132                 value: false,
8133                 writable: true,
8134                 configurable: true
8135               });
8136               Object.defineProperty(_assertThisInitialized(_this), 'onabort', {
8137                 value: null,
8138                 writable: true,
8139                 configurable: true
8140               });
8141               return _this;
8142             }
8143
8144             _createClass(AbortSignal, [{
8145               key: "toString",
8146               value: function toString() {
8147                 return '[object AbortSignal]';
8148               }
8149             }, {
8150               key: "dispatchEvent",
8151               value: function dispatchEvent(event) {
8152                 if (event.type === 'abort') {
8153                   this.aborted = true;
8154
8155                   if (typeof this.onabort === 'function') {
8156                     this.onabort.call(this, event);
8157                   }
8158                 }
8159
8160                 _get(_getPrototypeOf(AbortSignal.prototype), "dispatchEvent", this).call(this, event);
8161               }
8162             }]);
8163
8164             return AbortSignal;
8165           }(Emitter);
8166
8167           var AbortController = /*#__PURE__*/function () {
8168             function AbortController() {
8169               _classCallCheck(this, AbortController); // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
8170               // we want Object.keys(new AbortController()) to be [] for compat with the native impl
8171
8172
8173               Object.defineProperty(this, 'signal', {
8174                 value: new AbortSignal(),
8175                 writable: true,
8176                 configurable: true
8177               });
8178             }
8179
8180             _createClass(AbortController, [{
8181               key: "abort",
8182               value: function abort() {
8183                 var event;
8184
8185                 try {
8186                   event = new Event('abort');
8187                 } catch (e) {
8188                   if (typeof document !== 'undefined') {
8189                     if (!document.createEvent) {
8190                       // For Internet Explorer 8:
8191                       event = document.createEventObject();
8192                       event.type = 'abort';
8193                     } else {
8194                       // For Internet Explorer 11:
8195                       event = document.createEvent('Event');
8196                       event.initEvent('abort', false, false);
8197                     }
8198                   } else {
8199                     // Fallback where document isn't available:
8200                     event = {
8201                       type: 'abort',
8202                       bubbles: false,
8203                       cancelable: false
8204                     };
8205                   }
8206                 }
8207
8208                 this.signal.dispatchEvent(event);
8209               }
8210             }, {
8211               key: "toString",
8212               value: function toString() {
8213                 return '[object AbortController]';
8214               }
8215             }]);
8216
8217             return AbortController;
8218           }();
8219
8220           if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
8221             // These are necessary to make sure that we get correct output for:
8222             // Object.prototype.toString.call(new AbortController())
8223             AbortController.prototype[Symbol.toStringTag] = 'AbortController';
8224             AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
8225           }
8226
8227           function polyfillNeeded(self) {
8228             if (self.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
8229               console.log('__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL=true is set, will force install polyfill');
8230               return true;
8231             } // Note that the "unfetch" minimal fetch polyfill defines fetch() without
8232             // defining window.Request, and this polyfill need to work on top of unfetch
8233             // so the below feature detection needs the !self.AbortController part.
8234             // The Request.prototype check is also needed because Safari versions 11.1.2
8235             // up to and including 12.1.x has a window.AbortController present but still
8236             // does NOT correctly implement abortable fetch:
8237             // https://bugs.webkit.org/show_bug.cgi?id=174980#c2
8238
8239
8240             return typeof self.Request === 'function' && !self.Request.prototype.hasOwnProperty('signal') || !self.AbortController;
8241           }
8242           /**
8243            * Note: the "fetch.Request" default value is available for fetch imported from
8244            * the "node-fetch" package and not in browsers. This is OK since browsers
8245            * will be importing umd-polyfill.js from that path "self" is passed the
8246            * decorator so the default value will not be used (because browsers that define
8247            * fetch also has Request). One quirky setup where self.fetch exists but
8248            * self.Request does not is when the "unfetch" minimal fetch polyfill is used
8249            * on top of IE11; for this case the browser will try to use the fetch.Request
8250            * default value which in turn will be undefined but then then "if (Request)"
8251            * will ensure that you get a patched fetch but still no Request (as expected).
8252            * @param {fetch, Request = fetch.Request}
8253            * @returns {fetch: abortableFetch, Request: AbortableRequest}
8254            */
8255
8256
8257           function abortableFetchDecorator(patchTargets) {
8258             if ('function' === typeof patchTargets) {
8259               patchTargets = {
8260                 fetch: patchTargets
8261               };
8262             }
8263
8264             var _patchTargets = patchTargets,
8265                 fetch = _patchTargets.fetch,
8266                 _patchTargets$Request = _patchTargets.Request,
8267                 NativeRequest = _patchTargets$Request === void 0 ? fetch.Request : _patchTargets$Request,
8268                 NativeAbortController = _patchTargets.AbortController,
8269                 _patchTargets$__FORCE = _patchTargets.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL,
8270                 __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL = _patchTargets$__FORCE === void 0 ? false : _patchTargets$__FORCE;
8271
8272             if (!polyfillNeeded({
8273               fetch: fetch,
8274               Request: NativeRequest,
8275               AbortController: NativeAbortController,
8276               __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL: __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL
8277             })) {
8278               return {
8279                 fetch: fetch,
8280                 Request: Request
8281               };
8282             }
8283
8284             var Request = NativeRequest; // Note that the "unfetch" minimal fetch polyfill defines fetch() without
8285             // defining window.Request, and this polyfill need to work on top of unfetch
8286             // hence we only patch it if it's available. Also we don't patch it if signal
8287             // is already available on the Request prototype because in this case support
8288             // is present and the patching below can cause a crash since it assigns to
8289             // request.signal which is technically a read-only property. This latter error
8290             // happens when you run the main5.js node-fetch example in the repo
8291             // "abortcontroller-polyfill-examples". The exact error is:
8292             //   request.signal = init.signal;
8293             //   ^
8294             // TypeError: Cannot set property signal of #<Request> which has only a getter
8295
8296             if (Request && !Request.prototype.hasOwnProperty('signal') || __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
8297               Request = function Request(input, init) {
8298                 var signal;
8299
8300                 if (init && init.signal) {
8301                   signal = init.signal; // Never pass init.signal to the native Request implementation when the polyfill has
8302                   // been installed because if we're running on top of a browser with a
8303                   // working native AbortController (i.e. the polyfill was installed due to
8304                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
8305                   // fake AbortSignal to the native fetch will trigger:
8306                   // TypeError: Failed to construct 'Request': member signal is not of type AbortSignal.
8307
8308                   delete init.signal;
8309                 }
8310
8311                 var request = new NativeRequest(input, init);
8312
8313                 if (signal) {
8314                   Object.defineProperty(request, 'signal', {
8315                     writable: false,
8316                     enumerable: false,
8317                     configurable: true,
8318                     value: signal
8319                   });
8320                 }
8321
8322                 return request;
8323               };
8324
8325               Request.prototype = NativeRequest.prototype;
8326             }
8327
8328             var realFetch = fetch;
8329
8330             var abortableFetch = function abortableFetch(input, init) {
8331               var signal = Request && Request.prototype.isPrototypeOf(input) ? input.signal : init ? init.signal : undefined;
8332
8333               if (signal) {
8334                 var abortError;
8335
8336                 try {
8337                   abortError = new DOMException('Aborted', 'AbortError');
8338                 } catch (err) {
8339                   // IE 11 does not support calling the DOMException constructor, use a
8340                   // regular error object on it instead.
8341                   abortError = new Error('Aborted');
8342                   abortError.name = 'AbortError';
8343                 } // Return early if already aborted, thus avoiding making an HTTP request
8344
8345
8346                 if (signal.aborted) {
8347                   return Promise.reject(abortError);
8348                 } // Turn an event into a promise, reject it once `abort` is dispatched
8349
8350
8351                 var cancellation = new Promise(function (_, reject) {
8352                   signal.addEventListener('abort', function () {
8353                     return reject(abortError);
8354                   }, {
8355                     once: true
8356                   });
8357                 });
8358
8359                 if (init && init.signal) {
8360                   // Never pass .signal to the native implementation when the polyfill has
8361                   // been installed because if we're running on top of a browser with a
8362                   // working native AbortController (i.e. the polyfill was installed due to
8363                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
8364                   // fake AbortSignal to the native fetch will trigger:
8365                   // TypeError: Failed to execute 'fetch' on 'Window': member signal is not of type AbortSignal.
8366                   delete init.signal;
8367                 } // Return the fastest promise (don't need to wait for request to finish)
8368
8369
8370                 return Promise.race([cancellation, realFetch(input, init)]);
8371               }
8372
8373               return realFetch(input, init);
8374             };
8375
8376             return {
8377               fetch: abortableFetch,
8378               Request: Request
8379             };
8380           }
8381
8382           (function (self) {
8383             if (!polyfillNeeded(self)) {
8384               return;
8385             }
8386
8387             if (!self.fetch) {
8388               console.warn('fetch() is not available, cannot install abortcontroller-polyfill');
8389               return;
8390             }
8391
8392             var _abortableFetch = abortableFetchDecorator(self),
8393                 fetch = _abortableFetch.fetch,
8394                 Request = _abortableFetch.Request;
8395
8396             self.fetch = fetch;
8397             self.Request = Request;
8398             Object.defineProperty(self, 'AbortController', {
8399               writable: true,
8400               enumerable: false,
8401               configurable: true,
8402               value: AbortController
8403             });
8404             Object.defineProperty(self, 'AbortSignal', {
8405               writable: true,
8406               enumerable: false,
8407               configurable: true,
8408               value: AbortSignal
8409             });
8410           })(typeof self !== 'undefined' ? self : commonjsGlobal);
8411         });
8412
8413         function actionAddEntity(way) {
8414           return function (graph) {
8415             return graph.replace(way);
8416           };
8417         }
8418
8419         var $$E = _export;
8420         var fails$f = fails$N;
8421         var isArray$1 = isArray$6;
8422         var isObject$7 = isObject$r;
8423         var toObject$3 = toObject$i;
8424         var toLength$5 = toLength$q;
8425         var createProperty = createProperty$4;
8426         var arraySpeciesCreate = arraySpeciesCreate$3;
8427         var arrayMethodHasSpeciesSupport$1 = arrayMethodHasSpeciesSupport$5;
8428         var wellKnownSymbol$2 = wellKnownSymbol$s;
8429         var V8_VERSION = engineV8Version;
8430
8431         var IS_CONCAT_SPREADABLE = wellKnownSymbol$2('isConcatSpreadable');
8432         var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
8433         var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
8434
8435         // We can't use this feature detection in V8 since it causes
8436         // deoptimization and serious performance degradation
8437         // https://github.com/zloirock/core-js/issues/679
8438         var IS_CONCAT_SPREADABLE_SUPPORT = V8_VERSION >= 51 || !fails$f(function () {
8439           var array = [];
8440           array[IS_CONCAT_SPREADABLE] = false;
8441           return array.concat()[0] !== array;
8442         });
8443
8444         var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport$1('concat');
8445
8446         var isConcatSpreadable = function (O) {
8447           if (!isObject$7(O)) return false;
8448           var spreadable = O[IS_CONCAT_SPREADABLE];
8449           return spreadable !== undefined ? !!spreadable : isArray$1(O);
8450         };
8451
8452         var FORCED$8 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
8453
8454         // `Array.prototype.concat` method
8455         // https://tc39.es/ecma262/#sec-array.prototype.concat
8456         // with adding support of @@isConcatSpreadable and @@species
8457         $$E({ target: 'Array', proto: true, forced: FORCED$8 }, {
8458           // eslint-disable-next-line no-unused-vars -- required for `.length`
8459           concat: function concat(arg) {
8460             var O = toObject$3(this);
8461             var A = arraySpeciesCreate(O, 0);
8462             var n = 0;
8463             var i, k, length, len, E;
8464             for (i = -1, length = arguments.length; i < length; i++) {
8465               E = i === -1 ? O : arguments[i];
8466               if (isConcatSpreadable(E)) {
8467                 len = toLength$5(E.length);
8468                 if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
8469                 for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
8470               } else {
8471                 if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
8472                 createProperty(A, n++, E);
8473               }
8474             }
8475             A.length = n;
8476             return A;
8477           }
8478         });
8479
8480         var $$D = _export;
8481         var assign$1 = objectAssign;
8482
8483         // `Object.assign` method
8484         // https://tc39.es/ecma262/#sec-object.assign
8485         // eslint-disable-next-line es/no-object-assign -- required for testing
8486         $$D({ target: 'Object', stat: true, forced: Object.assign !== assign$1 }, {
8487           assign: assign$1
8488         });
8489
8490         var $$C = _export;
8491         var $filter = arrayIteration.filter;
8492         var arrayMethodHasSpeciesSupport = arrayMethodHasSpeciesSupport$5;
8493
8494         var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter');
8495
8496         // `Array.prototype.filter` method
8497         // https://tc39.es/ecma262/#sec-array.prototype.filter
8498         // with adding support of @@species
8499         $$C({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT }, {
8500           filter: function filter(callbackfn /* , thisArg */) {
8501             return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
8502           }
8503         });
8504
8505         var $$B = _export;
8506         var toObject$2 = toObject$i;
8507         var nativeKeys = objectKeys$4;
8508         var fails$e = fails$N;
8509
8510         var FAILS_ON_PRIMITIVES$1 = fails$e(function () { nativeKeys(1); });
8511
8512         // `Object.keys` method
8513         // https://tc39.es/ecma262/#sec-object.keys
8514         $$B({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$1 }, {
8515           keys: function keys(it) {
8516             return nativeKeys(toObject$2(it));
8517           }
8518         });
8519
8520         var $$A = _export;
8521         var isArray = isArray$6;
8522
8523         var nativeReverse = [].reverse;
8524         var test$1 = [1, 2];
8525
8526         // `Array.prototype.reverse` method
8527         // https://tc39.es/ecma262/#sec-array.prototype.reverse
8528         // fix for Safari 12.0 bug
8529         // https://bugs.webkit.org/show_bug.cgi?id=188794
8530         $$A({ target: 'Array', proto: true, forced: String(test$1) === String(test$1.reverse()) }, {
8531           reverse: function reverse() {
8532             // eslint-disable-next-line no-self-assign -- dirty hack
8533             if (isArray(this)) this.length = this.length;
8534             return nativeReverse.call(this);
8535           }
8536         });
8537
8538         var global$6 = global$F;
8539         var trim$4 = stringTrim.trim;
8540         var whitespaces$1 = whitespaces$4;
8541
8542         var $parseFloat = global$6.parseFloat;
8543         var FORCED$7 = 1 / $parseFloat(whitespaces$1 + '-0') !== -Infinity;
8544
8545         // `parseFloat` method
8546         // https://tc39.es/ecma262/#sec-parsefloat-string
8547         var numberParseFloat = FORCED$7 ? function parseFloat(string) {
8548           var trimmedString = trim$4(String(string));
8549           var result = $parseFloat(trimmedString);
8550           return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
8551         } : $parseFloat;
8552
8553         var $$z = _export;
8554         var parseFloatImplementation = numberParseFloat;
8555
8556         // `parseFloat` method
8557         // https://tc39.es/ecma262/#sec-parsefloat-string
8558         $$z({ global: true, forced: parseFloat != parseFloatImplementation }, {
8559           parseFloat: parseFloatImplementation
8560         });
8561
8562         /*
8563         Order the nodes of a way in reverse order and reverse any direction dependent tags
8564         other than `oneway`. (We assume that correcting a backwards oneway is the primary
8565         reason for reversing a way.)
8566
8567         In addition, numeric-valued `incline` tags are negated.
8568
8569         The JOSM implementation was used as a guide, but transformations that were of unclear benefit
8570         or adjusted tags that don't seem to be used in practice were omitted.
8571
8572         References:
8573             http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
8574             http://wiki.openstreetmap.org/wiki/Key:direction#Steps
8575             http://wiki.openstreetmap.org/wiki/Key:incline
8576             http://wiki.openstreetmap.org/wiki/Route#Members
8577             http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
8578             http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
8579             http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
8580         */
8581         function actionReverse(entityID, options) {
8582           var ignoreKey = /^.*(_|:)?(description|name|note|website|ref|source|comment|watch|attribution)(_|:)?/;
8583           var numeric = /^([+\-]?)(?=[\d.])/;
8584           var directionKey = /direction$/;
8585           var turn_lanes = /^turn:lanes:?/;
8586           var keyReplacements = [[/:right$/, ':left'], [/:left$/, ':right'], [/:forward$/, ':backward'], [/:backward$/, ':forward'], [/:right:/, ':left:'], [/:left:/, ':right:'], [/:forward:/, ':backward:'], [/:backward:/, ':forward:']];
8587           var valueReplacements = {
8588             left: 'right',
8589             right: 'left',
8590             up: 'down',
8591             down: 'up',
8592             forward: 'backward',
8593             backward: 'forward',
8594             forwards: 'backward',
8595             backwards: 'forward'
8596           };
8597           var roleReplacements = {
8598             forward: 'backward',
8599             backward: 'forward',
8600             forwards: 'backward',
8601             backwards: 'forward'
8602           };
8603           var onewayReplacements = {
8604             yes: '-1',
8605             '1': '-1',
8606             '-1': 'yes'
8607           };
8608           var compassReplacements = {
8609             N: 'S',
8610             NNE: 'SSW',
8611             NE: 'SW',
8612             ENE: 'WSW',
8613             E: 'W',
8614             ESE: 'WNW',
8615             SE: 'NW',
8616             SSE: 'NNW',
8617             S: 'N',
8618             SSW: 'NNE',
8619             SW: 'NE',
8620             WSW: 'ENE',
8621             W: 'E',
8622             WNW: 'ESE',
8623             NW: 'SE',
8624             NNW: 'SSE'
8625           };
8626
8627           function reverseKey(key) {
8628             for (var i = 0; i < keyReplacements.length; ++i) {
8629               var replacement = keyReplacements[i];
8630
8631               if (replacement[0].test(key)) {
8632                 return key.replace(replacement[0], replacement[1]);
8633               }
8634             }
8635
8636             return key;
8637           }
8638
8639           function reverseValue(key, value, includeAbsolute) {
8640             if (ignoreKey.test(key)) return value; // Turn lanes are left/right to key (not way) direction - #5674
8641
8642             if (turn_lanes.test(key)) {
8643               return value;
8644             } else if (key === 'incline' && numeric.test(value)) {
8645               return value.replace(numeric, function (_, sign) {
8646                 return sign === '-' ? '' : '-';
8647               });
8648             } else if (options && options.reverseOneway && key === 'oneway') {
8649               return onewayReplacements[value] || value;
8650             } else if (includeAbsolute && directionKey.test(key)) {
8651               if (compassReplacements[value]) return compassReplacements[value];
8652               var degrees = parseFloat(value);
8653
8654               if (typeof degrees === 'number' && !isNaN(degrees)) {
8655                 if (degrees < 180) {
8656                   degrees += 180;
8657                 } else {
8658                   degrees -= 180;
8659                 }
8660
8661                 return degrees.toString();
8662               }
8663             }
8664
8665             return valueReplacements[value] || value;
8666           } // Reverse the direction of tags attached to the nodes - #3076
8667
8668
8669           function reverseNodeTags(graph, nodeIDs) {
8670             for (var i = 0; i < nodeIDs.length; i++) {
8671               var node = graph.hasEntity(nodeIDs[i]);
8672               if (!node || !Object.keys(node.tags).length) continue;
8673               var tags = {};
8674
8675               for (var key in node.tags) {
8676                 tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID);
8677               }
8678
8679               graph = graph.replace(node.update({
8680                 tags: tags
8681               }));
8682             }
8683
8684             return graph;
8685           }
8686
8687           function reverseWay(graph, way) {
8688             var nodes = way.nodes.slice().reverse();
8689             var tags = {};
8690             var role;
8691
8692             for (var key in way.tags) {
8693               tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
8694             }
8695
8696             graph.parentRelations(way).forEach(function (relation) {
8697               relation.members.forEach(function (member, index) {
8698                 if (member.id === way.id && (role = roleReplacements[member.role])) {
8699                   relation = relation.updateMember({
8700                     role: role
8701                   }, index);
8702                   graph = graph.replace(relation);
8703                 }
8704               });
8705             }); // Reverse any associated directions on nodes on the way and then replace
8706             // the way itself with the reversed node ids and updated way tags
8707
8708             return reverseNodeTags(graph, nodes).replace(way.update({
8709               nodes: nodes,
8710               tags: tags
8711             }));
8712           }
8713
8714           var action = function action(graph) {
8715             var entity = graph.entity(entityID);
8716
8717             if (entity.type === 'way') {
8718               return reverseWay(graph, entity);
8719             }
8720
8721             return reverseNodeTags(graph, [entityID]);
8722           };
8723
8724           action.disabled = function (graph) {
8725             var entity = graph.hasEntity(entityID);
8726             if (!entity || entity.type === 'way') return false;
8727
8728             for (var key in entity.tags) {
8729               var value = entity.tags[key];
8730
8731               if (reverseKey(key) !== key || reverseValue(key, value, true) !== value) {
8732                 return false;
8733               }
8734             }
8735
8736             return 'nondirectional_node';
8737           };
8738
8739           action.entityID = function () {
8740             return entityID;
8741           };
8742
8743           return action;
8744         }
8745
8746         function osmIsInterestingTag(key) {
8747           return key !== 'attribution' && key !== 'created_by' && key !== 'source' && key !== 'odbl' && key.indexOf('source:') !== 0 && key.indexOf('source_ref') !== 0 && // purposely exclude colon
8748           key.indexOf('tiger:') !== 0;
8749         }
8750         var osmAreaKeys = {};
8751         function osmSetAreaKeys(value) {
8752           osmAreaKeys = value;
8753         } // returns an object with the tag from `tags` that implies an area geometry, if any
8754
8755         function osmTagSuggestingArea(tags) {
8756           if (tags.area === 'yes') return {
8757             area: 'yes'
8758           };
8759           if (tags.area === 'no') return null; // `highway` and `railway` are typically linear features, but there
8760           // are a few exceptions that should be treated as areas, even in the
8761           // absence of a proper `area=yes` or `areaKeys` tag.. see #4194
8762
8763           var lineKeys = {
8764             highway: {
8765               rest_area: true,
8766               services: true
8767             },
8768             railway: {
8769               roundhouse: true,
8770               station: true,
8771               traverser: true,
8772               turntable: true,
8773               wash: true
8774             }
8775           };
8776           var returnTags = {};
8777
8778           for (var key in tags) {
8779             if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
8780               returnTags[key] = tags[key];
8781               return returnTags;
8782             }
8783
8784             if (key in lineKeys && tags[key] in lineKeys[key]) {
8785               returnTags[key] = tags[key];
8786               return returnTags;
8787             }
8788           }
8789
8790           return null;
8791         } // Tags that indicate a node can be a standalone point
8792         // e.g. { amenity: { bar: true, parking: true, ... } ... }
8793
8794         var osmPointTags = {};
8795         function osmSetPointTags(value) {
8796           osmPointTags = value;
8797         } // Tags that indicate a node can be part of a way
8798         // e.g. { amenity: { parking: true, ... }, highway: { stop: true ... } ... }
8799
8800         var osmVertexTags = {};
8801         function osmSetVertexTags(value) {
8802           osmVertexTags = value;
8803         }
8804         function osmNodeGeometriesForTags(nodeTags) {
8805           var geometries = {};
8806
8807           for (var key in nodeTags) {
8808             if (osmPointTags[key] && (osmPointTags[key]['*'] || osmPointTags[key][nodeTags[key]])) {
8809               geometries.point = true;
8810             }
8811
8812             if (osmVertexTags[key] && (osmVertexTags[key]['*'] || osmVertexTags[key][nodeTags[key]])) {
8813               geometries.vertex = true;
8814             } // break early if both are already supported
8815
8816
8817             if (geometries.point && geometries.vertex) break;
8818           }
8819
8820           return geometries;
8821         }
8822         var osmOneWayTags = {
8823           'aerialway': {
8824             'chair_lift': true,
8825             'drag_lift': true,
8826             'j-bar': true,
8827             'magic_carpet': true,
8828             'mixed_lift': true,
8829             'platter': true,
8830             'rope_tow': true,
8831             't-bar': true,
8832             'zip_line': true
8833           },
8834           'highway': {
8835             'motorway': true
8836           },
8837           'junction': {
8838             'circular': true,
8839             'roundabout': true
8840           },
8841           'man_made': {
8842             'goods_conveyor': true,
8843             'piste:halfpipe': true
8844           },
8845           'piste:type': {
8846             'downhill': true,
8847             'sled': true,
8848             'yes': true
8849           },
8850           'waterway': {
8851             'canal': true,
8852             'ditch': true,
8853             'drain': true,
8854             'fish_pass': true,
8855             'river': true,
8856             'stream': true,
8857             'tidal_channel': true
8858           }
8859         }; // solid and smooth surfaces akin to the assumed default road surface in OSM
8860
8861         var osmPavedTags = {
8862           'surface': {
8863             'paved': true,
8864             'asphalt': true,
8865             'concrete': true,
8866             'concrete:lanes': true,
8867             'concrete:plates': true
8868           },
8869           'tracktype': {
8870             'grade1': true
8871           }
8872         }; // solid, if somewhat uncommon surfaces with a high range of smoothness
8873
8874         var osmSemipavedTags = {
8875           'surface': {
8876             'cobblestone': true,
8877             'cobblestone:flattened': true,
8878             'unhewn_cobblestone': true,
8879             'sett': true,
8880             'paving_stones': true,
8881             'metal': true,
8882             'wood': true
8883           }
8884         };
8885         var osmRightSideIsInsideTags = {
8886           'natural': {
8887             'cliff': true,
8888             'coastline': 'coastline'
8889           },
8890           'barrier': {
8891             'retaining_wall': true,
8892             'kerb': true,
8893             'guard_rail': true,
8894             'city_wall': true
8895           },
8896           'man_made': {
8897             'embankment': true
8898           },
8899           'waterway': {
8900             'weir': true
8901           }
8902         }; // "highway" tag values for pedestrian or vehicle right-of-ways that make up the routable network
8903         // (does not include `raceway`)
8904
8905         var osmRoutableHighwayTagValues = {
8906           motorway: true,
8907           trunk: true,
8908           primary: true,
8909           secondary: true,
8910           tertiary: true,
8911           residential: true,
8912           motorway_link: true,
8913           trunk_link: true,
8914           primary_link: true,
8915           secondary_link: true,
8916           tertiary_link: true,
8917           unclassified: true,
8918           road: true,
8919           service: true,
8920           track: true,
8921           living_street: true,
8922           bus_guideway: true,
8923           path: true,
8924           footway: true,
8925           cycleway: true,
8926           bridleway: true,
8927           pedestrian: true,
8928           corridor: true,
8929           steps: true
8930         }; // "highway" tag values that generally do not allow motor vehicles
8931
8932         var osmPathHighwayTagValues = {
8933           path: true,
8934           footway: true,
8935           cycleway: true,
8936           bridleway: true,
8937           pedestrian: true,
8938           corridor: true,
8939           steps: true
8940         }; // "railway" tag values representing existing railroad tracks (purposely does not include 'abandoned')
8941
8942         var osmRailwayTrackTagValues = {
8943           rail: true,
8944           light_rail: true,
8945           tram: true,
8946           subway: true,
8947           monorail: true,
8948           funicular: true,
8949           miniature: true,
8950           narrow_gauge: true,
8951           disused: true,
8952           preserved: true
8953         }; // "waterway" tag values for line features representing water flow
8954
8955         var osmFlowingWaterwayTagValues = {
8956           canal: true,
8957           ditch: true,
8958           drain: true,
8959           fish_pass: true,
8960           river: true,
8961           stream: true,
8962           tidal_channel: true
8963         };
8964
8965         var global$5 = global$F;
8966         var trim$3 = stringTrim.trim;
8967         var whitespaces = whitespaces$4;
8968
8969         var $parseInt = global$5.parseInt;
8970         var hex$2 = /^[+-]?0[Xx]/;
8971         var FORCED$6 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22;
8972
8973         // `parseInt` method
8974         // https://tc39.es/ecma262/#sec-parseint-string-radix
8975         var numberParseInt = FORCED$6 ? function parseInt(string, radix) {
8976           var S = trim$3(String(string));
8977           return $parseInt(S, (radix >>> 0) || (hex$2.test(S) ? 16 : 10));
8978         } : $parseInt;
8979
8980         var $$y = _export;
8981         var parseIntImplementation = numberParseInt;
8982
8983         // `parseInt` method
8984         // https://tc39.es/ecma262/#sec-parseint-string-radix
8985         $$y({ global: true, forced: parseInt != parseIntImplementation }, {
8986           parseInt: parseIntImplementation
8987         });
8988
8989         var internalMetadata = {exports: {}};
8990
8991         var fails$d = fails$N;
8992
8993         var freezing = !fails$d(function () {
8994           // eslint-disable-next-line es/no-object-isextensible, es/no-object-preventextensions -- required for testing
8995           return Object.isExtensible(Object.preventExtensions({}));
8996         });
8997
8998         var hiddenKeys = hiddenKeys$6;
8999         var isObject$6 = isObject$r;
9000         var has$2 = has$j;
9001         var defineProperty$3 = objectDefineProperty.f;
9002         var uid = uid$5;
9003         var FREEZING$1 = freezing;
9004
9005         var METADATA = uid('meta');
9006         var id$1 = 0;
9007
9008         // eslint-disable-next-line es/no-object-isextensible -- safe
9009         var isExtensible = Object.isExtensible || function () {
9010           return true;
9011         };
9012
9013         var setMetadata = function (it) {
9014           defineProperty$3(it, METADATA, { value: {
9015             objectID: 'O' + ++id$1, // object ID
9016             weakData: {}          // weak collections IDs
9017           } });
9018         };
9019
9020         var fastKey$1 = function (it, create) {
9021           // return a primitive with prefix
9022           if (!isObject$6(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
9023           if (!has$2(it, METADATA)) {
9024             // can't set metadata to uncaught frozen object
9025             if (!isExtensible(it)) return 'F';
9026             // not necessary to add metadata
9027             if (!create) return 'E';
9028             // add missing metadata
9029             setMetadata(it);
9030           // return object ID
9031           } return it[METADATA].objectID;
9032         };
9033
9034         var getWeakData = function (it, create) {
9035           if (!has$2(it, METADATA)) {
9036             // can't set metadata to uncaught frozen object
9037             if (!isExtensible(it)) return true;
9038             // not necessary to add metadata
9039             if (!create) return false;
9040             // add missing metadata
9041             setMetadata(it);
9042           // return the store of weak collections IDs
9043           } return it[METADATA].weakData;
9044         };
9045
9046         // add metadata on freeze-family methods calling
9047         var onFreeze$1 = function (it) {
9048           if (FREEZING$1 && meta.REQUIRED && isExtensible(it) && !has$2(it, METADATA)) setMetadata(it);
9049           return it;
9050         };
9051
9052         var meta = internalMetadata.exports = {
9053           REQUIRED: false,
9054           fastKey: fastKey$1,
9055           getWeakData: getWeakData,
9056           onFreeze: onFreeze$1
9057         };
9058
9059         hiddenKeys[METADATA] = true;
9060
9061         var $$x = _export;
9062         var global$4 = global$F;
9063         var isForced$2 = isForced_1;
9064         var redefine$3 = redefine$g.exports;
9065         var InternalMetadataModule = internalMetadata.exports;
9066         var iterate$1 = iterate$3;
9067         var anInstance$1 = anInstance$7;
9068         var isObject$5 = isObject$r;
9069         var fails$c = fails$N;
9070         var checkCorrectnessOfIteration$1 = checkCorrectnessOfIteration$4;
9071         var setToStringTag = setToStringTag$a;
9072         var inheritIfRequired$2 = inheritIfRequired$4;
9073
9074         var collection$2 = function (CONSTRUCTOR_NAME, wrapper, common) {
9075           var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
9076           var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
9077           var ADDER = IS_MAP ? 'set' : 'add';
9078           var NativeConstructor = global$4[CONSTRUCTOR_NAME];
9079           var NativePrototype = NativeConstructor && NativeConstructor.prototype;
9080           var Constructor = NativeConstructor;
9081           var exported = {};
9082
9083           var fixMethod = function (KEY) {
9084             var nativeMethod = NativePrototype[KEY];
9085             redefine$3(NativePrototype, KEY,
9086               KEY == 'add' ? function add(value) {
9087                 nativeMethod.call(this, value === 0 ? 0 : value);
9088                 return this;
9089               } : KEY == 'delete' ? function (key) {
9090                 return IS_WEAK && !isObject$5(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
9091               } : KEY == 'get' ? function get(key) {
9092                 return IS_WEAK && !isObject$5(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
9093               } : KEY == 'has' ? function has(key) {
9094                 return IS_WEAK && !isObject$5(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
9095               } : function set(key, value) {
9096                 nativeMethod.call(this, key === 0 ? 0 : key, value);
9097                 return this;
9098               }
9099             );
9100           };
9101
9102           var REPLACE = isForced$2(
9103             CONSTRUCTOR_NAME,
9104             typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails$c(function () {
9105               new NativeConstructor().entries().next();
9106             }))
9107           );
9108
9109           if (REPLACE) {
9110             // create collection constructor
9111             Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
9112             InternalMetadataModule.REQUIRED = true;
9113           } else if (isForced$2(CONSTRUCTOR_NAME, true)) {
9114             var instance = new Constructor();
9115             // early implementations not supports chaining
9116             var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;
9117             // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
9118             var THROWS_ON_PRIMITIVES = fails$c(function () { instance.has(1); });
9119             // most early implementations doesn't supports iterables, most modern - not close it correctly
9120             // eslint-disable-next-line no-new -- required for testing
9121             var ACCEPT_ITERABLES = checkCorrectnessOfIteration$1(function (iterable) { new NativeConstructor(iterable); });
9122             // for early implementations -0 and +0 not the same
9123             var BUGGY_ZERO = !IS_WEAK && fails$c(function () {
9124               // V8 ~ Chromium 42- fails only with 5+ elements
9125               var $instance = new NativeConstructor();
9126               var index = 5;
9127               while (index--) $instance[ADDER](index, index);
9128               return !$instance.has(-0);
9129             });
9130
9131             if (!ACCEPT_ITERABLES) {
9132               Constructor = wrapper(function (dummy, iterable) {
9133                 anInstance$1(dummy, Constructor, CONSTRUCTOR_NAME);
9134                 var that = inheritIfRequired$2(new NativeConstructor(), dummy, Constructor);
9135                 if (iterable != undefined) iterate$1(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
9136                 return that;
9137               });
9138               Constructor.prototype = NativePrototype;
9139               NativePrototype.constructor = Constructor;
9140             }
9141
9142             if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
9143               fixMethod('delete');
9144               fixMethod('has');
9145               IS_MAP && fixMethod('get');
9146             }
9147
9148             if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);
9149
9150             // weak collections should not contains .clear method
9151             if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
9152           }
9153
9154           exported[CONSTRUCTOR_NAME] = Constructor;
9155           $$x({ global: true, forced: Constructor != NativeConstructor }, exported);
9156
9157           setToStringTag(Constructor, CONSTRUCTOR_NAME);
9158
9159           if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
9160
9161           return Constructor;
9162         };
9163
9164         var defineProperty$2 = objectDefineProperty.f;
9165         var create$4 = objectCreate;
9166         var redefineAll = redefineAll$4;
9167         var bind$3 = functionBindContext;
9168         var anInstance = anInstance$7;
9169         var iterate = iterate$3;
9170         var defineIterator = defineIterator$3;
9171         var setSpecies$1 = setSpecies$5;
9172         var DESCRIPTORS$5 = descriptors;
9173         var fastKey = internalMetadata.exports.fastKey;
9174         var InternalStateModule = internalState;
9175
9176         var setInternalState = InternalStateModule.set;
9177         var internalStateGetterFor = InternalStateModule.getterFor;
9178
9179         var collectionStrong$2 = {
9180           getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
9181             var C = wrapper(function (that, iterable) {
9182               anInstance(that, C, CONSTRUCTOR_NAME);
9183               setInternalState(that, {
9184                 type: CONSTRUCTOR_NAME,
9185                 index: create$4(null),
9186                 first: undefined,
9187                 last: undefined,
9188                 size: 0
9189               });
9190               if (!DESCRIPTORS$5) that.size = 0;
9191               if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
9192             });
9193
9194             var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
9195
9196             var define = function (that, key, value) {
9197               var state = getInternalState(that);
9198               var entry = getEntry(that, key);
9199               var previous, index;
9200               // change existing entry
9201               if (entry) {
9202                 entry.value = value;
9203               // create new entry
9204               } else {
9205                 state.last = entry = {
9206                   index: index = fastKey(key, true),
9207                   key: key,
9208                   value: value,
9209                   previous: previous = state.last,
9210                   next: undefined,
9211                   removed: false
9212                 };
9213                 if (!state.first) state.first = entry;
9214                 if (previous) previous.next = entry;
9215                 if (DESCRIPTORS$5) state.size++;
9216                 else that.size++;
9217                 // add to index
9218                 if (index !== 'F') state.index[index] = entry;
9219               } return that;
9220             };
9221
9222             var getEntry = function (that, key) {
9223               var state = getInternalState(that);
9224               // fast case
9225               var index = fastKey(key);
9226               var entry;
9227               if (index !== 'F') return state.index[index];
9228               // frozen object case
9229               for (entry = state.first; entry; entry = entry.next) {
9230                 if (entry.key == key) return entry;
9231               }
9232             };
9233
9234             redefineAll(C.prototype, {
9235               // `{ Map, Set }.prototype.clear()` methods
9236               // https://tc39.es/ecma262/#sec-map.prototype.clear
9237               // https://tc39.es/ecma262/#sec-set.prototype.clear
9238               clear: function clear() {
9239                 var that = this;
9240                 var state = getInternalState(that);
9241                 var data = state.index;
9242                 var entry = state.first;
9243                 while (entry) {
9244                   entry.removed = true;
9245                   if (entry.previous) entry.previous = entry.previous.next = undefined;
9246                   delete data[entry.index];
9247                   entry = entry.next;
9248                 }
9249                 state.first = state.last = undefined;
9250                 if (DESCRIPTORS$5) state.size = 0;
9251                 else that.size = 0;
9252               },
9253               // `{ Map, Set }.prototype.delete(key)` methods
9254               // https://tc39.es/ecma262/#sec-map.prototype.delete
9255               // https://tc39.es/ecma262/#sec-set.prototype.delete
9256               'delete': function (key) {
9257                 var that = this;
9258                 var state = getInternalState(that);
9259                 var entry = getEntry(that, key);
9260                 if (entry) {
9261                   var next = entry.next;
9262                   var prev = entry.previous;
9263                   delete state.index[entry.index];
9264                   entry.removed = true;
9265                   if (prev) prev.next = next;
9266                   if (next) next.previous = prev;
9267                   if (state.first == entry) state.first = next;
9268                   if (state.last == entry) state.last = prev;
9269                   if (DESCRIPTORS$5) state.size--;
9270                   else that.size--;
9271                 } return !!entry;
9272               },
9273               // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods
9274               // https://tc39.es/ecma262/#sec-map.prototype.foreach
9275               // https://tc39.es/ecma262/#sec-set.prototype.foreach
9276               forEach: function forEach(callbackfn /* , that = undefined */) {
9277                 var state = getInternalState(this);
9278                 var boundFunction = bind$3(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
9279                 var entry;
9280                 while (entry = entry ? entry.next : state.first) {
9281                   boundFunction(entry.value, entry.key, this);
9282                   // revert to the last existing entry
9283                   while (entry && entry.removed) entry = entry.previous;
9284                 }
9285               },
9286               // `{ Map, Set}.prototype.has(key)` methods
9287               // https://tc39.es/ecma262/#sec-map.prototype.has
9288               // https://tc39.es/ecma262/#sec-set.prototype.has
9289               has: function has(key) {
9290                 return !!getEntry(this, key);
9291               }
9292             });
9293
9294             redefineAll(C.prototype, IS_MAP ? {
9295               // `Map.prototype.get(key)` method
9296               // https://tc39.es/ecma262/#sec-map.prototype.get
9297               get: function get(key) {
9298                 var entry = getEntry(this, key);
9299                 return entry && entry.value;
9300               },
9301               // `Map.prototype.set(key, value)` method
9302               // https://tc39.es/ecma262/#sec-map.prototype.set
9303               set: function set(key, value) {
9304                 return define(this, key === 0 ? 0 : key, value);
9305               }
9306             } : {
9307               // `Set.prototype.add(value)` method
9308               // https://tc39.es/ecma262/#sec-set.prototype.add
9309               add: function add(value) {
9310                 return define(this, value = value === 0 ? 0 : value, value);
9311               }
9312             });
9313             if (DESCRIPTORS$5) defineProperty$2(C.prototype, 'size', {
9314               get: function () {
9315                 return getInternalState(this).size;
9316               }
9317             });
9318             return C;
9319           },
9320           setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
9321             var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
9322             var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
9323             var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
9324             // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods
9325             // https://tc39.es/ecma262/#sec-map.prototype.entries
9326             // https://tc39.es/ecma262/#sec-map.prototype.keys
9327             // https://tc39.es/ecma262/#sec-map.prototype.values
9328             // https://tc39.es/ecma262/#sec-map.prototype-@@iterator
9329             // https://tc39.es/ecma262/#sec-set.prototype.entries
9330             // https://tc39.es/ecma262/#sec-set.prototype.keys
9331             // https://tc39.es/ecma262/#sec-set.prototype.values
9332             // https://tc39.es/ecma262/#sec-set.prototype-@@iterator
9333             defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
9334               setInternalState(this, {
9335                 type: ITERATOR_NAME,
9336                 target: iterated,
9337                 state: getInternalCollectionState(iterated),
9338                 kind: kind,
9339                 last: undefined
9340               });
9341             }, function () {
9342               var state = getInternalIteratorState(this);
9343               var kind = state.kind;
9344               var entry = state.last;
9345               // revert to the last existing entry
9346               while (entry && entry.removed) entry = entry.previous;
9347               // get next entry
9348               if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
9349                 // or finish the iteration
9350                 state.target = undefined;
9351                 return { value: undefined, done: true };
9352               }
9353               // return step by kind
9354               if (kind == 'keys') return { value: entry.key, done: false };
9355               if (kind == 'values') return { value: entry.value, done: false };
9356               return { value: [entry.key, entry.value], done: false };
9357             }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
9358
9359             // `{ Map, Set }.prototype[@@species]` accessors
9360             // https://tc39.es/ecma262/#sec-get-map-@@species
9361             // https://tc39.es/ecma262/#sec-get-set-@@species
9362             setSpecies$1(CONSTRUCTOR_NAME);
9363           }
9364         };
9365
9366         var collection$1 = collection$2;
9367         var collectionStrong$1 = collectionStrong$2;
9368
9369         // `Set` constructor
9370         // https://tc39.es/ecma262/#sec-set-objects
9371         collection$1('Set', function (init) {
9372           return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };
9373         }, collectionStrong$1);
9374
9375         function d3_ascending (a, b) {
9376           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
9377         }
9378
9379         function d3_bisector (f) {
9380           var delta = f;
9381           var compare = f;
9382
9383           if (f.length === 1) {
9384             delta = function delta(d, x) {
9385               return f(d) - x;
9386             };
9387
9388             compare = ascendingComparator(f);
9389           }
9390
9391           function left(a, x, lo, hi) {
9392             if (lo == null) lo = 0;
9393             if (hi == null) hi = a.length;
9394
9395             while (lo < hi) {
9396               var mid = lo + hi >>> 1;
9397               if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid;
9398             }
9399
9400             return lo;
9401           }
9402
9403           function right(a, x, lo, hi) {
9404             if (lo == null) lo = 0;
9405             if (hi == null) hi = a.length;
9406
9407             while (lo < hi) {
9408               var mid = lo + hi >>> 1;
9409               if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1;
9410             }
9411
9412             return lo;
9413           }
9414
9415           function center(a, x, lo, hi) {
9416             if (lo == null) lo = 0;
9417             if (hi == null) hi = a.length;
9418             var i = left(a, x, lo, hi - 1);
9419             return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
9420           }
9421
9422           return {
9423             left: left,
9424             center: center,
9425             right: right
9426           };
9427         }
9428
9429         function ascendingComparator(f) {
9430           return function (d, x) {
9431             return d3_ascending(f(d), x);
9432           };
9433         }
9434
9435         var defineWellKnownSymbol = defineWellKnownSymbol$4;
9436
9437         // `Symbol.asyncIterator` well-known symbol
9438         // https://tc39.es/ecma262/#sec-symbol.asynciterator
9439         defineWellKnownSymbol('asyncIterator');
9440
9441         var runtime = {exports: {}};
9442
9443         (function (module) {
9444           var runtime = function (exports) {
9445
9446             var Op = Object.prototype;
9447             var hasOwn = Op.hasOwnProperty;
9448             var undefined$1; // More compressible than void 0.
9449
9450             var $Symbol = typeof Symbol === "function" ? Symbol : {};
9451             var iteratorSymbol = $Symbol.iterator || "@@iterator";
9452             var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
9453             var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
9454
9455             function define(obj, key, value) {
9456               Object.defineProperty(obj, key, {
9457                 value: value,
9458                 enumerable: true,
9459                 configurable: true,
9460                 writable: true
9461               });
9462               return obj[key];
9463             }
9464
9465             try {
9466               // IE 8 has a broken Object.defineProperty that only works on DOM objects.
9467               define({}, "");
9468             } catch (err) {
9469               define = function define(obj, key, value) {
9470                 return obj[key] = value;
9471               };
9472             }
9473
9474             function wrap(innerFn, outerFn, self, tryLocsList) {
9475               // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
9476               var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
9477               var generator = Object.create(protoGenerator.prototype);
9478               var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
9479               // .throw, and .return methods.
9480
9481               generator._invoke = makeInvokeMethod(innerFn, self, context);
9482               return generator;
9483             }
9484
9485             exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
9486             // record like context.tryEntries[i].completion. This interface could
9487             // have been (and was previously) designed to take a closure to be
9488             // invoked without arguments, but in all the cases we care about we
9489             // already have an existing method we want to call, so there's no need
9490             // to create a new function object. We can even get away with assuming
9491             // the method takes exactly one argument, since that happens to be true
9492             // in every case, so we don't have to touch the arguments object. The
9493             // only additional allocation required is the completion record, which
9494             // has a stable shape and so hopefully should be cheap to allocate.
9495
9496             function tryCatch(fn, obj, arg) {
9497               try {
9498                 return {
9499                   type: "normal",
9500                   arg: fn.call(obj, arg)
9501                 };
9502               } catch (err) {
9503                 return {
9504                   type: "throw",
9505                   arg: err
9506                 };
9507               }
9508             }
9509
9510             var GenStateSuspendedStart = "suspendedStart";
9511             var GenStateSuspendedYield = "suspendedYield";
9512             var GenStateExecuting = "executing";
9513             var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
9514             // breaking out of the dispatch switch statement.
9515
9516             var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
9517             // .constructor.prototype properties for functions that return Generator
9518             // objects. For full spec compliance, you may wish to configure your
9519             // minifier not to mangle the names of these two functions.
9520
9521             function Generator() {}
9522
9523             function GeneratorFunction() {}
9524
9525             function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
9526             // don't natively support it.
9527
9528
9529             var IteratorPrototype = {};
9530
9531             IteratorPrototype[iteratorSymbol] = function () {
9532               return this;
9533             };
9534
9535             var getProto = Object.getPrototypeOf;
9536             var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
9537
9538             if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
9539               // This environment has a native %IteratorPrototype%; use it instead
9540               // of the polyfill.
9541               IteratorPrototype = NativeIteratorPrototype;
9542             }
9543
9544             var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
9545             GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
9546             GeneratorFunctionPrototype.constructor = GeneratorFunction;
9547             GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
9548             // Iterator interface in terms of a single ._invoke method.
9549
9550             function defineIteratorMethods(prototype) {
9551               ["next", "throw", "return"].forEach(function (method) {
9552                 define(prototype, method, function (arg) {
9553                   return this._invoke(method, arg);
9554                 });
9555               });
9556             }
9557
9558             exports.isGeneratorFunction = function (genFun) {
9559               var ctor = typeof genFun === "function" && genFun.constructor;
9560               return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
9561               // do is to check its .name property.
9562               (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
9563             };
9564
9565             exports.mark = function (genFun) {
9566               if (Object.setPrototypeOf) {
9567                 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
9568               } else {
9569                 genFun.__proto__ = GeneratorFunctionPrototype;
9570                 define(genFun, toStringTagSymbol, "GeneratorFunction");
9571               }
9572
9573               genFun.prototype = Object.create(Gp);
9574               return genFun;
9575             }; // Within the body of any async function, `await x` is transformed to
9576             // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
9577             // `hasOwn.call(value, "__await")` to determine if the yielded value is
9578             // meant to be awaited.
9579
9580
9581             exports.awrap = function (arg) {
9582               return {
9583                 __await: arg
9584               };
9585             };
9586
9587             function AsyncIterator(generator, PromiseImpl) {
9588               function invoke(method, arg, resolve, reject) {
9589                 var record = tryCatch(generator[method], generator, arg);
9590
9591                 if (record.type === "throw") {
9592                   reject(record.arg);
9593                 } else {
9594                   var result = record.arg;
9595                   var value = result.value;
9596
9597                   if (value && _typeof(value) === "object" && hasOwn.call(value, "__await")) {
9598                     return PromiseImpl.resolve(value.__await).then(function (value) {
9599                       invoke("next", value, resolve, reject);
9600                     }, function (err) {
9601                       invoke("throw", err, resolve, reject);
9602                     });
9603                   }
9604
9605                   return PromiseImpl.resolve(value).then(function (unwrapped) {
9606                     // When a yielded Promise is resolved, its final value becomes
9607                     // the .value of the Promise<{value,done}> result for the
9608                     // current iteration.
9609                     result.value = unwrapped;
9610                     resolve(result);
9611                   }, function (error) {
9612                     // If a rejected Promise was yielded, throw the rejection back
9613                     // into the async generator function so it can be handled there.
9614                     return invoke("throw", error, resolve, reject);
9615                   });
9616                 }
9617               }
9618
9619               var previousPromise;
9620
9621               function enqueue(method, arg) {
9622                 function callInvokeWithMethodAndArg() {
9623                   return new PromiseImpl(function (resolve, reject) {
9624                     invoke(method, arg, resolve, reject);
9625                   });
9626                 }
9627
9628                 return previousPromise = // If enqueue has been called before, then we want to wait until
9629                 // all previous Promises have been resolved before calling invoke,
9630                 // so that results are always delivered in the correct order. If
9631                 // enqueue has not been called before, then it is important to
9632                 // call invoke immediately, without waiting on a callback to fire,
9633                 // so that the async generator function has the opportunity to do
9634                 // any necessary setup in a predictable way. This predictability
9635                 // is why the Promise constructor synchronously invokes its
9636                 // executor callback, and why async functions synchronously
9637                 // execute code before the first await. Since we implement simple
9638                 // async functions in terms of async generators, it is especially
9639                 // important to get this right, even though it requires care.
9640                 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
9641                 // invocations of the iterator.
9642                 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
9643               } // Define the unified helper method that is used to implement .next,
9644               // .throw, and .return (see defineIteratorMethods).
9645
9646
9647               this._invoke = enqueue;
9648             }
9649
9650             defineIteratorMethods(AsyncIterator.prototype);
9651
9652             AsyncIterator.prototype[asyncIteratorSymbol] = function () {
9653               return this;
9654             };
9655
9656             exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
9657             // AsyncIterator objects; they just return a Promise for the value of
9658             // the final result produced by the iterator.
9659
9660             exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
9661               if (PromiseImpl === void 0) PromiseImpl = Promise;
9662               var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
9663               return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
9664               : iter.next().then(function (result) {
9665                 return result.done ? result.value : iter.next();
9666               });
9667             };
9668
9669             function makeInvokeMethod(innerFn, self, context) {
9670               var state = GenStateSuspendedStart;
9671               return function invoke(method, arg) {
9672                 if (state === GenStateExecuting) {
9673                   throw new Error("Generator is already running");
9674                 }
9675
9676                 if (state === GenStateCompleted) {
9677                   if (method === "throw") {
9678                     throw arg;
9679                   } // Be forgiving, per 25.3.3.3.3 of the spec:
9680                   // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
9681
9682
9683                   return doneResult();
9684                 }
9685
9686                 context.method = method;
9687                 context.arg = arg;
9688
9689                 while (true) {
9690                   var delegate = context.delegate;
9691
9692                   if (delegate) {
9693                     var delegateResult = maybeInvokeDelegate(delegate, context);
9694
9695                     if (delegateResult) {
9696                       if (delegateResult === ContinueSentinel) continue;
9697                       return delegateResult;
9698                     }
9699                   }
9700
9701                   if (context.method === "next") {
9702                     // Setting context._sent for legacy support of Babel's
9703                     // function.sent implementation.
9704                     context.sent = context._sent = context.arg;
9705                   } else if (context.method === "throw") {
9706                     if (state === GenStateSuspendedStart) {
9707                       state = GenStateCompleted;
9708                       throw context.arg;
9709                     }
9710
9711                     context.dispatchException(context.arg);
9712                   } else if (context.method === "return") {
9713                     context.abrupt("return", context.arg);
9714                   }
9715
9716                   state = GenStateExecuting;
9717                   var record = tryCatch(innerFn, self, context);
9718
9719                   if (record.type === "normal") {
9720                     // If an exception is thrown from innerFn, we leave state ===
9721                     // GenStateExecuting and loop back for another invocation.
9722                     state = context.done ? GenStateCompleted : GenStateSuspendedYield;
9723
9724                     if (record.arg === ContinueSentinel) {
9725                       continue;
9726                     }
9727
9728                     return {
9729                       value: record.arg,
9730                       done: context.done
9731                     };
9732                   } else if (record.type === "throw") {
9733                     state = GenStateCompleted; // Dispatch the exception by looping back around to the
9734                     // context.dispatchException(context.arg) call above.
9735
9736                     context.method = "throw";
9737                     context.arg = record.arg;
9738                   }
9739                 }
9740               };
9741             } // Call delegate.iterator[context.method](context.arg) and handle the
9742             // result, either by returning a { value, done } result from the
9743             // delegate iterator, or by modifying context.method and context.arg,
9744             // setting context.delegate to null, and returning the ContinueSentinel.
9745
9746
9747             function maybeInvokeDelegate(delegate, context) {
9748               var method = delegate.iterator[context.method];
9749
9750               if (method === undefined$1) {
9751                 // A .throw or .return when the delegate iterator has no .throw
9752                 // method always terminates the yield* loop.
9753                 context.delegate = null;
9754
9755                 if (context.method === "throw") {
9756                   // Note: ["return"] must be used for ES3 parsing compatibility.
9757                   if (delegate.iterator["return"]) {
9758                     // If the delegate iterator has a return method, give it a
9759                     // chance to clean up.
9760                     context.method = "return";
9761                     context.arg = undefined$1;
9762                     maybeInvokeDelegate(delegate, context);
9763
9764                     if (context.method === "throw") {
9765                       // If maybeInvokeDelegate(context) changed context.method from
9766                       // "return" to "throw", let that override the TypeError below.
9767                       return ContinueSentinel;
9768                     }
9769                   }
9770
9771                   context.method = "throw";
9772                   context.arg = new TypeError("The iterator does not provide a 'throw' method");
9773                 }
9774
9775                 return ContinueSentinel;
9776               }
9777
9778               var record = tryCatch(method, delegate.iterator, context.arg);
9779
9780               if (record.type === "throw") {
9781                 context.method = "throw";
9782                 context.arg = record.arg;
9783                 context.delegate = null;
9784                 return ContinueSentinel;
9785               }
9786
9787               var info = record.arg;
9788
9789               if (!info) {
9790                 context.method = "throw";
9791                 context.arg = new TypeError("iterator result is not an object");
9792                 context.delegate = null;
9793                 return ContinueSentinel;
9794               }
9795
9796               if (info.done) {
9797                 // Assign the result of the finished delegate to the temporary
9798                 // variable specified by delegate.resultName (see delegateYield).
9799                 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
9800
9801                 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
9802                 // exception, let the outer generator proceed normally. If
9803                 // context.method was "next", forget context.arg since it has been
9804                 // "consumed" by the delegate iterator. If context.method was
9805                 // "return", allow the original .return call to continue in the
9806                 // outer generator.
9807
9808                 if (context.method !== "return") {
9809                   context.method = "next";
9810                   context.arg = undefined$1;
9811                 }
9812               } else {
9813                 // Re-yield the result returned by the delegate method.
9814                 return info;
9815               } // The delegate iterator is finished, so forget it and continue with
9816               // the outer generator.
9817
9818
9819               context.delegate = null;
9820               return ContinueSentinel;
9821             } // Define Generator.prototype.{next,throw,return} in terms of the
9822             // unified ._invoke helper method.
9823
9824
9825             defineIteratorMethods(Gp);
9826             define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
9827             // @@iterator function is called on it. Some browsers' implementations of the
9828             // iterator prototype chain incorrectly implement this, causing the Generator
9829             // object to not be returned from this call. This ensures that doesn't happen.
9830             // See https://github.com/facebook/regenerator/issues/274 for more details.
9831
9832             Gp[iteratorSymbol] = function () {
9833               return this;
9834             };
9835
9836             Gp.toString = function () {
9837               return "[object Generator]";
9838             };
9839
9840             function pushTryEntry(locs) {
9841               var entry = {
9842                 tryLoc: locs[0]
9843               };
9844
9845               if (1 in locs) {
9846                 entry.catchLoc = locs[1];
9847               }
9848
9849               if (2 in locs) {
9850                 entry.finallyLoc = locs[2];
9851                 entry.afterLoc = locs[3];
9852               }
9853
9854               this.tryEntries.push(entry);
9855             }
9856
9857             function resetTryEntry(entry) {
9858               var record = entry.completion || {};
9859               record.type = "normal";
9860               delete record.arg;
9861               entry.completion = record;
9862             }
9863
9864             function Context(tryLocsList) {
9865               // The root entry object (effectively a try statement without a catch
9866               // or a finally block) gives us a place to store values thrown from
9867               // locations where there is no enclosing try statement.
9868               this.tryEntries = [{
9869                 tryLoc: "root"
9870               }];
9871               tryLocsList.forEach(pushTryEntry, this);
9872               this.reset(true);
9873             }
9874
9875             exports.keys = function (object) {
9876               var keys = [];
9877
9878               for (var key in object) {
9879                 keys.push(key);
9880               }
9881
9882               keys.reverse(); // Rather than returning an object with a next method, we keep
9883               // things simple and return the next function itself.
9884
9885               return function next() {
9886                 while (keys.length) {
9887                   var key = keys.pop();
9888
9889                   if (key in object) {
9890                     next.value = key;
9891                     next.done = false;
9892                     return next;
9893                   }
9894                 } // To avoid creating an additional object, we just hang the .value
9895                 // and .done properties off the next function object itself. This
9896                 // also ensures that the minifier will not anonymize the function.
9897
9898
9899                 next.done = true;
9900                 return next;
9901               };
9902             };
9903
9904             function values(iterable) {
9905               if (iterable) {
9906                 var iteratorMethod = iterable[iteratorSymbol];
9907
9908                 if (iteratorMethod) {
9909                   return iteratorMethod.call(iterable);
9910                 }
9911
9912                 if (typeof iterable.next === "function") {
9913                   return iterable;
9914                 }
9915
9916                 if (!isNaN(iterable.length)) {
9917                   var i = -1,
9918                       next = function next() {
9919                     while (++i < iterable.length) {
9920                       if (hasOwn.call(iterable, i)) {
9921                         next.value = iterable[i];
9922                         next.done = false;
9923                         return next;
9924                       }
9925                     }
9926
9927                     next.value = undefined$1;
9928                     next.done = true;
9929                     return next;
9930                   };
9931
9932                   return next.next = next;
9933                 }
9934               } // Return an iterator with no values.
9935
9936
9937               return {
9938                 next: doneResult
9939               };
9940             }
9941
9942             exports.values = values;
9943
9944             function doneResult() {
9945               return {
9946                 value: undefined$1,
9947                 done: true
9948               };
9949             }
9950
9951             Context.prototype = {
9952               constructor: Context,
9953               reset: function reset(skipTempReset) {
9954                 this.prev = 0;
9955                 this.next = 0; // Resetting context._sent for legacy support of Babel's
9956                 // function.sent implementation.
9957
9958                 this.sent = this._sent = undefined$1;
9959                 this.done = false;
9960                 this.delegate = null;
9961                 this.method = "next";
9962                 this.arg = undefined$1;
9963                 this.tryEntries.forEach(resetTryEntry);
9964
9965                 if (!skipTempReset) {
9966                   for (var name in this) {
9967                     // Not sure about the optimal order of these conditions:
9968                     if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
9969                       this[name] = undefined$1;
9970                     }
9971                   }
9972                 }
9973               },
9974               stop: function stop() {
9975                 this.done = true;
9976                 var rootEntry = this.tryEntries[0];
9977                 var rootRecord = rootEntry.completion;
9978
9979                 if (rootRecord.type === "throw") {
9980                   throw rootRecord.arg;
9981                 }
9982
9983                 return this.rval;
9984               },
9985               dispatchException: function dispatchException(exception) {
9986                 if (this.done) {
9987                   throw exception;
9988                 }
9989
9990                 var context = this;
9991
9992                 function handle(loc, caught) {
9993                   record.type = "throw";
9994                   record.arg = exception;
9995                   context.next = loc;
9996
9997                   if (caught) {
9998                     // If the dispatched exception was caught by a catch block,
9999                     // then let that catch block handle the exception normally.
10000                     context.method = "next";
10001                     context.arg = undefined$1;
10002                   }
10003
10004                   return !!caught;
10005                 }
10006
10007                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10008                   var entry = this.tryEntries[i];
10009                   var record = entry.completion;
10010
10011                   if (entry.tryLoc === "root") {
10012                     // Exception thrown outside of any try block that could handle
10013                     // it, so set the completion value of the entire function to
10014                     // throw the exception.
10015                     return handle("end");
10016                   }
10017
10018                   if (entry.tryLoc <= this.prev) {
10019                     var hasCatch = hasOwn.call(entry, "catchLoc");
10020                     var hasFinally = hasOwn.call(entry, "finallyLoc");
10021
10022                     if (hasCatch && hasFinally) {
10023                       if (this.prev < entry.catchLoc) {
10024                         return handle(entry.catchLoc, true);
10025                       } else if (this.prev < entry.finallyLoc) {
10026                         return handle(entry.finallyLoc);
10027                       }
10028                     } else if (hasCatch) {
10029                       if (this.prev < entry.catchLoc) {
10030                         return handle(entry.catchLoc, true);
10031                       }
10032                     } else if (hasFinally) {
10033                       if (this.prev < entry.finallyLoc) {
10034                         return handle(entry.finallyLoc);
10035                       }
10036                     } else {
10037                       throw new Error("try statement without catch or finally");
10038                     }
10039                   }
10040                 }
10041               },
10042               abrupt: function abrupt(type, arg) {
10043                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10044                   var entry = this.tryEntries[i];
10045
10046                   if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
10047                     var finallyEntry = entry;
10048                     break;
10049                   }
10050                 }
10051
10052                 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
10053                   // Ignore the finally entry if control is not jumping to a
10054                   // location outside the try/catch block.
10055                   finallyEntry = null;
10056                 }
10057
10058                 var record = finallyEntry ? finallyEntry.completion : {};
10059                 record.type = type;
10060                 record.arg = arg;
10061
10062                 if (finallyEntry) {
10063                   this.method = "next";
10064                   this.next = finallyEntry.finallyLoc;
10065                   return ContinueSentinel;
10066                 }
10067
10068                 return this.complete(record);
10069               },
10070               complete: function complete(record, afterLoc) {
10071                 if (record.type === "throw") {
10072                   throw record.arg;
10073                 }
10074
10075                 if (record.type === "break" || record.type === "continue") {
10076                   this.next = record.arg;
10077                 } else if (record.type === "return") {
10078                   this.rval = this.arg = record.arg;
10079                   this.method = "return";
10080                   this.next = "end";
10081                 } else if (record.type === "normal" && afterLoc) {
10082                   this.next = afterLoc;
10083                 }
10084
10085                 return ContinueSentinel;
10086               },
10087               finish: function finish(finallyLoc) {
10088                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10089                   var entry = this.tryEntries[i];
10090
10091                   if (entry.finallyLoc === finallyLoc) {
10092                     this.complete(entry.completion, entry.afterLoc);
10093                     resetTryEntry(entry);
10094                     return ContinueSentinel;
10095                   }
10096                 }
10097               },
10098               "catch": function _catch(tryLoc) {
10099                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10100                   var entry = this.tryEntries[i];
10101
10102                   if (entry.tryLoc === tryLoc) {
10103                     var record = entry.completion;
10104
10105                     if (record.type === "throw") {
10106                       var thrown = record.arg;
10107                       resetTryEntry(entry);
10108                     }
10109
10110                     return thrown;
10111                   }
10112                 } // The context.catch method must only be called with a location
10113                 // argument that corresponds to a known catch block.
10114
10115
10116                 throw new Error("illegal catch attempt");
10117               },
10118               delegateYield: function delegateYield(iterable, resultName, nextLoc) {
10119                 this.delegate = {
10120                   iterator: values(iterable),
10121                   resultName: resultName,
10122                   nextLoc: nextLoc
10123                 };
10124
10125                 if (this.method === "next") {
10126                   // Deliberately forget the last sent value so that we don't
10127                   // accidentally pass it on to the delegate.
10128                   this.arg = undefined$1;
10129                 }
10130
10131                 return ContinueSentinel;
10132               }
10133             }; // Regardless of whether this script is executing as a CommonJS module
10134             // or not, return the runtime object so that we can declare the variable
10135             // regeneratorRuntime in the outer scope, which allows this module to be
10136             // injected easily by `bin/regenerator --include-runtime script.js`.
10137
10138             return exports;
10139           }( // If this script is executing as a CommonJS module, use module.exports
10140           // as the regeneratorRuntime namespace. Otherwise create a new empty
10141           // object. Either way, the resulting object will be used to initialize
10142           // the regeneratorRuntime variable at the top of this file.
10143           module.exports );
10144
10145           try {
10146             regeneratorRuntime = runtime;
10147           } catch (accidentalStrictMode) {
10148             // This module should not be running in strict mode, so the above
10149             // assignment should always work unless something is misconfigured. Just
10150             // in case runtime.js accidentally runs in strict mode, we can escape
10151             // strict mode using a global Function call. This could conceivably fail
10152             // if a Content Security Policy forbids using Function, but in that case
10153             // the proper solution is to fix the accidental strict mode problem. If
10154             // you've misconfigured your bundler to force strict mode and applied a
10155             // CSP to forbid Function, and you're not willing to fix either of those
10156             // problems, please detail your unique predicament in a GitHub issue.
10157             Function("r", "regeneratorRuntime = r")(runtime);
10158           }
10159         })(runtime);
10160
10161         var _marked$3 = /*#__PURE__*/regeneratorRuntime.mark(numbers);
10162
10163         function number$1 (x) {
10164           return x === null ? NaN : +x;
10165         }
10166         function numbers(values, valueof) {
10167           var _iterator, _step, value, index, _iterator2, _step2, _value;
10168
10169           return regeneratorRuntime.wrap(function numbers$(_context) {
10170             while (1) {
10171               switch (_context.prev = _context.next) {
10172                 case 0:
10173                   if (!(valueof === undefined)) {
10174                     _context.next = 21;
10175                     break;
10176                   }
10177
10178                   _iterator = _createForOfIteratorHelper(values);
10179                   _context.prev = 2;
10180
10181                   _iterator.s();
10182
10183                 case 4:
10184                   if ((_step = _iterator.n()).done) {
10185                     _context.next = 11;
10186                     break;
10187                   }
10188
10189                   value = _step.value;
10190
10191                   if (!(value != null && (value = +value) >= value)) {
10192                     _context.next = 9;
10193                     break;
10194                   }
10195
10196                   _context.next = 9;
10197                   return value;
10198
10199                 case 9:
10200                   _context.next = 4;
10201                   break;
10202
10203                 case 11:
10204                   _context.next = 16;
10205                   break;
10206
10207                 case 13:
10208                   _context.prev = 13;
10209                   _context.t0 = _context["catch"](2);
10210
10211                   _iterator.e(_context.t0);
10212
10213                 case 16:
10214                   _context.prev = 16;
10215
10216                   _iterator.f();
10217
10218                   return _context.finish(16);
10219
10220                 case 19:
10221                   _context.next = 40;
10222                   break;
10223
10224                 case 21:
10225                   index = -1;
10226                   _iterator2 = _createForOfIteratorHelper(values);
10227                   _context.prev = 23;
10228
10229                   _iterator2.s();
10230
10231                 case 25:
10232                   if ((_step2 = _iterator2.n()).done) {
10233                     _context.next = 32;
10234                     break;
10235                   }
10236
10237                   _value = _step2.value;
10238
10239                   if (!((_value = valueof(_value, ++index, values)) != null && (_value = +_value) >= _value)) {
10240                     _context.next = 30;
10241                     break;
10242                   }
10243
10244                   _context.next = 30;
10245                   return _value;
10246
10247                 case 30:
10248                   _context.next = 25;
10249                   break;
10250
10251                 case 32:
10252                   _context.next = 37;
10253                   break;
10254
10255                 case 34:
10256                   _context.prev = 34;
10257                   _context.t1 = _context["catch"](23);
10258
10259                   _iterator2.e(_context.t1);
10260
10261                 case 37:
10262                   _context.prev = 37;
10263
10264                   _iterator2.f();
10265
10266                   return _context.finish(37);
10267
10268                 case 40:
10269                 case "end":
10270                   return _context.stop();
10271               }
10272             }
10273           }, _marked$3, null, [[2, 13, 16, 19], [23, 34, 37, 40]]);
10274         }
10275
10276         var ascendingBisect = d3_bisector(d3_ascending);
10277         var bisectRight = ascendingBisect.right;
10278         d3_bisector(number$1).center;
10279
10280         var $$w = _export;
10281         var from = arrayFrom$1;
10282         var checkCorrectnessOfIteration = checkCorrectnessOfIteration$4;
10283
10284         var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
10285           // eslint-disable-next-line es/no-array-from -- required for testing
10286           Array.from(iterable);
10287         });
10288
10289         // `Array.from` method
10290         // https://tc39.es/ecma262/#sec-array.from
10291         $$w({ target: 'Array', stat: true, forced: INCORRECT_ITERATION }, {
10292           from: from
10293         });
10294
10295         var $$v = _export;
10296         var fill = arrayFill$1;
10297         var addToUnscopables$3 = addToUnscopables$5;
10298
10299         // `Array.prototype.fill` method
10300         // https://tc39.es/ecma262/#sec-array.prototype.fill
10301         $$v({ target: 'Array', proto: true }, {
10302           fill: fill
10303         });
10304
10305         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
10306         addToUnscopables$3('fill');
10307
10308         var $$u = _export;
10309         var $some = arrayIteration.some;
10310         var arrayMethodIsStrict$3 = arrayMethodIsStrict$8;
10311
10312         var STRICT_METHOD$3 = arrayMethodIsStrict$3('some');
10313
10314         // `Array.prototype.some` method
10315         // https://tc39.es/ecma262/#sec-array.prototype.some
10316         $$u({ target: 'Array', proto: true, forced: !STRICT_METHOD$3 }, {
10317           some: function some(callbackfn /* , thisArg */) {
10318             return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
10319           }
10320         });
10321
10322         var TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS = typedArrayConstructorsRequireWrappers;
10323         var exportTypedArrayStaticMethod = arrayBufferViewCore.exportTypedArrayStaticMethod;
10324         var typedArrayFrom = typedArrayFrom$2;
10325
10326         // `%TypedArray%.from` method
10327         // https://tc39.es/ecma262/#sec-%typedarray%.from
10328         exportTypedArrayStaticMethod('from', typedArrayFrom, TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS);
10329
10330         var createTypedArrayConstructor = typedArrayConstructor.exports;
10331
10332         // `Float64Array` constructor
10333         // https://tc39.es/ecma262/#sec-typedarray-objects
10334         createTypedArrayConstructor('Float64', function (init) {
10335           return function Float64Array(data, byteOffset, length) {
10336             return init(this, data, byteOffset, length);
10337           };
10338         });
10339
10340         function d3_descending (a, b) {
10341           return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
10342         }
10343
10344         // https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
10345         var Adder = /*#__PURE__*/function () {
10346           function Adder() {
10347             _classCallCheck$1(this, Adder);
10348
10349             this._partials = new Float64Array(32);
10350             this._n = 0;
10351           }
10352
10353           _createClass$1(Adder, [{
10354             key: "add",
10355             value: function add(x) {
10356               var p = this._partials;
10357               var i = 0;
10358
10359               for (var j = 0; j < this._n && j < 32; j++) {
10360                 var y = p[j],
10361                     hi = x + y,
10362                     lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
10363                 if (lo) p[i++] = lo;
10364                 x = hi;
10365               }
10366
10367               p[i] = x;
10368               this._n = i + 1;
10369               return this;
10370             }
10371           }, {
10372             key: "valueOf",
10373             value: function valueOf() {
10374               var p = this._partials;
10375               var n = this._n,
10376                   x,
10377                   y,
10378                   lo,
10379                   hi = 0;
10380
10381               if (n > 0) {
10382                 hi = p[--n];
10383
10384                 while (n > 0) {
10385                   x = hi;
10386                   y = p[--n];
10387                   hi = x + y;
10388                   lo = y - (hi - x);
10389                   if (lo) break;
10390                 }
10391
10392                 if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
10393                   y = lo * 2;
10394                   x = hi + y;
10395                   if (y == x - hi) hi = x;
10396                 }
10397               }
10398
10399               return hi;
10400             }
10401           }]);
10402
10403           return Adder;
10404         }();
10405
10406         var $$t = _export;
10407         var DESCRIPTORS$4 = descriptors;
10408         var defineProperties = objectDefineProperties;
10409
10410         // `Object.defineProperties` method
10411         // https://tc39.es/ecma262/#sec-object.defineproperties
10412         $$t({ target: 'Object', stat: true, forced: !DESCRIPTORS$4, sham: !DESCRIPTORS$4 }, {
10413           defineProperties: defineProperties
10414         });
10415
10416         var collection = collection$2;
10417         var collectionStrong = collectionStrong$2;
10418
10419         // `Map` constructor
10420         // https://tc39.es/ecma262/#sec-map-objects
10421         collection('Map', function (init) {
10422           return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };
10423         }, collectionStrong);
10424
10425         var $$s = _export;
10426         var aFunction = aFunction$9;
10427         var toObject$1 = toObject$i;
10428         var toLength$4 = toLength$q;
10429         var fails$b = fails$N;
10430         var internalSort = arraySort;
10431         var arrayMethodIsStrict$2 = arrayMethodIsStrict$8;
10432         var FF = engineFfVersion;
10433         var IE_OR_EDGE = engineIsIeOrEdge;
10434         var V8 = engineV8Version;
10435         var WEBKIT = engineWebkitVersion;
10436
10437         var test = [];
10438         var nativeSort = test.sort;
10439
10440         // IE8-
10441         var FAILS_ON_UNDEFINED = fails$b(function () {
10442           test.sort(undefined);
10443         });
10444         // V8 bug
10445         var FAILS_ON_NULL = fails$b(function () {
10446           test.sort(null);
10447         });
10448         // Old WebKit
10449         var STRICT_METHOD$2 = arrayMethodIsStrict$2('sort');
10450
10451         var STABLE_SORT = !fails$b(function () {
10452           // feature detection can be too slow, so check engines versions
10453           if (V8) return V8 < 70;
10454           if (FF && FF > 3) return;
10455           if (IE_OR_EDGE) return true;
10456           if (WEBKIT) return WEBKIT < 603;
10457
10458           var result = '';
10459           var code, chr, value, index;
10460
10461           // generate an array with more 512 elements (Chakra and old V8 fails only in this case)
10462           for (code = 65; code < 76; code++) {
10463             chr = String.fromCharCode(code);
10464
10465             switch (code) {
10466               case 66: case 69: case 70: case 72: value = 3; break;
10467               case 68: case 71: value = 4; break;
10468               default: value = 2;
10469             }
10470
10471             for (index = 0; index < 47; index++) {
10472               test.push({ k: chr + index, v: value });
10473             }
10474           }
10475
10476           test.sort(function (a, b) { return b.v - a.v; });
10477
10478           for (index = 0; index < test.length; index++) {
10479             chr = test[index].k.charAt(0);
10480             if (result.charAt(result.length - 1) !== chr) result += chr;
10481           }
10482
10483           return result !== 'DGBEFHACIJK';
10484         });
10485
10486         var FORCED$5 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$2 || !STABLE_SORT;
10487
10488         var getSortCompare = function (comparefn) {
10489           return function (x, y) {
10490             if (y === undefined) return -1;
10491             if (x === undefined) return 1;
10492             if (comparefn !== undefined) return +comparefn(x, y) || 0;
10493             return String(x) > String(y) ? 1 : -1;
10494           };
10495         };
10496
10497         // `Array.prototype.sort` method
10498         // https://tc39.es/ecma262/#sec-array.prototype.sort
10499         $$s({ target: 'Array', proto: true, forced: FORCED$5 }, {
10500           sort: function sort(comparefn) {
10501             if (comparefn !== undefined) aFunction(comparefn);
10502
10503             var array = toObject$1(this);
10504
10505             if (STABLE_SORT) return comparefn === undefined ? nativeSort.call(array) : nativeSort.call(array, comparefn);
10506
10507             var items = [];
10508             var arrayLength = toLength$4(array.length);
10509             var itemsLength, index;
10510
10511             for (index = 0; index < arrayLength; index++) {
10512               if (index in array) items.push(array[index]);
10513             }
10514
10515             items = internalSort(items, getSortCompare(comparefn));
10516             itemsLength = items.length;
10517             index = 0;
10518
10519             while (index < itemsLength) array[index] = items[index++];
10520             while (index < arrayLength) delete array[index++];
10521
10522             return array;
10523           }
10524         });
10525
10526         var e10 = Math.sqrt(50),
10527             e5 = Math.sqrt(10),
10528             e2 = Math.sqrt(2);
10529         function ticks (start, stop, count) {
10530           var reverse,
10531               i = -1,
10532               n,
10533               ticks,
10534               step;
10535           stop = +stop, start = +start, count = +count;
10536           if (start === stop && count > 0) return [start];
10537           if (reverse = stop < start) n = start, start = stop, stop = n;
10538           if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
10539
10540           if (step > 0) {
10541             var r0 = Math.round(start / step),
10542                 r1 = Math.round(stop / step);
10543             if (r0 * step < start) ++r0;
10544             if (r1 * step > stop) --r1;
10545             ticks = new Array(n = r1 - r0 + 1);
10546
10547             while (++i < n) {
10548               ticks[i] = (r0 + i) * step;
10549             }
10550           } else {
10551             step = -step;
10552
10553             var _r = Math.round(start * step),
10554                 _r2 = Math.round(stop * step);
10555
10556             if (_r / step < start) ++_r;
10557             if (_r2 / step > stop) --_r2;
10558             ticks = new Array(n = _r2 - _r + 1);
10559
10560             while (++i < n) {
10561               ticks[i] = (_r + i) / step;
10562             }
10563           }
10564
10565           if (reverse) ticks.reverse();
10566           return ticks;
10567         }
10568         function tickIncrement(start, stop, count) {
10569           var step = (stop - start) / Math.max(0, count),
10570               power = Math.floor(Math.log(step) / Math.LN10),
10571               error = step / Math.pow(10, power);
10572           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);
10573         }
10574         function tickStep(start, stop, count) {
10575           var step0 = Math.abs(stop - start) / Math.max(0, count),
10576               step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
10577               error = step0 / step1;
10578           if (error >= e10) step1 *= 10;else if (error >= e5) step1 *= 5;else if (error >= e2) step1 *= 2;
10579           return stop < start ? -step1 : step1;
10580         }
10581
10582         function max(values, valueof) {
10583           var max;
10584
10585           if (valueof === undefined) {
10586             var _iterator = _createForOfIteratorHelper(values),
10587                 _step;
10588
10589             try {
10590               for (_iterator.s(); !(_step = _iterator.n()).done;) {
10591                 var value = _step.value;
10592
10593                 if (value != null && (max < value || max === undefined && value >= value)) {
10594                   max = value;
10595                 }
10596               }
10597             } catch (err) {
10598               _iterator.e(err);
10599             } finally {
10600               _iterator.f();
10601             }
10602           } else {
10603             var index = -1;
10604
10605             var _iterator2 = _createForOfIteratorHelper(values),
10606                 _step2;
10607
10608             try {
10609               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
10610                 var _value = _step2.value;
10611
10612                 if ((_value = valueof(_value, ++index, values)) != null && (max < _value || max === undefined && _value >= _value)) {
10613                   max = _value;
10614                 }
10615               }
10616             } catch (err) {
10617               _iterator2.e(err);
10618             } finally {
10619               _iterator2.f();
10620             }
10621           }
10622
10623           return max;
10624         }
10625
10626         function min$2(values, valueof) {
10627           var min;
10628
10629           if (valueof === undefined) {
10630             var _iterator = _createForOfIteratorHelper(values),
10631                 _step;
10632
10633             try {
10634               for (_iterator.s(); !(_step = _iterator.n()).done;) {
10635                 var value = _step.value;
10636
10637                 if (value != null && (min > value || min === undefined && value >= value)) {
10638                   min = value;
10639                 }
10640               }
10641             } catch (err) {
10642               _iterator.e(err);
10643             } finally {
10644               _iterator.f();
10645             }
10646           } else {
10647             var index = -1;
10648
10649             var _iterator2 = _createForOfIteratorHelper(values),
10650                 _step2;
10651
10652             try {
10653               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
10654                 var _value = _step2.value;
10655
10656                 if ((_value = valueof(_value, ++index, values)) != null && (min > _value || min === undefined && _value >= _value)) {
10657                   min = _value;
10658                 }
10659               }
10660             } catch (err) {
10661               _iterator2.e(err);
10662             } finally {
10663               _iterator2.f();
10664             }
10665           }
10666
10667           return min;
10668         }
10669
10670         // ISC license, Copyright 2018 Vladimir Agafonkin.
10671
10672         function quickselect$3(array, k) {
10673           var left = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
10674           var right = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : array.length - 1;
10675           var compare = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : d3_ascending;
10676
10677           while (right > left) {
10678             if (right - left > 600) {
10679               var n = right - left + 1;
10680               var m = k - left + 1;
10681               var z = Math.log(n);
10682               var s = 0.5 * Math.exp(2 * z / 3);
10683               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
10684               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
10685               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
10686               quickselect$3(array, k, newLeft, newRight, compare);
10687             }
10688
10689             var t = array[k];
10690             var i = left;
10691             var j = right;
10692             swap$1(array, left, k);
10693             if (compare(array[right], t) > 0) swap$1(array, left, right);
10694
10695             while (i < j) {
10696               swap$1(array, i, j), ++i, --j;
10697
10698               while (compare(array[i], t) < 0) {
10699                 ++i;
10700               }
10701
10702               while (compare(array[j], t) > 0) {
10703                 --j;
10704               }
10705             }
10706
10707             if (compare(array[left], t) === 0) swap$1(array, left, j);else ++j, swap$1(array, j, right);
10708             if (j <= k) left = j + 1;
10709             if (k <= j) right = j - 1;
10710           }
10711
10712           return array;
10713         }
10714
10715         function swap$1(array, i, j) {
10716           var t = array[i];
10717           array[i] = array[j];
10718           array[j] = t;
10719         }
10720
10721         function quantile(values, p, valueof) {
10722           values = Float64Array.from(numbers(values, valueof));
10723           if (!(n = values.length)) return;
10724           if ((p = +p) <= 0 || n < 2) return min$2(values);
10725           if (p >= 1) return max(values);
10726           var n,
10727               i = (n - 1) * p,
10728               i0 = Math.floor(i),
10729               value0 = max(quickselect$3(values, i0).subarray(0, i0 + 1)),
10730               value1 = min$2(values.subarray(i0 + 1));
10731           return value0 + (value1 - value0) * (i - i0);
10732         }
10733
10734         function d3_median (values, valueof) {
10735           return quantile(values, 0.5, valueof);
10736         }
10737
10738         var _marked$2 = /*#__PURE__*/regeneratorRuntime.mark(flatten);
10739
10740         function flatten(arrays) {
10741           var _iterator, _step, array;
10742
10743           return regeneratorRuntime.wrap(function flatten$(_context) {
10744             while (1) {
10745               switch (_context.prev = _context.next) {
10746                 case 0:
10747                   _iterator = _createForOfIteratorHelper(arrays);
10748                   _context.prev = 1;
10749
10750                   _iterator.s();
10751
10752                 case 3:
10753                   if ((_step = _iterator.n()).done) {
10754                     _context.next = 8;
10755                     break;
10756                   }
10757
10758                   array = _step.value;
10759                   return _context.delegateYield(array, "t0", 6);
10760
10761                 case 6:
10762                   _context.next = 3;
10763                   break;
10764
10765                 case 8:
10766                   _context.next = 13;
10767                   break;
10768
10769                 case 10:
10770                   _context.prev = 10;
10771                   _context.t1 = _context["catch"](1);
10772
10773                   _iterator.e(_context.t1);
10774
10775                 case 13:
10776                   _context.prev = 13;
10777
10778                   _iterator.f();
10779
10780                   return _context.finish(13);
10781
10782                 case 16:
10783                 case "end":
10784                   return _context.stop();
10785               }
10786             }
10787           }, _marked$2, null, [[1, 10, 13, 16]]);
10788         }
10789
10790         function merge$4(arrays) {
10791           return Array.from(flatten(arrays));
10792         }
10793
10794         function range$1 (start, stop, step) {
10795           start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
10796           var i = -1,
10797               n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
10798               range = new Array(n);
10799
10800           while (++i < n) {
10801             range[i] = start + i * step;
10802           }
10803
10804           return range;
10805         }
10806
10807         // `SameValue` abstract operation
10808         // https://tc39.es/ecma262/#sec-samevalue
10809         // eslint-disable-next-line es/no-object-is -- safe
10810         var sameValue$1 = Object.is || function is(x, y) {
10811           // eslint-disable-next-line no-self-compare -- NaN check
10812           return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
10813         };
10814
10815         var $$r = _export;
10816
10817         // eslint-disable-next-line es/no-math-hypot -- required for testing
10818         var $hypot = Math.hypot;
10819         var abs$3 = Math.abs;
10820         var sqrt$1 = Math.sqrt;
10821
10822         // Chrome 77 bug
10823         // https://bugs.chromium.org/p/v8/issues/detail?id=9546
10824         var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity;
10825
10826         // `Math.hypot` method
10827         // https://tc39.es/ecma262/#sec-math.hypot
10828         $$r({ target: 'Math', stat: true, forced: BUGGY }, {
10829           // eslint-disable-next-line no-unused-vars -- required for `.length`
10830           hypot: function hypot(value1, value2) {
10831             var sum = 0;
10832             var i = 0;
10833             var aLen = arguments.length;
10834             var larg = 0;
10835             var arg, div;
10836             while (i < aLen) {
10837               arg = abs$3(arguments[i++]);
10838               if (larg < arg) {
10839                 div = larg / arg;
10840                 sum = sum * div * div + 1;
10841                 larg = arg;
10842               } else if (arg > 0) {
10843                 div = arg / larg;
10844                 sum += div * div;
10845               } else sum += arg;
10846             }
10847             return larg === Infinity ? Infinity : larg * sqrt$1(sum);
10848           }
10849         });
10850
10851         // `Math.sign` method implementation
10852         // https://tc39.es/ecma262/#sec-math.sign
10853         // eslint-disable-next-line es/no-math-sign -- safe
10854         var mathSign = Math.sign || function sign(x) {
10855           // eslint-disable-next-line no-self-compare -- NaN check
10856           return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;
10857         };
10858
10859         var $$q = _export;
10860         var sign$1 = mathSign;
10861
10862         // `Math.sign` method
10863         // https://tc39.es/ecma262/#sec-math.sign
10864         $$q({ target: 'Math', stat: true }, {
10865           sign: sign$1
10866         });
10867
10868         var epsilon$1 = 1e-6;
10869         var epsilon2$1 = 1e-12;
10870         var pi = Math.PI;
10871         var halfPi = pi / 2;
10872         var quarterPi = pi / 4;
10873         var tau = pi * 2;
10874         var degrees$1 = 180 / pi;
10875         var radians = pi / 180;
10876         var abs$2 = Math.abs;
10877         var atan = Math.atan;
10878         var atan2 = Math.atan2;
10879         var cos = Math.cos;
10880         var exp$2 = Math.exp;
10881         var log$1 = Math.log;
10882         var sin = Math.sin;
10883         var sign = Math.sign || function (x) {
10884           return x > 0 ? 1 : x < 0 ? -1 : 0;
10885         };
10886         var sqrt = Math.sqrt;
10887         var tan = Math.tan;
10888         function acos(x) {
10889           return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
10890         }
10891         function asin(x) {
10892           return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
10893         }
10894
10895         function noop$1() {}
10896
10897         function streamGeometry(geometry, stream) {
10898           if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
10899             streamGeometryType[geometry.type](geometry, stream);
10900           }
10901         }
10902
10903         var streamObjectType = {
10904           Feature: function Feature(object, stream) {
10905             streamGeometry(object.geometry, stream);
10906           },
10907           FeatureCollection: function FeatureCollection(object, stream) {
10908             var features = object.features,
10909                 i = -1,
10910                 n = features.length;
10911
10912             while (++i < n) {
10913               streamGeometry(features[i].geometry, stream);
10914             }
10915           }
10916         };
10917         var streamGeometryType = {
10918           Sphere: function Sphere(object, stream) {
10919             stream.sphere();
10920           },
10921           Point: function Point(object, stream) {
10922             object = object.coordinates;
10923             stream.point(object[0], object[1], object[2]);
10924           },
10925           MultiPoint: function MultiPoint(object, stream) {
10926             var coordinates = object.coordinates,
10927                 i = -1,
10928                 n = coordinates.length;
10929
10930             while (++i < n) {
10931               object = coordinates[i], stream.point(object[0], object[1], object[2]);
10932             }
10933           },
10934           LineString: function LineString(object, stream) {
10935             streamLine(object.coordinates, stream, 0);
10936           },
10937           MultiLineString: function MultiLineString(object, stream) {
10938             var coordinates = object.coordinates,
10939                 i = -1,
10940                 n = coordinates.length;
10941
10942             while (++i < n) {
10943               streamLine(coordinates[i], stream, 0);
10944             }
10945           },
10946           Polygon: function Polygon(object, stream) {
10947             streamPolygon(object.coordinates, stream);
10948           },
10949           MultiPolygon: function MultiPolygon(object, stream) {
10950             var coordinates = object.coordinates,
10951                 i = -1,
10952                 n = coordinates.length;
10953
10954             while (++i < n) {
10955               streamPolygon(coordinates[i], stream);
10956             }
10957           },
10958           GeometryCollection: function GeometryCollection(object, stream) {
10959             var geometries = object.geometries,
10960                 i = -1,
10961                 n = geometries.length;
10962
10963             while (++i < n) {
10964               streamGeometry(geometries[i], stream);
10965             }
10966           }
10967         };
10968
10969         function streamLine(coordinates, stream, closed) {
10970           var i = -1,
10971               n = coordinates.length - closed,
10972               coordinate;
10973           stream.lineStart();
10974
10975           while (++i < n) {
10976             coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
10977           }
10978
10979           stream.lineEnd();
10980         }
10981
10982         function streamPolygon(coordinates, stream) {
10983           var i = -1,
10984               n = coordinates.length;
10985           stream.polygonStart();
10986
10987           while (++i < n) {
10988             streamLine(coordinates[i], stream, 1);
10989           }
10990
10991           stream.polygonEnd();
10992         }
10993
10994         function d3_geoStream (object, stream) {
10995           if (object && streamObjectType.hasOwnProperty(object.type)) {
10996             streamObjectType[object.type](object, stream);
10997           } else {
10998             streamGeometry(object, stream);
10999           }
11000         }
11001
11002         var areaRingSum$1 = new Adder(); // hello?
11003
11004         var areaSum$1 = new Adder(),
11005             lambda00$1,
11006             phi00$1,
11007             lambda0$2,
11008             cosPhi0$1,
11009             sinPhi0$1;
11010         var areaStream$1 = {
11011           point: noop$1,
11012           lineStart: noop$1,
11013           lineEnd: noop$1,
11014           polygonStart: function polygonStart() {
11015             areaRingSum$1 = new Adder();
11016             areaStream$1.lineStart = areaRingStart$1;
11017             areaStream$1.lineEnd = areaRingEnd$1;
11018           },
11019           polygonEnd: function polygonEnd() {
11020             var areaRing = +areaRingSum$1;
11021             areaSum$1.add(areaRing < 0 ? tau + areaRing : areaRing);
11022             this.lineStart = this.lineEnd = this.point = noop$1;
11023           },
11024           sphere: function sphere() {
11025             areaSum$1.add(tau);
11026           }
11027         };
11028
11029         function areaRingStart$1() {
11030           areaStream$1.point = areaPointFirst$1;
11031         }
11032
11033         function areaRingEnd$1() {
11034           areaPoint$1(lambda00$1, phi00$1);
11035         }
11036
11037         function areaPointFirst$1(lambda, phi) {
11038           areaStream$1.point = areaPoint$1;
11039           lambda00$1 = lambda, phi00$1 = phi;
11040           lambda *= radians, phi *= radians;
11041           lambda0$2 = lambda, cosPhi0$1 = cos(phi = phi / 2 + quarterPi), sinPhi0$1 = sin(phi);
11042         }
11043
11044         function areaPoint$1(lambda, phi) {
11045           lambda *= radians, phi *= radians;
11046           phi = phi / 2 + quarterPi; // half the angular distance from south pole
11047           // Spherical excess E for a spherical triangle with vertices: south pole,
11048           // previous point, current point.  Uses a formula derived from Cagnoli’s
11049           // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
11050
11051           var dLambda = lambda - lambda0$2,
11052               sdLambda = dLambda >= 0 ? 1 : -1,
11053               adLambda = sdLambda * dLambda,
11054               cosPhi = cos(phi),
11055               sinPhi = sin(phi),
11056               k = sinPhi0$1 * sinPhi,
11057               u = cosPhi0$1 * cosPhi + k * cos(adLambda),
11058               v = k * sdLambda * sin(adLambda);
11059           areaRingSum$1.add(atan2(v, u)); // Advance the previous points.
11060
11061           lambda0$2 = lambda, cosPhi0$1 = cosPhi, sinPhi0$1 = sinPhi;
11062         }
11063
11064         function d3_geoArea (object) {
11065           areaSum$1 = new Adder();
11066           d3_geoStream(object, areaStream$1);
11067           return areaSum$1 * 2;
11068         }
11069
11070         function spherical(cartesian) {
11071           return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
11072         }
11073         function cartesian(spherical) {
11074           var lambda = spherical[0],
11075               phi = spherical[1],
11076               cosPhi = cos(phi);
11077           return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
11078         }
11079         function cartesianDot(a, b) {
11080           return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
11081         }
11082         function cartesianCross(a, b) {
11083           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]];
11084         } // TODO return a
11085
11086         function cartesianAddInPlace(a, b) {
11087           a[0] += b[0], a[1] += b[1], a[2] += b[2];
11088         }
11089         function cartesianScale(vector, k) {
11090           return [vector[0] * k, vector[1] * k, vector[2] * k];
11091         } // TODO return d
11092
11093         function cartesianNormalizeInPlace(d) {
11094           var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
11095           d[0] /= l, d[1] /= l, d[2] /= l;
11096         }
11097
11098         var lambda0$1, phi0, lambda1, phi1, // bounds
11099         lambda2, // previous lambda-coordinate
11100         lambda00, phi00, // first point
11101         p0, // previous 3D point
11102         deltaSum, ranges, range;
11103         var boundsStream$1 = {
11104           point: boundsPoint$1,
11105           lineStart: boundsLineStart,
11106           lineEnd: boundsLineEnd,
11107           polygonStart: function polygonStart() {
11108             boundsStream$1.point = boundsRingPoint;
11109             boundsStream$1.lineStart = boundsRingStart;
11110             boundsStream$1.lineEnd = boundsRingEnd;
11111             deltaSum = new Adder();
11112             areaStream$1.polygonStart();
11113           },
11114           polygonEnd: function polygonEnd() {
11115             areaStream$1.polygonEnd();
11116             boundsStream$1.point = boundsPoint$1;
11117             boundsStream$1.lineStart = boundsLineStart;
11118             boundsStream$1.lineEnd = boundsLineEnd;
11119             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;
11120             range[0] = lambda0$1, range[1] = lambda1;
11121           },
11122           sphere: function sphere() {
11123             lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
11124           }
11125         };
11126
11127         function boundsPoint$1(lambda, phi) {
11128           ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
11129           if (phi < phi0) phi0 = phi;
11130           if (phi > phi1) phi1 = phi;
11131         }
11132
11133         function linePoint(lambda, phi) {
11134           var p = cartesian([lambda * radians, phi * radians]);
11135
11136           if (p0) {
11137             var normal = cartesianCross(p0, p),
11138                 equatorial = [normal[1], -normal[0], 0],
11139                 inflection = cartesianCross(equatorial, normal);
11140             cartesianNormalizeInPlace(inflection);
11141             inflection = spherical(inflection);
11142             var delta = lambda - lambda2,
11143                 sign = delta > 0 ? 1 : -1,
11144                 lambdai = inflection[0] * degrees$1 * sign,
11145                 phii,
11146                 antimeridian = abs$2(delta) > 180;
11147
11148             if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
11149               phii = inflection[1] * degrees$1;
11150               if (phii > phi1) phi1 = phii;
11151             } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
11152               phii = -inflection[1] * degrees$1;
11153               if (phii < phi0) phi0 = phii;
11154             } else {
11155               if (phi < phi0) phi0 = phi;
11156               if (phi > phi1) phi1 = phi;
11157             }
11158
11159             if (antimeridian) {
11160               if (lambda < lambda2) {
11161                 if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
11162               } else {
11163                 if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
11164               }
11165             } else {
11166               if (lambda1 >= lambda0$1) {
11167                 if (lambda < lambda0$1) lambda0$1 = lambda;
11168                 if (lambda > lambda1) lambda1 = lambda;
11169               } else {
11170                 if (lambda > lambda2) {
11171                   if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
11172                 } else {
11173                   if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
11174                 }
11175               }
11176             }
11177           } else {
11178             ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
11179           }
11180
11181           if (phi < phi0) phi0 = phi;
11182           if (phi > phi1) phi1 = phi;
11183           p0 = p, lambda2 = lambda;
11184         }
11185
11186         function boundsLineStart() {
11187           boundsStream$1.point = linePoint;
11188         }
11189
11190         function boundsLineEnd() {
11191           range[0] = lambda0$1, range[1] = lambda1;
11192           boundsStream$1.point = boundsPoint$1;
11193           p0 = null;
11194         }
11195
11196         function boundsRingPoint(lambda, phi) {
11197           if (p0) {
11198             var delta = lambda - lambda2;
11199             deltaSum.add(abs$2(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
11200           } else {
11201             lambda00 = lambda, phi00 = phi;
11202           }
11203
11204           areaStream$1.point(lambda, phi);
11205           linePoint(lambda, phi);
11206         }
11207
11208         function boundsRingStart() {
11209           areaStream$1.lineStart();
11210         }
11211
11212         function boundsRingEnd() {
11213           boundsRingPoint(lambda00, phi00);
11214           areaStream$1.lineEnd();
11215           if (abs$2(deltaSum) > epsilon$1) lambda0$1 = -(lambda1 = 180);
11216           range[0] = lambda0$1, range[1] = lambda1;
11217           p0 = null;
11218         } // Finds the left-right distance between two longitudes.
11219         // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
11220         // the distance between ±180° to be 360°.
11221
11222
11223         function angle(lambda0, lambda1) {
11224           return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
11225         }
11226
11227         function rangeCompare(a, b) {
11228           return a[0] - b[0];
11229         }
11230
11231         function rangeContains(range, x) {
11232           return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
11233         }
11234
11235         function d3_geoBounds (feature) {
11236           var i, n, a, b, merged, deltaMax, delta;
11237           phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
11238           ranges = [];
11239           d3_geoStream(feature, boundsStream$1); // First, sort ranges by their minimum longitudes.
11240
11241           if (n = ranges.length) {
11242             ranges.sort(rangeCompare); // Then, merge any ranges that overlap.
11243
11244             for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
11245               b = ranges[i];
11246
11247               if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
11248                 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
11249                 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
11250               } else {
11251                 merged.push(a = b);
11252               }
11253             } // Finally, find the largest gap between the merged ranges.
11254             // The final bounding box will be the inverse of this gap.
11255
11256
11257             for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
11258               b = merged[i];
11259               if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
11260             }
11261           }
11262
11263           ranges = range = null;
11264           return lambda0$1 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0$1, phi0], [lambda1, phi1]];
11265         }
11266
11267         function compose (a, b) {
11268           function compose(x, y) {
11269             return x = a(x, y), b(x[0], x[1]);
11270           }
11271
11272           if (a.invert && b.invert) compose.invert = function (x, y) {
11273             return x = b.invert(x, y), x && a.invert(x[0], x[1]);
11274           };
11275           return compose;
11276         }
11277
11278         function rotationIdentity(lambda, phi) {
11279           return [abs$2(lambda) > pi ? lambda + Math.round(-lambda / tau) * tau : lambda, phi];
11280         }
11281
11282         rotationIdentity.invert = rotationIdentity;
11283         function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
11284           return (deltaLambda %= tau) ? deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) : rotationLambda(deltaLambda) : deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) : rotationIdentity;
11285         }
11286
11287         function forwardRotationLambda(deltaLambda) {
11288           return function (lambda, phi) {
11289             return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
11290           };
11291         }
11292
11293         function rotationLambda(deltaLambda) {
11294           var rotation = forwardRotationLambda(deltaLambda);
11295           rotation.invert = forwardRotationLambda(-deltaLambda);
11296           return rotation;
11297         }
11298
11299         function rotationPhiGamma(deltaPhi, deltaGamma) {
11300           var cosDeltaPhi = cos(deltaPhi),
11301               sinDeltaPhi = sin(deltaPhi),
11302               cosDeltaGamma = cos(deltaGamma),
11303               sinDeltaGamma = sin(deltaGamma);
11304
11305           function rotation(lambda, phi) {
11306             var cosPhi = cos(phi),
11307                 x = cos(lambda) * cosPhi,
11308                 y = sin(lambda) * cosPhi,
11309                 z = sin(phi),
11310                 k = z * cosDeltaPhi + x * sinDeltaPhi;
11311             return [atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), asin(k * cosDeltaGamma + y * sinDeltaGamma)];
11312           }
11313
11314           rotation.invert = function (lambda, phi) {
11315             var cosPhi = cos(phi),
11316                 x = cos(lambda) * cosPhi,
11317                 y = sin(lambda) * cosPhi,
11318                 z = sin(phi),
11319                 k = z * cosDeltaGamma - y * sinDeltaGamma;
11320             return [atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), asin(k * cosDeltaPhi - x * sinDeltaPhi)];
11321           };
11322
11323           return rotation;
11324         }
11325
11326         function rotation (rotate) {
11327           rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
11328
11329           function forward(coordinates) {
11330             coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
11331             return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
11332           }
11333
11334           forward.invert = function (coordinates) {
11335             coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
11336             return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
11337           };
11338
11339           return forward;
11340         }
11341
11342         function circleStream(stream, radius, delta, direction, t0, t1) {
11343           if (!delta) return;
11344           var cosRadius = cos(radius),
11345               sinRadius = sin(radius),
11346               step = direction * delta;
11347
11348           if (t0 == null) {
11349             t0 = radius + direction * tau;
11350             t1 = radius - step / 2;
11351           } else {
11352             t0 = circleRadius(cosRadius, t0);
11353             t1 = circleRadius(cosRadius, t1);
11354             if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
11355           }
11356
11357           for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
11358             point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
11359             stream.point(point[0], point[1]);
11360           }
11361         } // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
11362
11363         function circleRadius(cosRadius, point) {
11364           point = cartesian(point), point[0] -= cosRadius;
11365           cartesianNormalizeInPlace(point);
11366           var radius = acos(-point[1]);
11367           return ((-point[2] < 0 ? -radius : radius) + tau - epsilon$1) % tau;
11368         }
11369
11370         function clipBuffer () {
11371           var lines = [],
11372               line;
11373           return {
11374             point: function point(x, y, m) {
11375               line.push([x, y, m]);
11376             },
11377             lineStart: function lineStart() {
11378               lines.push(line = []);
11379             },
11380             lineEnd: noop$1,
11381             rejoin: function rejoin() {
11382               if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
11383             },
11384             result: function result() {
11385               var result = lines;
11386               lines = [];
11387               line = null;
11388               return result;
11389             }
11390           };
11391         }
11392
11393         function pointEqual (a, b) {
11394           return abs$2(a[0] - b[0]) < epsilon$1 && abs$2(a[1] - b[1]) < epsilon$1;
11395         }
11396
11397         function Intersection(point, points, other, entry) {
11398           this.x = point;
11399           this.z = points;
11400           this.o = other; // another intersection
11401
11402           this.e = entry; // is an entry?
11403
11404           this.v = false; // visited
11405
11406           this.n = this.p = null; // next & previous
11407         } // A generalized polygon clipping algorithm: given a polygon that has been cut
11408         // into its visible line segments, and rejoins the segments by interpolating
11409         // along the clip edge.
11410
11411
11412         function clipRejoin (segments, compareIntersection, startInside, interpolate, stream) {
11413           var subject = [],
11414               clip = [],
11415               i,
11416               n;
11417           segments.forEach(function (segment) {
11418             if ((n = segment.length - 1) <= 0) return;
11419             var n,
11420                 p0 = segment[0],
11421                 p1 = segment[n],
11422                 x;
11423
11424             if (pointEqual(p0, p1)) {
11425               if (!p0[2] && !p1[2]) {
11426                 stream.lineStart();
11427
11428                 for (i = 0; i < n; ++i) {
11429                   stream.point((p0 = segment[i])[0], p0[1]);
11430                 }
11431
11432                 stream.lineEnd();
11433                 return;
11434               } // handle degenerate cases by moving the point
11435
11436
11437               p1[0] += 2 * epsilon$1;
11438             }
11439
11440             subject.push(x = new Intersection(p0, segment, null, true));
11441             clip.push(x.o = new Intersection(p0, null, x, false));
11442             subject.push(x = new Intersection(p1, segment, null, false));
11443             clip.push(x.o = new Intersection(p1, null, x, true));
11444           });
11445           if (!subject.length) return;
11446           clip.sort(compareIntersection);
11447           link(subject);
11448           link(clip);
11449
11450           for (i = 0, n = clip.length; i < n; ++i) {
11451             clip[i].e = startInside = !startInside;
11452           }
11453
11454           var start = subject[0],
11455               points,
11456               point;
11457
11458           while (1) {
11459             // Find first unvisited intersection.
11460             var current = start,
11461                 isSubject = true;
11462
11463             while (current.v) {
11464               if ((current = current.n) === start) return;
11465             }
11466
11467             points = current.z;
11468             stream.lineStart();
11469
11470             do {
11471               current.v = current.o.v = true;
11472
11473               if (current.e) {
11474                 if (isSubject) {
11475                   for (i = 0, n = points.length; i < n; ++i) {
11476                     stream.point((point = points[i])[0], point[1]);
11477                   }
11478                 } else {
11479                   interpolate(current.x, current.n.x, 1, stream);
11480                 }
11481
11482                 current = current.n;
11483               } else {
11484                 if (isSubject) {
11485                   points = current.p.z;
11486
11487                   for (i = points.length - 1; i >= 0; --i) {
11488                     stream.point((point = points[i])[0], point[1]);
11489                   }
11490                 } else {
11491                   interpolate(current.x, current.p.x, -1, stream);
11492                 }
11493
11494                 current = current.p;
11495               }
11496
11497               current = current.o;
11498               points = current.z;
11499               isSubject = !isSubject;
11500             } while (!current.v);
11501
11502             stream.lineEnd();
11503           }
11504         }
11505
11506         function link(array) {
11507           if (!(n = array.length)) return;
11508           var n,
11509               i = 0,
11510               a = array[0],
11511               b;
11512
11513           while (++i < n) {
11514             a.n = b = array[i];
11515             b.p = a;
11516             a = b;
11517           }
11518
11519           a.n = b = array[0];
11520           b.p = a;
11521         }
11522
11523         function longitude(point) {
11524           if (abs$2(point[0]) <= pi) return point[0];else return sign(point[0]) * ((abs$2(point[0]) + pi) % tau - pi);
11525         }
11526
11527         function polygonContains (polygon, point) {
11528           var lambda = longitude(point),
11529               phi = point[1],
11530               sinPhi = sin(phi),
11531               normal = [sin(lambda), -cos(lambda), 0],
11532               angle = 0,
11533               winding = 0;
11534           var sum = new Adder();
11535           if (sinPhi === 1) phi = halfPi + epsilon$1;else if (sinPhi === -1) phi = -halfPi - epsilon$1;
11536
11537           for (var i = 0, n = polygon.length; i < n; ++i) {
11538             if (!(m = (ring = polygon[i]).length)) continue;
11539             var ring,
11540                 m,
11541                 point0 = ring[m - 1],
11542                 lambda0 = longitude(point0),
11543                 phi0 = point0[1] / 2 + quarterPi,
11544                 sinPhi0 = sin(phi0),
11545                 cosPhi0 = cos(phi0);
11546
11547             for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
11548               var point1 = ring[j],
11549                   lambda1 = longitude(point1),
11550                   phi1 = point1[1] / 2 + quarterPi,
11551                   sinPhi1 = sin(phi1),
11552                   cosPhi1 = cos(phi1),
11553                   delta = lambda1 - lambda0,
11554                   sign = delta >= 0 ? 1 : -1,
11555                   absDelta = sign * delta,
11556                   antimeridian = absDelta > pi,
11557                   k = sinPhi0 * sinPhi1;
11558               sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
11559               angle += antimeridian ? delta + sign * tau : delta; // Are the longitudes either side of the point’s meridian (lambda),
11560               // and are the latitudes smaller than the parallel (phi)?
11561
11562               if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
11563                 var arc = cartesianCross(cartesian(point0), cartesian(point1));
11564                 cartesianNormalizeInPlace(arc);
11565                 var intersection = cartesianCross(normal, arc);
11566                 cartesianNormalizeInPlace(intersection);
11567                 var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
11568
11569                 if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
11570                   winding += antimeridian ^ delta >= 0 ? 1 : -1;
11571                 }
11572               }
11573             }
11574           } // First, determine whether the South pole is inside or outside:
11575           //
11576           // It is inside if:
11577           // * the polygon winds around it in a clockwise direction.
11578           // * the polygon does not (cumulatively) wind around it, but has a negative
11579           //   (counter-clockwise) area.
11580           //
11581           // Second, count the (signed) number of times a segment crosses a lambda
11582           // from the point to the South pole.  If it is zero, then the point is the
11583           // same side as the South pole.
11584
11585
11586           return (angle < -epsilon$1 || angle < epsilon$1 && sum < -epsilon2$1) ^ winding & 1;
11587         }
11588
11589         function clip (pointVisible, clipLine, interpolate, start) {
11590           return function (sink) {
11591             var line = clipLine(sink),
11592                 ringBuffer = clipBuffer(),
11593                 ringSink = clipLine(ringBuffer),
11594                 polygonStarted = false,
11595                 polygon,
11596                 segments,
11597                 ring;
11598             var clip = {
11599               point: point,
11600               lineStart: lineStart,
11601               lineEnd: lineEnd,
11602               polygonStart: function polygonStart() {
11603                 clip.point = pointRing;
11604                 clip.lineStart = ringStart;
11605                 clip.lineEnd = ringEnd;
11606                 segments = [];
11607                 polygon = [];
11608               },
11609               polygonEnd: function polygonEnd() {
11610                 clip.point = point;
11611                 clip.lineStart = lineStart;
11612                 clip.lineEnd = lineEnd;
11613                 segments = merge$4(segments);
11614                 var startInside = polygonContains(polygon, start);
11615
11616                 if (segments.length) {
11617                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
11618                   clipRejoin(segments, compareIntersection, startInside, interpolate, sink);
11619                 } else if (startInside) {
11620                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
11621                   sink.lineStart();
11622                   interpolate(null, null, 1, sink);
11623                   sink.lineEnd();
11624                 }
11625
11626                 if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
11627                 segments = polygon = null;
11628               },
11629               sphere: function sphere() {
11630                 sink.polygonStart();
11631                 sink.lineStart();
11632                 interpolate(null, null, 1, sink);
11633                 sink.lineEnd();
11634                 sink.polygonEnd();
11635               }
11636             };
11637
11638             function point(lambda, phi) {
11639               if (pointVisible(lambda, phi)) sink.point(lambda, phi);
11640             }
11641
11642             function pointLine(lambda, phi) {
11643               line.point(lambda, phi);
11644             }
11645
11646             function lineStart() {
11647               clip.point = pointLine;
11648               line.lineStart();
11649             }
11650
11651             function lineEnd() {
11652               clip.point = point;
11653               line.lineEnd();
11654             }
11655
11656             function pointRing(lambda, phi) {
11657               ring.push([lambda, phi]);
11658               ringSink.point(lambda, phi);
11659             }
11660
11661             function ringStart() {
11662               ringSink.lineStart();
11663               ring = [];
11664             }
11665
11666             function ringEnd() {
11667               pointRing(ring[0][0], ring[0][1]);
11668               ringSink.lineEnd();
11669               var clean = ringSink.clean(),
11670                   ringSegments = ringBuffer.result(),
11671                   i,
11672                   n = ringSegments.length,
11673                   m,
11674                   segment,
11675                   point;
11676               ring.pop();
11677               polygon.push(ring);
11678               ring = null;
11679               if (!n) return; // No intersections.
11680
11681               if (clean & 1) {
11682                 segment = ringSegments[0];
11683
11684                 if ((m = segment.length - 1) > 0) {
11685                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
11686                   sink.lineStart();
11687
11688                   for (i = 0; i < m; ++i) {
11689                     sink.point((point = segment[i])[0], point[1]);
11690                   }
11691
11692                   sink.lineEnd();
11693                 }
11694
11695                 return;
11696               } // Rejoin connected segments.
11697               // TODO reuse ringBuffer.rejoin()?
11698
11699
11700               if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
11701               segments.push(ringSegments.filter(validSegment));
11702             }
11703
11704             return clip;
11705           };
11706         }
11707
11708         function validSegment(segment) {
11709           return segment.length > 1;
11710         } // Intersections are sorted along the clip edge. For both antimeridian cutting
11711         // and circle clipping, the same comparison is used.
11712
11713
11714         function compareIntersection(a, b) {
11715           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]);
11716         }
11717
11718         var clipAntimeridian = clip(function () {
11719           return true;
11720         }, clipAntimeridianLine, clipAntimeridianInterpolate, [-pi, -halfPi]); // Takes a line and cuts into visible segments. Return values: 0 - there were
11721         // intersections or the line was empty; 1 - no intersections; 2 - there were
11722         // intersections, and the first and last segments should be rejoined.
11723
11724         function clipAntimeridianLine(stream) {
11725           var lambda0 = NaN,
11726               phi0 = NaN,
11727               sign0 = NaN,
11728               _clean; // no intersections
11729
11730
11731           return {
11732             lineStart: function lineStart() {
11733               stream.lineStart();
11734               _clean = 1;
11735             },
11736             point: function point(lambda1, phi1) {
11737               var sign1 = lambda1 > 0 ? pi : -pi,
11738                   delta = abs$2(lambda1 - lambda0);
11739
11740               if (abs$2(delta - pi) < epsilon$1) {
11741                 // line crosses a pole
11742                 stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
11743                 stream.point(sign0, phi0);
11744                 stream.lineEnd();
11745                 stream.lineStart();
11746                 stream.point(sign1, phi0);
11747                 stream.point(lambda1, phi0);
11748                 _clean = 0;
11749               } else if (sign0 !== sign1 && delta >= pi) {
11750                 // line crosses antimeridian
11751                 if (abs$2(lambda0 - sign0) < epsilon$1) lambda0 -= sign0 * epsilon$1; // handle degeneracies
11752
11753                 if (abs$2(lambda1 - sign1) < epsilon$1) lambda1 -= sign1 * epsilon$1;
11754                 phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
11755                 stream.point(sign0, phi0);
11756                 stream.lineEnd();
11757                 stream.lineStart();
11758                 stream.point(sign1, phi0);
11759                 _clean = 0;
11760               }
11761
11762               stream.point(lambda0 = lambda1, phi0 = phi1);
11763               sign0 = sign1;
11764             },
11765             lineEnd: function lineEnd() {
11766               stream.lineEnd();
11767               lambda0 = phi0 = NaN;
11768             },
11769             clean: function clean() {
11770               return 2 - _clean; // if intersections, rejoin first and last segments
11771             }
11772           };
11773         }
11774
11775         function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
11776           var cosPhi0,
11777               cosPhi1,
11778               sinLambda0Lambda1 = sin(lambda0 - lambda1);
11779           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;
11780         }
11781
11782         function clipAntimeridianInterpolate(from, to, direction, stream) {
11783           var phi;
11784
11785           if (from == null) {
11786             phi = direction * halfPi;
11787             stream.point(-pi, phi);
11788             stream.point(0, phi);
11789             stream.point(pi, phi);
11790             stream.point(pi, 0);
11791             stream.point(pi, -phi);
11792             stream.point(0, -phi);
11793             stream.point(-pi, -phi);
11794             stream.point(-pi, 0);
11795             stream.point(-pi, phi);
11796           } else if (abs$2(from[0] - to[0]) > epsilon$1) {
11797             var lambda = from[0] < to[0] ? pi : -pi;
11798             phi = direction * lambda / 2;
11799             stream.point(-lambda, phi);
11800             stream.point(0, phi);
11801             stream.point(lambda, phi);
11802           } else {
11803             stream.point(to[0], to[1]);
11804           }
11805         }
11806
11807         function clipCircle (radius) {
11808           var cr = cos(radius),
11809               delta = 6 * radians,
11810               smallRadius = cr > 0,
11811               notHemisphere = abs$2(cr) > epsilon$1; // TODO optimise for this common case
11812
11813           function interpolate(from, to, direction, stream) {
11814             circleStream(stream, radius, delta, direction, from, to);
11815           }
11816
11817           function visible(lambda, phi) {
11818             return cos(lambda) * cos(phi) > cr;
11819           } // Takes a line and cuts into visible segments. Return values used for polygon
11820           // clipping: 0 - there were intersections or the line was empty; 1 - no
11821           // intersections 2 - there were intersections, and the first and last segments
11822           // should be rejoined.
11823
11824
11825           function clipLine(stream) {
11826             var point0, // previous point
11827             c0, // code for previous point
11828             v0, // visibility of previous point
11829             v00, // visibility of first point
11830             _clean; // no intersections
11831
11832
11833             return {
11834               lineStart: function lineStart() {
11835                 v00 = v0 = false;
11836                 _clean = 1;
11837               },
11838               point: function point(lambda, phi) {
11839                 var point1 = [lambda, phi],
11840                     point2,
11841                     v = visible(lambda, phi),
11842                     c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
11843                 if (!point0 && (v00 = v0 = v)) stream.lineStart();
11844
11845                 if (v !== v0) {
11846                   point2 = intersect(point0, point1);
11847                   if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) point1[2] = 1;
11848                 }
11849
11850                 if (v !== v0) {
11851                   _clean = 0;
11852
11853                   if (v) {
11854                     // outside going in
11855                     stream.lineStart();
11856                     point2 = intersect(point1, point0);
11857                     stream.point(point2[0], point2[1]);
11858                   } else {
11859                     // inside going out
11860                     point2 = intersect(point0, point1);
11861                     stream.point(point2[0], point2[1], 2);
11862                     stream.lineEnd();
11863                   }
11864
11865                   point0 = point2;
11866                 } else if (notHemisphere && point0 && smallRadius ^ v) {
11867                   var t; // If the codes for two points are different, or are both zero,
11868                   // and there this segment intersects with the small circle.
11869
11870                   if (!(c & c0) && (t = intersect(point1, point0, true))) {
11871                     _clean = 0;
11872
11873                     if (smallRadius) {
11874                       stream.lineStart();
11875                       stream.point(t[0][0], t[0][1]);
11876                       stream.point(t[1][0], t[1][1]);
11877                       stream.lineEnd();
11878                     } else {
11879                       stream.point(t[1][0], t[1][1]);
11880                       stream.lineEnd();
11881                       stream.lineStart();
11882                       stream.point(t[0][0], t[0][1], 3);
11883                     }
11884                   }
11885                 }
11886
11887                 if (v && (!point0 || !pointEqual(point0, point1))) {
11888                   stream.point(point1[0], point1[1]);
11889                 }
11890
11891                 point0 = point1, v0 = v, c0 = c;
11892               },
11893               lineEnd: function lineEnd() {
11894                 if (v0) stream.lineEnd();
11895                 point0 = null;
11896               },
11897               // Rejoin first and last segments if there were intersections and the first
11898               // and last points were visible.
11899               clean: function clean() {
11900                 return _clean | (v00 && v0) << 1;
11901               }
11902             };
11903           } // Intersects the great circle between a and b with the clip circle.
11904
11905
11906           function intersect(a, b, two) {
11907             var pa = cartesian(a),
11908                 pb = cartesian(b); // We have two planes, n1.p = d1 and n2.p = d2.
11909             // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
11910
11911             var n1 = [1, 0, 0],
11912                 // normal
11913             n2 = cartesianCross(pa, pb),
11914                 n2n2 = cartesianDot(n2, n2),
11915                 n1n2 = n2[0],
11916                 // cartesianDot(n1, n2),
11917             determinant = n2n2 - n1n2 * n1n2; // Two polar points.
11918
11919             if (!determinant) return !two && a;
11920             var c1 = cr * n2n2 / determinant,
11921                 c2 = -cr * n1n2 / determinant,
11922                 n1xn2 = cartesianCross(n1, n2),
11923                 A = cartesianScale(n1, c1),
11924                 B = cartesianScale(n2, c2);
11925             cartesianAddInPlace(A, B); // Solve |p(t)|^2 = 1.
11926
11927             var u = n1xn2,
11928                 w = cartesianDot(A, u),
11929                 uu = cartesianDot(u, u),
11930                 t2 = w * w - uu * (cartesianDot(A, A) - 1);
11931             if (t2 < 0) return;
11932             var t = sqrt(t2),
11933                 q = cartesianScale(u, (-w - t) / uu);
11934             cartesianAddInPlace(q, A);
11935             q = spherical(q);
11936             if (!two) return q; // Two intersection points.
11937
11938             var lambda0 = a[0],
11939                 lambda1 = b[0],
11940                 phi0 = a[1],
11941                 phi1 = b[1],
11942                 z;
11943             if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
11944             var delta = lambda1 - lambda0,
11945                 polar = abs$2(delta - pi) < epsilon$1,
11946                 meridian = polar || delta < epsilon$1;
11947             if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b.
11948
11949             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)) {
11950               var q1 = cartesianScale(u, (-w + t) / uu);
11951               cartesianAddInPlace(q1, A);
11952               return [q, spherical(q1)];
11953             }
11954           } // Generates a 4-bit vector representing the location of a point relative to
11955           // the small circle's bounding box.
11956
11957
11958           function code(lambda, phi) {
11959             var r = smallRadius ? radius : pi - radius,
11960                 code = 0;
11961             if (lambda < -r) code |= 1; // left
11962             else if (lambda > r) code |= 2; // right
11963
11964             if (phi < -r) code |= 4; // below
11965             else if (phi > r) code |= 8; // above
11966
11967             return code;
11968           }
11969
11970           return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
11971         }
11972
11973         function clipLine (a, b, x0, y0, x1, y1) {
11974           var ax = a[0],
11975               ay = a[1],
11976               bx = b[0],
11977               by = b[1],
11978               t0 = 0,
11979               t1 = 1,
11980               dx = bx - ax,
11981               dy = by - ay,
11982               r;
11983           r = x0 - ax;
11984           if (!dx && r > 0) return;
11985           r /= dx;
11986
11987           if (dx < 0) {
11988             if (r < t0) return;
11989             if (r < t1) t1 = r;
11990           } else if (dx > 0) {
11991             if (r > t1) return;
11992             if (r > t0) t0 = r;
11993           }
11994
11995           r = x1 - ax;
11996           if (!dx && r < 0) return;
11997           r /= dx;
11998
11999           if (dx < 0) {
12000             if (r > t1) return;
12001             if (r > t0) t0 = r;
12002           } else if (dx > 0) {
12003             if (r < t0) return;
12004             if (r < t1) t1 = r;
12005           }
12006
12007           r = y0 - ay;
12008           if (!dy && r > 0) return;
12009           r /= dy;
12010
12011           if (dy < 0) {
12012             if (r < t0) return;
12013             if (r < t1) t1 = r;
12014           } else if (dy > 0) {
12015             if (r > t1) return;
12016             if (r > t0) t0 = r;
12017           }
12018
12019           r = y1 - ay;
12020           if (!dy && r < 0) return;
12021           r /= dy;
12022
12023           if (dy < 0) {
12024             if (r > t1) return;
12025             if (r > t0) t0 = r;
12026           } else if (dy > 0) {
12027             if (r < t0) return;
12028             if (r < t1) t1 = r;
12029           }
12030
12031           if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
12032           if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
12033           return true;
12034         }
12035
12036         var clipMax = 1e9,
12037             clipMin = -clipMax; // TODO Use d3-polygon’s polygonContains here for the ring check?
12038         // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
12039
12040         function clipRectangle(x0, y0, x1, y1) {
12041           function visible(x, y) {
12042             return x0 <= x && x <= x1 && y0 <= y && y <= y1;
12043           }
12044
12045           function interpolate(from, to, direction, stream) {
12046             var a = 0,
12047                 a1 = 0;
12048
12049             if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
12050               do {
12051                 stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
12052               } while ((a = (a + direction + 4) % 4) !== a1);
12053             } else {
12054               stream.point(to[0], to[1]);
12055             }
12056           }
12057
12058           function corner(p, direction) {
12059             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
12060           }
12061
12062           function compareIntersection(a, b) {
12063             return comparePoint(a.x, b.x);
12064           }
12065
12066           function comparePoint(a, b) {
12067             var ca = corner(a, 1),
12068                 cb = corner(b, 1);
12069             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];
12070           }
12071
12072           return function (stream) {
12073             var activeStream = stream,
12074                 bufferStream = clipBuffer(),
12075                 segments,
12076                 polygon,
12077                 ring,
12078                 x__,
12079                 y__,
12080                 v__,
12081                 // first point
12082             x_,
12083                 y_,
12084                 v_,
12085                 // previous point
12086             first,
12087                 clean;
12088             var clipStream = {
12089               point: point,
12090               lineStart: lineStart,
12091               lineEnd: lineEnd,
12092               polygonStart: polygonStart,
12093               polygonEnd: polygonEnd
12094             };
12095
12096             function point(x, y) {
12097               if (visible(x, y)) activeStream.point(x, y);
12098             }
12099
12100             function polygonInside() {
12101               var winding = 0;
12102
12103               for (var i = 0, n = polygon.length; i < n; ++i) {
12104                 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
12105                   a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
12106
12107                   if (a1 <= y1) {
12108                     if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding;
12109                   } else {
12110                     if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding;
12111                   }
12112                 }
12113               }
12114
12115               return winding;
12116             } // Buffer geometry within a polygon and then clip it en masse.
12117
12118
12119             function polygonStart() {
12120               activeStream = bufferStream, segments = [], polygon = [], clean = true;
12121             }
12122
12123             function polygonEnd() {
12124               var startInside = polygonInside(),
12125                   cleanInside = clean && startInside,
12126                   visible = (segments = merge$4(segments)).length;
12127
12128               if (cleanInside || visible) {
12129                 stream.polygonStart();
12130
12131                 if (cleanInside) {
12132                   stream.lineStart();
12133                   interpolate(null, null, 1, stream);
12134                   stream.lineEnd();
12135                 }
12136
12137                 if (visible) {
12138                   clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
12139                 }
12140
12141                 stream.polygonEnd();
12142               }
12143
12144               activeStream = stream, segments = polygon = ring = null;
12145             }
12146
12147             function lineStart() {
12148               clipStream.point = linePoint;
12149               if (polygon) polygon.push(ring = []);
12150               first = true;
12151               v_ = false;
12152               x_ = y_ = NaN;
12153             } // TODO rather than special-case polygons, simply handle them separately.
12154             // Ideally, coincident intersection points should be jittered to avoid
12155             // clipping issues.
12156
12157
12158             function lineEnd() {
12159               if (segments) {
12160                 linePoint(x__, y__);
12161                 if (v__ && v_) bufferStream.rejoin();
12162                 segments.push(bufferStream.result());
12163               }
12164
12165               clipStream.point = point;
12166               if (v_) activeStream.lineEnd();
12167             }
12168
12169             function linePoint(x, y) {
12170               var v = visible(x, y);
12171               if (polygon) ring.push([x, y]);
12172
12173               if (first) {
12174                 x__ = x, y__ = y, v__ = v;
12175                 first = false;
12176
12177                 if (v) {
12178                   activeStream.lineStart();
12179                   activeStream.point(x, y);
12180                 }
12181               } else {
12182                 if (v && v_) activeStream.point(x, y);else {
12183                   var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
12184                       b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
12185
12186                   if (clipLine(a, b, x0, y0, x1, y1)) {
12187                     if (!v_) {
12188                       activeStream.lineStart();
12189                       activeStream.point(a[0], a[1]);
12190                     }
12191
12192                     activeStream.point(b[0], b[1]);
12193                     if (!v) activeStream.lineEnd();
12194                     clean = false;
12195                   } else if (v) {
12196                     activeStream.lineStart();
12197                     activeStream.point(x, y);
12198                     clean = false;
12199                   }
12200                 }
12201               }
12202
12203               x_ = x, y_ = y, v_ = v;
12204             }
12205
12206             return clipStream;
12207           };
12208         }
12209
12210         var lengthSum$1, lambda0, sinPhi0, cosPhi0;
12211         var lengthStream$1 = {
12212           sphere: noop$1,
12213           point: noop$1,
12214           lineStart: lengthLineStart,
12215           lineEnd: noop$1,
12216           polygonStart: noop$1,
12217           polygonEnd: noop$1
12218         };
12219
12220         function lengthLineStart() {
12221           lengthStream$1.point = lengthPointFirst$1;
12222           lengthStream$1.lineEnd = lengthLineEnd;
12223         }
12224
12225         function lengthLineEnd() {
12226           lengthStream$1.point = lengthStream$1.lineEnd = noop$1;
12227         }
12228
12229         function lengthPointFirst$1(lambda, phi) {
12230           lambda *= radians, phi *= radians;
12231           lambda0 = lambda, sinPhi0 = sin(phi), cosPhi0 = cos(phi);
12232           lengthStream$1.point = lengthPoint$1;
12233         }
12234
12235         function lengthPoint$1(lambda, phi) {
12236           lambda *= radians, phi *= radians;
12237           var sinPhi = sin(phi),
12238               cosPhi = cos(phi),
12239               delta = abs$2(lambda - lambda0),
12240               cosDelta = cos(delta),
12241               sinDelta = sin(delta),
12242               x = cosPhi * sinDelta,
12243               y = cosPhi0 * sinPhi - sinPhi0 * cosPhi * cosDelta,
12244               z = sinPhi0 * sinPhi + cosPhi0 * cosPhi * cosDelta;
12245           lengthSum$1.add(atan2(sqrt(x * x + y * y), z));
12246           lambda0 = lambda, sinPhi0 = sinPhi, cosPhi0 = cosPhi;
12247         }
12248
12249         function d3_geoLength (object) {
12250           lengthSum$1 = new Adder();
12251           d3_geoStream(object, lengthStream$1);
12252           return +lengthSum$1;
12253         }
12254
12255         var identity$4 = (function (x) {
12256           return x;
12257         });
12258
12259         var areaSum = new Adder(),
12260             areaRingSum = new Adder(),
12261             x00$2,
12262             y00$2,
12263             x0$3,
12264             y0$3;
12265         var areaStream = {
12266           point: noop$1,
12267           lineStart: noop$1,
12268           lineEnd: noop$1,
12269           polygonStart: function polygonStart() {
12270             areaStream.lineStart = areaRingStart;
12271             areaStream.lineEnd = areaRingEnd;
12272           },
12273           polygonEnd: function polygonEnd() {
12274             areaStream.lineStart = areaStream.lineEnd = areaStream.point = noop$1;
12275             areaSum.add(abs$2(areaRingSum));
12276             areaRingSum = new Adder();
12277           },
12278           result: function result() {
12279             var area = areaSum / 2;
12280             areaSum = new Adder();
12281             return area;
12282           }
12283         };
12284
12285         function areaRingStart() {
12286           areaStream.point = areaPointFirst;
12287         }
12288
12289         function areaPointFirst(x, y) {
12290           areaStream.point = areaPoint;
12291           x00$2 = x0$3 = x, y00$2 = y0$3 = y;
12292         }
12293
12294         function areaPoint(x, y) {
12295           areaRingSum.add(y0$3 * x - x0$3 * y);
12296           x0$3 = x, y0$3 = y;
12297         }
12298
12299         function areaRingEnd() {
12300           areaPoint(x00$2, y00$2);
12301         }
12302
12303         var x0$2 = Infinity,
12304             y0$2 = x0$2,
12305             x1 = -x0$2,
12306             y1 = x1;
12307         var boundsStream = {
12308           point: boundsPoint,
12309           lineStart: noop$1,
12310           lineEnd: noop$1,
12311           polygonStart: noop$1,
12312           polygonEnd: noop$1,
12313           result: function result() {
12314             var bounds = [[x0$2, y0$2], [x1, y1]];
12315             x1 = y1 = -(y0$2 = x0$2 = Infinity);
12316             return bounds;
12317           }
12318         };
12319
12320         function boundsPoint(x, y) {
12321           if (x < x0$2) x0$2 = x;
12322           if (x > x1) x1 = x;
12323           if (y < y0$2) y0$2 = y;
12324           if (y > y1) y1 = y;
12325         }
12326
12327         var X0 = 0,
12328             Y0 = 0,
12329             Z0 = 0,
12330             X1 = 0,
12331             Y1 = 0,
12332             Z1 = 0,
12333             X2 = 0,
12334             Y2 = 0,
12335             Z2 = 0,
12336             x00$1,
12337             y00$1,
12338             x0$1,
12339             y0$1;
12340         var centroidStream = {
12341           point: centroidPoint,
12342           lineStart: centroidLineStart,
12343           lineEnd: centroidLineEnd,
12344           polygonStart: function polygonStart() {
12345             centroidStream.lineStart = centroidRingStart;
12346             centroidStream.lineEnd = centroidRingEnd;
12347           },
12348           polygonEnd: function polygonEnd() {
12349             centroidStream.point = centroidPoint;
12350             centroidStream.lineStart = centroidLineStart;
12351             centroidStream.lineEnd = centroidLineEnd;
12352           },
12353           result: function result() {
12354             var centroid = Z2 ? [X2 / Z2, Y2 / Z2] : Z1 ? [X1 / Z1, Y1 / Z1] : Z0 ? [X0 / Z0, Y0 / Z0] : [NaN, NaN];
12355             X0 = Y0 = Z0 = X1 = Y1 = Z1 = X2 = Y2 = Z2 = 0;
12356             return centroid;
12357           }
12358         };
12359
12360         function centroidPoint(x, y) {
12361           X0 += x;
12362           Y0 += y;
12363           ++Z0;
12364         }
12365
12366         function centroidLineStart() {
12367           centroidStream.point = centroidPointFirstLine;
12368         }
12369
12370         function centroidPointFirstLine(x, y) {
12371           centroidStream.point = centroidPointLine;
12372           centroidPoint(x0$1 = x, y0$1 = y);
12373         }
12374
12375         function centroidPointLine(x, y) {
12376           var dx = x - x0$1,
12377               dy = y - y0$1,
12378               z = sqrt(dx * dx + dy * dy);
12379           X1 += z * (x0$1 + x) / 2;
12380           Y1 += z * (y0$1 + y) / 2;
12381           Z1 += z;
12382           centroidPoint(x0$1 = x, y0$1 = y);
12383         }
12384
12385         function centroidLineEnd() {
12386           centroidStream.point = centroidPoint;
12387         }
12388
12389         function centroidRingStart() {
12390           centroidStream.point = centroidPointFirstRing;
12391         }
12392
12393         function centroidRingEnd() {
12394           centroidPointRing(x00$1, y00$1);
12395         }
12396
12397         function centroidPointFirstRing(x, y) {
12398           centroidStream.point = centroidPointRing;
12399           centroidPoint(x00$1 = x0$1 = x, y00$1 = y0$1 = y);
12400         }
12401
12402         function centroidPointRing(x, y) {
12403           var dx = x - x0$1,
12404               dy = y - y0$1,
12405               z = sqrt(dx * dx + dy * dy);
12406           X1 += z * (x0$1 + x) / 2;
12407           Y1 += z * (y0$1 + y) / 2;
12408           Z1 += z;
12409           z = y0$1 * x - x0$1 * y;
12410           X2 += z * (x0$1 + x);
12411           Y2 += z * (y0$1 + y);
12412           Z2 += z * 3;
12413           centroidPoint(x0$1 = x, y0$1 = y);
12414         }
12415
12416         function PathContext(context) {
12417           this._context = context;
12418         }
12419         PathContext.prototype = {
12420           _radius: 4.5,
12421           pointRadius: function pointRadius(_) {
12422             return this._radius = _, this;
12423           },
12424           polygonStart: function polygonStart() {
12425             this._line = 0;
12426           },
12427           polygonEnd: function polygonEnd() {
12428             this._line = NaN;
12429           },
12430           lineStart: function lineStart() {
12431             this._point = 0;
12432           },
12433           lineEnd: function lineEnd() {
12434             if (this._line === 0) this._context.closePath();
12435             this._point = NaN;
12436           },
12437           point: function point(x, y) {
12438             switch (this._point) {
12439               case 0:
12440                 {
12441                   this._context.moveTo(x, y);
12442
12443                   this._point = 1;
12444                   break;
12445                 }
12446
12447               case 1:
12448                 {
12449                   this._context.lineTo(x, y);
12450
12451                   break;
12452                 }
12453
12454               default:
12455                 {
12456                   this._context.moveTo(x + this._radius, y);
12457
12458                   this._context.arc(x, y, this._radius, 0, tau);
12459
12460                   break;
12461                 }
12462             }
12463           },
12464           result: noop$1
12465         };
12466
12467         var lengthSum = new Adder(),
12468             lengthRing,
12469             x00,
12470             y00,
12471             x0,
12472             y0;
12473         var lengthStream = {
12474           point: noop$1,
12475           lineStart: function lineStart() {
12476             lengthStream.point = lengthPointFirst;
12477           },
12478           lineEnd: function lineEnd() {
12479             if (lengthRing) lengthPoint(x00, y00);
12480             lengthStream.point = noop$1;
12481           },
12482           polygonStart: function polygonStart() {
12483             lengthRing = true;
12484           },
12485           polygonEnd: function polygonEnd() {
12486             lengthRing = null;
12487           },
12488           result: function result() {
12489             var length = +lengthSum;
12490             lengthSum = new Adder();
12491             return length;
12492           }
12493         };
12494
12495         function lengthPointFirst(x, y) {
12496           lengthStream.point = lengthPoint;
12497           x00 = x0 = x, y00 = y0 = y;
12498         }
12499
12500         function lengthPoint(x, y) {
12501           x0 -= x, y0 -= y;
12502           lengthSum.add(sqrt(x0 * x0 + y0 * y0));
12503           x0 = x, y0 = y;
12504         }
12505
12506         function PathString() {
12507           this._string = [];
12508         }
12509         PathString.prototype = {
12510           _radius: 4.5,
12511           _circle: circle(4.5),
12512           pointRadius: function pointRadius(_) {
12513             if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
12514             return this;
12515           },
12516           polygonStart: function polygonStart() {
12517             this._line = 0;
12518           },
12519           polygonEnd: function polygonEnd() {
12520             this._line = NaN;
12521           },
12522           lineStart: function lineStart() {
12523             this._point = 0;
12524           },
12525           lineEnd: function lineEnd() {
12526             if (this._line === 0) this._string.push("Z");
12527             this._point = NaN;
12528           },
12529           point: function point(x, y) {
12530             switch (this._point) {
12531               case 0:
12532                 {
12533                   this._string.push("M", x, ",", y);
12534
12535                   this._point = 1;
12536                   break;
12537                 }
12538
12539               case 1:
12540                 {
12541                   this._string.push("L", x, ",", y);
12542
12543                   break;
12544                 }
12545
12546               default:
12547                 {
12548                   if (this._circle == null) this._circle = circle(this._radius);
12549
12550                   this._string.push("M", x, ",", y, this._circle);
12551
12552                   break;
12553                 }
12554             }
12555           },
12556           result: function result() {
12557             if (this._string.length) {
12558               var result = this._string.join("");
12559
12560               this._string = [];
12561               return result;
12562             } else {
12563               return null;
12564             }
12565           }
12566         };
12567
12568         function circle(radius) {
12569           return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
12570         }
12571
12572         function d3_geoPath (projection, context) {
12573           var pointRadius = 4.5,
12574               projectionStream,
12575               contextStream;
12576
12577           function path(object) {
12578             if (object) {
12579               if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
12580               d3_geoStream(object, projectionStream(contextStream));
12581             }
12582
12583             return contextStream.result();
12584           }
12585
12586           path.area = function (object) {
12587             d3_geoStream(object, projectionStream(areaStream));
12588             return areaStream.result();
12589           };
12590
12591           path.measure = function (object) {
12592             d3_geoStream(object, projectionStream(lengthStream));
12593             return lengthStream.result();
12594           };
12595
12596           path.bounds = function (object) {
12597             d3_geoStream(object, projectionStream(boundsStream));
12598             return boundsStream.result();
12599           };
12600
12601           path.centroid = function (object) {
12602             d3_geoStream(object, projectionStream(centroidStream));
12603             return centroidStream.result();
12604           };
12605
12606           path.projection = function (_) {
12607             return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
12608           };
12609
12610           path.context = function (_) {
12611             if (!arguments.length) return context;
12612             contextStream = _ == null ? (context = null, new PathString()) : new PathContext(context = _);
12613             if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
12614             return path;
12615           };
12616
12617           path.pointRadius = function (_) {
12618             if (!arguments.length) return pointRadius;
12619             pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
12620             return path;
12621           };
12622
12623           return path.projection(projection).context(context);
12624         }
12625
12626         function d3_geoTransform (methods) {
12627           return {
12628             stream: transformer$1(methods)
12629           };
12630         }
12631         function transformer$1(methods) {
12632           return function (stream) {
12633             var s = new TransformStream();
12634
12635             for (var key in methods) {
12636               s[key] = methods[key];
12637             }
12638
12639             s.stream = stream;
12640             return s;
12641           };
12642         }
12643
12644         function TransformStream() {}
12645
12646         TransformStream.prototype = {
12647           constructor: TransformStream,
12648           point: function point(x, y) {
12649             this.stream.point(x, y);
12650           },
12651           sphere: function sphere() {
12652             this.stream.sphere();
12653           },
12654           lineStart: function lineStart() {
12655             this.stream.lineStart();
12656           },
12657           lineEnd: function lineEnd() {
12658             this.stream.lineEnd();
12659           },
12660           polygonStart: function polygonStart() {
12661             this.stream.polygonStart();
12662           },
12663           polygonEnd: function polygonEnd() {
12664             this.stream.polygonEnd();
12665           }
12666         };
12667
12668         function fit(projection, fitBounds, object) {
12669           var clip = projection.clipExtent && projection.clipExtent();
12670           projection.scale(150).translate([0, 0]);
12671           if (clip != null) projection.clipExtent(null);
12672           d3_geoStream(object, projection.stream(boundsStream));
12673           fitBounds(boundsStream.result());
12674           if (clip != null) projection.clipExtent(clip);
12675           return projection;
12676         }
12677
12678         function fitExtent(projection, extent, object) {
12679           return fit(projection, function (b) {
12680             var w = extent[1][0] - extent[0][0],
12681                 h = extent[1][1] - extent[0][1],
12682                 k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
12683                 x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
12684                 y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
12685             projection.scale(150 * k).translate([x, y]);
12686           }, object);
12687         }
12688         function fitSize(projection, size, object) {
12689           return fitExtent(projection, [[0, 0], size], object);
12690         }
12691         function fitWidth(projection, width, object) {
12692           return fit(projection, function (b) {
12693             var w = +width,
12694                 k = w / (b[1][0] - b[0][0]),
12695                 x = (w - k * (b[1][0] + b[0][0])) / 2,
12696                 y = -k * b[0][1];
12697             projection.scale(150 * k).translate([x, y]);
12698           }, object);
12699         }
12700         function fitHeight(projection, height, object) {
12701           return fit(projection, function (b) {
12702             var h = +height,
12703                 k = h / (b[1][1] - b[0][1]),
12704                 x = -k * b[0][0],
12705                 y = (h - k * (b[1][1] + b[0][1])) / 2;
12706             projection.scale(150 * k).translate([x, y]);
12707           }, object);
12708         }
12709
12710         var maxDepth = 16,
12711             // maximum depth of subdivision
12712         cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
12713
12714         function resample (project, delta2) {
12715           return +delta2 ? resample$1(project, delta2) : resampleNone(project);
12716         }
12717
12718         function resampleNone(project) {
12719           return transformer$1({
12720             point: function point(x, y) {
12721               x = project(x, y);
12722               this.stream.point(x[0], x[1]);
12723             }
12724           });
12725         }
12726
12727         function resample$1(project, delta2) {
12728           function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
12729             var dx = x1 - x0,
12730                 dy = y1 - y0,
12731                 d2 = dx * dx + dy * dy;
12732
12733             if (d2 > 4 * delta2 && depth--) {
12734               var a = a0 + a1,
12735                   b = b0 + b1,
12736                   c = c0 + c1,
12737                   m = sqrt(a * a + b * b + c * c),
12738                   phi2 = asin(c /= m),
12739                   lambda2 = abs$2(abs$2(c) - 1) < epsilon$1 || abs$2(lambda0 - lambda1) < epsilon$1 ? (lambda0 + lambda1) / 2 : atan2(b, a),
12740                   p = project(lambda2, phi2),
12741                   x2 = p[0],
12742                   y2 = p[1],
12743                   dx2 = x2 - x0,
12744                   dy2 = y2 - y0,
12745                   dz = dy * dx2 - dx * dy2;
12746
12747               if (dz * dz / d2 > delta2 // perpendicular projected distance
12748               || abs$2((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
12749               || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
12750                 // angular distance
12751                 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
12752                 stream.point(x2, y2);
12753                 resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
12754               }
12755             }
12756           }
12757
12758           return function (stream) {
12759             var lambda00, x00, y00, a00, b00, c00, // first point
12760             lambda0, x0, y0, a0, b0, c0; // previous point
12761
12762             var resampleStream = {
12763               point: point,
12764               lineStart: lineStart,
12765               lineEnd: lineEnd,
12766               polygonStart: function polygonStart() {
12767                 stream.polygonStart();
12768                 resampleStream.lineStart = ringStart;
12769               },
12770               polygonEnd: function polygonEnd() {
12771                 stream.polygonEnd();
12772                 resampleStream.lineStart = lineStart;
12773               }
12774             };
12775
12776             function point(x, y) {
12777               x = project(x, y);
12778               stream.point(x[0], x[1]);
12779             }
12780
12781             function lineStart() {
12782               x0 = NaN;
12783               resampleStream.point = linePoint;
12784               stream.lineStart();
12785             }
12786
12787             function linePoint(lambda, phi) {
12788               var c = cartesian([lambda, phi]),
12789                   p = project(lambda, phi);
12790               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);
12791               stream.point(x0, y0);
12792             }
12793
12794             function lineEnd() {
12795               resampleStream.point = point;
12796               stream.lineEnd();
12797             }
12798
12799             function ringStart() {
12800               lineStart();
12801               resampleStream.point = ringPoint;
12802               resampleStream.lineEnd = ringEnd;
12803             }
12804
12805             function ringPoint(lambda, phi) {
12806               linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
12807               resampleStream.point = linePoint;
12808             }
12809
12810             function ringEnd() {
12811               resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
12812               resampleStream.lineEnd = lineEnd;
12813               lineEnd();
12814             }
12815
12816             return resampleStream;
12817           };
12818         }
12819
12820         var transformRadians = transformer$1({
12821           point: function point(x, y) {
12822             this.stream.point(x * radians, y * radians);
12823           }
12824         });
12825
12826         function transformRotate(rotate) {
12827           return transformer$1({
12828             point: function point(x, y) {
12829               var r = rotate(x, y);
12830               return this.stream.point(r[0], r[1]);
12831             }
12832           });
12833         }
12834
12835         function scaleTranslate(k, dx, dy, sx, sy) {
12836           function transform(x, y) {
12837             x *= sx;
12838             y *= sy;
12839             return [dx + k * x, dy - k * y];
12840           }
12841
12842           transform.invert = function (x, y) {
12843             return [(x - dx) / k * sx, (dy - y) / k * sy];
12844           };
12845
12846           return transform;
12847         }
12848
12849         function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
12850           if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
12851           var cosAlpha = cos(alpha),
12852               sinAlpha = sin(alpha),
12853               a = cosAlpha * k,
12854               b = sinAlpha * k,
12855               ai = cosAlpha / k,
12856               bi = sinAlpha / k,
12857               ci = (sinAlpha * dy - cosAlpha * dx) / k,
12858               fi = (sinAlpha * dx + cosAlpha * dy) / k;
12859
12860           function transform(x, y) {
12861             x *= sx;
12862             y *= sy;
12863             return [a * x - b * y + dx, dy - b * x - a * y];
12864           }
12865
12866           transform.invert = function (x, y) {
12867             return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
12868           };
12869
12870           return transform;
12871         }
12872
12873         function projection(project) {
12874           return projectionMutator(function () {
12875             return project;
12876           })();
12877         }
12878         function projectionMutator(projectAt) {
12879           var project,
12880               k = 150,
12881               // scale
12882           x = 480,
12883               y = 250,
12884               // translate
12885           lambda = 0,
12886               phi = 0,
12887               // center
12888           deltaLambda = 0,
12889               deltaPhi = 0,
12890               deltaGamma = 0,
12891               rotate,
12892               // pre-rotate
12893           alpha = 0,
12894               // post-rotate angle
12895           sx = 1,
12896               // reflectX
12897           sy = 1,
12898               // reflectX
12899           theta = null,
12900               preclip = clipAntimeridian,
12901               // pre-clip angle
12902           x0 = null,
12903               y0,
12904               x1,
12905               y1,
12906               postclip = identity$4,
12907               // post-clip extent
12908           delta2 = 0.5,
12909               // precision
12910           projectResample,
12911               projectTransform,
12912               projectRotateTransform,
12913               cache,
12914               cacheStream;
12915
12916           function projection(point) {
12917             return projectRotateTransform(point[0] * radians, point[1] * radians);
12918           }
12919
12920           function invert(point) {
12921             point = projectRotateTransform.invert(point[0], point[1]);
12922             return point && [point[0] * degrees$1, point[1] * degrees$1];
12923           }
12924
12925           projection.stream = function (stream) {
12926             return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
12927           };
12928
12929           projection.preclip = function (_) {
12930             return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip;
12931           };
12932
12933           projection.postclip = function (_) {
12934             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12935           };
12936
12937           projection.clipAngle = function (_) {
12938             return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
12939           };
12940
12941           projection.clipExtent = function (_) {
12942             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]];
12943           };
12944
12945           projection.scale = function (_) {
12946             return arguments.length ? (k = +_, recenter()) : k;
12947           };
12948
12949           projection.translate = function (_) {
12950             return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
12951           };
12952
12953           projection.center = function (_) {
12954             return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
12955           };
12956
12957           projection.rotate = function (_) {
12958             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];
12959           };
12960
12961           projection.angle = function (_) {
12962             return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees$1;
12963           };
12964
12965           projection.reflectX = function (_) {
12966             return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
12967           };
12968
12969           projection.reflectY = function (_) {
12970             return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
12971           };
12972
12973           projection.precision = function (_) {
12974             return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
12975           };
12976
12977           projection.fitExtent = function (extent, object) {
12978             return fitExtent(projection, extent, object);
12979           };
12980
12981           projection.fitSize = function (size, object) {
12982             return fitSize(projection, size, object);
12983           };
12984
12985           projection.fitWidth = function (width, object) {
12986             return fitWidth(projection, width, object);
12987           };
12988
12989           projection.fitHeight = function (height, object) {
12990             return fitHeight(projection, height, object);
12991           };
12992
12993           function recenter() {
12994             var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
12995                 transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
12996             rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
12997             projectTransform = compose(project, transform);
12998             projectRotateTransform = compose(rotate, projectTransform);
12999             projectResample = resample(projectTransform, delta2);
13000             return reset();
13001           }
13002
13003           function reset() {
13004             cache = cacheStream = null;
13005             return projection;
13006           }
13007
13008           return function () {
13009             project = projectAt.apply(this, arguments);
13010             projection.invert = project.invert && invert;
13011             return recenter();
13012           };
13013         }
13014
13015         function mercatorRaw(lambda, phi) {
13016           return [lambda, log$1(tan((halfPi + phi) / 2))];
13017         }
13018
13019         mercatorRaw.invert = function (x, y) {
13020           return [x, 2 * atan(exp$2(y)) - halfPi];
13021         };
13022
13023         function mercator () {
13024           return mercatorProjection(mercatorRaw).scale(961 / tau);
13025         }
13026         function mercatorProjection(project) {
13027           var m = projection(project),
13028               center = m.center,
13029               scale = m.scale,
13030               translate = m.translate,
13031               clipExtent = m.clipExtent,
13032               x0 = null,
13033               y0,
13034               x1,
13035               y1; // clip extent
13036
13037           m.scale = function (_) {
13038             return arguments.length ? (scale(_), reclip()) : scale();
13039           };
13040
13041           m.translate = function (_) {
13042             return arguments.length ? (translate(_), reclip()) : translate();
13043           };
13044
13045           m.center = function (_) {
13046             return arguments.length ? (center(_), reclip()) : center();
13047           };
13048
13049           m.clipExtent = function (_) {
13050             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]];
13051           };
13052
13053           function reclip() {
13054             var k = pi * scale(),
13055                 t = m(rotation(m.rotate()).invert([0, 0]));
13056             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)]]);
13057           }
13058
13059           return reclip();
13060         }
13061
13062         function d3_geoIdentity () {
13063           var k = 1,
13064               tx = 0,
13065               ty = 0,
13066               sx = 1,
13067               sy = 1,
13068               // scale, translate and reflect
13069           alpha = 0,
13070               ca,
13071               sa,
13072               // angle
13073           x0 = null,
13074               y0,
13075               x1,
13076               y1,
13077               // clip extent
13078           kx = 1,
13079               ky = 1,
13080               transform = transformer$1({
13081             point: function point(x, y) {
13082               var p = projection([x, y]);
13083               this.stream.point(p[0], p[1]);
13084             }
13085           }),
13086               postclip = identity$4,
13087               cache,
13088               cacheStream;
13089
13090           function reset() {
13091             kx = k * sx;
13092             ky = k * sy;
13093             cache = cacheStream = null;
13094             return projection;
13095           }
13096
13097           function projection(p) {
13098             var x = p[0] * kx,
13099                 y = p[1] * ky;
13100
13101             if (alpha) {
13102               var t = y * ca - x * sa;
13103               x = x * ca + y * sa;
13104               y = t;
13105             }
13106
13107             return [x + tx, y + ty];
13108           }
13109
13110           projection.invert = function (p) {
13111             var x = p[0] - tx,
13112                 y = p[1] - ty;
13113
13114             if (alpha) {
13115               var t = y * ca + x * sa;
13116               x = x * ca - y * sa;
13117               y = t;
13118             }
13119
13120             return [x / kx, y / ky];
13121           };
13122
13123           projection.stream = function (stream) {
13124             return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream));
13125           };
13126
13127           projection.postclip = function (_) {
13128             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
13129           };
13130
13131           projection.clipExtent = function (_) {
13132             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]];
13133           };
13134
13135           projection.scale = function (_) {
13136             return arguments.length ? (k = +_, reset()) : k;
13137           };
13138
13139           projection.translate = function (_) {
13140             return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
13141           };
13142
13143           projection.angle = function (_) {
13144             return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees$1;
13145           };
13146
13147           projection.reflectX = function (_) {
13148             return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
13149           };
13150
13151           projection.reflectY = function (_) {
13152             return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
13153           };
13154
13155           projection.fitExtent = function (extent, object) {
13156             return fitExtent(projection, extent, object);
13157           };
13158
13159           projection.fitSize = function (size, object) {
13160             return fitSize(projection, size, object);
13161           };
13162
13163           projection.fitWidth = function (width, object) {
13164             return fitWidth(projection, width, object);
13165           };
13166
13167           projection.fitHeight = function (height, object) {
13168             return fitHeight(projection, height, object);
13169           };
13170
13171           return projection;
13172         }
13173
13174         // constants
13175         var TAU = 2 * Math.PI;
13176         var EQUATORIAL_RADIUS = 6356752.314245179;
13177         var POLAR_RADIUS = 6378137.0;
13178         function geoLatToMeters(dLat) {
13179           return dLat * (TAU * POLAR_RADIUS / 360);
13180         }
13181         function geoLonToMeters(dLon, atLat) {
13182           return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
13183         }
13184         function geoMetersToLat(m) {
13185           return m / (TAU * POLAR_RADIUS / 360);
13186         }
13187         function geoMetersToLon(m, atLat) {
13188           return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
13189         }
13190         function geoMetersToOffset(meters, tileSize) {
13191           tileSize = tileSize || 256;
13192           return [meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS), -meters[1] * tileSize / (TAU * POLAR_RADIUS)];
13193         }
13194         function geoOffsetToMeters(offset, tileSize) {
13195           tileSize = tileSize || 256;
13196           return [offset[0] * TAU * EQUATORIAL_RADIUS / tileSize, -offset[1] * TAU * POLAR_RADIUS / tileSize];
13197         } // Equirectangular approximation of spherical distances on Earth
13198
13199         function geoSphericalDistance(a, b) {
13200           var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
13201           var y = geoLatToMeters(a[1] - b[1]);
13202           return Math.sqrt(x * x + y * y);
13203         } // scale to zoom
13204
13205         function geoScaleToZoom(k, tileSize) {
13206           tileSize = tileSize || 256;
13207           var log2ts = Math.log(tileSize) * Math.LOG2E;
13208           return Math.log(k * TAU) / Math.LN2 - log2ts;
13209         } // zoom to scale
13210
13211         function geoZoomToScale(z, tileSize) {
13212           tileSize = tileSize || 256;
13213           return tileSize * Math.pow(2, z) / TAU;
13214         } // returns info about the node from `nodes` closest to the given `point`
13215
13216         function geoSphericalClosestNode(nodes, point) {
13217           var minDistance = Infinity,
13218               distance;
13219           var indexOfMin;
13220
13221           for (var i in nodes) {
13222             distance = geoSphericalDistance(nodes[i].loc, point);
13223
13224             if (distance < minDistance) {
13225               minDistance = distance;
13226               indexOfMin = i;
13227             }
13228           }
13229
13230           if (indexOfMin !== undefined) {
13231             return {
13232               index: indexOfMin,
13233               distance: minDistance,
13234               node: nodes[indexOfMin]
13235             };
13236           } else {
13237             return null;
13238           }
13239         }
13240
13241         function geoExtent(min, max) {
13242           if (!(this instanceof geoExtent)) {
13243             return new geoExtent(min, max);
13244           } else if (min instanceof geoExtent) {
13245             return min;
13246           } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
13247             this[0] = min[0];
13248             this[1] = min[1];
13249           } else {
13250             this[0] = min || [Infinity, Infinity];
13251             this[1] = max || min || [-Infinity, -Infinity];
13252           }
13253         }
13254         geoExtent.prototype = new Array(2);
13255         Object.assign(geoExtent.prototype, {
13256           equals: function equals(obj) {
13257             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];
13258           },
13259           extend: function extend(obj) {
13260             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13261             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])]);
13262           },
13263           _extend: function _extend(extent) {
13264             this[0][0] = Math.min(extent[0][0], this[0][0]);
13265             this[0][1] = Math.min(extent[0][1], this[0][1]);
13266             this[1][0] = Math.max(extent[1][0], this[1][0]);
13267             this[1][1] = Math.max(extent[1][1], this[1][1]);
13268           },
13269           area: function area() {
13270             return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
13271           },
13272           center: function center() {
13273             return [(this[0][0] + this[1][0]) / 2, (this[0][1] + this[1][1]) / 2];
13274           },
13275           rectangle: function rectangle() {
13276             return [this[0][0], this[0][1], this[1][0], this[1][1]];
13277           },
13278           bbox: function bbox() {
13279             return {
13280               minX: this[0][0],
13281               minY: this[0][1],
13282               maxX: this[1][0],
13283               maxY: this[1][1]
13284             };
13285           },
13286           polygon: function polygon() {
13287             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]]];
13288           },
13289           contains: function contains(obj) {
13290             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13291             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];
13292           },
13293           intersects: function intersects(obj) {
13294             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13295             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];
13296           },
13297           intersection: function intersection(obj) {
13298             if (!this.intersects(obj)) return new geoExtent();
13299             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])]);
13300           },
13301           percentContainedIn: function percentContainedIn(obj) {
13302             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13303             var a1 = this.intersection(obj).area();
13304             var a2 = this.area();
13305
13306             if (a1 === Infinity || a2 === Infinity) {
13307               return 0;
13308             } else if (a1 === 0 || a2 === 0) {
13309               if (obj.contains(this)) {
13310                 return 1;
13311               }
13312
13313               return 0;
13314             } else {
13315               return a1 / a2;
13316             }
13317           },
13318           padByMeters: function padByMeters(meters) {
13319             var dLat = geoMetersToLat(meters);
13320             var dLon = geoMetersToLon(meters, this.center()[1]);
13321             return geoExtent([this[0][0] - dLon, this[0][1] - dLat], [this[1][0] + dLon, this[1][1] + dLat]);
13322           },
13323           toParam: function toParam() {
13324             return this.rectangle().join(',');
13325           }
13326         });
13327
13328         var $$p = _export;
13329         var $every = arrayIteration.every;
13330         var arrayMethodIsStrict$1 = arrayMethodIsStrict$8;
13331
13332         var STRICT_METHOD$1 = arrayMethodIsStrict$1('every');
13333
13334         // `Array.prototype.every` method
13335         // https://tc39.es/ecma262/#sec-array.prototype.every
13336         $$p({ target: 'Array', proto: true, forced: !STRICT_METHOD$1 }, {
13337           every: function every(callbackfn /* , thisArg */) {
13338             return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
13339           }
13340         });
13341
13342         var $$o = _export;
13343         var $reduce = arrayReduce.left;
13344         var arrayMethodIsStrict = arrayMethodIsStrict$8;
13345         var CHROME_VERSION = engineV8Version;
13346         var IS_NODE = engineIsNode;
13347
13348         var STRICT_METHOD = arrayMethodIsStrict('reduce');
13349         // Chrome 80-82 has a critical bug
13350         // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
13351         var CHROME_BUG = !IS_NODE && CHROME_VERSION > 79 && CHROME_VERSION < 83;
13352
13353         // `Array.prototype.reduce` method
13354         // https://tc39.es/ecma262/#sec-array.prototype.reduce
13355         $$o({ target: 'Array', proto: true, forced: !STRICT_METHOD || CHROME_BUG }, {
13356           reduce: function reduce(callbackfn /* , initialValue */) {
13357             return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
13358           }
13359         });
13360
13361         function d3_polygonArea (polygon) {
13362           var i = -1,
13363               n = polygon.length,
13364               a,
13365               b = polygon[n - 1],
13366               area = 0;
13367
13368           while (++i < n) {
13369             a = b;
13370             b = polygon[i];
13371             area += a[1] * b[0] - a[0] * b[1];
13372           }
13373
13374           return area / 2;
13375         }
13376
13377         function d3_polygonCentroid (polygon) {
13378           var i = -1,
13379               n = polygon.length,
13380               x = 0,
13381               y = 0,
13382               a,
13383               b = polygon[n - 1],
13384               c,
13385               k = 0;
13386
13387           while (++i < n) {
13388             a = b;
13389             b = polygon[i];
13390             k += c = a[0] * b[1] - b[0] * a[1];
13391             x += (a[0] + b[0]) * c;
13392             y += (a[1] + b[1]) * c;
13393           }
13394
13395           return k *= 3, [x / k, y / k];
13396         }
13397
13398         // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
13399         // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
13400         // right, +y is up). Returns a positive value if ABC is counter-clockwise,
13401         // negative if clockwise, and zero if the points are collinear.
13402         function cross (a, b, c) {
13403           return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
13404         }
13405
13406         function lexicographicOrder(a, b) {
13407           return a[0] - b[0] || a[1] - b[1];
13408         } // Computes the upper convex hull per the monotone chain algorithm.
13409         // Assumes points.length >= 3, is sorted by x, unique in y.
13410         // Returns an array of indices into points in left-to-right order.
13411
13412
13413         function computeUpperHullIndexes(points) {
13414           var n = points.length,
13415               indexes = [0, 1];
13416           var size = 2,
13417               i;
13418
13419           for (i = 2; i < n; ++i) {
13420             while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) {
13421               --size;
13422             }
13423
13424             indexes[size++] = i;
13425           }
13426
13427           return indexes.slice(0, size); // remove popped points
13428         }
13429
13430         function d3_polygonHull (points) {
13431           if ((n = points.length) < 3) return null;
13432           var i,
13433               n,
13434               sortedPoints = new Array(n),
13435               flippedPoints = new Array(n);
13436
13437           for (i = 0; i < n; ++i) {
13438             sortedPoints[i] = [+points[i][0], +points[i][1], i];
13439           }
13440
13441           sortedPoints.sort(lexicographicOrder);
13442
13443           for (i = 0; i < n; ++i) {
13444             flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
13445           }
13446
13447           var upperIndexes = computeUpperHullIndexes(sortedPoints),
13448               lowerIndexes = computeUpperHullIndexes(flippedPoints); // Construct the hull polygon, removing possible duplicate endpoints.
13449
13450           var skipLeft = lowerIndexes[0] === upperIndexes[0],
13451               skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
13452               hull = []; // Add upper hull in right-to-l order.
13453           // Then add lower hull in left-to-right order.
13454
13455           for (i = upperIndexes.length - 1; i >= 0; --i) {
13456             hull.push(points[sortedPoints[upperIndexes[i]][2]]);
13457           }
13458
13459           for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) {
13460             hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
13461           }
13462
13463           return hull;
13464         }
13465
13466         // vector equals
13467         function geoVecEqual(a, b, epsilon) {
13468           if (epsilon) {
13469             return Math.abs(a[0] - b[0]) <= epsilon && Math.abs(a[1] - b[1]) <= epsilon;
13470           } else {
13471             return a[0] === b[0] && a[1] === b[1];
13472           }
13473         } // vector addition
13474
13475         function geoVecAdd(a, b) {
13476           return [a[0] + b[0], a[1] + b[1]];
13477         } // vector subtraction
13478
13479         function geoVecSubtract(a, b) {
13480           return [a[0] - b[0], a[1] - b[1]];
13481         } // vector scaling
13482
13483         function geoVecScale(a, mag) {
13484           return [a[0] * mag, a[1] * mag];
13485         } // vector rounding (was: geoRoundCoordinates)
13486
13487         function geoVecFloor(a) {
13488           return [Math.floor(a[0]), Math.floor(a[1])];
13489         } // linear interpolation
13490
13491         function geoVecInterp(a, b, t) {
13492           return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
13493         } // http://jsperf.com/id-dist-optimization
13494
13495         function geoVecLength(a, b) {
13496           return Math.sqrt(geoVecLengthSquare(a, b));
13497         } // length of vector raised to the power two
13498
13499         function geoVecLengthSquare(a, b) {
13500           b = b || [0, 0];
13501           var x = a[0] - b[0];
13502           var y = a[1] - b[1];
13503           return x * x + y * y;
13504         } // get a unit vector
13505
13506         function geoVecNormalize(a) {
13507           var length = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
13508
13509           if (length !== 0) {
13510             return geoVecScale(a, 1 / length);
13511           }
13512
13513           return [0, 0];
13514         } // Return the counterclockwise angle in the range (-pi, pi)
13515         // between the positive X axis and the line intersecting a and b.
13516
13517         function geoVecAngle(a, b) {
13518           return Math.atan2(b[1] - a[1], b[0] - a[0]);
13519         } // dot product
13520
13521         function geoVecDot(a, b, origin) {
13522           origin = origin || [0, 0];
13523           var p = geoVecSubtract(a, origin);
13524           var q = geoVecSubtract(b, origin);
13525           return p[0] * q[0] + p[1] * q[1];
13526         } // normalized dot product
13527
13528         function geoVecNormalizedDot(a, b, origin) {
13529           origin = origin || [0, 0];
13530           var p = geoVecNormalize(geoVecSubtract(a, origin));
13531           var q = geoVecNormalize(geoVecSubtract(b, origin));
13532           return geoVecDot(p, q);
13533         } // 2D cross product of OA and OB vectors, returns magnitude of Z vector
13534         // Returns a positive value, if OAB makes a counter-clockwise turn,
13535         // negative for clockwise turn, and zero if the points are collinear.
13536
13537         function geoVecCross(a, b, origin) {
13538           origin = origin || [0, 0];
13539           var p = geoVecSubtract(a, origin);
13540           var q = geoVecSubtract(b, origin);
13541           return p[0] * q[1] - p[1] * q[0];
13542         } // find closest orthogonal projection of point onto points array
13543
13544         function geoVecProject(a, points) {
13545           var min = Infinity;
13546           var idx;
13547           var target;
13548
13549           for (var i = 0; i < points.length - 1; i++) {
13550             var o = points[i];
13551             var s = geoVecSubtract(points[i + 1], o);
13552             var v = geoVecSubtract(a, o);
13553             var proj = geoVecDot(v, s) / geoVecDot(s, s);
13554             var p;
13555
13556             if (proj < 0) {
13557               p = o;
13558             } else if (proj > 1) {
13559               p = points[i + 1];
13560             } else {
13561               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
13562             }
13563
13564             var dist = geoVecLength(p, a);
13565
13566             if (dist < min) {
13567               min = dist;
13568               idx = i + 1;
13569               target = p;
13570             }
13571           }
13572
13573           if (idx !== undefined) {
13574             return {
13575               index: idx,
13576               distance: min,
13577               target: target
13578             };
13579           } else {
13580             return null;
13581           }
13582         }
13583
13584         // between the positive X axis and the line intersecting a and b.
13585
13586         function geoAngle(a, b, projection) {
13587           return geoVecAngle(projection(a.loc), projection(b.loc));
13588         }
13589         function geoEdgeEqual(a, b) {
13590           return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
13591         } // Rotate all points counterclockwise around a pivot point by given angle
13592
13593         function geoRotate(points, angle, around) {
13594           return points.map(function (point) {
13595             var radial = geoVecSubtract(point, around);
13596             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]];
13597           });
13598         } // Choose the edge with the minimal distance from `point` to its orthogonal
13599         // projection onto that edge, if such a projection exists, or the distance to
13600         // the closest vertex on that edge. Returns an object with the `index` of the
13601         // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
13602
13603         function geoChooseEdge(nodes, point, projection, activeID) {
13604           var dist = geoVecLength;
13605           var points = nodes.map(function (n) {
13606             return projection(n.loc);
13607           });
13608           var ids = nodes.map(function (n) {
13609             return n.id;
13610           });
13611           var min = Infinity;
13612           var idx;
13613           var loc;
13614
13615           for (var i = 0; i < points.length - 1; i++) {
13616             if (ids[i] === activeID || ids[i + 1] === activeID) continue;
13617             var o = points[i];
13618             var s = geoVecSubtract(points[i + 1], o);
13619             var v = geoVecSubtract(point, o);
13620             var proj = geoVecDot(v, s) / geoVecDot(s, s);
13621             var p;
13622
13623             if (proj < 0) {
13624               p = o;
13625             } else if (proj > 1) {
13626               p = points[i + 1];
13627             } else {
13628               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
13629             }
13630
13631             var d = dist(p, point);
13632
13633             if (d < min) {
13634               min = d;
13635               idx = i + 1;
13636               loc = projection.invert(p);
13637             }
13638           }
13639
13640           if (idx !== undefined) {
13641             return {
13642               index: idx,
13643               distance: min,
13644               loc: loc
13645             };
13646           } else {
13647             return null;
13648           }
13649         } // Test active (dragged or drawing) segments against inactive segments
13650         // This is used to test e.g. multipolygon rings that cross
13651         // `activeNodes` is the ring containing the activeID being dragged.
13652         // `inactiveNodes` is the other ring to test against
13653
13654         function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
13655           var actives = [];
13656           var inactives = [];
13657           var j, k, n1, n2, segment; // gather active segments (only segments in activeNodes that contain the activeID)
13658
13659           for (j = 0; j < activeNodes.length - 1; j++) {
13660             n1 = activeNodes[j];
13661             n2 = activeNodes[j + 1];
13662             segment = [n1.loc, n2.loc];
13663
13664             if (n1.id === activeID || n2.id === activeID) {
13665               actives.push(segment);
13666             }
13667           } // gather inactive segments
13668
13669
13670           for (j = 0; j < inactiveNodes.length - 1; j++) {
13671             n1 = inactiveNodes[j];
13672             n2 = inactiveNodes[j + 1];
13673             segment = [n1.loc, n2.loc];
13674             inactives.push(segment);
13675           } // test
13676
13677
13678           for (j = 0; j < actives.length; j++) {
13679             for (k = 0; k < inactives.length; k++) {
13680               var p = actives[j];
13681               var q = inactives[k];
13682               var hit = geoLineIntersection(p, q);
13683
13684               if (hit) {
13685                 return true;
13686               }
13687             }
13688           }
13689
13690           return false;
13691         } // Test active (dragged or drawing) segments against inactive segments
13692         // This is used to test whether a way intersects with itself.
13693
13694         function geoHasSelfIntersections(nodes, activeID) {
13695           var actives = [];
13696           var inactives = [];
13697           var j, k; // group active and passive segments along the nodes
13698
13699           for (j = 0; j < nodes.length - 1; j++) {
13700             var n1 = nodes[j];
13701             var n2 = nodes[j + 1];
13702             var segment = [n1.loc, n2.loc];
13703
13704             if (n1.id === activeID || n2.id === activeID) {
13705               actives.push(segment);
13706             } else {
13707               inactives.push(segment);
13708             }
13709           } // test
13710
13711
13712           for (j = 0; j < actives.length; j++) {
13713             for (k = 0; k < inactives.length; k++) {
13714               var p = actives[j];
13715               var q = inactives[k]; // skip if segments share an endpoint
13716
13717               if (geoVecEqual(p[1], q[0]) || geoVecEqual(p[0], q[1]) || geoVecEqual(p[0], q[0]) || geoVecEqual(p[1], q[1])) {
13718                 continue;
13719               }
13720
13721               var hit = geoLineIntersection(p, q);
13722
13723               if (hit) {
13724                 var epsilon = 1e-8; // skip if the hit is at the segment's endpoint
13725
13726                 if (geoVecEqual(p[1], hit, epsilon) || geoVecEqual(p[0], hit, epsilon) || geoVecEqual(q[1], hit, epsilon) || geoVecEqual(q[0], hit, epsilon)) {
13727                   continue;
13728                 } else {
13729                   return true;
13730                 }
13731               }
13732             }
13733           }
13734
13735           return false;
13736         } // Return the intersection point of 2 line segments.
13737         // From https://github.com/pgkelley4/line-segments-intersect
13738         // This uses the vector cross product approach described below:
13739         //  http://stackoverflow.com/a/565282/786339
13740
13741         function geoLineIntersection(a, b) {
13742           var p = [a[0][0], a[0][1]];
13743           var p2 = [a[1][0], a[1][1]];
13744           var q = [b[0][0], b[0][1]];
13745           var q2 = [b[1][0], b[1][1]];
13746           var r = geoVecSubtract(p2, p);
13747           var s = geoVecSubtract(q2, q);
13748           var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
13749           var denominator = geoVecCross(r, s);
13750
13751           if (uNumerator && denominator) {
13752             var u = uNumerator / denominator;
13753             var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
13754
13755             if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
13756               return geoVecInterp(p, p2, t);
13757             }
13758           }
13759
13760           return null;
13761         }
13762         function geoPathIntersections(path1, path2) {
13763           var intersections = [];
13764
13765           for (var i = 0; i < path1.length - 1; i++) {
13766             for (var j = 0; j < path2.length - 1; j++) {
13767               var a = [path1[i], path1[i + 1]];
13768               var b = [path2[j], path2[j + 1]];
13769               var hit = geoLineIntersection(a, b);
13770
13771               if (hit) {
13772                 intersections.push(hit);
13773               }
13774             }
13775           }
13776
13777           return intersections;
13778         }
13779         function geoPathHasIntersections(path1, path2) {
13780           for (var i = 0; i < path1.length - 1; i++) {
13781             for (var j = 0; j < path2.length - 1; j++) {
13782               var a = [path1[i], path1[i + 1]];
13783               var b = [path2[j], path2[j + 1]];
13784               var hit = geoLineIntersection(a, b);
13785
13786               if (hit) {
13787                 return true;
13788               }
13789             }
13790           }
13791
13792           return false;
13793         } // Return whether point is contained in polygon.
13794         //
13795         // `point` should be a 2-item array of coordinates.
13796         // `polygon` should be an array of 2-item arrays of coordinates.
13797         //
13798         // From https://github.com/substack/point-in-polygon.
13799         // ray-casting algorithm based on
13800         // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
13801         //
13802
13803         function geoPointInPolygon(point, polygon) {
13804           var x = point[0];
13805           var y = point[1];
13806           var inside = false;
13807
13808           for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
13809             var xi = polygon[i][0];
13810             var yi = polygon[i][1];
13811             var xj = polygon[j][0];
13812             var yj = polygon[j][1];
13813             var intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
13814             if (intersect) inside = !inside;
13815           }
13816
13817           return inside;
13818         }
13819         function geoPolygonContainsPolygon(outer, inner) {
13820           return inner.every(function (point) {
13821             return geoPointInPolygon(point, outer);
13822           });
13823         }
13824         function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
13825           function testPoints(outer, inner) {
13826             return inner.some(function (point) {
13827               return geoPointInPolygon(point, outer);
13828             });
13829           }
13830
13831           return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
13832         } // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
13833         // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
13834
13835         function geoGetSmallestSurroundingRectangle(points) {
13836           var hull = d3_polygonHull(points);
13837           var centroid = d3_polygonCentroid(hull);
13838           var minArea = Infinity;
13839           var ssrExtent = [];
13840           var ssrAngle = 0;
13841           var c1 = hull[0];
13842
13843           for (var i = 0; i <= hull.length - 1; i++) {
13844             var c2 = i === hull.length - 1 ? hull[0] : hull[i + 1];
13845             var angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
13846             var poly = geoRotate(hull, -angle, centroid);
13847             var extent = poly.reduce(function (extent, point) {
13848               return extent.extend(geoExtent(point));
13849             }, geoExtent());
13850             var area = extent.area();
13851
13852             if (area < minArea) {
13853               minArea = area;
13854               ssrExtent = extent;
13855               ssrAngle = angle;
13856             }
13857
13858             c1 = c2;
13859           }
13860
13861           return {
13862             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
13863             angle: ssrAngle
13864           };
13865         }
13866         function geoPathLength(path) {
13867           var length = 0;
13868
13869           for (var i = 0; i < path.length - 1; i++) {
13870             length += geoVecLength(path[i], path[i + 1]);
13871           }
13872
13873           return length;
13874         } // If the given point is at the edge of the padded viewport,
13875         // return a vector that will nudge the viewport in that direction
13876
13877         function geoViewportEdge(point, dimensions) {
13878           var pad = [80, 20, 50, 20]; // top, right, bottom, left
13879
13880           var x = 0;
13881           var y = 0;
13882
13883           if (point[0] > dimensions[0] - pad[1]) {
13884             x = -10;
13885           }
13886
13887           if (point[0] < pad[3]) {
13888             x = 10;
13889           }
13890
13891           if (point[1] > dimensions[1] - pad[2]) {
13892             y = -10;
13893           }
13894
13895           if (point[1] < pad[0]) {
13896             y = 10;
13897           }
13898
13899           if (x || y) {
13900             return [x, y];
13901           } else {
13902             return null;
13903           }
13904         }
13905
13906         var noop = {
13907           value: function value() {}
13908         };
13909
13910         function dispatch$8() {
13911           for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
13912             if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
13913             _[t] = [];
13914           }
13915
13916           return new Dispatch(_);
13917         }
13918
13919         function Dispatch(_) {
13920           this._ = _;
13921         }
13922
13923         function parseTypenames$1(typenames, types) {
13924           return typenames.trim().split(/^|\s+/).map(function (t) {
13925             var name = "",
13926                 i = t.indexOf(".");
13927             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13928             if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
13929             return {
13930               type: t,
13931               name: name
13932             };
13933           });
13934         }
13935
13936         Dispatch.prototype = dispatch$8.prototype = {
13937           constructor: Dispatch,
13938           on: function on(typename, callback) {
13939             var _ = this._,
13940                 T = parseTypenames$1(typename + "", _),
13941                 t,
13942                 i = -1,
13943                 n = T.length; // If no callback was specified, return the callback of the given type and name.
13944
13945             if (arguments.length < 2) {
13946               while (++i < n) {
13947                 if ((t = (typename = T[i]).type) && (t = get$2(_[t], typename.name))) return t;
13948               }
13949
13950               return;
13951             } // If a type was specified, set the callback for the given type and name.
13952             // Otherwise, if a null callback was specified, remove callbacks of the given name.
13953
13954
13955             if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
13956
13957             while (++i < n) {
13958               if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);else if (callback == null) for (t in _) {
13959                 _[t] = set$1(_[t], typename.name, null);
13960               }
13961             }
13962
13963             return this;
13964           },
13965           copy: function copy() {
13966             var copy = {},
13967                 _ = this._;
13968
13969             for (var t in _) {
13970               copy[t] = _[t].slice();
13971             }
13972
13973             return new Dispatch(copy);
13974           },
13975           call: function call(type, that) {
13976             if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) {
13977               args[i] = arguments[i + 2];
13978             }
13979             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13980
13981             for (t = this._[type], i = 0, n = t.length; i < n; ++i) {
13982               t[i].value.apply(that, args);
13983             }
13984           },
13985           apply: function apply(type, that, args) {
13986             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13987
13988             for (var t = this._[type], i = 0, n = t.length; i < n; ++i) {
13989               t[i].value.apply(that, args);
13990             }
13991           }
13992         };
13993
13994         function get$2(type, name) {
13995           for (var i = 0, n = type.length, c; i < n; ++i) {
13996             if ((c = type[i]).name === name) {
13997               return c.value;
13998             }
13999           }
14000         }
14001
14002         function set$1(type, name, callback) {
14003           for (var i = 0, n = type.length; i < n; ++i) {
14004             if (type[i].name === name) {
14005               type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
14006               break;
14007             }
14008           }
14009
14010           if (callback != null) type.push({
14011             name: name,
14012             value: callback
14013           });
14014           return type;
14015         }
14016
14017         var xhtml = "http://www.w3.org/1999/xhtml";
14018         var namespaces = {
14019           svg: "http://www.w3.org/2000/svg",
14020           xhtml: xhtml,
14021           xlink: "http://www.w3.org/1999/xlink",
14022           xml: "http://www.w3.org/XML/1998/namespace",
14023           xmlns: "http://www.w3.org/2000/xmlns/"
14024         };
14025
14026         function namespace (name) {
14027           var prefix = name += "",
14028               i = prefix.indexOf(":");
14029           if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
14030           return namespaces.hasOwnProperty(prefix) ? {
14031             space: namespaces[prefix],
14032             local: name
14033           } : name; // eslint-disable-line no-prototype-builtins
14034         }
14035
14036         function creatorInherit(name) {
14037           return function () {
14038             var document = this.ownerDocument,
14039                 uri = this.namespaceURI;
14040             return uri === xhtml && document.documentElement.namespaceURI === xhtml ? document.createElement(name) : document.createElementNS(uri, name);
14041           };
14042         }
14043
14044         function creatorFixed(fullname) {
14045           return function () {
14046             return this.ownerDocument.createElementNS(fullname.space, fullname.local);
14047           };
14048         }
14049
14050         function creator (name) {
14051           var fullname = namespace(name);
14052           return (fullname.local ? creatorFixed : creatorInherit)(fullname);
14053         }
14054
14055         function none() {}
14056
14057         function selector (selector) {
14058           return selector == null ? none : function () {
14059             return this.querySelector(selector);
14060           };
14061         }
14062
14063         function selection_select (select) {
14064           if (typeof select !== "function") select = selector(select);
14065
14066           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
14067             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
14068               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
14069                 if ("__data__" in node) subnode.__data__ = node.__data__;
14070                 subgroup[i] = subnode;
14071               }
14072             }
14073           }
14074
14075           return new Selection$1(subgroups, this._parents);
14076         }
14077
14078         function array (x) {
14079           return _typeof(x) === "object" && "length" in x ? x // Array, TypedArray, NodeList, array-like
14080           : Array.from(x); // Map, Set, iterable, string, or anything else
14081         }
14082
14083         function empty() {
14084           return [];
14085         }
14086
14087         function selectorAll (selector) {
14088           return selector == null ? empty : function () {
14089             return this.querySelectorAll(selector);
14090           };
14091         }
14092
14093         function arrayAll(select) {
14094           return function () {
14095             var group = select.apply(this, arguments);
14096             return group == null ? [] : array(group);
14097           };
14098         }
14099
14100         function selection_selectAll (select) {
14101           if (typeof select === "function") select = arrayAll(select);else select = selectorAll(select);
14102
14103           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
14104             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
14105               if (node = group[i]) {
14106                 subgroups.push(select.call(node, node.__data__, i, group));
14107                 parents.push(node);
14108               }
14109             }
14110           }
14111
14112           return new Selection$1(subgroups, parents);
14113         }
14114
14115         var $$n = _export;
14116         var $find = arrayIteration.find;
14117         var addToUnscopables$2 = addToUnscopables$5;
14118
14119         var FIND = 'find';
14120         var SKIPS_HOLES$1 = true;
14121
14122         // Shouldn't skip holes
14123         if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES$1 = false; });
14124
14125         // `Array.prototype.find` method
14126         // https://tc39.es/ecma262/#sec-array.prototype.find
14127         $$n({ target: 'Array', proto: true, forced: SKIPS_HOLES$1 }, {
14128           find: function find(callbackfn /* , that = undefined */) {
14129             return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
14130           }
14131         });
14132
14133         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
14134         addToUnscopables$2(FIND);
14135
14136         function matcher (selector) {
14137           return function () {
14138             return this.matches(selector);
14139           };
14140         }
14141         function childMatcher(selector) {
14142           return function (node) {
14143             return node.matches(selector);
14144           };
14145         }
14146
14147         var find = Array.prototype.find;
14148
14149         function childFind(match) {
14150           return function () {
14151             return find.call(this.children, match);
14152           };
14153         }
14154
14155         function childFirst() {
14156           return this.firstElementChild;
14157         }
14158
14159         function selection_selectChild (match) {
14160           return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
14161         }
14162
14163         var filter = Array.prototype.filter;
14164
14165         function children() {
14166           return this.children;
14167         }
14168
14169         function childrenFilter(match) {
14170           return function () {
14171             return filter.call(this.children, match);
14172           };
14173         }
14174
14175         function selection_selectChildren (match) {
14176           return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
14177         }
14178
14179         function selection_filter (match) {
14180           if (typeof match !== "function") match = matcher(match);
14181
14182           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
14183             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
14184               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
14185                 subgroup.push(node);
14186               }
14187             }
14188           }
14189
14190           return new Selection$1(subgroups, this._parents);
14191         }
14192
14193         function sparse (update) {
14194           return new Array(update.length);
14195         }
14196
14197         function selection_enter () {
14198           return new Selection$1(this._enter || this._groups.map(sparse), this._parents);
14199         }
14200         function EnterNode(parent, datum) {
14201           this.ownerDocument = parent.ownerDocument;
14202           this.namespaceURI = parent.namespaceURI;
14203           this._next = null;
14204           this._parent = parent;
14205           this.__data__ = datum;
14206         }
14207         EnterNode.prototype = {
14208           constructor: EnterNode,
14209           appendChild: function appendChild(child) {
14210             return this._parent.insertBefore(child, this._next);
14211           },
14212           insertBefore: function insertBefore(child, next) {
14213             return this._parent.insertBefore(child, next);
14214           },
14215           querySelector: function querySelector(selector) {
14216             return this._parent.querySelector(selector);
14217           },
14218           querySelectorAll: function querySelectorAll(selector) {
14219             return this._parent.querySelectorAll(selector);
14220           }
14221         };
14222
14223         function constant$3 (x) {
14224           return function () {
14225             return x;
14226           };
14227         }
14228
14229         function bindIndex(parent, group, enter, update, exit, data) {
14230           var i = 0,
14231               node,
14232               groupLength = group.length,
14233               dataLength = data.length; // Put any non-null nodes that fit into update.
14234           // Put any null nodes into enter.
14235           // Put any remaining data into enter.
14236
14237           for (; i < dataLength; ++i) {
14238             if (node = group[i]) {
14239               node.__data__ = data[i];
14240               update[i] = node;
14241             } else {
14242               enter[i] = new EnterNode(parent, data[i]);
14243             }
14244           } // Put any non-null nodes that don’t fit into exit.
14245
14246
14247           for (; i < groupLength; ++i) {
14248             if (node = group[i]) {
14249               exit[i] = node;
14250             }
14251           }
14252         }
14253
14254         function bindKey(parent, group, enter, update, exit, data, key) {
14255           var i,
14256               node,
14257               nodeByKeyValue = new Map(),
14258               groupLength = group.length,
14259               dataLength = data.length,
14260               keyValues = new Array(groupLength),
14261               keyValue; // Compute the key for each node.
14262           // If multiple nodes have the same key, the duplicates are added to exit.
14263
14264           for (i = 0; i < groupLength; ++i) {
14265             if (node = group[i]) {
14266               keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
14267
14268               if (nodeByKeyValue.has(keyValue)) {
14269                 exit[i] = node;
14270               } else {
14271                 nodeByKeyValue.set(keyValue, node);
14272               }
14273             }
14274           } // Compute the key for each datum.
14275           // If there a node associated with this key, join and add it to update.
14276           // If there is not (or the key is a duplicate), add it to enter.
14277
14278
14279           for (i = 0; i < dataLength; ++i) {
14280             keyValue = key.call(parent, data[i], i, data) + "";
14281
14282             if (node = nodeByKeyValue.get(keyValue)) {
14283               update[i] = node;
14284               node.__data__ = data[i];
14285               nodeByKeyValue["delete"](keyValue);
14286             } else {
14287               enter[i] = new EnterNode(parent, data[i]);
14288             }
14289           } // Add any remaining nodes that were not bound to data to exit.
14290
14291
14292           for (i = 0; i < groupLength; ++i) {
14293             if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
14294               exit[i] = node;
14295             }
14296           }
14297         }
14298
14299         function datum(node) {
14300           return node.__data__;
14301         }
14302
14303         function selection_data (value, key) {
14304           if (!arguments.length) return Array.from(this, datum);
14305           var bind = key ? bindKey : bindIndex,
14306               parents = this._parents,
14307               groups = this._groups;
14308           if (typeof value !== "function") value = constant$3(value);
14309
14310           for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
14311             var parent = parents[j],
14312                 group = groups[j],
14313                 groupLength = group.length,
14314                 data = array(value.call(parent, parent && parent.__data__, j, parents)),
14315                 dataLength = data.length,
14316                 enterGroup = enter[j] = new Array(dataLength),
14317                 updateGroup = update[j] = new Array(dataLength),
14318                 exitGroup = exit[j] = new Array(groupLength);
14319             bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); // Now connect the enter nodes to their following update node, such that
14320             // appendChild can insert the materialized enter node before this node,
14321             // rather than at the end of the parent node.
14322
14323             for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
14324               if (previous = enterGroup[i0]) {
14325                 if (i0 >= i1) i1 = i0 + 1;
14326
14327                 while (!(next = updateGroup[i1]) && ++i1 < dataLength) {
14328                 }
14329
14330                 previous._next = next || null;
14331               }
14332             }
14333           }
14334
14335           update = new Selection$1(update, parents);
14336           update._enter = enter;
14337           update._exit = exit;
14338           return update;
14339         }
14340
14341         function selection_exit () {
14342           return new Selection$1(this._exit || this._groups.map(sparse), this._parents);
14343         }
14344
14345         function selection_join (onenter, onupdate, onexit) {
14346           var enter = this.enter(),
14347               update = this,
14348               exit = this.exit();
14349           enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
14350           if (onupdate != null) update = onupdate(update);
14351           if (onexit == null) exit.remove();else onexit(exit);
14352           return enter && update ? enter.merge(update).order() : update;
14353         }
14354
14355         function selection_merge (selection) {
14356           if (!(selection instanceof Selection$1)) throw new Error("invalid merge");
14357
14358           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) {
14359             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
14360               if (node = group0[i] || group1[i]) {
14361                 merge[i] = node;
14362               }
14363             }
14364           }
14365
14366           for (; j < m0; ++j) {
14367             merges[j] = groups0[j];
14368           }
14369
14370           return new Selection$1(merges, this._parents);
14371         }
14372
14373         function selection_order () {
14374           for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
14375             for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
14376               if (node = group[i]) {
14377                 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
14378                 next = node;
14379               }
14380             }
14381           }
14382
14383           return this;
14384         }
14385
14386         function selection_sort (compare) {
14387           if (!compare) compare = ascending;
14388
14389           function compareNode(a, b) {
14390             return a && b ? compare(a.__data__, b.__data__) : !a - !b;
14391           }
14392
14393           for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
14394             for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
14395               if (node = group[i]) {
14396                 sortgroup[i] = node;
14397               }
14398             }
14399
14400             sortgroup.sort(compareNode);
14401           }
14402
14403           return new Selection$1(sortgroups, this._parents).order();
14404         }
14405
14406         function ascending(a, b) {
14407           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
14408         }
14409
14410         function selection_call () {
14411           var callback = arguments[0];
14412           arguments[0] = this;
14413           callback.apply(null, arguments);
14414           return this;
14415         }
14416
14417         function selection_nodes () {
14418           return Array.from(this);
14419         }
14420
14421         function selection_node () {
14422           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
14423             for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
14424               var node = group[i];
14425               if (node) return node;
14426             }
14427           }
14428
14429           return null;
14430         }
14431
14432         function selection_size () {
14433           var size = 0;
14434
14435           var _iterator = _createForOfIteratorHelper(this),
14436               _step;
14437
14438           try {
14439             for (_iterator.s(); !(_step = _iterator.n()).done;) {
14440               var node = _step.value;
14441               ++size;
14442             } // eslint-disable-line no-unused-vars
14443
14444           } catch (err) {
14445             _iterator.e(err);
14446           } finally {
14447             _iterator.f();
14448           }
14449
14450           return size;
14451         }
14452
14453         function selection_empty () {
14454           return !this.node();
14455         }
14456
14457         function selection_each (callback) {
14458           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
14459             for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
14460               if (node = group[i]) callback.call(node, node.__data__, i, group);
14461             }
14462           }
14463
14464           return this;
14465         }
14466
14467         function attrRemove$1(name) {
14468           return function () {
14469             this.removeAttribute(name);
14470           };
14471         }
14472
14473         function attrRemoveNS$1(fullname) {
14474           return function () {
14475             this.removeAttributeNS(fullname.space, fullname.local);
14476           };
14477         }
14478
14479         function attrConstant$1(name, value) {
14480           return function () {
14481             this.setAttribute(name, value);
14482           };
14483         }
14484
14485         function attrConstantNS$1(fullname, value) {
14486           return function () {
14487             this.setAttributeNS(fullname.space, fullname.local, value);
14488           };
14489         }
14490
14491         function attrFunction$1(name, value) {
14492           return function () {
14493             var v = value.apply(this, arguments);
14494             if (v == null) this.removeAttribute(name);else this.setAttribute(name, v);
14495           };
14496         }
14497
14498         function attrFunctionNS$1(fullname, value) {
14499           return function () {
14500             var v = value.apply(this, arguments);
14501             if (v == null) this.removeAttributeNS(fullname.space, fullname.local);else this.setAttributeNS(fullname.space, fullname.local, v);
14502           };
14503         }
14504
14505         function selection_attr (name, value) {
14506           var fullname = namespace(name);
14507
14508           if (arguments.length < 2) {
14509             var node = this.node();
14510             return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
14511           }
14512
14513           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));
14514         }
14515
14516         function defaultView (node) {
14517           return node.ownerDocument && node.ownerDocument.defaultView || // node is a Node
14518           node.document && node // node is a Window
14519           || node.defaultView; // node is a Document
14520         }
14521
14522         function styleRemove$1(name) {
14523           return function () {
14524             this.style.removeProperty(name);
14525           };
14526         }
14527
14528         function styleConstant$1(name, value, priority) {
14529           return function () {
14530             this.style.setProperty(name, value, priority);
14531           };
14532         }
14533
14534         function styleFunction$1(name, value, priority) {
14535           return function () {
14536             var v = value.apply(this, arguments);
14537             if (v == null) this.style.removeProperty(name);else this.style.setProperty(name, v, priority);
14538           };
14539         }
14540
14541         function selection_style (name, value, priority) {
14542           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);
14543         }
14544         function styleValue(node, name) {
14545           return node.style.getPropertyValue(name) || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
14546         }
14547
14548         function propertyRemove(name) {
14549           return function () {
14550             delete this[name];
14551           };
14552         }
14553
14554         function propertyConstant(name, value) {
14555           return function () {
14556             this[name] = value;
14557           };
14558         }
14559
14560         function propertyFunction(name, value) {
14561           return function () {
14562             var v = value.apply(this, arguments);
14563             if (v == null) delete this[name];else this[name] = v;
14564           };
14565         }
14566
14567         function selection_property (name, value) {
14568           return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
14569         }
14570
14571         function classArray(string) {
14572           return string.trim().split(/^|\s+/);
14573         }
14574
14575         function classList(node) {
14576           return node.classList || new ClassList(node);
14577         }
14578
14579         function ClassList(node) {
14580           this._node = node;
14581           this._names = classArray(node.getAttribute("class") || "");
14582         }
14583
14584         ClassList.prototype = {
14585           add: function add(name) {
14586             var i = this._names.indexOf(name);
14587
14588             if (i < 0) {
14589               this._names.push(name);
14590
14591               this._node.setAttribute("class", this._names.join(" "));
14592             }
14593           },
14594           remove: function remove(name) {
14595             var i = this._names.indexOf(name);
14596
14597             if (i >= 0) {
14598               this._names.splice(i, 1);
14599
14600               this._node.setAttribute("class", this._names.join(" "));
14601             }
14602           },
14603           contains: function contains(name) {
14604             return this._names.indexOf(name) >= 0;
14605           }
14606         };
14607
14608         function classedAdd(node, names) {
14609           var list = classList(node),
14610               i = -1,
14611               n = names.length;
14612
14613           while (++i < n) {
14614             list.add(names[i]);
14615           }
14616         }
14617
14618         function classedRemove(node, names) {
14619           var list = classList(node),
14620               i = -1,
14621               n = names.length;
14622
14623           while (++i < n) {
14624             list.remove(names[i]);
14625           }
14626         }
14627
14628         function classedTrue(names) {
14629           return function () {
14630             classedAdd(this, names);
14631           };
14632         }
14633
14634         function classedFalse(names) {
14635           return function () {
14636             classedRemove(this, names);
14637           };
14638         }
14639
14640         function classedFunction(names, value) {
14641           return function () {
14642             (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
14643           };
14644         }
14645
14646         function selection_classed (name, value) {
14647           var names = classArray(name + "");
14648
14649           if (arguments.length < 2) {
14650             var list = classList(this.node()),
14651                 i = -1,
14652                 n = names.length;
14653
14654             while (++i < n) {
14655               if (!list.contains(names[i])) return false;
14656             }
14657
14658             return true;
14659           }
14660
14661           return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
14662         }
14663
14664         function textRemove() {
14665           this.textContent = "";
14666         }
14667
14668         function textConstant$1(value) {
14669           return function () {
14670             this.textContent = value;
14671           };
14672         }
14673
14674         function textFunction$1(value) {
14675           return function () {
14676             var v = value.apply(this, arguments);
14677             this.textContent = v == null ? "" : v;
14678           };
14679         }
14680
14681         function selection_text (value) {
14682           return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction$1 : textConstant$1)(value)) : this.node().textContent;
14683         }
14684
14685         function htmlRemove() {
14686           this.innerHTML = "";
14687         }
14688
14689         function htmlConstant(value) {
14690           return function () {
14691             this.innerHTML = value;
14692           };
14693         }
14694
14695         function htmlFunction(value) {
14696           return function () {
14697             var v = value.apply(this, arguments);
14698             this.innerHTML = v == null ? "" : v;
14699           };
14700         }
14701
14702         function selection_html (value) {
14703           return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
14704         }
14705
14706         function raise() {
14707           if (this.nextSibling) this.parentNode.appendChild(this);
14708         }
14709
14710         function selection_raise () {
14711           return this.each(raise);
14712         }
14713
14714         function lower() {
14715           if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
14716         }
14717
14718         function selection_lower () {
14719           return this.each(lower);
14720         }
14721
14722         function selection_append (name) {
14723           var create = typeof name === "function" ? name : creator(name);
14724           return this.select(function () {
14725             return this.appendChild(create.apply(this, arguments));
14726           });
14727         }
14728
14729         function constantNull() {
14730           return null;
14731         }
14732
14733         function selection_insert (name, before) {
14734           var create = typeof name === "function" ? name : creator(name),
14735               select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
14736           return this.select(function () {
14737             return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
14738           });
14739         }
14740
14741         function remove$7() {
14742           var parent = this.parentNode;
14743           if (parent) parent.removeChild(this);
14744         }
14745
14746         function selection_remove () {
14747           return this.each(remove$7);
14748         }
14749
14750         function selection_cloneShallow() {
14751           var clone = this.cloneNode(false),
14752               parent = this.parentNode;
14753           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
14754         }
14755
14756         function selection_cloneDeep() {
14757           var clone = this.cloneNode(true),
14758               parent = this.parentNode;
14759           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
14760         }
14761
14762         function selection_clone (deep) {
14763           return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
14764         }
14765
14766         function selection_datum (value) {
14767           return arguments.length ? this.property("__data__", value) : this.node().__data__;
14768         }
14769
14770         function contextListener(listener) {
14771           return function (event) {
14772             listener.call(this, event, this.__data__);
14773           };
14774         }
14775
14776         function parseTypenames(typenames) {
14777           return typenames.trim().split(/^|\s+/).map(function (t) {
14778             var name = "",
14779                 i = t.indexOf(".");
14780             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
14781             return {
14782               type: t,
14783               name: name
14784             };
14785           });
14786         }
14787
14788         function onRemove(typename) {
14789           return function () {
14790             var on = this.__on;
14791             if (!on) return;
14792
14793             for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
14794               if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
14795                 this.removeEventListener(o.type, o.listener, o.options);
14796               } else {
14797                 on[++i] = o;
14798               }
14799             }
14800
14801             if (++i) on.length = i;else delete this.__on;
14802           };
14803         }
14804
14805         function onAdd(typename, value, options) {
14806           return function () {
14807             var on = this.__on,
14808                 o,
14809                 listener = contextListener(value);
14810             if (on) for (var j = 0, m = on.length; j < m; ++j) {
14811               if ((o = on[j]).type === typename.type && o.name === typename.name) {
14812                 this.removeEventListener(o.type, o.listener, o.options);
14813                 this.addEventListener(o.type, o.listener = listener, o.options = options);
14814                 o.value = value;
14815                 return;
14816               }
14817             }
14818             this.addEventListener(typename.type, listener, options);
14819             o = {
14820               type: typename.type,
14821               name: typename.name,
14822               value: value,
14823               listener: listener,
14824               options: options
14825             };
14826             if (!on) this.__on = [o];else on.push(o);
14827           };
14828         }
14829
14830         function selection_on (typename, value, options) {
14831           var typenames = parseTypenames(typename + ""),
14832               i,
14833               n = typenames.length,
14834               t;
14835
14836           if (arguments.length < 2) {
14837             var on = this.node().__on;
14838
14839             if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
14840               for (i = 0, o = on[j]; i < n; ++i) {
14841                 if ((t = typenames[i]).type === o.type && t.name === o.name) {
14842                   return o.value;
14843                 }
14844               }
14845             }
14846             return;
14847           }
14848
14849           on = value ? onAdd : onRemove;
14850
14851           for (i = 0; i < n; ++i) {
14852             this.each(on(typenames[i], value, options));
14853           }
14854
14855           return this;
14856         }
14857
14858         function dispatchEvent(node, type, params) {
14859           var window = defaultView(node),
14860               event = window.CustomEvent;
14861
14862           if (typeof event === "function") {
14863             event = new event(type, params);
14864           } else {
14865             event = window.document.createEvent("Event");
14866             if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;else event.initEvent(type, false, false);
14867           }
14868
14869           node.dispatchEvent(event);
14870         }
14871
14872         function dispatchConstant(type, params) {
14873           return function () {
14874             return dispatchEvent(this, type, params);
14875           };
14876         }
14877
14878         function dispatchFunction(type, params) {
14879           return function () {
14880             return dispatchEvent(this, type, params.apply(this, arguments));
14881           };
14882         }
14883
14884         function selection_dispatch (type, params) {
14885           return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
14886         }
14887
14888         var _marked$1 = /*#__PURE__*/regeneratorRuntime.mark(_callee);
14889
14890         function _callee() {
14891           var groups, j, m, group, i, n, node;
14892           return regeneratorRuntime.wrap(function _callee$(_context) {
14893             while (1) {
14894               switch (_context.prev = _context.next) {
14895                 case 0:
14896                   groups = this._groups, j = 0, m = groups.length;
14897
14898                 case 1:
14899                   if (!(j < m)) {
14900                     _context.next = 13;
14901                     break;
14902                   }
14903
14904                   group = groups[j], i = 0, n = group.length;
14905
14906                 case 3:
14907                   if (!(i < n)) {
14908                     _context.next = 10;
14909                     break;
14910                   }
14911
14912                   if (!(node = group[i])) {
14913                     _context.next = 7;
14914                     break;
14915                   }
14916
14917                   _context.next = 7;
14918                   return node;
14919
14920                 case 7:
14921                   ++i;
14922                   _context.next = 3;
14923                   break;
14924
14925                 case 10:
14926                   ++j;
14927                   _context.next = 1;
14928                   break;
14929
14930                 case 13:
14931                 case "end":
14932                   return _context.stop();
14933               }
14934             }
14935           }, _marked$1, this);
14936         }
14937
14938         var root$1 = [null];
14939         function Selection$1(groups, parents) {
14940           this._groups = groups;
14941           this._parents = parents;
14942         }
14943
14944         function selection() {
14945           return new Selection$1([[document.documentElement]], root$1);
14946         }
14947
14948         function selection_selection() {
14949           return this;
14950         }
14951
14952         Selection$1.prototype = selection.prototype = _defineProperty({
14953           constructor: Selection$1,
14954           select: selection_select,
14955           selectAll: selection_selectAll,
14956           selectChild: selection_selectChild,
14957           selectChildren: selection_selectChildren,
14958           filter: selection_filter,
14959           data: selection_data,
14960           enter: selection_enter,
14961           exit: selection_exit,
14962           join: selection_join,
14963           merge: selection_merge,
14964           selection: selection_selection,
14965           order: selection_order,
14966           sort: selection_sort,
14967           call: selection_call,
14968           nodes: selection_nodes,
14969           node: selection_node,
14970           size: selection_size,
14971           empty: selection_empty,
14972           each: selection_each,
14973           attr: selection_attr,
14974           style: selection_style,
14975           property: selection_property,
14976           classed: selection_classed,
14977           text: selection_text,
14978           html: selection_html,
14979           raise: selection_raise,
14980           lower: selection_lower,
14981           append: selection_append,
14982           insert: selection_insert,
14983           remove: selection_remove,
14984           clone: selection_clone,
14985           datum: selection_datum,
14986           on: selection_on,
14987           dispatch: selection_dispatch
14988         }, Symbol.iterator, _callee);
14989
14990         function select (selector) {
14991           return typeof selector === "string" ? new Selection$1([[document.querySelector(selector)]], [document.documentElement]) : new Selection$1([[selector]], root$1);
14992         }
14993
14994         function sourceEvent (event) {
14995           var sourceEvent;
14996
14997           while (sourceEvent = event.sourceEvent) {
14998             event = sourceEvent;
14999           }
15000
15001           return event;
15002         }
15003
15004         function pointer (event, node) {
15005           event = sourceEvent(event);
15006           if (node === undefined) node = event.currentTarget;
15007
15008           if (node) {
15009             var svg = node.ownerSVGElement || node;
15010
15011             if (svg.createSVGPoint) {
15012               var point = svg.createSVGPoint();
15013               point.x = event.clientX, point.y = event.clientY;
15014               point = point.matrixTransform(node.getScreenCTM().inverse());
15015               return [point.x, point.y];
15016             }
15017
15018             if (node.getBoundingClientRect) {
15019               var rect = node.getBoundingClientRect();
15020               return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
15021             }
15022           }
15023
15024           return [event.pageX, event.pageY];
15025         }
15026
15027         function selectAll (selector) {
15028           return typeof selector === "string" ? new Selection$1([document.querySelectorAll(selector)], [document.documentElement]) : new Selection$1([selector == null ? [] : array(selector)], root$1);
15029         }
15030
15031         function nopropagation$1(event) {
15032           event.stopImmediatePropagation();
15033         }
15034         function noevent$1 (event) {
15035           event.preventDefault();
15036           event.stopImmediatePropagation();
15037         }
15038
15039         function dragDisable (view) {
15040           var root = view.document.documentElement,
15041               selection = select(view).on("dragstart.drag", noevent$1, true);
15042
15043           if ("onselectstart" in root) {
15044             selection.on("selectstart.drag", noevent$1, true);
15045           } else {
15046             root.__noselect = root.style.MozUserSelect;
15047             root.style.MozUserSelect = "none";
15048           }
15049         }
15050         function yesdrag(view, noclick) {
15051           var root = view.document.documentElement,
15052               selection = select(view).on("dragstart.drag", null);
15053
15054           if (noclick) {
15055             selection.on("click.drag", noevent$1, true);
15056             setTimeout(function () {
15057               selection.on("click.drag", null);
15058             }, 0);
15059           }
15060
15061           if ("onselectstart" in root) {
15062             selection.on("selectstart.drag", null);
15063           } else {
15064             root.style.MozUserSelect = root.__noselect;
15065             delete root.__noselect;
15066           }
15067         }
15068
15069         var constant$2 = (function (x) {
15070           return function () {
15071             return x;
15072           };
15073         });
15074
15075         function DragEvent(type, _ref) {
15076           var sourceEvent = _ref.sourceEvent,
15077               subject = _ref.subject,
15078               target = _ref.target,
15079               identifier = _ref.identifier,
15080               active = _ref.active,
15081               x = _ref.x,
15082               y = _ref.y,
15083               dx = _ref.dx,
15084               dy = _ref.dy,
15085               dispatch = _ref.dispatch;
15086           Object.defineProperties(this, {
15087             type: {
15088               value: type,
15089               enumerable: true,
15090               configurable: true
15091             },
15092             sourceEvent: {
15093               value: sourceEvent,
15094               enumerable: true,
15095               configurable: true
15096             },
15097             subject: {
15098               value: subject,
15099               enumerable: true,
15100               configurable: true
15101             },
15102             target: {
15103               value: target,
15104               enumerable: true,
15105               configurable: true
15106             },
15107             identifier: {
15108               value: identifier,
15109               enumerable: true,
15110               configurable: true
15111             },
15112             active: {
15113               value: active,
15114               enumerable: true,
15115               configurable: true
15116             },
15117             x: {
15118               value: x,
15119               enumerable: true,
15120               configurable: true
15121             },
15122             y: {
15123               value: y,
15124               enumerable: true,
15125               configurable: true
15126             },
15127             dx: {
15128               value: dx,
15129               enumerable: true,
15130               configurable: true
15131             },
15132             dy: {
15133               value: dy,
15134               enumerable: true,
15135               configurable: true
15136             },
15137             _: {
15138               value: dispatch
15139             }
15140           });
15141         }
15142
15143         DragEvent.prototype.on = function () {
15144           var value = this._.on.apply(this._, arguments);
15145
15146           return value === this._ ? this : value;
15147         };
15148
15149         function defaultFilter$2(event) {
15150           return !event.ctrlKey && !event.button;
15151         }
15152
15153         function defaultContainer() {
15154           return this.parentNode;
15155         }
15156
15157         function defaultSubject(event, d) {
15158           return d == null ? {
15159             x: event.x,
15160             y: event.y
15161           } : d;
15162         }
15163
15164         function defaultTouchable$1() {
15165           return navigator.maxTouchPoints || "ontouchstart" in this;
15166         }
15167
15168         function d3_drag () {
15169           var filter = defaultFilter$2,
15170               container = defaultContainer,
15171               subject = defaultSubject,
15172               touchable = defaultTouchable$1,
15173               gestures = {},
15174               listeners = dispatch$8("start", "drag", "end"),
15175               active = 0,
15176               mousedownx,
15177               mousedowny,
15178               mousemoving,
15179               touchending,
15180               clickDistance2 = 0;
15181
15182           function drag(selection) {
15183             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)");
15184           }
15185
15186           function mousedowned(event, d) {
15187             if (touchending || !filter.call(this, event, d)) return;
15188             var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
15189             if (!gesture) return;
15190             select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
15191             dragDisable(event.view);
15192             nopropagation$1(event);
15193             mousemoving = false;
15194             mousedownx = event.clientX;
15195             mousedowny = event.clientY;
15196             gesture("start", event);
15197           }
15198
15199           function mousemoved(event) {
15200             noevent$1(event);
15201
15202             if (!mousemoving) {
15203               var dx = event.clientX - mousedownx,
15204                   dy = event.clientY - mousedowny;
15205               mousemoving = dx * dx + dy * dy > clickDistance2;
15206             }
15207
15208             gestures.mouse("drag", event);
15209           }
15210
15211           function mouseupped(event) {
15212             select(event.view).on("mousemove.drag mouseup.drag", null);
15213             yesdrag(event.view, mousemoving);
15214             noevent$1(event);
15215             gestures.mouse("end", event);
15216           }
15217
15218           function touchstarted(event, d) {
15219             if (!filter.call(this, event, d)) return;
15220             var touches = event.changedTouches,
15221                 c = container.call(this, event, d),
15222                 n = touches.length,
15223                 i,
15224                 gesture;
15225
15226             for (i = 0; i < n; ++i) {
15227               if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
15228                 nopropagation$1(event);
15229                 gesture("start", event, touches[i]);
15230               }
15231             }
15232           }
15233
15234           function touchmoved(event) {
15235             var touches = event.changedTouches,
15236                 n = touches.length,
15237                 i,
15238                 gesture;
15239
15240             for (i = 0; i < n; ++i) {
15241               if (gesture = gestures[touches[i].identifier]) {
15242                 noevent$1(event);
15243                 gesture("drag", event, touches[i]);
15244               }
15245             }
15246           }
15247
15248           function touchended(event) {
15249             var touches = event.changedTouches,
15250                 n = touches.length,
15251                 i,
15252                 gesture;
15253             if (touchending) clearTimeout(touchending);
15254             touchending = setTimeout(function () {
15255               touchending = null;
15256             }, 500); // Ghost clicks are delayed!
15257
15258             for (i = 0; i < n; ++i) {
15259               if (gesture = gestures[touches[i].identifier]) {
15260                 nopropagation$1(event);
15261                 gesture("end", event, touches[i]);
15262               }
15263             }
15264           }
15265
15266           function beforestart(that, container, event, d, identifier, touch) {
15267             var dispatch = listeners.copy(),
15268                 p = pointer(touch || event, container),
15269                 dx,
15270                 dy,
15271                 s;
15272             if ((s = subject.call(that, new DragEvent("beforestart", {
15273               sourceEvent: event,
15274               target: drag,
15275               identifier: identifier,
15276               active: active,
15277               x: p[0],
15278               y: p[1],
15279               dx: 0,
15280               dy: 0,
15281               dispatch: dispatch
15282             }), d)) == null) return;
15283             dx = s.x - p[0] || 0;
15284             dy = s.y - p[1] || 0;
15285             return function gesture(type, event, touch) {
15286               var p0 = p,
15287                   n;
15288
15289               switch (type) {
15290                 case "start":
15291                   gestures[identifier] = gesture, n = active++;
15292                   break;
15293
15294                 case "end":
15295                   delete gestures[identifier], --active;
15296                 // nobreak
15297
15298                 case "drag":
15299                   p = pointer(touch || event, container), n = active;
15300                   break;
15301               }
15302
15303               dispatch.call(type, that, new DragEvent(type, {
15304                 sourceEvent: event,
15305                 subject: s,
15306                 target: drag,
15307                 identifier: identifier,
15308                 active: n,
15309                 x: p[0] + dx,
15310                 y: p[1] + dy,
15311                 dx: p[0] - p0[0],
15312                 dy: p[1] - p0[1],
15313                 dispatch: dispatch
15314               }), d);
15315             };
15316           }
15317
15318           drag.filter = function (_) {
15319             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
15320           };
15321
15322           drag.container = function (_) {
15323             return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
15324           };
15325
15326           drag.subject = function (_) {
15327             return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
15328           };
15329
15330           drag.touchable = function (_) {
15331             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$2(!!_), drag) : touchable;
15332           };
15333
15334           drag.on = function () {
15335             var value = listeners.on.apply(listeners, arguments);
15336             return value === listeners ? drag : value;
15337           };
15338
15339           drag.clickDistance = function (_) {
15340             return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
15341           };
15342
15343           return drag;
15344         }
15345
15346         var DESCRIPTORS$3 = descriptors;
15347         var global$3 = global$F;
15348         var isForced$1 = isForced_1;
15349         var inheritIfRequired$1 = inheritIfRequired$4;
15350         var createNonEnumerableProperty = createNonEnumerableProperty$e;
15351         var defineProperty$1 = objectDefineProperty.f;
15352         var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
15353         var isRegExp$1 = isRegexp;
15354         var getFlags = regexpFlags$1;
15355         var stickyHelpers = regexpStickyHelpers;
15356         var redefine$2 = redefine$g.exports;
15357         var fails$a = fails$N;
15358         var has$1 = has$j;
15359         var enforceInternalState = internalState.enforce;
15360         var setSpecies = setSpecies$5;
15361         var wellKnownSymbol$1 = wellKnownSymbol$s;
15362         var UNSUPPORTED_DOT_ALL = regexpUnsupportedDotAll;
15363         var UNSUPPORTED_NCG = regexpUnsupportedNcg;
15364
15365         var MATCH$1 = wellKnownSymbol$1('match');
15366         var NativeRegExp = global$3.RegExp;
15367         var RegExpPrototype = NativeRegExp.prototype;
15368         // TODO: Use only propper RegExpIdentifierName
15369         var IS_NCG = /^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/;
15370         var re1 = /a/g;
15371         var re2 = /a/g;
15372
15373         // "new" should create a new object, old webkit bug
15374         var CORRECT_NEW = new NativeRegExp(re1) !== re1;
15375
15376         var UNSUPPORTED_Y = stickyHelpers.UNSUPPORTED_Y;
15377
15378         var BASE_FORCED = DESCRIPTORS$3 &&
15379           (!CORRECT_NEW || UNSUPPORTED_Y || UNSUPPORTED_DOT_ALL || UNSUPPORTED_NCG || fails$a(function () {
15380             re2[MATCH$1] = false;
15381             // RegExp constructor can alter flags and IsRegExp works correct with @@match
15382             return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
15383           }));
15384
15385         var handleDotAll = function (string) {
15386           var length = string.length;
15387           var index = 0;
15388           var result = '';
15389           var brackets = false;
15390           var chr;
15391           for (; index <= length; index++) {
15392             chr = string.charAt(index);
15393             if (chr === '\\') {
15394               result += chr + string.charAt(++index);
15395               continue;
15396             }
15397             if (!brackets && chr === '.') {
15398               result += '[\\s\\S]';
15399             } else {
15400               if (chr === '[') {
15401                 brackets = true;
15402               } else if (chr === ']') {
15403                 brackets = false;
15404               } result += chr;
15405             }
15406           } return result;
15407         };
15408
15409         var handleNCG = function (string) {
15410           var length = string.length;
15411           var index = 0;
15412           var result = '';
15413           var named = [];
15414           var names = {};
15415           var brackets = false;
15416           var ncg = false;
15417           var groupid = 0;
15418           var groupname = '';
15419           var chr;
15420           for (; index <= length; index++) {
15421             chr = string.charAt(index);
15422             if (chr === '\\') {
15423               chr = chr + string.charAt(++index);
15424             } else if (chr === ']') {
15425               brackets = false;
15426             } else if (!brackets) switch (true) {
15427               case chr === '[':
15428                 brackets = true;
15429                 break;
15430               case chr === '(':
15431                 if (IS_NCG.test(string.slice(index + 1))) {
15432                   index += 2;
15433                   ncg = true;
15434                 }
15435                 result += chr;
15436                 groupid++;
15437                 continue;
15438               case chr === '>' && ncg:
15439                 if (groupname === '' || has$1(names, groupname)) {
15440                   throw new SyntaxError('Invalid capture group name');
15441                 }
15442                 names[groupname] = true;
15443                 named.push([groupname, groupid]);
15444                 ncg = false;
15445                 groupname = '';
15446                 continue;
15447             }
15448             if (ncg) groupname += chr;
15449             else result += chr;
15450           } return [result, named];
15451         };
15452
15453         // `RegExp` constructor
15454         // https://tc39.es/ecma262/#sec-regexp-constructor
15455         if (isForced$1('RegExp', BASE_FORCED)) {
15456           var RegExpWrapper = function RegExp(pattern, flags) {
15457             var thisIsRegExp = this instanceof RegExpWrapper;
15458             var patternIsRegExp = isRegExp$1(pattern);
15459             var flagsAreUndefined = flags === undefined;
15460             var groups = [];
15461             var rawPattern, rawFlags, dotAll, sticky, handled, result, state;
15462
15463             if (!thisIsRegExp && patternIsRegExp && pattern.constructor === RegExpWrapper && flagsAreUndefined) {
15464               return pattern;
15465             }
15466
15467             if (CORRECT_NEW) {
15468               if (patternIsRegExp && !flagsAreUndefined) pattern = pattern.source;
15469             } else if (pattern instanceof RegExpWrapper) {
15470               if (flagsAreUndefined) flags = getFlags.call(pattern);
15471               pattern = pattern.source;
15472             }
15473
15474             pattern = pattern === undefined ? '' : String(pattern);
15475             flags = flags === undefined ? '' : String(flags);
15476             rawPattern = pattern;
15477
15478             if (UNSUPPORTED_DOT_ALL && 'dotAll' in re1) {
15479               dotAll = !!flags && flags.indexOf('s') > -1;
15480               if (dotAll) flags = flags.replace(/s/g, '');
15481             }
15482
15483             rawFlags = flags;
15484
15485             if (UNSUPPORTED_Y && 'sticky' in re1) {
15486               sticky = !!flags && flags.indexOf('y') > -1;
15487               if (sticky) flags = flags.replace(/y/g, '');
15488             }
15489
15490             if (UNSUPPORTED_NCG) {
15491               handled = handleNCG(pattern);
15492               pattern = handled[0];
15493               groups = handled[1];
15494             }
15495
15496             result = inheritIfRequired$1(
15497               CORRECT_NEW ? new NativeRegExp(pattern, flags) : NativeRegExp(pattern, flags),
15498               thisIsRegExp ? this : RegExpPrototype,
15499               RegExpWrapper
15500             );
15501
15502             if (dotAll || sticky || groups.length) {
15503               state = enforceInternalState(result);
15504               if (dotAll) {
15505                 state.dotAll = true;
15506                 state.raw = RegExpWrapper(handleDotAll(pattern), rawFlags);
15507               }
15508               if (sticky) state.sticky = true;
15509               if (groups.length) state.groups = groups;
15510             }
15511
15512             if (pattern !== rawPattern) try {
15513               // fails in old engines, but we have no alternatives for unsupported regex syntax
15514               createNonEnumerableProperty(result, 'source', rawPattern === '' ? '(?:)' : rawPattern);
15515             } catch (error) { /* empty */ }
15516
15517             return result;
15518           };
15519
15520           var proxy = function (key) {
15521             key in RegExpWrapper || defineProperty$1(RegExpWrapper, key, {
15522               configurable: true,
15523               get: function () { return NativeRegExp[key]; },
15524               set: function (it) { NativeRegExp[key] = it; }
15525             });
15526           };
15527
15528           for (var keys$1 = getOwnPropertyNames$1(NativeRegExp), index$1 = 0; keys$1.length > index$1;) {
15529             proxy(keys$1[index$1++]);
15530           }
15531
15532           RegExpPrototype.constructor = RegExpWrapper;
15533           RegExpWrapper.prototype = RegExpPrototype;
15534           redefine$2(global$3, 'RegExp', RegExpWrapper);
15535         }
15536
15537         // https://tc39.es/ecma262/#sec-get-regexp-@@species
15538         setSpecies('RegExp');
15539
15540         function define (constructor, factory, prototype) {
15541           constructor.prototype = factory.prototype = prototype;
15542           prototype.constructor = constructor;
15543         }
15544         function extend$3(parent, definition) {
15545           var prototype = Object.create(parent.prototype);
15546
15547           for (var key in definition) {
15548             prototype[key] = definition[key];
15549           }
15550
15551           return prototype;
15552         }
15553
15554         function Color() {}
15555         var _darker = 0.7;
15556
15557         var _brighter = 1 / _darker;
15558         var reI = "\\s*([+-]?\\d+)\\s*",
15559             reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
15560             reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
15561             reHex = /^#([0-9a-f]{3,8})$/,
15562             reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
15563             reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
15564             reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
15565             reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
15566             reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
15567             reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
15568         var named = {
15569           aliceblue: 0xf0f8ff,
15570           antiquewhite: 0xfaebd7,
15571           aqua: 0x00ffff,
15572           aquamarine: 0x7fffd4,
15573           azure: 0xf0ffff,
15574           beige: 0xf5f5dc,
15575           bisque: 0xffe4c4,
15576           black: 0x000000,
15577           blanchedalmond: 0xffebcd,
15578           blue: 0x0000ff,
15579           blueviolet: 0x8a2be2,
15580           brown: 0xa52a2a,
15581           burlywood: 0xdeb887,
15582           cadetblue: 0x5f9ea0,
15583           chartreuse: 0x7fff00,
15584           chocolate: 0xd2691e,
15585           coral: 0xff7f50,
15586           cornflowerblue: 0x6495ed,
15587           cornsilk: 0xfff8dc,
15588           crimson: 0xdc143c,
15589           cyan: 0x00ffff,
15590           darkblue: 0x00008b,
15591           darkcyan: 0x008b8b,
15592           darkgoldenrod: 0xb8860b,
15593           darkgray: 0xa9a9a9,
15594           darkgreen: 0x006400,
15595           darkgrey: 0xa9a9a9,
15596           darkkhaki: 0xbdb76b,
15597           darkmagenta: 0x8b008b,
15598           darkolivegreen: 0x556b2f,
15599           darkorange: 0xff8c00,
15600           darkorchid: 0x9932cc,
15601           darkred: 0x8b0000,
15602           darksalmon: 0xe9967a,
15603           darkseagreen: 0x8fbc8f,
15604           darkslateblue: 0x483d8b,
15605           darkslategray: 0x2f4f4f,
15606           darkslategrey: 0x2f4f4f,
15607           darkturquoise: 0x00ced1,
15608           darkviolet: 0x9400d3,
15609           deeppink: 0xff1493,
15610           deepskyblue: 0x00bfff,
15611           dimgray: 0x696969,
15612           dimgrey: 0x696969,
15613           dodgerblue: 0x1e90ff,
15614           firebrick: 0xb22222,
15615           floralwhite: 0xfffaf0,
15616           forestgreen: 0x228b22,
15617           fuchsia: 0xff00ff,
15618           gainsboro: 0xdcdcdc,
15619           ghostwhite: 0xf8f8ff,
15620           gold: 0xffd700,
15621           goldenrod: 0xdaa520,
15622           gray: 0x808080,
15623           green: 0x008000,
15624           greenyellow: 0xadff2f,
15625           grey: 0x808080,
15626           honeydew: 0xf0fff0,
15627           hotpink: 0xff69b4,
15628           indianred: 0xcd5c5c,
15629           indigo: 0x4b0082,
15630           ivory: 0xfffff0,
15631           khaki: 0xf0e68c,
15632           lavender: 0xe6e6fa,
15633           lavenderblush: 0xfff0f5,
15634           lawngreen: 0x7cfc00,
15635           lemonchiffon: 0xfffacd,
15636           lightblue: 0xadd8e6,
15637           lightcoral: 0xf08080,
15638           lightcyan: 0xe0ffff,
15639           lightgoldenrodyellow: 0xfafad2,
15640           lightgray: 0xd3d3d3,
15641           lightgreen: 0x90ee90,
15642           lightgrey: 0xd3d3d3,
15643           lightpink: 0xffb6c1,
15644           lightsalmon: 0xffa07a,
15645           lightseagreen: 0x20b2aa,
15646           lightskyblue: 0x87cefa,
15647           lightslategray: 0x778899,
15648           lightslategrey: 0x778899,
15649           lightsteelblue: 0xb0c4de,
15650           lightyellow: 0xffffe0,
15651           lime: 0x00ff00,
15652           limegreen: 0x32cd32,
15653           linen: 0xfaf0e6,
15654           magenta: 0xff00ff,
15655           maroon: 0x800000,
15656           mediumaquamarine: 0x66cdaa,
15657           mediumblue: 0x0000cd,
15658           mediumorchid: 0xba55d3,
15659           mediumpurple: 0x9370db,
15660           mediumseagreen: 0x3cb371,
15661           mediumslateblue: 0x7b68ee,
15662           mediumspringgreen: 0x00fa9a,
15663           mediumturquoise: 0x48d1cc,
15664           mediumvioletred: 0xc71585,
15665           midnightblue: 0x191970,
15666           mintcream: 0xf5fffa,
15667           mistyrose: 0xffe4e1,
15668           moccasin: 0xffe4b5,
15669           navajowhite: 0xffdead,
15670           navy: 0x000080,
15671           oldlace: 0xfdf5e6,
15672           olive: 0x808000,
15673           olivedrab: 0x6b8e23,
15674           orange: 0xffa500,
15675           orangered: 0xff4500,
15676           orchid: 0xda70d6,
15677           palegoldenrod: 0xeee8aa,
15678           palegreen: 0x98fb98,
15679           paleturquoise: 0xafeeee,
15680           palevioletred: 0xdb7093,
15681           papayawhip: 0xffefd5,
15682           peachpuff: 0xffdab9,
15683           peru: 0xcd853f,
15684           pink: 0xffc0cb,
15685           plum: 0xdda0dd,
15686           powderblue: 0xb0e0e6,
15687           purple: 0x800080,
15688           rebeccapurple: 0x663399,
15689           red: 0xff0000,
15690           rosybrown: 0xbc8f8f,
15691           royalblue: 0x4169e1,
15692           saddlebrown: 0x8b4513,
15693           salmon: 0xfa8072,
15694           sandybrown: 0xf4a460,
15695           seagreen: 0x2e8b57,
15696           seashell: 0xfff5ee,
15697           sienna: 0xa0522d,
15698           silver: 0xc0c0c0,
15699           skyblue: 0x87ceeb,
15700           slateblue: 0x6a5acd,
15701           slategray: 0x708090,
15702           slategrey: 0x708090,
15703           snow: 0xfffafa,
15704           springgreen: 0x00ff7f,
15705           steelblue: 0x4682b4,
15706           tan: 0xd2b48c,
15707           teal: 0x008080,
15708           thistle: 0xd8bfd8,
15709           tomato: 0xff6347,
15710           turquoise: 0x40e0d0,
15711           violet: 0xee82ee,
15712           wheat: 0xf5deb3,
15713           white: 0xffffff,
15714           whitesmoke: 0xf5f5f5,
15715           yellow: 0xffff00,
15716           yellowgreen: 0x9acd32
15717         };
15718         define(Color, color, {
15719           copy: function copy(channels) {
15720             return Object.assign(new this.constructor(), this, channels);
15721           },
15722           displayable: function displayable() {
15723             return this.rgb().displayable();
15724           },
15725           hex: color_formatHex,
15726           // Deprecated! Use color.formatHex.
15727           formatHex: color_formatHex,
15728           formatHsl: color_formatHsl,
15729           formatRgb: color_formatRgb,
15730           toString: color_formatRgb
15731         });
15732
15733         function color_formatHex() {
15734           return this.rgb().formatHex();
15735         }
15736
15737         function color_formatHsl() {
15738           return hslConvert(this).formatHsl();
15739         }
15740
15741         function color_formatRgb() {
15742           return this.rgb().formatRgb();
15743         }
15744
15745         function color(format) {
15746           var m, l;
15747           format = (format + "").trim().toLowerCase();
15748           return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
15749           : l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
15750           : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
15751           : 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
15752           : null // invalid hex
15753           ) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
15754           : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
15755           : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
15756           : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
15757           : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
15758           : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
15759           : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
15760           : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
15761         }
15762
15763         function rgbn(n) {
15764           return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
15765         }
15766
15767         function rgba(r, g, b, a) {
15768           if (a <= 0) r = g = b = NaN;
15769           return new Rgb(r, g, b, a);
15770         }
15771
15772         function rgbConvert(o) {
15773           if (!(o instanceof Color)) o = color(o);
15774           if (!o) return new Rgb();
15775           o = o.rgb();
15776           return new Rgb(o.r, o.g, o.b, o.opacity);
15777         }
15778         function rgb(r, g, b, opacity) {
15779           return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
15780         }
15781         function Rgb(r, g, b, opacity) {
15782           this.r = +r;
15783           this.g = +g;
15784           this.b = +b;
15785           this.opacity = +opacity;
15786         }
15787         define(Rgb, rgb, extend$3(Color, {
15788           brighter: function brighter(k) {
15789             k = k == null ? _brighter : Math.pow(_brighter, k);
15790             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
15791           },
15792           darker: function darker(k) {
15793             k = k == null ? _darker : Math.pow(_darker, k);
15794             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
15795           },
15796           rgb: function rgb() {
15797             return this;
15798           },
15799           displayable: function displayable() {
15800             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;
15801           },
15802           hex: rgb_formatHex,
15803           // Deprecated! Use color.formatHex.
15804           formatHex: rgb_formatHex,
15805           formatRgb: rgb_formatRgb,
15806           toString: rgb_formatRgb
15807         }));
15808
15809         function rgb_formatHex() {
15810           return "#" + hex$1(this.r) + hex$1(this.g) + hex$1(this.b);
15811         }
15812
15813         function rgb_formatRgb() {
15814           var a = this.opacity;
15815           a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
15816           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 + ")");
15817         }
15818
15819         function hex$1(value) {
15820           value = Math.max(0, Math.min(255, Math.round(value) || 0));
15821           return (value < 16 ? "0" : "") + value.toString(16);
15822         }
15823
15824         function hsla(h, s, l, a) {
15825           if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
15826           return new Hsl(h, s, l, a);
15827         }
15828
15829         function hslConvert(o) {
15830           if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
15831           if (!(o instanceof Color)) o = color(o);
15832           if (!o) return new Hsl();
15833           if (o instanceof Hsl) return o;
15834           o = o.rgb();
15835           var r = o.r / 255,
15836               g = o.g / 255,
15837               b = o.b / 255,
15838               min = Math.min(r, g, b),
15839               max = Math.max(r, g, b),
15840               h = NaN,
15841               s = max - min,
15842               l = (max + min) / 2;
15843
15844           if (s) {
15845             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;
15846             s /= l < 0.5 ? max + min : 2 - max - min;
15847             h *= 60;
15848           } else {
15849             s = l > 0 && l < 1 ? 0 : h;
15850           }
15851
15852           return new Hsl(h, s, l, o.opacity);
15853         }
15854         function hsl(h, s, l, opacity) {
15855           return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
15856         }
15857
15858         function Hsl(h, s, l, opacity) {
15859           this.h = +h;
15860           this.s = +s;
15861           this.l = +l;
15862           this.opacity = +opacity;
15863         }
15864
15865         define(Hsl, hsl, extend$3(Color, {
15866           brighter: function brighter(k) {
15867             k = k == null ? _brighter : Math.pow(_brighter, k);
15868             return new Hsl(this.h, this.s, this.l * k, this.opacity);
15869           },
15870           darker: function darker(k) {
15871             k = k == null ? _darker : Math.pow(_darker, k);
15872             return new Hsl(this.h, this.s, this.l * k, this.opacity);
15873           },
15874           rgb: function rgb() {
15875             var h = this.h % 360 + (this.h < 0) * 360,
15876                 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
15877                 l = this.l,
15878                 m2 = l + (l < 0.5 ? l : 1 - l) * s,
15879                 m1 = 2 * l - m2;
15880             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);
15881           },
15882           displayable: function displayable() {
15883             return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
15884           },
15885           formatHsl: function formatHsl() {
15886             var a = this.opacity;
15887             a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
15888             return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
15889           }
15890         }));
15891         /* From FvD 13.37, CSS Color Module Level 3 */
15892
15893         function hsl2rgb(h, m1, m2) {
15894           return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
15895         }
15896
15897         var constant$1 = (function (x) {
15898           return function () {
15899             return x;
15900           };
15901         });
15902
15903         function linear$2(a, d) {
15904           return function (t) {
15905             return a + t * d;
15906           };
15907         }
15908
15909         function exponential(a, b, y) {
15910           return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function (t) {
15911             return Math.pow(a + t * b, y);
15912           };
15913         }
15914         function gamma(y) {
15915           return (y = +y) === 1 ? nogamma : function (a, b) {
15916             return b - a ? exponential(a, b, y) : constant$1(isNaN(a) ? b : a);
15917           };
15918         }
15919         function nogamma(a, b) {
15920           var d = b - a;
15921           return d ? linear$2(a, d) : constant$1(isNaN(a) ? b : a);
15922         }
15923
15924         var d3_interpolateRgb = (function rgbGamma(y) {
15925           var color = gamma(y);
15926
15927           function rgb$1(start, end) {
15928             var r = color((start = rgb(start)).r, (end = rgb(end)).r),
15929                 g = color(start.g, end.g),
15930                 b = color(start.b, end.b),
15931                 opacity = nogamma(start.opacity, end.opacity);
15932             return function (t) {
15933               start.r = r(t);
15934               start.g = g(t);
15935               start.b = b(t);
15936               start.opacity = opacity(t);
15937               return start + "";
15938             };
15939           }
15940
15941           rgb$1.gamma = rgbGamma;
15942           return rgb$1;
15943         })(1);
15944
15945         function numberArray (a, b) {
15946           if (!b) b = [];
15947           var n = a ? Math.min(b.length, a.length) : 0,
15948               c = b.slice(),
15949               i;
15950           return function (t) {
15951             for (i = 0; i < n; ++i) {
15952               c[i] = a[i] * (1 - t) + b[i] * t;
15953             }
15954
15955             return c;
15956           };
15957         }
15958         function isNumberArray(x) {
15959           return ArrayBuffer.isView(x) && !(x instanceof DataView);
15960         }
15961
15962         function genericArray(a, b) {
15963           var nb = b ? b.length : 0,
15964               na = a ? Math.min(nb, a.length) : 0,
15965               x = new Array(na),
15966               c = new Array(nb),
15967               i;
15968
15969           for (i = 0; i < na; ++i) {
15970             x[i] = interpolate$1(a[i], b[i]);
15971           }
15972
15973           for (; i < nb; ++i) {
15974             c[i] = b[i];
15975           }
15976
15977           return function (t) {
15978             for (i = 0; i < na; ++i) {
15979               c[i] = x[i](t);
15980             }
15981
15982             return c;
15983           };
15984         }
15985
15986         function date (a, b) {
15987           var d = new Date();
15988           return a = +a, b = +b, function (t) {
15989             return d.setTime(a * (1 - t) + b * t), d;
15990           };
15991         }
15992
15993         function d3_interpolateNumber (a, b) {
15994           return a = +a, b = +b, function (t) {
15995             return a * (1 - t) + b * t;
15996           };
15997         }
15998
15999         function object (a, b) {
16000           var i = {},
16001               c = {},
16002               k;
16003           if (a === null || _typeof(a) !== "object") a = {};
16004           if (b === null || _typeof(b) !== "object") b = {};
16005
16006           for (k in b) {
16007             if (k in a) {
16008               i[k] = interpolate$1(a[k], b[k]);
16009             } else {
16010               c[k] = b[k];
16011             }
16012           }
16013
16014           return function (t) {
16015             for (k in i) {
16016               c[k] = i[k](t);
16017             }
16018
16019             return c;
16020           };
16021         }
16022
16023         var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
16024             reB = new RegExp(reA.source, "g");
16025
16026         function zero(b) {
16027           return function () {
16028             return b;
16029           };
16030         }
16031
16032         function one(b) {
16033           return function (t) {
16034             return b(t) + "";
16035           };
16036         }
16037
16038         function interpolateString (a, b) {
16039           var bi = reA.lastIndex = reB.lastIndex = 0,
16040               // scan index for next number in b
16041           am,
16042               // current match in a
16043           bm,
16044               // current match in b
16045           bs,
16046               // string preceding current number in b, if any
16047           i = -1,
16048               // index in s
16049           s = [],
16050               // string constants and placeholders
16051           q = []; // number interpolators
16052           // Coerce inputs to strings.
16053
16054           a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b.
16055
16056           while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
16057             if ((bs = bm.index) > bi) {
16058               // a string precedes the next number in b
16059               bs = b.slice(bi, bs);
16060               if (s[i]) s[i] += bs; // coalesce with previous string
16061               else s[++i] = bs;
16062             }
16063
16064             if ((am = am[0]) === (bm = bm[0])) {
16065               // numbers in a & b match
16066               if (s[i]) s[i] += bm; // coalesce with previous string
16067               else s[++i] = bm;
16068             } else {
16069               // interpolate non-matching numbers
16070               s[++i] = null;
16071               q.push({
16072                 i: i,
16073                 x: d3_interpolateNumber(am, bm)
16074               });
16075             }
16076
16077             bi = reB.lastIndex;
16078           } // Add remains of b.
16079
16080
16081           if (bi < b.length) {
16082             bs = b.slice(bi);
16083             if (s[i]) s[i] += bs; // coalesce with previous string
16084             else s[++i] = bs;
16085           } // Special optimization for only a single match.
16086           // Otherwise, interpolate each of the numbers and rejoin the string.
16087
16088
16089           return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function (t) {
16090             for (var i = 0, o; i < b; ++i) {
16091               s[(o = q[i]).i] = o.x(t);
16092             }
16093
16094             return s.join("");
16095           });
16096         }
16097
16098         function interpolate$1 (a, b) {
16099           var t = _typeof(b),
16100               c;
16101
16102           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);
16103         }
16104
16105         function interpolateRound (a, b) {
16106           return a = +a, b = +b, function (t) {
16107             return Math.round(a * (1 - t) + b * t);
16108           };
16109         }
16110
16111         var degrees = 180 / Math.PI;
16112         var identity$3 = {
16113           translateX: 0,
16114           translateY: 0,
16115           rotate: 0,
16116           skewX: 0,
16117           scaleX: 1,
16118           scaleY: 1
16119         };
16120         function decompose (a, b, c, d, e, f) {
16121           var scaleX, scaleY, skewX;
16122           if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
16123           if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
16124           if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
16125           if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
16126           return {
16127             translateX: e,
16128             translateY: f,
16129             rotate: Math.atan2(b, a) * degrees,
16130             skewX: Math.atan(skewX) * degrees,
16131             scaleX: scaleX,
16132             scaleY: scaleY
16133           };
16134         }
16135
16136         var svgNode;
16137         /* eslint-disable no-undef */
16138
16139         function parseCss(value) {
16140           var m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
16141           return m.isIdentity ? identity$3 : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
16142         }
16143         function parseSvg(value) {
16144           if (value == null) return identity$3;
16145           if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
16146           svgNode.setAttribute("transform", value);
16147           if (!(value = svgNode.transform.baseVal.consolidate())) return identity$3;
16148           value = value.matrix;
16149           return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
16150         }
16151
16152         function interpolateTransform(parse, pxComma, pxParen, degParen) {
16153           function pop(s) {
16154             return s.length ? s.pop() + " " : "";
16155           }
16156
16157           function translate(xa, ya, xb, yb, s, q) {
16158             if (xa !== xb || ya !== yb) {
16159               var i = s.push("translate(", null, pxComma, null, pxParen);
16160               q.push({
16161                 i: i - 4,
16162                 x: d3_interpolateNumber(xa, xb)
16163               }, {
16164                 i: i - 2,
16165                 x: d3_interpolateNumber(ya, yb)
16166               });
16167             } else if (xb || yb) {
16168               s.push("translate(" + xb + pxComma + yb + pxParen);
16169             }
16170           }
16171
16172           function rotate(a, b, s, q) {
16173             if (a !== b) {
16174               if (a - b > 180) b += 360;else if (b - a > 180) a += 360; // shortest path
16175
16176               q.push({
16177                 i: s.push(pop(s) + "rotate(", null, degParen) - 2,
16178                 x: d3_interpolateNumber(a, b)
16179               });
16180             } else if (b) {
16181               s.push(pop(s) + "rotate(" + b + degParen);
16182             }
16183           }
16184
16185           function skewX(a, b, s, q) {
16186             if (a !== b) {
16187               q.push({
16188                 i: s.push(pop(s) + "skewX(", null, degParen) - 2,
16189                 x: d3_interpolateNumber(a, b)
16190               });
16191             } else if (b) {
16192               s.push(pop(s) + "skewX(" + b + degParen);
16193             }
16194           }
16195
16196           function scale(xa, ya, xb, yb, s, q) {
16197             if (xa !== xb || ya !== yb) {
16198               var i = s.push(pop(s) + "scale(", null, ",", null, ")");
16199               q.push({
16200                 i: i - 4,
16201                 x: d3_interpolateNumber(xa, xb)
16202               }, {
16203                 i: i - 2,
16204                 x: d3_interpolateNumber(ya, yb)
16205               });
16206             } else if (xb !== 1 || yb !== 1) {
16207               s.push(pop(s) + "scale(" + xb + "," + yb + ")");
16208             }
16209           }
16210
16211           return function (a, b) {
16212             var s = [],
16213                 // string constants and placeholders
16214             q = []; // number interpolators
16215
16216             a = parse(a), b = parse(b);
16217             translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
16218             rotate(a.rotate, b.rotate, s, q);
16219             skewX(a.skewX, b.skewX, s, q);
16220             scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
16221             a = b = null; // gc
16222
16223             return function (t) {
16224               var i = -1,
16225                   n = q.length,
16226                   o;
16227
16228               while (++i < n) {
16229                 s[(o = q[i]).i] = o.x(t);
16230               }
16231
16232               return s.join("");
16233             };
16234           };
16235         }
16236
16237         var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
16238         var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
16239
16240         var epsilon2 = 1e-12;
16241
16242         function cosh(x) {
16243           return ((x = Math.exp(x)) + 1 / x) / 2;
16244         }
16245
16246         function sinh(x) {
16247           return ((x = Math.exp(x)) - 1 / x) / 2;
16248         }
16249
16250         function tanh(x) {
16251           return ((x = Math.exp(2 * x)) - 1) / (x + 1);
16252         }
16253
16254         var interpolateZoom = (function zoomRho(rho, rho2, rho4) {
16255           // p0 = [ux0, uy0, w0]
16256           // p1 = [ux1, uy1, w1]
16257           function zoom(p0, p1) {
16258             var ux0 = p0[0],
16259                 uy0 = p0[1],
16260                 w0 = p0[2],
16261                 ux1 = p1[0],
16262                 uy1 = p1[1],
16263                 w1 = p1[2],
16264                 dx = ux1 - ux0,
16265                 dy = uy1 - uy0,
16266                 d2 = dx * dx + dy * dy,
16267                 i,
16268                 S; // Special case for u0 ≅ u1.
16269
16270             if (d2 < epsilon2) {
16271               S = Math.log(w1 / w0) / rho;
16272
16273               i = function i(t) {
16274                 return [ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(rho * t * S)];
16275               };
16276             } // General case.
16277             else {
16278                 var d1 = Math.sqrt(d2),
16279                     b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
16280                     b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
16281                     r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
16282                     r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
16283                 S = (r1 - r0) / rho;
16284
16285                 i = function i(t) {
16286                   var s = t * S,
16287                       coshr0 = cosh(r0),
16288                       u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
16289                   return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(rho * s + r0)];
16290                 };
16291               }
16292
16293             i.duration = S * 1000 * rho / Math.SQRT2;
16294             return i;
16295           }
16296
16297           zoom.rho = function (_) {
16298             var _1 = Math.max(1e-3, +_),
16299                 _2 = _1 * _1,
16300                 _4 = _2 * _2;
16301
16302             return zoomRho(_1, _2, _4);
16303           };
16304
16305           return zoom;
16306         })(Math.SQRT2, 2, 4);
16307
16308         function d3_quantize (interpolator, n) {
16309           var samples = new Array(n);
16310
16311           for (var i = 0; i < n; ++i) {
16312             samples[i] = interpolator(i / (n - 1));
16313           }
16314
16315           return samples;
16316         }
16317
16318         var $$m = _export;
16319         var bind$2 = functionBind;
16320
16321         // `Function.prototype.bind` method
16322         // https://tc39.es/ecma262/#sec-function.prototype.bind
16323         $$m({ target: 'Function', proto: true }, {
16324           bind: bind$2
16325         });
16326
16327         var frame = 0,
16328             // is an animation frame pending?
16329         timeout = 0,
16330             // is a timeout pending?
16331         interval = 0,
16332             // are any timers active?
16333         pokeDelay = 1000,
16334             // how frequently we check for clock skew
16335         taskHead,
16336             taskTail,
16337             clockLast = 0,
16338             clockNow = 0,
16339             clockSkew = 0,
16340             clock = (typeof performance === "undefined" ? "undefined" : _typeof(performance)) === "object" && performance.now ? performance : Date,
16341             setFrame = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function (f) {
16342           setTimeout(f, 17);
16343         };
16344         function now$1() {
16345           return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
16346         }
16347
16348         function clearNow() {
16349           clockNow = 0;
16350         }
16351
16352         function Timer() {
16353           this._call = this._time = this._next = null;
16354         }
16355         Timer.prototype = timer.prototype = {
16356           constructor: Timer,
16357           restart: function restart(callback, delay, time) {
16358             if (typeof callback !== "function") throw new TypeError("callback is not a function");
16359             time = (time == null ? now$1() : +time) + (delay == null ? 0 : +delay);
16360
16361             if (!this._next && taskTail !== this) {
16362               if (taskTail) taskTail._next = this;else taskHead = this;
16363               taskTail = this;
16364             }
16365
16366             this._call = callback;
16367             this._time = time;
16368             sleep();
16369           },
16370           stop: function stop() {
16371             if (this._call) {
16372               this._call = null;
16373               this._time = Infinity;
16374               sleep();
16375             }
16376           }
16377         };
16378         function timer(callback, delay, time) {
16379           var t = new Timer();
16380           t.restart(callback, delay, time);
16381           return t;
16382         }
16383         function timerFlush() {
16384           now$1(); // Get the current time, if not already set.
16385
16386           ++frame; // Pretend we’ve set an alarm, if we haven’t already.
16387
16388           var t = taskHead,
16389               e;
16390
16391           while (t) {
16392             if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
16393             t = t._next;
16394           }
16395
16396           --frame;
16397         }
16398
16399         function wake() {
16400           clockNow = (clockLast = clock.now()) + clockSkew;
16401           frame = timeout = 0;
16402
16403           try {
16404             timerFlush();
16405           } finally {
16406             frame = 0;
16407             nap();
16408             clockNow = 0;
16409           }
16410         }
16411
16412         function poke() {
16413           var now = clock.now(),
16414               delay = now - clockLast;
16415           if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
16416         }
16417
16418         function nap() {
16419           var t0,
16420               t1 = taskHead,
16421               t2,
16422               time = Infinity;
16423
16424           while (t1) {
16425             if (t1._call) {
16426               if (time > t1._time) time = t1._time;
16427               t0 = t1, t1 = t1._next;
16428             } else {
16429               t2 = t1._next, t1._next = null;
16430               t1 = t0 ? t0._next = t2 : taskHead = t2;
16431             }
16432           }
16433
16434           taskTail = t0;
16435           sleep(time);
16436         }
16437
16438         function sleep(time) {
16439           if (frame) return; // Soonest alarm already set, or will be.
16440
16441           if (timeout) timeout = clearTimeout(timeout);
16442           var delay = time - clockNow; // Strictly less than if we recomputed clockNow.
16443
16444           if (delay > 24) {
16445             if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
16446             if (interval) interval = clearInterval(interval);
16447           } else {
16448             if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
16449             frame = 1, setFrame(wake);
16450           }
16451         }
16452
16453         function d3_timeout (callback, delay, time) {
16454           var t = new Timer();
16455           delay = delay == null ? 0 : +delay;
16456           t.restart(function (elapsed) {
16457             t.stop();
16458             callback(elapsed + delay);
16459           }, delay, time);
16460           return t;
16461         }
16462
16463         var emptyOn = dispatch$8("start", "end", "cancel", "interrupt");
16464         var emptyTween = [];
16465         var CREATED = 0;
16466         var SCHEDULED = 1;
16467         var STARTING = 2;
16468         var STARTED = 3;
16469         var RUNNING = 4;
16470         var ENDING = 5;
16471         var ENDED = 6;
16472         function schedule (node, name, id, index, group, timing) {
16473           var schedules = node.__transition;
16474           if (!schedules) node.__transition = {};else if (id in schedules) return;
16475           create$3(node, id, {
16476             name: name,
16477             index: index,
16478             // For context during callback.
16479             group: group,
16480             // For context during callback.
16481             on: emptyOn,
16482             tween: emptyTween,
16483             time: timing.time,
16484             delay: timing.delay,
16485             duration: timing.duration,
16486             ease: timing.ease,
16487             timer: null,
16488             state: CREATED
16489           });
16490         }
16491         function init(node, id) {
16492           var schedule = get$1(node, id);
16493           if (schedule.state > CREATED) throw new Error("too late; already scheduled");
16494           return schedule;
16495         }
16496         function set(node, id) {
16497           var schedule = get$1(node, id);
16498           if (schedule.state > STARTED) throw new Error("too late; already running");
16499           return schedule;
16500         }
16501         function get$1(node, id) {
16502           var schedule = node.__transition;
16503           if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
16504           return schedule;
16505         }
16506
16507         function create$3(node, id, self) {
16508           var schedules = node.__transition,
16509               tween; // Initialize the self timer when the transition is created.
16510           // Note the actual delay is not known until the first callback!
16511
16512           schedules[id] = self;
16513           self.timer = timer(schedule, 0, self.time);
16514
16515           function schedule(elapsed) {
16516             self.state = SCHEDULED;
16517             self.timer.restart(start, self.delay, self.time); // If the elapsed delay is less than our first sleep, start immediately.
16518
16519             if (self.delay <= elapsed) start(elapsed - self.delay);
16520           }
16521
16522           function start(elapsed) {
16523             var i, j, n, o; // If the state is not SCHEDULED, then we previously errored on start.
16524
16525             if (self.state !== SCHEDULED) return stop();
16526
16527             for (i in schedules) {
16528               o = schedules[i];
16529               if (o.name !== self.name) continue; // While this element already has a starting transition during this frame,
16530               // defer starting an interrupting transition until that transition has a
16531               // chance to tick (and possibly end); see d3/d3-transition#54!
16532
16533               if (o.state === STARTED) return d3_timeout(start); // Interrupt the active transition, if any.
16534
16535               if (o.state === RUNNING) {
16536                 o.state = ENDED;
16537                 o.timer.stop();
16538                 o.on.call("interrupt", node, node.__data__, o.index, o.group);
16539                 delete schedules[i];
16540               } // Cancel any pre-empted transitions.
16541               else if (+i < id) {
16542                   o.state = ENDED;
16543                   o.timer.stop();
16544                   o.on.call("cancel", node, node.__data__, o.index, o.group);
16545                   delete schedules[i];
16546                 }
16547             } // Defer the first tick to end of the current frame; see d3/d3#1576.
16548             // Note the transition may be canceled after start and before the first tick!
16549             // Note this must be scheduled before the start event; see d3/d3-transition#16!
16550             // Assuming this is successful, subsequent callbacks go straight to tick.
16551
16552
16553             d3_timeout(function () {
16554               if (self.state === STARTED) {
16555                 self.state = RUNNING;
16556                 self.timer.restart(tick, self.delay, self.time);
16557                 tick(elapsed);
16558               }
16559             }); // Dispatch the start event.
16560             // Note this must be done before the tween are initialized.
16561
16562             self.state = STARTING;
16563             self.on.call("start", node, node.__data__, self.index, self.group);
16564             if (self.state !== STARTING) return; // interrupted
16565
16566             self.state = STARTED; // Initialize the tween, deleting null tween.
16567
16568             tween = new Array(n = self.tween.length);
16569
16570             for (i = 0, j = -1; i < n; ++i) {
16571               if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
16572                 tween[++j] = o;
16573               }
16574             }
16575
16576             tween.length = j + 1;
16577           }
16578
16579           function tick(elapsed) {
16580             var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
16581                 i = -1,
16582                 n = tween.length;
16583
16584             while (++i < n) {
16585               tween[i].call(node, t);
16586             } // Dispatch the end event.
16587
16588
16589             if (self.state === ENDING) {
16590               self.on.call("end", node, node.__data__, self.index, self.group);
16591               stop();
16592             }
16593           }
16594
16595           function stop() {
16596             self.state = ENDED;
16597             self.timer.stop();
16598             delete schedules[id];
16599
16600             for (var i in schedules) {
16601               return;
16602             } // eslint-disable-line no-unused-vars
16603
16604
16605             delete node.__transition;
16606           }
16607         }
16608
16609         function interrupt (node, name) {
16610           var schedules = node.__transition,
16611               schedule,
16612               active,
16613               empty = true,
16614               i;
16615           if (!schedules) return;
16616           name = name == null ? null : name + "";
16617
16618           for (i in schedules) {
16619             if ((schedule = schedules[i]).name !== name) {
16620               empty = false;
16621               continue;
16622             }
16623
16624             active = schedule.state > STARTING && schedule.state < ENDING;
16625             schedule.state = ENDED;
16626             schedule.timer.stop();
16627             schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
16628             delete schedules[i];
16629           }
16630
16631           if (empty) delete node.__transition;
16632         }
16633
16634         function selection_interrupt (name) {
16635           return this.each(function () {
16636             interrupt(this, name);
16637           });
16638         }
16639
16640         function tweenRemove(id, name) {
16641           var tween0, tween1;
16642           return function () {
16643             var schedule = set(this, id),
16644                 tween = schedule.tween; // If this node shared tween with the previous node,
16645             // just assign the updated shared tween and we’re done!
16646             // Otherwise, copy-on-write.
16647
16648             if (tween !== tween0) {
16649               tween1 = tween0 = tween;
16650
16651               for (var i = 0, n = tween1.length; i < n; ++i) {
16652                 if (tween1[i].name === name) {
16653                   tween1 = tween1.slice();
16654                   tween1.splice(i, 1);
16655                   break;
16656                 }
16657               }
16658             }
16659
16660             schedule.tween = tween1;
16661           };
16662         }
16663
16664         function tweenFunction(id, name, value) {
16665           var tween0, tween1;
16666           if (typeof value !== "function") throw new Error();
16667           return function () {
16668             var schedule = set(this, id),
16669                 tween = schedule.tween; // If this node shared tween with the previous node,
16670             // just assign the updated shared tween and we’re done!
16671             // Otherwise, copy-on-write.
16672
16673             if (tween !== tween0) {
16674               tween1 = (tween0 = tween).slice();
16675
16676               for (var t = {
16677                 name: name,
16678                 value: value
16679               }, i = 0, n = tween1.length; i < n; ++i) {
16680                 if (tween1[i].name === name) {
16681                   tween1[i] = t;
16682                   break;
16683                 }
16684               }
16685
16686               if (i === n) tween1.push(t);
16687             }
16688
16689             schedule.tween = tween1;
16690           };
16691         }
16692
16693         function transition_tween (name, value) {
16694           var id = this._id;
16695           name += "";
16696
16697           if (arguments.length < 2) {
16698             var tween = get$1(this.node(), id).tween;
16699
16700             for (var i = 0, n = tween.length, t; i < n; ++i) {
16701               if ((t = tween[i]).name === name) {
16702                 return t.value;
16703               }
16704             }
16705
16706             return null;
16707           }
16708
16709           return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
16710         }
16711         function tweenValue(transition, name, value) {
16712           var id = transition._id;
16713           transition.each(function () {
16714             var schedule = set(this, id);
16715             (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
16716           });
16717           return function (node) {
16718             return get$1(node, id).value[name];
16719           };
16720         }
16721
16722         function interpolate (a, b) {
16723           var c;
16724           return (typeof b === "number" ? d3_interpolateNumber : b instanceof color ? d3_interpolateRgb : (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString)(a, b);
16725         }
16726
16727         function attrRemove(name) {
16728           return function () {
16729             this.removeAttribute(name);
16730           };
16731         }
16732
16733         function attrRemoveNS(fullname) {
16734           return function () {
16735             this.removeAttributeNS(fullname.space, fullname.local);
16736           };
16737         }
16738
16739         function attrConstant(name, interpolate, value1) {
16740           var string00,
16741               string1 = value1 + "",
16742               interpolate0;
16743           return function () {
16744             var string0 = this.getAttribute(name);
16745             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16746           };
16747         }
16748
16749         function attrConstantNS(fullname, interpolate, value1) {
16750           var string00,
16751               string1 = value1 + "",
16752               interpolate0;
16753           return function () {
16754             var string0 = this.getAttributeNS(fullname.space, fullname.local);
16755             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16756           };
16757         }
16758
16759         function attrFunction(name, interpolate, value) {
16760           var string00, string10, interpolate0;
16761           return function () {
16762             var string0,
16763                 value1 = value(this),
16764                 string1;
16765             if (value1 == null) return void this.removeAttribute(name);
16766             string0 = this.getAttribute(name);
16767             string1 = value1 + "";
16768             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16769           };
16770         }
16771
16772         function attrFunctionNS(fullname, interpolate, value) {
16773           var string00, string10, interpolate0;
16774           return function () {
16775             var string0,
16776                 value1 = value(this),
16777                 string1;
16778             if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
16779             string0 = this.getAttributeNS(fullname.space, fullname.local);
16780             string1 = value1 + "";
16781             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16782           };
16783         }
16784
16785         function transition_attr (name, value) {
16786           var fullname = namespace(name),
16787               i = fullname === "transform" ? interpolateTransformSvg : interpolate;
16788           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));
16789         }
16790
16791         function attrInterpolate(name, i) {
16792           return function (t) {
16793             this.setAttribute(name, i.call(this, t));
16794           };
16795         }
16796
16797         function attrInterpolateNS(fullname, i) {
16798           return function (t) {
16799             this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));
16800           };
16801         }
16802
16803         function attrTweenNS(fullname, value) {
16804           var t0, i0;
16805
16806           function tween() {
16807             var i = value.apply(this, arguments);
16808             if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
16809             return t0;
16810           }
16811
16812           tween._value = value;
16813           return tween;
16814         }
16815
16816         function attrTween(name, value) {
16817           var t0, i0;
16818
16819           function tween() {
16820             var i = value.apply(this, arguments);
16821             if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
16822             return t0;
16823           }
16824
16825           tween._value = value;
16826           return tween;
16827         }
16828
16829         function transition_attrTween (name, value) {
16830           var key = "attr." + name;
16831           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
16832           if (value == null) return this.tween(key, null);
16833           if (typeof value !== "function") throw new Error();
16834           var fullname = namespace(name);
16835           return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
16836         }
16837
16838         function delayFunction(id, value) {
16839           return function () {
16840             init(this, id).delay = +value.apply(this, arguments);
16841           };
16842         }
16843
16844         function delayConstant(id, value) {
16845           return value = +value, function () {
16846             init(this, id).delay = value;
16847           };
16848         }
16849
16850         function transition_delay (value) {
16851           var id = this._id;
16852           return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id, value)) : get$1(this.node(), id).delay;
16853         }
16854
16855         function durationFunction(id, value) {
16856           return function () {
16857             set(this, id).duration = +value.apply(this, arguments);
16858           };
16859         }
16860
16861         function durationConstant(id, value) {
16862           return value = +value, function () {
16863             set(this, id).duration = value;
16864           };
16865         }
16866
16867         function transition_duration (value) {
16868           var id = this._id;
16869           return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id, value)) : get$1(this.node(), id).duration;
16870         }
16871
16872         function easeConstant(id, value) {
16873           if (typeof value !== "function") throw new Error();
16874           return function () {
16875             set(this, id).ease = value;
16876           };
16877         }
16878
16879         function transition_ease (value) {
16880           var id = this._id;
16881           return arguments.length ? this.each(easeConstant(id, value)) : get$1(this.node(), id).ease;
16882         }
16883
16884         function easeVarying(id, value) {
16885           return function () {
16886             var v = value.apply(this, arguments);
16887             if (typeof v !== "function") throw new Error();
16888             set(this, id).ease = v;
16889           };
16890         }
16891
16892         function transition_easeVarying (value) {
16893           if (typeof value !== "function") throw new Error();
16894           return this.each(easeVarying(this._id, value));
16895         }
16896
16897         function transition_filter (match) {
16898           if (typeof match !== "function") match = matcher(match);
16899
16900           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
16901             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
16902               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
16903                 subgroup.push(node);
16904               }
16905             }
16906           }
16907
16908           return new Transition(subgroups, this._parents, this._name, this._id);
16909         }
16910
16911         function transition_merge (transition) {
16912           if (transition._id !== this._id) throw new Error();
16913
16914           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) {
16915             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
16916               if (node = group0[i] || group1[i]) {
16917                 merge[i] = node;
16918               }
16919             }
16920           }
16921
16922           for (; j < m0; ++j) {
16923             merges[j] = groups0[j];
16924           }
16925
16926           return new Transition(merges, this._parents, this._name, this._id);
16927         }
16928
16929         function start(name) {
16930           return (name + "").trim().split(/^|\s+/).every(function (t) {
16931             var i = t.indexOf(".");
16932             if (i >= 0) t = t.slice(0, i);
16933             return !t || t === "start";
16934           });
16935         }
16936
16937         function onFunction(id, name, listener) {
16938           var on0,
16939               on1,
16940               sit = start(name) ? init : set;
16941           return function () {
16942             var schedule = sit(this, id),
16943                 on = schedule.on; // If this node shared a dispatch with the previous node,
16944             // just assign the updated shared dispatch and we’re done!
16945             // Otherwise, copy-on-write.
16946
16947             if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
16948             schedule.on = on1;
16949           };
16950         }
16951
16952         function transition_on (name, listener) {
16953           var id = this._id;
16954           return arguments.length < 2 ? get$1(this.node(), id).on.on(name) : this.each(onFunction(id, name, listener));
16955         }
16956
16957         function removeFunction(id) {
16958           return function () {
16959             var parent = this.parentNode;
16960
16961             for (var i in this.__transition) {
16962               if (+i !== id) return;
16963             }
16964
16965             if (parent) parent.removeChild(this);
16966           };
16967         }
16968
16969         function transition_remove () {
16970           return this.on("end.remove", removeFunction(this._id));
16971         }
16972
16973         function transition_select (select) {
16974           var name = this._name,
16975               id = this._id;
16976           if (typeof select !== "function") select = selector(select);
16977
16978           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
16979             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
16980               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
16981                 if ("__data__" in node) subnode.__data__ = node.__data__;
16982                 subgroup[i] = subnode;
16983                 schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
16984               }
16985             }
16986           }
16987
16988           return new Transition(subgroups, this._parents, name, id);
16989         }
16990
16991         function transition_selectAll (select) {
16992           var name = this._name,
16993               id = this._id;
16994           if (typeof select !== "function") select = selectorAll(select);
16995
16996           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
16997             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16998               if (node = group[i]) {
16999                 for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
17000                   if (child = children[k]) {
17001                     schedule(child, name, id, k, children, inherit);
17002                   }
17003                 }
17004
17005                 subgroups.push(children);
17006                 parents.push(node);
17007               }
17008             }
17009           }
17010
17011           return new Transition(subgroups, parents, name, id);
17012         }
17013
17014         var Selection = selection.prototype.constructor;
17015         function transition_selection () {
17016           return new Selection(this._groups, this._parents);
17017         }
17018
17019         function styleNull(name, interpolate) {
17020           var string00, string10, interpolate0;
17021           return function () {
17022             var string0 = styleValue(this, name),
17023                 string1 = (this.style.removeProperty(name), styleValue(this, name));
17024             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
17025           };
17026         }
17027
17028         function styleRemove(name) {
17029           return function () {
17030             this.style.removeProperty(name);
17031           };
17032         }
17033
17034         function styleConstant(name, interpolate, value1) {
17035           var string00,
17036               string1 = value1 + "",
17037               interpolate0;
17038           return function () {
17039             var string0 = styleValue(this, name);
17040             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
17041           };
17042         }
17043
17044         function styleFunction(name, interpolate, value) {
17045           var string00, string10, interpolate0;
17046           return function () {
17047             var string0 = styleValue(this, name),
17048                 value1 = value(this),
17049                 string1 = value1 + "";
17050             if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
17051             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
17052           };
17053         }
17054
17055         function styleMaybeRemove(id, name) {
17056           var on0,
17057               on1,
17058               listener0,
17059               key = "style." + name,
17060               event = "end." + key,
17061               remove;
17062           return function () {
17063             var schedule = set(this, id),
17064                 on = schedule.on,
17065                 listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined; // If this node shared a dispatch with the previous node,
17066             // just assign the updated shared dispatch and we’re done!
17067             // Otherwise, copy-on-write.
17068
17069             if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
17070             schedule.on = on1;
17071           };
17072         }
17073
17074         function transition_style (name, value, priority) {
17075           var i = (name += "") === "transform" ? interpolateTransformCss : interpolate;
17076           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);
17077         }
17078
17079         function styleInterpolate(name, i, priority) {
17080           return function (t) {
17081             this.style.setProperty(name, i.call(this, t), priority);
17082           };
17083         }
17084
17085         function styleTween(name, value, priority) {
17086           var t, i0;
17087
17088           function tween() {
17089             var i = value.apply(this, arguments);
17090             if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);
17091             return t;
17092           }
17093
17094           tween._value = value;
17095           return tween;
17096         }
17097
17098         function transition_styleTween (name, value, priority) {
17099           var key = "style." + (name += "");
17100           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
17101           if (value == null) return this.tween(key, null);
17102           if (typeof value !== "function") throw new Error();
17103           return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
17104         }
17105
17106         function textConstant(value) {
17107           return function () {
17108             this.textContent = value;
17109           };
17110         }
17111
17112         function textFunction(value) {
17113           return function () {
17114             var value1 = value(this);
17115             this.textContent = value1 == null ? "" : value1;
17116           };
17117         }
17118
17119         function transition_text (value) {
17120           return this.tween("text", typeof value === "function" ? textFunction(tweenValue(this, "text", value)) : textConstant(value == null ? "" : value + ""));
17121         }
17122
17123         function textInterpolate(i) {
17124           return function (t) {
17125             this.textContent = i.call(this, t);
17126           };
17127         }
17128
17129         function textTween(value) {
17130           var t0, i0;
17131
17132           function tween() {
17133             var i = value.apply(this, arguments);
17134             if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
17135             return t0;
17136           }
17137
17138           tween._value = value;
17139           return tween;
17140         }
17141
17142         function transition_textTween (value) {
17143           var key = "text";
17144           if (arguments.length < 1) return (key = this.tween(key)) && key._value;
17145           if (value == null) return this.tween(key, null);
17146           if (typeof value !== "function") throw new Error();
17147           return this.tween(key, textTween(value));
17148         }
17149
17150         function transition_transition () {
17151           var name = this._name,
17152               id0 = this._id,
17153               id1 = newId();
17154
17155           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
17156             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
17157               if (node = group[i]) {
17158                 var inherit = get$1(node, id0);
17159                 schedule(node, name, id1, i, group, {
17160                   time: inherit.time + inherit.delay + inherit.duration,
17161                   delay: 0,
17162                   duration: inherit.duration,
17163                   ease: inherit.ease
17164                 });
17165               }
17166             }
17167           }
17168
17169           return new Transition(groups, this._parents, name, id1);
17170         }
17171
17172         function transition_end () {
17173           var on0,
17174               on1,
17175               that = this,
17176               id = that._id,
17177               size = that.size();
17178           return new Promise(function (resolve, reject) {
17179             var cancel = {
17180               value: reject
17181             },
17182                 end = {
17183               value: function value() {
17184                 if (--size === 0) resolve();
17185               }
17186             };
17187             that.each(function () {
17188               var schedule = set(this, id),
17189                   on = schedule.on; // If this node shared a dispatch with the previous node,
17190               // just assign the updated shared dispatch and we’re done!
17191               // Otherwise, copy-on-write.
17192
17193               if (on !== on0) {
17194                 on1 = (on0 = on).copy();
17195
17196                 on1._.cancel.push(cancel);
17197
17198                 on1._.interrupt.push(cancel);
17199
17200                 on1._.end.push(end);
17201               }
17202
17203               schedule.on = on1;
17204             }); // The selection was empty, resolve end immediately
17205
17206             if (size === 0) resolve();
17207           });
17208         }
17209
17210         var id = 0;
17211         function Transition(groups, parents, name, id) {
17212           this._groups = groups;
17213           this._parents = parents;
17214           this._name = name;
17215           this._id = id;
17216         }
17217         function newId() {
17218           return ++id;
17219         }
17220         var selection_prototype = selection.prototype;
17221         Transition.prototype = _defineProperty({
17222           constructor: Transition,
17223           select: transition_select,
17224           selectAll: transition_selectAll,
17225           filter: transition_filter,
17226           merge: transition_merge,
17227           selection: transition_selection,
17228           transition: transition_transition,
17229           call: selection_prototype.call,
17230           nodes: selection_prototype.nodes,
17231           node: selection_prototype.node,
17232           size: selection_prototype.size,
17233           empty: selection_prototype.empty,
17234           each: selection_prototype.each,
17235           on: transition_on,
17236           attr: transition_attr,
17237           attrTween: transition_attrTween,
17238           style: transition_style,
17239           styleTween: transition_styleTween,
17240           text: transition_text,
17241           textTween: transition_textTween,
17242           remove: transition_remove,
17243           tween: transition_tween,
17244           delay: transition_delay,
17245           duration: transition_duration,
17246           ease: transition_ease,
17247           easeVarying: transition_easeVarying,
17248           end: transition_end
17249         }, Symbol.iterator, selection_prototype[Symbol.iterator]);
17250
17251         var linear$1 = function linear(t) {
17252           return +t;
17253         };
17254
17255         function cubicInOut(t) {
17256           return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
17257         }
17258
17259         var defaultTiming = {
17260           time: null,
17261           // Set on use.
17262           delay: 0,
17263           duration: 250,
17264           ease: cubicInOut
17265         };
17266
17267         function inherit(node, id) {
17268           var timing;
17269
17270           while (!(timing = node.__transition) || !(timing = timing[id])) {
17271             if (!(node = node.parentNode)) {
17272               throw new Error("transition ".concat(id, " not found"));
17273             }
17274           }
17275
17276           return timing;
17277         }
17278
17279         function selection_transition (name) {
17280           var id, timing;
17281
17282           if (name instanceof Transition) {
17283             id = name._id, name = name._name;
17284           } else {
17285             id = newId(), (timing = defaultTiming).time = now$1(), name = name == null ? null : name + "";
17286           }
17287
17288           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
17289             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
17290               if (node = group[i]) {
17291                 schedule(node, name, id, i, group, timing || inherit(node, id));
17292               }
17293             }
17294           }
17295
17296           return new Transition(groups, this._parents, name, id);
17297         }
17298
17299         selection.prototype.interrupt = selection_interrupt;
17300         selection.prototype.transition = selection_transition;
17301
17302         var constant = (function (x) {
17303           return function () {
17304             return x;
17305           };
17306         });
17307
17308         function ZoomEvent(type, _ref) {
17309           var sourceEvent = _ref.sourceEvent,
17310               target = _ref.target,
17311               transform = _ref.transform,
17312               dispatch = _ref.dispatch;
17313           Object.defineProperties(this, {
17314             type: {
17315               value: type,
17316               enumerable: true,
17317               configurable: true
17318             },
17319             sourceEvent: {
17320               value: sourceEvent,
17321               enumerable: true,
17322               configurable: true
17323             },
17324             target: {
17325               value: target,
17326               enumerable: true,
17327               configurable: true
17328             },
17329             transform: {
17330               value: transform,
17331               enumerable: true,
17332               configurable: true
17333             },
17334             _: {
17335               value: dispatch
17336             }
17337           });
17338         }
17339
17340         function Transform(k, x, y) {
17341           this.k = k;
17342           this.x = x;
17343           this.y = y;
17344         }
17345         Transform.prototype = {
17346           constructor: Transform,
17347           scale: function scale(k) {
17348             return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
17349           },
17350           translate: function translate(x, y) {
17351             return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
17352           },
17353           apply: function apply(point) {
17354             return [point[0] * this.k + this.x, point[1] * this.k + this.y];
17355           },
17356           applyX: function applyX(x) {
17357             return x * this.k + this.x;
17358           },
17359           applyY: function applyY(y) {
17360             return y * this.k + this.y;
17361           },
17362           invert: function invert(location) {
17363             return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
17364           },
17365           invertX: function invertX(x) {
17366             return (x - this.x) / this.k;
17367           },
17368           invertY: function invertY(y) {
17369             return (y - this.y) / this.k;
17370           },
17371           rescaleX: function rescaleX(x) {
17372             return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
17373           },
17374           rescaleY: function rescaleY(y) {
17375             return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
17376           },
17377           toString: function toString() {
17378             return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
17379           }
17380         };
17381         var identity$2 = new Transform(1, 0, 0);
17382
17383         function nopropagation(event) {
17384           event.stopImmediatePropagation();
17385         }
17386         function noevent (event) {
17387           event.preventDefault();
17388           event.stopImmediatePropagation();
17389         }
17390
17391         // except for pinch-to-zoom, which is sent as a wheel+ctrlKey event
17392
17393         function defaultFilter$1(event) {
17394           return (!event.ctrlKey || event.type === 'wheel') && !event.button;
17395         }
17396
17397         function defaultExtent$1() {
17398           var e = this;
17399
17400           if (e instanceof SVGElement) {
17401             e = e.ownerSVGElement || e;
17402
17403             if (e.hasAttribute("viewBox")) {
17404               e = e.viewBox.baseVal;
17405               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
17406             }
17407
17408             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
17409           }
17410
17411           return [[0, 0], [e.clientWidth, e.clientHeight]];
17412         }
17413
17414         function defaultTransform() {
17415           return this.__zoom || identity$2;
17416         }
17417
17418         function defaultWheelDelta$1(event) {
17419           return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);
17420         }
17421
17422         function defaultTouchable() {
17423           return navigator.maxTouchPoints || "ontouchstart" in this;
17424         }
17425
17426         function defaultConstrain$1(transform, extent, translateExtent) {
17427           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
17428               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
17429               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
17430               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
17431           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));
17432         }
17433
17434         function d3_zoom () {
17435           var filter = defaultFilter$1,
17436               extent = defaultExtent$1,
17437               constrain = defaultConstrain$1,
17438               wheelDelta = defaultWheelDelta$1,
17439               touchable = defaultTouchable,
17440               scaleExtent = [0, Infinity],
17441               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
17442               duration = 250,
17443               interpolate = interpolateZoom,
17444               listeners = dispatch$8("start", "zoom", "end"),
17445               touchstarting,
17446               touchfirst,
17447               touchending,
17448               touchDelay = 500,
17449               wheelDelay = 150,
17450               clickDistance2 = 0,
17451               tapDistance = 10;
17452
17453           function zoom(selection) {
17454             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)");
17455           }
17456
17457           zoom.transform = function (collection, transform, point, event) {
17458             var selection = collection.selection ? collection.selection() : collection;
17459             selection.property("__zoom", defaultTransform);
17460
17461             if (collection !== selection) {
17462               schedule(collection, transform, point, event);
17463             } else {
17464               selection.interrupt().each(function () {
17465                 gesture(this, arguments).event(event).start().zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform).end();
17466               });
17467             }
17468           };
17469
17470           zoom.scaleBy = function (selection, k, p, event) {
17471             zoom.scaleTo(selection, function () {
17472               var k0 = this.__zoom.k,
17473                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
17474               return k0 * k1;
17475             }, p, event);
17476           };
17477
17478           zoom.scaleTo = function (selection, k, p, event) {
17479             zoom.transform(selection, function () {
17480               var e = extent.apply(this, arguments),
17481                   t0 = this.__zoom,
17482                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p,
17483                   p1 = t0.invert(p0),
17484                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
17485               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
17486             }, p, event);
17487           };
17488
17489           zoom.translateBy = function (selection, x, y, event) {
17490             zoom.transform(selection, function () {
17491               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);
17492             }, null, event);
17493           };
17494
17495           zoom.translateTo = function (selection, x, y, p, event) {
17496             zoom.transform(selection, function () {
17497               var e = extent.apply(this, arguments),
17498                   t = this.__zoom,
17499                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
17500               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);
17501             }, p, event);
17502           };
17503
17504           function scale(transform, k) {
17505             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
17506             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
17507           }
17508
17509           function translate(transform, p0, p1) {
17510             var x = p0[0] - p1[0] * transform.k,
17511                 y = p0[1] - p1[1] * transform.k;
17512             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
17513           }
17514
17515           function centroid(extent) {
17516             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
17517           }
17518
17519           function schedule(transition, transform, point, event) {
17520             transition.on("start.zoom", function () {
17521               gesture(this, arguments).event(event).start();
17522             }).on("interrupt.zoom end.zoom", function () {
17523               gesture(this, arguments).event(event).end();
17524             }).tween("zoom", function () {
17525               var that = this,
17526                   args = arguments,
17527                   g = gesture(that, args).event(event),
17528                   e = extent.apply(that, args),
17529                   p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point,
17530                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
17531                   a = that.__zoom,
17532                   b = typeof transform === "function" ? transform.apply(that, args) : transform,
17533                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
17534               return function (t) {
17535                 if (t === 1) t = b; // Avoid rounding error on end.
17536                 else {
17537                     var l = i(t),
17538                         k = w / l[2];
17539                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
17540                   }
17541                 g.zoom(null, t);
17542               };
17543             });
17544           }
17545
17546           function gesture(that, args, clean) {
17547             return !clean && that.__zooming || new Gesture(that, args);
17548           }
17549
17550           function Gesture(that, args) {
17551             this.that = that;
17552             this.args = args;
17553             this.active = 0;
17554             this.sourceEvent = null;
17555             this.extent = extent.apply(that, args);
17556             this.taps = 0;
17557           }
17558
17559           Gesture.prototype = {
17560             event: function event(_event) {
17561               if (_event) this.sourceEvent = _event;
17562               return this;
17563             },
17564             start: function start() {
17565               if (++this.active === 1) {
17566                 this.that.__zooming = this;
17567                 this.emit("start");
17568               }
17569
17570               return this;
17571             },
17572             zoom: function zoom(key, transform) {
17573               if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
17574               if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
17575               if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
17576               this.that.__zoom = transform;
17577               this.emit("zoom");
17578               return this;
17579             },
17580             end: function end() {
17581               if (--this.active === 0) {
17582                 delete this.that.__zooming;
17583                 this.emit("end");
17584               }
17585
17586               return this;
17587             },
17588             emit: function emit(type) {
17589               var d = select(this.that).datum();
17590               listeners.call(type, this.that, new ZoomEvent(type, {
17591                 sourceEvent: this.sourceEvent,
17592                 target: zoom,
17593                 type: type,
17594                 transform: this.that.__zoom,
17595                 dispatch: listeners
17596               }), d);
17597             }
17598           };
17599
17600           function wheeled(event) {
17601             for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
17602               args[_key - 1] = arguments[_key];
17603             }
17604
17605             if (!filter.apply(this, arguments)) return;
17606             var g = gesture(this, args).event(event),
17607                 t = this.__zoom,
17608                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
17609                 p = pointer(event); // If the mouse is in the same location as before, reuse it.
17610             // If there were recent wheel events, reset the wheel idle timeout.
17611
17612             if (g.wheel) {
17613               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
17614                 g.mouse[1] = t.invert(g.mouse[0] = p);
17615               }
17616
17617               clearTimeout(g.wheel);
17618             } // If this wheel event won’t trigger a transform change, ignore it.
17619             else if (t.k === k) return; // Otherwise, capture the mouse point and location at the start.
17620               else {
17621                   g.mouse = [p, t.invert(p)];
17622                   interrupt(this);
17623                   g.start();
17624                 }
17625
17626             noevent(event);
17627             g.wheel = setTimeout(wheelidled, wheelDelay);
17628             g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
17629
17630             function wheelidled() {
17631               g.wheel = null;
17632               g.end();
17633             }
17634           }
17635
17636           function mousedowned(event) {
17637             for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
17638               args[_key2 - 1] = arguments[_key2];
17639             }
17640
17641             if (touchending || !filter.apply(this, arguments)) return;
17642             var g = gesture(this, args, true).event(event),
17643                 v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
17644                 p = pointer(event, currentTarget),
17645                 currentTarget = event.currentTarget,
17646                 x0 = event.clientX,
17647                 y0 = event.clientY;
17648             dragDisable(event.view);
17649             nopropagation(event);
17650             g.mouse = [p, this.__zoom.invert(p)];
17651             interrupt(this);
17652             g.start();
17653
17654             function mousemoved(event) {
17655               noevent(event);
17656
17657               if (!g.moved) {
17658                 var dx = event.clientX - x0,
17659                     dy = event.clientY - y0;
17660                 g.moved = dx * dx + dy * dy > clickDistance2;
17661               }
17662
17663               g.event(event).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
17664             }
17665
17666             function mouseupped(event) {
17667               v.on("mousemove.zoom mouseup.zoom", null);
17668               yesdrag(event.view, g.moved);
17669               noevent(event);
17670               g.event(event).end();
17671             }
17672           }
17673
17674           function dblclicked(event) {
17675             for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
17676               args[_key3 - 1] = arguments[_key3];
17677             }
17678
17679             if (!filter.apply(this, arguments)) return;
17680             var t0 = this.__zoom,
17681                 p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),
17682                 p1 = t0.invert(p0),
17683                 k1 = t0.k * (event.shiftKey ? 0.5 : 2),
17684                 t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
17685             noevent(event);
17686             if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);else select(this).call(zoom.transform, t1, p0, event);
17687           }
17688
17689           function touchstarted(event) {
17690             for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
17691               args[_key4 - 1] = arguments[_key4];
17692             }
17693
17694             if (!filter.apply(this, arguments)) return;
17695             var touches = event.touches,
17696                 n = touches.length,
17697                 g = gesture(this, args, event.changedTouches.length === n).event(event),
17698                 started,
17699                 i,
17700                 t,
17701                 p;
17702             nopropagation(event);
17703
17704             for (i = 0; i < n; ++i) {
17705               t = touches[i], p = pointer(t, this);
17706               p = [p, this.__zoom.invert(p), t.identifier];
17707               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;
17708             }
17709
17710             if (touchstarting) touchstarting = clearTimeout(touchstarting);
17711
17712             if (started) {
17713               if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function () {
17714                 touchstarting = null;
17715               }, touchDelay);
17716               interrupt(this);
17717               g.start();
17718             }
17719           }
17720
17721           function touchmoved(event) {
17722             if (!this.__zooming) return;
17723
17724             for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
17725               args[_key5 - 1] = arguments[_key5];
17726             }
17727
17728             var g = gesture(this, args).event(event),
17729                 touches = event.changedTouches,
17730                 n = touches.length,
17731                 i,
17732                 t,
17733                 p,
17734                 l;
17735             noevent(event);
17736
17737             for (i = 0; i < n; ++i) {
17738               t = touches[i], p = pointer(t, this);
17739               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;
17740             }
17741
17742             t = g.that.__zoom;
17743
17744             if (g.touch1) {
17745               var p0 = g.touch0[0],
17746                   l0 = g.touch0[1],
17747                   p1 = g.touch1[0],
17748                   l1 = g.touch1[1],
17749                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
17750                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
17751               t = scale(t, Math.sqrt(dp / dl));
17752               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
17753               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
17754             } else if (g.touch0) p = g.touch0[0], l = g.touch0[1];else return;
17755
17756             g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
17757           }
17758
17759           function touchended(event) {
17760             for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
17761               args[_key6 - 1] = arguments[_key6];
17762             }
17763
17764             if (!this.__zooming) return;
17765             var g = gesture(this, args).event(event),
17766                 touches = event.changedTouches,
17767                 n = touches.length,
17768                 i,
17769                 t;
17770             nopropagation(event);
17771             if (touchending) clearTimeout(touchending);
17772             touchending = setTimeout(function () {
17773               touchending = null;
17774             }, touchDelay);
17775
17776             for (i = 0; i < n; ++i) {
17777               t = touches[i];
17778               if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
17779             }
17780
17781             if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
17782             if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);else {
17783               g.end(); // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.
17784
17785               if (g.taps === 2) {
17786                 t = pointer(t, this);
17787
17788                 if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
17789                   var p = select(this).on("dblclick.zoom");
17790                   if (p) p.apply(this, arguments);
17791                 }
17792               }
17793             }
17794           }
17795
17796           zoom.wheelDelta = function (_) {
17797             return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant(+_), zoom) : wheelDelta;
17798           };
17799
17800           zoom.filter = function (_) {
17801             return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), zoom) : filter;
17802           };
17803
17804           zoom.touchable = function (_) {
17805             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), zoom) : touchable;
17806           };
17807
17808           zoom.extent = function (_) {
17809             return arguments.length ? (extent = typeof _ === "function" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
17810           };
17811
17812           zoom.scaleExtent = function (_) {
17813             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
17814           };
17815
17816           zoom.translateExtent = function (_) {
17817             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]]];
17818           };
17819
17820           zoom.constrain = function (_) {
17821             return arguments.length ? (constrain = _, zoom) : constrain;
17822           };
17823
17824           zoom.duration = function (_) {
17825             return arguments.length ? (duration = +_, zoom) : duration;
17826           };
17827
17828           zoom.interpolate = function (_) {
17829             return arguments.length ? (interpolate = _, zoom) : interpolate;
17830           };
17831
17832           zoom.on = function () {
17833             var value = listeners.on.apply(listeners, arguments);
17834             return value === listeners ? zoom : value;
17835           };
17836
17837           zoom.clickDistance = function (_) {
17838             return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
17839           };
17840
17841           zoom.tapDistance = function (_) {
17842             return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
17843           };
17844
17845           return zoom;
17846         }
17847
17848         /*
17849             Bypasses features of D3's default projection stream pipeline that are unnecessary:
17850             * Antimeridian clipping
17851             * Spherical rotation
17852             * Resampling
17853         */
17854
17855         function geoRawMercator() {
17856           var project = mercatorRaw;
17857           var k = 512 / Math.PI; // scale
17858
17859           var x = 0;
17860           var y = 0; // translate
17861
17862           var clipExtent = [[0, 0], [0, 0]];
17863
17864           function projection(point) {
17865             point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
17866             return [point[0] * k + x, y - point[1] * k];
17867           }
17868
17869           projection.invert = function (point) {
17870             point = project.invert((point[0] - x) / k, (y - point[1]) / k);
17871             return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
17872           };
17873
17874           projection.scale = function (_) {
17875             if (!arguments.length) return k;
17876             k = +_;
17877             return projection;
17878           };
17879
17880           projection.translate = function (_) {
17881             if (!arguments.length) return [x, y];
17882             x = +_[0];
17883             y = +_[1];
17884             return projection;
17885           };
17886
17887           projection.clipExtent = function (_) {
17888             if (!arguments.length) return clipExtent;
17889             clipExtent = _;
17890             return projection;
17891           };
17892
17893           projection.transform = function (obj) {
17894             if (!arguments.length) return identity$2.translate(x, y).scale(k);
17895             x = +obj.x;
17896             y = +obj.y;
17897             k = +obj.k;
17898             return projection;
17899           };
17900
17901           projection.stream = d3_geoTransform({
17902             point: function point(x, y) {
17903               var vec = projection([x, y]);
17904               this.stream.point(vec[0], vec[1]);
17905             }
17906           }).stream;
17907           return projection;
17908         }
17909
17910         function geoOrthoNormalizedDotProduct(a, b, origin) {
17911           if (geoVecEqual(origin, a) || geoVecEqual(origin, b)) {
17912             return 1; // coincident points, treat as straight and try to remove
17913           }
17914
17915           return geoVecNormalizedDot(a, b, origin);
17916         }
17917
17918         function geoOrthoFilterDotProduct(dotp, epsilon, lowerThreshold, upperThreshold, allowStraightAngles) {
17919           var val = Math.abs(dotp);
17920
17921           if (val < epsilon) {
17922             return 0; // already orthogonal
17923           } else if (allowStraightAngles && Math.abs(val - 1) < epsilon) {
17924             return 0; // straight angle, which is okay in this case
17925           } else if (val < lowerThreshold || val > upperThreshold) {
17926             return dotp; // can be adjusted
17927           } else {
17928             return null; // ignore vertex
17929           }
17930         }
17931
17932         function geoOrthoCalcScore(points, isClosed, epsilon, threshold) {
17933           var score = 0;
17934           var first = isClosed ? 0 : 1;
17935           var last = isClosed ? points.length : points.length - 1;
17936           var coords = points.map(function (p) {
17937             return p.coord;
17938           });
17939           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
17940           var upperThreshold = Math.cos(threshold * Math.PI / 180);
17941
17942           for (var i = first; i < last; i++) {
17943             var a = coords[(i - 1 + coords.length) % coords.length];
17944             var origin = coords[i];
17945             var b = coords[(i + 1) % coords.length];
17946             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold);
17947             if (dotp === null) continue; // ignore vertex
17948
17949             score = score + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
17950           }
17951
17952           return score;
17953         } // returns the maximum angle less than `lessThan` between the actual corner and a 0° or 90° corner
17954
17955         function geoOrthoMaxOffsetAngle(coords, isClosed, lessThan) {
17956           var max = -Infinity;
17957           var first = isClosed ? 0 : 1;
17958           var last = isClosed ? coords.length : coords.length - 1;
17959
17960           for (var i = first; i < last; i++) {
17961             var a = coords[(i - 1 + coords.length) % coords.length];
17962             var origin = coords[i];
17963             var b = coords[(i + 1) % coords.length];
17964             var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin);
17965             var angle = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
17966             if (angle > 45) angle = 90 - angle;
17967             if (angle >= lessThan) continue;
17968             if (angle > max) max = angle;
17969           }
17970
17971           if (max === -Infinity) return null;
17972           return max;
17973         } // similar to geoOrthoCalcScore, but returns quickly if there is something to do
17974
17975         function geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles) {
17976           var score = null;
17977           var first = isClosed ? 0 : 1;
17978           var last = isClosed ? coords.length : coords.length - 1;
17979           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
17980           var upperThreshold = Math.cos(threshold * Math.PI / 180);
17981
17982           for (var i = first; i < last; i++) {
17983             var a = coords[(i - 1 + coords.length) % coords.length];
17984             var origin = coords[i];
17985             var b = coords[(i + 1) % coords.length];
17986             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold, allowStraightAngles);
17987             if (dotp === null) continue; // ignore vertex
17988
17989             if (Math.abs(dotp) > 0) return 1; // something to do
17990
17991             score = 0; // already square
17992           }
17993
17994           return score;
17995         }
17996
17997         var $$l = _export;
17998         var FREEZING = freezing;
17999         var fails$9 = fails$N;
18000         var isObject$4 = isObject$r;
18001         var onFreeze = internalMetadata.exports.onFreeze;
18002
18003         // eslint-disable-next-line es/no-object-freeze -- safe
18004         var $freeze = Object.freeze;
18005         var FAILS_ON_PRIMITIVES = fails$9(function () { $freeze(1); });
18006
18007         // `Object.freeze` method
18008         // https://tc39.es/ecma262/#sec-object.freeze
18009         $$l({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES, sham: !FREEZING }, {
18010           freeze: function freeze(it) {
18011             return $freeze && isObject$4(it) ? $freeze(onFreeze(it)) : it;
18012           }
18013         });
18014
18015         // Returns true if a and b have the same elements at the same indices.
18016         function utilArrayIdentical(a, b) {
18017           // an array is always identical to itself
18018           if (a === b) return true;
18019           var i = a.length;
18020           if (i !== b.length) return false;
18021
18022           while (i--) {
18023             if (a[i] !== b[i]) return false;
18024           }
18025
18026           return true;
18027         } // http://2ality.com/2015/01/es6-set-operations.html
18028         // Difference (a \ b): create a set that contains those elements of set a that are not in set b.
18029         // This operation is also sometimes called minus (-).
18030         // var a = [1,2,3];
18031         // var b = [4,3,2];
18032         // utilArrayDifference(a, b)
18033         //   [1]
18034         // utilArrayDifference(b, a)
18035         //   [4]
18036
18037         function utilArrayDifference(a, b) {
18038           var other = new Set(b);
18039           return Array.from(new Set(a)).filter(function (v) {
18040             return !other.has(v);
18041           });
18042         } // Intersection (a ∩ b): create a set that contains those elements of set a that are also in set b.
18043         // var a = [1,2,3];
18044         // var b = [4,3,2];
18045         // utilArrayIntersection(a, b)
18046         //   [2,3]
18047
18048         function utilArrayIntersection(a, b) {
18049           var other = new Set(b);
18050           return Array.from(new Set(a)).filter(function (v) {
18051             return other.has(v);
18052           });
18053         } // Union (a ∪ b): create a set that contains the elements of both set a and set b.
18054         // var a = [1,2,3];
18055         // var b = [4,3,2];
18056         // utilArrayUnion(a, b)
18057         //   [1,2,3,4]
18058
18059         function utilArrayUnion(a, b) {
18060           var result = new Set(a);
18061           b.forEach(function (v) {
18062             result.add(v);
18063           });
18064           return Array.from(result);
18065         } // Returns an Array with all the duplicates removed
18066         // var a = [1,1,2,3,3];
18067         // utilArrayUniq(a)
18068         //   [1,2,3]
18069
18070         function utilArrayUniq(a) {
18071           return Array.from(new Set(a));
18072         } // Splits array into chunks of given chunk size
18073         // var a = [1,2,3,4,5,6,7];
18074         // utilArrayChunk(a, 3);
18075         //   [[1,2,3],[4,5,6],[7]];
18076
18077         function utilArrayChunk(a, chunkSize) {
18078           if (!chunkSize || chunkSize < 0) return [a.slice()];
18079           var result = new Array(Math.ceil(a.length / chunkSize));
18080           return Array.from(result, function (item, i) {
18081             return a.slice(i * chunkSize, i * chunkSize + chunkSize);
18082           });
18083         } // Flattens two level array into a single level
18084         // var a = [[1,2,3],[4,5,6],[7]];
18085         // utilArrayFlatten(a);
18086         //   [1,2,3,4,5,6,7];
18087
18088         function utilArrayFlatten(a) {
18089           return a.reduce(function (acc, val) {
18090             return acc.concat(val);
18091           }, []);
18092         } // Groups the items of the Array according to the given key
18093         // `key` can be passed as a property or as a key function
18094         //
18095         // var pets = [
18096         //     { type: 'Dog', name: 'Spot' },
18097         //     { type: 'Cat', name: 'Tiger' },
18098         //     { type: 'Dog', name: 'Rover' },
18099         //     { type: 'Cat', name: 'Leo' }
18100         // ];
18101         //
18102         // utilArrayGroupBy(pets, 'type')
18103         //   {
18104         //     'Dog': [{type: 'Dog', name: 'Spot'}, {type: 'Dog', name: 'Rover'}],
18105         //     'Cat': [{type: 'Cat', name: 'Tiger'}, {type: 'Cat', name: 'Leo'}]
18106         //   }
18107         //
18108         // utilArrayGroupBy(pets, function(item) { return item.name.length; })
18109         //   {
18110         //     3: [{type: 'Cat', name: 'Leo'}],
18111         //     4: [{type: 'Dog', name: 'Spot'}],
18112         //     5: [{type: 'Cat', name: 'Tiger'}, {type: 'Dog', name: 'Rover'}]
18113         //   }
18114
18115         function utilArrayGroupBy(a, key) {
18116           return a.reduce(function (acc, item) {
18117             var group = typeof key === 'function' ? key(item) : item[key];
18118             (acc[group] = acc[group] || []).push(item);
18119             return acc;
18120           }, {});
18121         } // Returns an Array with all the duplicates removed
18122         // where uniqueness determined by the given key
18123         // `key` can be passed as a property or as a key function
18124         //
18125         // var pets = [
18126         //     { type: 'Dog', name: 'Spot' },
18127         //     { type: 'Cat', name: 'Tiger' },
18128         //     { type: 'Dog', name: 'Rover' },
18129         //     { type: 'Cat', name: 'Leo' }
18130         // ];
18131         //
18132         // utilArrayUniqBy(pets, 'type')
18133         //   [
18134         //     { type: 'Dog', name: 'Spot' },
18135         //     { type: 'Cat', name: 'Tiger' }
18136         //   ]
18137         //
18138         // utilArrayUniqBy(pets, function(item) { return item.name.length; })
18139         //   [
18140         //     { type: 'Dog', name: 'Spot' },
18141         //     { type: 'Cat', name: 'Tiger' },
18142         //     { type: 'Cat', name: 'Leo' }
18143         //   }
18144
18145         function utilArrayUniqBy(a, key) {
18146           var seen = new Set();
18147           return a.reduce(function (acc, item) {
18148             var val = typeof key === 'function' ? key(item) : item[key];
18149
18150             if (val && !seen.has(val)) {
18151               seen.add(val);
18152               acc.push(item);
18153             }
18154
18155             return acc;
18156           }, []);
18157         }
18158
18159         var DESCRIPTORS$2 = descriptors;
18160         var global$2 = global$F;
18161         var isForced = isForced_1;
18162         var redefine$1 = redefine$g.exports;
18163         var has = has$j;
18164         var classof$1 = classofRaw$1;
18165         var inheritIfRequired = inheritIfRequired$4;
18166         var toPrimitive$1 = toPrimitive$7;
18167         var fails$8 = fails$N;
18168         var create$2 = objectCreate;
18169         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
18170         var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
18171         var defineProperty = objectDefineProperty.f;
18172         var trim$2 = stringTrim.trim;
18173
18174         var NUMBER = 'Number';
18175         var NativeNumber = global$2[NUMBER];
18176         var NumberPrototype = NativeNumber.prototype;
18177
18178         // Opera ~12 has broken Object#toString
18179         var BROKEN_CLASSOF = classof$1(create$2(NumberPrototype)) == NUMBER;
18180
18181         // `ToNumber` abstract operation
18182         // https://tc39.es/ecma262/#sec-tonumber
18183         var toNumber$1 = function (argument) {
18184           var it = toPrimitive$1(argument, false);
18185           var first, third, radix, maxCode, digits, length, index, code;
18186           if (typeof it == 'string' && it.length > 2) {
18187             it = trim$2(it);
18188             first = it.charCodeAt(0);
18189             if (first === 43 || first === 45) {
18190               third = it.charCodeAt(2);
18191               if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
18192             } else if (first === 48) {
18193               switch (it.charCodeAt(1)) {
18194                 case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i
18195                 case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i
18196                 default: return +it;
18197               }
18198               digits = it.slice(2);
18199               length = digits.length;
18200               for (index = 0; index < length; index++) {
18201                 code = digits.charCodeAt(index);
18202                 // parseInt parses a string to a first unavailable symbol
18203                 // but ToNumber should return NaN if a string contains unavailable symbols
18204                 if (code < 48 || code > maxCode) return NaN;
18205               } return parseInt(digits, radix);
18206             }
18207           } return +it;
18208         };
18209
18210         // `Number` constructor
18211         // https://tc39.es/ecma262/#sec-number-constructor
18212         if (isForced(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
18213           var NumberWrapper = function Number(value) {
18214             var it = arguments.length < 1 ? 0 : value;
18215             var dummy = this;
18216             return dummy instanceof NumberWrapper
18217               // check on 1..constructor(foo) case
18218               && (BROKEN_CLASSOF ? fails$8(function () { NumberPrototype.valueOf.call(dummy); }) : classof$1(dummy) != NUMBER)
18219                 ? inheritIfRequired(new NativeNumber(toNumber$1(it)), dummy, NumberWrapper) : toNumber$1(it);
18220           };
18221           for (var keys = DESCRIPTORS$2 ? getOwnPropertyNames(NativeNumber) : (
18222             // ES3:
18223             'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +
18224             // ES2015 (in case, if modules with ES2015 Number statics required before):
18225             'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +
18226             'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,' +
18227             // ESNext
18228             'fromString,range'
18229           ).split(','), j$1 = 0, key; keys.length > j$1; j$1++) {
18230             if (has(NativeNumber, key = keys[j$1]) && !has(NumberWrapper, key)) {
18231               defineProperty(NumberWrapper, key, getOwnPropertyDescriptor$2(NativeNumber, key));
18232             }
18233           }
18234           NumberWrapper.prototype = NumberPrototype;
18235           NumberPrototype.constructor = NumberWrapper;
18236           redefine$1(global$2, NUMBER, NumberWrapper);
18237         }
18238
18239         var fixRegExpWellKnownSymbolLogic$1 = fixRegexpWellKnownSymbolLogic;
18240         var anObject$1 = anObject$m;
18241         var toLength$3 = toLength$q;
18242         var requireObjectCoercible$7 = requireObjectCoercible$e;
18243         var advanceStringIndex = advanceStringIndex$3;
18244         var regExpExec$1 = regexpExecAbstract;
18245
18246         // @@match logic
18247         fixRegExpWellKnownSymbolLogic$1('match', function (MATCH, nativeMatch, maybeCallNative) {
18248           return [
18249             // `String.prototype.match` method
18250             // https://tc39.es/ecma262/#sec-string.prototype.match
18251             function match(regexp) {
18252               var O = requireObjectCoercible$7(this);
18253               var matcher = regexp == undefined ? undefined : regexp[MATCH];
18254               return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
18255             },
18256             // `RegExp.prototype[@@match]` method
18257             // https://tc39.es/ecma262/#sec-regexp.prototype-@@match
18258             function (string) {
18259               var res = maybeCallNative(nativeMatch, this, string);
18260               if (res.done) return res.value;
18261
18262               var rx = anObject$1(this);
18263               var S = String(string);
18264
18265               if (!rx.global) return regExpExec$1(rx, S);
18266
18267               var fullUnicode = rx.unicode;
18268               rx.lastIndex = 0;
18269               var A = [];
18270               var n = 0;
18271               var result;
18272               while ((result = regExpExec$1(rx, S)) !== null) {
18273                 var matchStr = String(result[0]);
18274                 A[n] = matchStr;
18275                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength$3(rx.lastIndex), fullUnicode);
18276                 n++;
18277               }
18278               return n === 0 ? null : A;
18279             }
18280           ];
18281         });
18282
18283         var diacritics = {};
18284
18285         var remove$6 = diacritics.remove = removeDiacritics;
18286         var replacementList = [{
18287           base: ' ',
18288           chars: "\xA0"
18289         }, {
18290           base: '0',
18291           chars: "\u07C0"
18292         }, {
18293           base: 'A',
18294           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"
18295         }, {
18296           base: 'AA',
18297           chars: "\uA732"
18298         }, {
18299           base: 'AE',
18300           chars: "\xC6\u01FC\u01E2"
18301         }, {
18302           base: 'AO',
18303           chars: "\uA734"
18304         }, {
18305           base: 'AU',
18306           chars: "\uA736"
18307         }, {
18308           base: 'AV',
18309           chars: "\uA738\uA73A"
18310         }, {
18311           base: 'AY',
18312           chars: "\uA73C"
18313         }, {
18314           base: 'B',
18315           chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181"
18316         }, {
18317           base: 'C',
18318           chars: "\u24B8\uFF23\uA73E\u1E08\u0106C\u0108\u010A\u010C\xC7\u0187\u023B"
18319         }, {
18320           base: 'D',
18321           chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779"
18322         }, {
18323           base: 'Dh',
18324           chars: "\xD0"
18325         }, {
18326           base: 'DZ',
18327           chars: "\u01F1\u01C4"
18328         }, {
18329           base: 'Dz',
18330           chars: "\u01F2\u01C5"
18331         }, {
18332           base: 'E',
18333           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"
18334         }, {
18335           base: 'F',
18336           chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B"
18337         }, {
18338           base: 'G',
18339           chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262"
18340         }, {
18341           base: 'H',
18342           chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"
18343         }, {
18344           base: 'I',
18345           chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"
18346         }, {
18347           base: 'J',
18348           chars: "\u24BF\uFF2A\u0134\u0248\u0237"
18349         }, {
18350           base: 'K',
18351           chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"
18352         }, {
18353           base: 'L',
18354           chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"
18355         }, {
18356           base: 'LJ',
18357           chars: "\u01C7"
18358         }, {
18359           base: 'Lj',
18360           chars: "\u01C8"
18361         }, {
18362           base: 'M',
18363           chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB"
18364         }, {
18365           base: 'N',
18366           chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E"
18367         }, {
18368           base: 'NJ',
18369           chars: "\u01CA"
18370         }, {
18371           base: 'Nj',
18372           chars: "\u01CB"
18373         }, {
18374           base: 'O',
18375           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"
18376         }, {
18377           base: 'OE',
18378           chars: "\u0152"
18379         }, {
18380           base: 'OI',
18381           chars: "\u01A2"
18382         }, {
18383           base: 'OO',
18384           chars: "\uA74E"
18385         }, {
18386           base: 'OU',
18387           chars: "\u0222"
18388         }, {
18389           base: 'P',
18390           chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"
18391         }, {
18392           base: 'Q',
18393           chars: "\u24C6\uFF31\uA756\uA758\u024A"
18394         }, {
18395           base: 'R',
18396           chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"
18397         }, {
18398           base: 'S',
18399           chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"
18400         }, {
18401           base: 'T',
18402           chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"
18403         }, {
18404           base: 'Th',
18405           chars: "\xDE"
18406         }, {
18407           base: 'TZ',
18408           chars: "\uA728"
18409         }, {
18410           base: 'U',
18411           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"
18412         }, {
18413           base: 'V',
18414           chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"
18415         }, {
18416           base: 'VY',
18417           chars: "\uA760"
18418         }, {
18419           base: 'W',
18420           chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"
18421         }, {
18422           base: 'X',
18423           chars: "\u24CD\uFF38\u1E8A\u1E8C"
18424         }, {
18425           base: 'Y',
18426           chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"
18427         }, {
18428           base: 'Z',
18429           chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"
18430         }, {
18431           base: 'a',
18432           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"
18433         }, {
18434           base: 'aa',
18435           chars: "\uA733"
18436         }, {
18437           base: 'ae',
18438           chars: "\xE6\u01FD\u01E3"
18439         }, {
18440           base: 'ao',
18441           chars: "\uA735"
18442         }, {
18443           base: 'au',
18444           chars: "\uA737"
18445         }, {
18446           base: 'av',
18447           chars: "\uA739\uA73B"
18448         }, {
18449           base: 'ay',
18450           chars: "\uA73D"
18451         }, {
18452           base: 'b',
18453           chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182"
18454         }, {
18455           base: 'c',
18456           chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\xE7\u1E09\u0188\u023C\uA73F\u2184"
18457         }, {
18458           base: 'd',
18459           chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA"
18460         }, {
18461           base: 'dh',
18462           chars: "\xF0"
18463         }, {
18464           base: 'dz',
18465           chars: "\u01F3\u01C6"
18466         }, {
18467           base: 'e',
18468           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"
18469         }, {
18470           base: 'f',
18471           chars: "\u24D5\uFF46\u1E1F\u0192"
18472         }, {
18473           base: 'ff',
18474           chars: "\uFB00"
18475         }, {
18476           base: 'fi',
18477           chars: "\uFB01"
18478         }, {
18479           base: 'fl',
18480           chars: "\uFB02"
18481         }, {
18482           base: 'ffi',
18483           chars: "\uFB03"
18484         }, {
18485           base: 'ffl',
18486           chars: "\uFB04"
18487         }, {
18488           base: 'g',
18489           chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79"
18490         }, {
18491           base: 'h',
18492           chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"
18493         }, {
18494           base: 'hv',
18495           chars: "\u0195"
18496         }, {
18497           base: 'i',
18498           chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"
18499         }, {
18500           base: 'j',
18501           chars: "\u24D9\uFF4A\u0135\u01F0\u0249"
18502         }, {
18503           base: 'k',
18504           chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"
18505         }, {
18506           base: 'l',
18507           chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D"
18508         }, {
18509           base: 'lj',
18510           chars: "\u01C9"
18511         }, {
18512           base: 'm',
18513           chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"
18514         }, {
18515           base: 'n',
18516           chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509"
18517         }, {
18518           base: 'nj',
18519           chars: "\u01CC"
18520         }, {
18521           base: 'o',
18522           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"
18523         }, {
18524           base: 'oe',
18525           chars: "\u0153"
18526         }, {
18527           base: 'oi',
18528           chars: "\u01A3"
18529         }, {
18530           base: 'oo',
18531           chars: "\uA74F"
18532         }, {
18533           base: 'ou',
18534           chars: "\u0223"
18535         }, {
18536           base: 'p',
18537           chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1"
18538         }, {
18539           base: 'q',
18540           chars: "\u24E0\uFF51\u024B\uA757\uA759"
18541         }, {
18542           base: 'r',
18543           chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"
18544         }, {
18545           base: 's',
18546           chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282"
18547         }, {
18548           base: 'ss',
18549           chars: "\xDF"
18550         }, {
18551           base: 't',
18552           chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"
18553         }, {
18554           base: 'th',
18555           chars: "\xFE"
18556         }, {
18557           base: 'tz',
18558           chars: "\uA729"
18559         }, {
18560           base: 'u',
18561           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"
18562         }, {
18563           base: 'v',
18564           chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"
18565         }, {
18566           base: 'vy',
18567           chars: "\uA761"
18568         }, {
18569           base: 'w',
18570           chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"
18571         }, {
18572           base: 'x',
18573           chars: "\u24E7\uFF58\u1E8B\u1E8D"
18574         }, {
18575           base: 'y',
18576           chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"
18577         }, {
18578           base: 'z',
18579           chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"
18580         }];
18581         var diacriticsMap = {};
18582
18583         for (var i$1 = 0; i$1 < replacementList.length; i$1 += 1) {
18584           var chars = replacementList[i$1].chars;
18585
18586           for (var j = 0; j < chars.length; j += 1) {
18587             diacriticsMap[chars[j]] = replacementList[i$1].base;
18588           }
18589         }
18590
18591         function removeDiacritics(str) {
18592           return str.replace(/[^\u0000-\u007e]/g, function (c) {
18593             return diacriticsMap[c] || c;
18594           });
18595         }
18596
18597         diacritics.replacementList = replacementList;
18598         diacritics.diacriticsMap = diacriticsMap;
18599
18600         var lib = {};
18601
18602         var isArabic$1 = {};
18603
18604         Object.defineProperty(isArabic$1, "__esModule", {
18605           value: true
18606         });
18607         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
18608         ];
18609
18610         function isArabic(_char) {
18611           if (_char.length > 1) {
18612             // allow the newer chars?
18613             throw new Error('isArabic works on only one-character strings');
18614           }
18615
18616           var code = _char.charCodeAt(0);
18617
18618           for (var i = 0; i < arabicBlocks.length; i++) {
18619             var block = arabicBlocks[i];
18620
18621             if (code >= block[0] && code <= block[1]) {
18622               return true;
18623             }
18624           }
18625
18626           return false;
18627         }
18628
18629         isArabic$1.isArabic = isArabic;
18630
18631         function isMath(_char2) {
18632           if (_char2.length > 2) {
18633             // allow the newer chars?
18634             throw new Error('isMath works on only one-character strings');
18635           }
18636
18637           var code = _char2.charCodeAt(0);
18638
18639           return code >= 0x660 && code <= 0x66C || code >= 0x6F0 && code <= 0x6F9;
18640         }
18641
18642         isArabic$1.isMath = isMath;
18643
18644         var GlyphSplitter$1 = {};
18645
18646         var reference = {};
18647
18648         var unicodeArabic = {};
18649
18650         Object.defineProperty(unicodeArabic, "__esModule", {
18651           value: true
18652         });
18653         var arabicReference = {
18654           "alef": {
18655             "normal": ["\u0627"],
18656             "madda_above": {
18657               "normal": ["\u0627\u0653", "\u0622"],
18658               "isolated": "\uFE81",
18659               "final": "\uFE82"
18660             },
18661             "hamza_above": {
18662               "normal": ["\u0627\u0654", "\u0623"],
18663               "isolated": "\uFE83",
18664               "final": "\uFE84"
18665             },
18666             "hamza_below": {
18667               "normal": ["\u0627\u0655", "\u0625"],
18668               "isolated": "\uFE87",
18669               "final": "\uFE88"
18670             },
18671             "wasla": {
18672               "normal": "\u0671",
18673               "isolated": "\uFB50",
18674               "final": "\uFB51"
18675             },
18676             "wavy_hamza_above": ["\u0672"],
18677             "wavy_hamza_below": ["\u0627\u065F", "\u0673"],
18678             "high_hamza": ["\u0675", "\u0627\u0674"],
18679             "indic_two_above": ["\u0773"],
18680             "indic_three_above": ["\u0774"],
18681             "fathatan": {
18682               "normal": ["\u0627\u064B"],
18683               "final": "\uFD3C",
18684               "isolated": "\uFD3D"
18685             },
18686             "isolated": "\uFE8D",
18687             "final": "\uFE8E"
18688           },
18689           "beh": {
18690             "normal": ["\u0628"],
18691             "dotless": ["\u066E"],
18692             "three_dots_horizontally_below": ["\u0750"],
18693             "dot_below_three_dots_above": ["\u0751"],
18694             "three_dots_pointing_upwards_below": ["\u0752"],
18695             "three_dots_pointing_upwards_below_two_dots_above": ["\u0753"],
18696             "two_dots_below_dot_above": ["\u0754"],
18697             "inverted_small_v_below": ["\u0755"],
18698             "small_v": ["\u0756"],
18699             "small_v_below": ["\u08A0"],
18700             "hamza_above": ["\u08A1"],
18701             "small_meem_above": ["\u08B6"],
18702             "isolated": "\uFE8F",
18703             "final": "\uFE90",
18704             "initial": "\uFE91",
18705             "medial": "\uFE92"
18706           },
18707           "teh marbuta": {
18708             "normal": ["\u0629"],
18709             "isolated": "\uFE93",
18710             "final": "\uFE94"
18711           },
18712           "teh": {
18713             "normal": ["\u062A"],
18714             "ring": ["\u067C"],
18715             "three_dots_above_downwards": ["\u067D"],
18716             "small_teh_above": ["\u08B8"],
18717             "isolated": "\uFE95",
18718             "final": "\uFE96",
18719             "initial": "\uFE97",
18720             "medial": "\uFE98"
18721           },
18722           "theh": {
18723             "normal": ["\u062B"],
18724             "isolated": "\uFE99",
18725             "final": "\uFE9A",
18726             "initial": "\uFE9B",
18727             "medial": "\uFE9C"
18728           },
18729           "jeem": {
18730             "normal": ["\u062C"],
18731             "two_dots_above": ["\u08A2"],
18732             "isolated": "\uFE9D",
18733             "final": "\uFE9E",
18734             "initial": "\uFE9F",
18735             "medial": "\uFEA0"
18736           },
18737           "hah": {
18738             "normal": ["\u062D"],
18739             "hamza_above": ["\u0681"],
18740             "two_dots_vertical_above": ["\u0682"],
18741             "three_dots_above": ["\u0685"],
18742             "two_dots_above": ["\u0757"],
18743             "three_dots_pointing_upwards_below": ["\u0758"],
18744             "small_tah_below": ["\u076E"],
18745             "small_tah_two_dots": ["\u076F"],
18746             "small_tah_above": ["\u0772"],
18747             "indic_four_below": ["\u077C"],
18748             "isolated": "\uFEA1",
18749             "final": "\uFEA2",
18750             "initial": "\uFEA3",
18751             "medial": "\uFEA4"
18752           },
18753           "khah": {
18754             "normal": ["\u062E"],
18755             "isolated": "\uFEA5",
18756             "final": "\uFEA6",
18757             "initial": "\uFEA7",
18758             "medial": "\uFEA8"
18759           },
18760           "dal": {
18761             "normal": ["\u062F"],
18762             "ring": ["\u0689"],
18763             "dot_below": ["\u068A"],
18764             "dot_below_small_tah": ["\u068B"],
18765             "three_dots_above_downwards": ["\u068F"],
18766             "four_dots_above": ["\u0690"],
18767             "inverted_v": ["\u06EE"],
18768             "two_dots_vertically_below_small_tah": ["\u0759"],
18769             "inverted_small_v_below": ["\u075A"],
18770             "three_dots_below": ["\u08AE"],
18771             "isolated": "\uFEA9",
18772             "final": "\uFEAA"
18773           },
18774           "thal": {
18775             "normal": ["\u0630"],
18776             "isolated": "\uFEAB",
18777             "final": "\uFEAC"
18778           },
18779           "reh": {
18780             "normal": ["\u0631"],
18781             "small_v": ["\u0692"],
18782             "ring": ["\u0693"],
18783             "dot_below": ["\u0694"],
18784             "small_v_below": ["\u0695"],
18785             "dot_below_dot_above": ["\u0696"],
18786             "two_dots_above": ["\u0697"],
18787             "four_dots_above": ["\u0699"],
18788             "inverted_v": ["\u06EF"],
18789             "stroke": ["\u075B"],
18790             "two_dots_vertically_above": ["\u076B"],
18791             "hamza_above": ["\u076C"],
18792             "small_tah_two_dots": ["\u0771"],
18793             "loop": ["\u08AA"],
18794             "small_noon_above": ["\u08B9"],
18795             "isolated": "\uFEAD",
18796             "final": "\uFEAE"
18797           },
18798           "zain": {
18799             "normal": ["\u0632"],
18800             "inverted_v_above": ["\u08B2"],
18801             "isolated": "\uFEAF",
18802             "final": "\uFEB0"
18803           },
18804           "seen": {
18805             "normal": ["\u0633"],
18806             "dot_below_dot_above": ["\u069A"],
18807             "three_dots_below": ["\u069B"],
18808             "three_dots_below_three_dots_above": ["\u069C"],
18809             "four_dots_above": ["\u075C"],
18810             "two_dots_vertically_above": ["\u076D"],
18811             "small_tah_two_dots": ["\u0770"],
18812             "indic_four_above": ["\u077D"],
18813             "inverted_v": ["\u077E"],
18814             "isolated": "\uFEB1",
18815             "final": "\uFEB2",
18816             "initial": "\uFEB3",
18817             "medial": "\uFEB4"
18818           },
18819           "sheen": {
18820             "normal": ["\u0634"],
18821             "dot_below": ["\u06FA"],
18822             "isolated": "\uFEB5",
18823             "final": "\uFEB6",
18824             "initial": "\uFEB7",
18825             "medial": "\uFEB8"
18826           },
18827           "sad": {
18828             "normal": ["\u0635"],
18829             "two_dots_below": ["\u069D"],
18830             "three_dots_above": ["\u069E"],
18831             "three_dots_below": ["\u08AF"],
18832             "isolated": "\uFEB9",
18833             "final": "\uFEBA",
18834             "initial": "\uFEBB",
18835             "medial": "\uFEBC"
18836           },
18837           "dad": {
18838             "normal": ["\u0636"],
18839             "dot_below": ["\u06FB"],
18840             "isolated": "\uFEBD",
18841             "final": "\uFEBE",
18842             "initial": "\uFEBF",
18843             "medial": "\uFEC0"
18844           },
18845           "tah": {
18846             "normal": ["\u0637"],
18847             "three_dots_above": ["\u069F"],
18848             "two_dots_above": ["\u08A3"],
18849             "isolated": "\uFEC1",
18850             "final": "\uFEC2",
18851             "initial": "\uFEC3",
18852             "medial": "\uFEC4"
18853           },
18854           "zah": {
18855             "normal": ["\u0638"],
18856             "isolated": "\uFEC5",
18857             "final": "\uFEC6",
18858             "initial": "\uFEC7",
18859             "medial": "\uFEC8"
18860           },
18861           "ain": {
18862             "normal": ["\u0639"],
18863             "three_dots_above": ["\u06A0"],
18864             "two_dots_above": ["\u075D"],
18865             "three_dots_pointing_downwards_above": ["\u075E"],
18866             "two_dots_vertically_above": ["\u075F"],
18867             "three_dots_below": ["\u08B3"],
18868             "isolated": "\uFEC9",
18869             "final": "\uFECA",
18870             "initial": "\uFECB",
18871             "medial": "\uFECC"
18872           },
18873           "ghain": {
18874             "normal": ["\u063A"],
18875             "dot_below": ["\u06FC"],
18876             "isolated": "\uFECD",
18877             "final": "\uFECE",
18878             "initial": "\uFECF",
18879             "medial": "\uFED0"
18880           },
18881           "feh": {
18882             "normal": ["\u0641"],
18883             "dotless": ["\u06A1"],
18884             "dot_moved_below": ["\u06A2"],
18885             "dot_below": ["\u06A3"],
18886             "three_dots_below": ["\u06A5"],
18887             "two_dots_below": ["\u0760"],
18888             "three_dots_pointing_upwards_below": ["\u0761"],
18889             "dot_below_three_dots_above": ["\u08A4"],
18890             "isolated": "\uFED1",
18891             "final": "\uFED2",
18892             "initial": "\uFED3",
18893             "medial": "\uFED4"
18894           },
18895           "qaf": {
18896             "normal": ["\u0642"],
18897             "dotless": ["\u066F"],
18898             "dot_above": ["\u06A7"],
18899             "three_dots_above": ["\u06A8"],
18900             "dot_below": ["\u08A5"],
18901             "isolated": "\uFED5",
18902             "final": "\uFED6",
18903             "initial": "\uFED7",
18904             "medial": "\uFED8"
18905           },
18906           "kaf": {
18907             "normal": ["\u0643"],
18908             "swash": ["\u06AA"],
18909             "ring": ["\u06AB"],
18910             "dot_above": ["\u06AC"],
18911             "three_dots_below": ["\u06AE"],
18912             "two_dots_above": ["\u077F"],
18913             "dot_below": ["\u08B4"],
18914             "isolated": "\uFED9",
18915             "final": "\uFEDA",
18916             "initial": "\uFEDB",
18917             "medial": "\uFEDC"
18918           },
18919           "lam": {
18920             "normal": ["\u0644"],
18921             "small_v": ["\u06B5"],
18922             "dot_above": ["\u06B6"],
18923             "three_dots_above": ["\u06B7"],
18924             "three_dots_below": ["\u06B8"],
18925             "bar": ["\u076A"],
18926             "double_bar": ["\u08A6"],
18927             "isolated": "\uFEDD",
18928             "final": "\uFEDE",
18929             "initial": "\uFEDF",
18930             "medial": "\uFEE0"
18931           },
18932           "meem": {
18933             "normal": ["\u0645"],
18934             "dot_above": ["\u0765"],
18935             "dot_below": ["\u0766"],
18936             "three_dots_above": ["\u08A7"],
18937             "isolated": "\uFEE1",
18938             "final": "\uFEE2",
18939             "initial": "\uFEE3",
18940             "medial": "\uFEE4"
18941           },
18942           "noon": {
18943             "normal": ["\u0646"],
18944             "dot_below": ["\u06B9"],
18945             "ring": ["\u06BC"],
18946             "three_dots_above": ["\u06BD"],
18947             "two_dots_below": ["\u0767"],
18948             "small_tah": ["\u0768"],
18949             "small_v": ["\u0769"],
18950             "isolated": "\uFEE5",
18951             "final": "\uFEE6",
18952             "initial": "\uFEE7",
18953             "medial": "\uFEE8"
18954           },
18955           "heh": {
18956             "normal": ["\u0647"],
18957             "isolated": "\uFEE9",
18958             "final": "\uFEEA",
18959             "initial": "\uFEEB",
18960             "medial": "\uFEEC"
18961           },
18962           "waw": {
18963             "normal": ["\u0648"],
18964             "hamza_above": {
18965               "normal": ["\u0624", "\u0648\u0654"],
18966               "isolated": "\uFE85",
18967               "final": "\uFE86"
18968             },
18969             "high_hamza": ["\u0676", "\u0648\u0674"],
18970             "ring": ["\u06C4"],
18971             "two_dots_above": ["\u06CA"],
18972             "dot_above": ["\u06CF"],
18973             "indic_two_above": ["\u0778"],
18974             "indic_three_above": ["\u0779"],
18975             "dot_within": ["\u08AB"],
18976             "isolated": "\uFEED",
18977             "final": "\uFEEE"
18978           },
18979           "alef_maksura": {
18980             "normal": ["\u0649"],
18981             "hamza_above": ["\u0626", "\u064A\u0654"],
18982             "initial": "\uFBE8",
18983             "medial": "\uFBE9",
18984             "isolated": "\uFEEF",
18985             "final": "\uFEF0"
18986           },
18987           "yeh": {
18988             "normal": ["\u064A"],
18989             "hamza_above": {
18990               "normal": ["\u0626", "\u0649\u0654"],
18991               "isolated": "\uFE89",
18992               "final": "\uFE8A",
18993               "initial": "\uFE8B",
18994               "medial": "\uFE8C"
18995             },
18996             "two_dots_below_hamza_above": ["\u08A8"],
18997             "high_hamza": ["\u0678", "\u064A\u0674"],
18998             "tail": ["\u06CD"],
18999             "small_v": ["\u06CE"],
19000             "three_dots_below": ["\u06D1"],
19001             "two_dots_below_dot_above": ["\u08A9"],
19002             "two_dots_below_small_noon_above": ["\u08BA"],
19003             "isolated": "\uFEF1",
19004             "final": "\uFEF2",
19005             "initial": "\uFEF3",
19006             "medial": "\uFEF4"
19007           },
19008           "tteh": {
19009             "normal": ["\u0679"],
19010             "isolated": "\uFB66",
19011             "final": "\uFB67",
19012             "initial": "\uFB68",
19013             "medial": "\uFB69"
19014           },
19015           "tteheh": {
19016             "normal": ["\u067A"],
19017             "isolated": "\uFB5E",
19018             "final": "\uFB5F",
19019             "initial": "\uFB60",
19020             "medial": "\uFB61"
19021           },
19022           "beeh": {
19023             "normal": ["\u067B"],
19024             "isolated": "\uFB52",
19025             "final": "\uFB53",
19026             "initial": "\uFB54",
19027             "medial": "\uFB55"
19028           },
19029           "peh": {
19030             "normal": ["\u067E"],
19031             "small_meem_above": ["\u08B7"],
19032             "isolated": "\uFB56",
19033             "final": "\uFB57",
19034             "initial": "\uFB58",
19035             "medial": "\uFB59"
19036           },
19037           "teheh": {
19038             "normal": ["\u067F"],
19039             "isolated": "\uFB62",
19040             "final": "\uFB63",
19041             "initial": "\uFB64",
19042             "medial": "\uFB65"
19043           },
19044           "beheh": {
19045             "normal": ["\u0680"],
19046             "isolated": "\uFB5A",
19047             "final": "\uFB5B",
19048             "initial": "\uFB5C",
19049             "medial": "\uFB5D"
19050           },
19051           "nyeh": {
19052             "normal": ["\u0683"],
19053             "isolated": "\uFB76",
19054             "final": "\uFB77",
19055             "initial": "\uFB78",
19056             "medial": "\uFB79"
19057           },
19058           "dyeh": {
19059             "normal": ["\u0684"],
19060             "isolated": "\uFB72",
19061             "final": "\uFB73",
19062             "initial": "\uFB74",
19063             "medial": "\uFB75"
19064           },
19065           "tcheh": {
19066             "normal": ["\u0686"],
19067             "dot_above": ["\u06BF"],
19068             "isolated": "\uFB7A",
19069             "final": "\uFB7B",
19070             "initial": "\uFB7C",
19071             "medial": "\uFB7D"
19072           },
19073           "tcheheh": {
19074             "normal": ["\u0687"],
19075             "isolated": "\uFB7E",
19076             "final": "\uFB7F",
19077             "initial": "\uFB80",
19078             "medial": "\uFB81"
19079           },
19080           "ddal": {
19081             "normal": ["\u0688"],
19082             "isolated": "\uFB88",
19083             "final": "\uFB89"
19084           },
19085           "dahal": {
19086             "normal": ["\u068C"],
19087             "isolated": "\uFB84",
19088             "final": "\uFB85"
19089           },
19090           "ddahal": {
19091             "normal": ["\u068D"],
19092             "isolated": "\uFB82",
19093             "final": "\uFB83"
19094           },
19095           "dul": {
19096             "normal": ["\u068F", "\u068E"],
19097             "isolated": "\uFB86",
19098             "final": "\uFB87"
19099           },
19100           "rreh": {
19101             "normal": ["\u0691"],
19102             "isolated": "\uFB8C",
19103             "final": "\uFB8D"
19104           },
19105           "jeh": {
19106             "normal": ["\u0698"],
19107             "isolated": "\uFB8A",
19108             "final": "\uFB8B"
19109           },
19110           "veh": {
19111             "normal": ["\u06A4"],
19112             "isolated": "\uFB6A",
19113             "final": "\uFB6B",
19114             "initial": "\uFB6C",
19115             "medial": "\uFB6D"
19116           },
19117           "peheh": {
19118             "normal": ["\u06A6"],
19119             "isolated": "\uFB6E",
19120             "final": "\uFB6F",
19121             "initial": "\uFB70",
19122             "medial": "\uFB71"
19123           },
19124           "keheh": {
19125             "normal": ["\u06A9"],
19126             "dot_above": ["\u0762"],
19127             "three_dots_above": ["\u0763"],
19128             "three_dots_pointing_upwards_below": ["\u0764"],
19129             "isolated": "\uFB8E",
19130             "final": "\uFB8F",
19131             "initial": "\uFB90",
19132             "medial": "\uFB91"
19133           },
19134           "ng": {
19135             "normal": ["\u06AD"],
19136             "isolated": "\uFBD3",
19137             "final": "\uFBD4",
19138             "initial": "\uFBD5",
19139             "medial": "\uFBD6"
19140           },
19141           "gaf": {
19142             "normal": ["\u06AF"],
19143             "ring": ["\u06B0"],
19144             "two_dots_below": ["\u06B2"],
19145             "three_dots_above": ["\u06B4"],
19146             "inverted_stroke": ["\u08B0"],
19147             "isolated": "\uFB92",
19148             "final": "\uFB93",
19149             "initial": "\uFB94",
19150             "medial": "\uFB95"
19151           },
19152           "ngoeh": {
19153             "normal": ["\u06B1"],
19154             "isolated": "\uFB9A",
19155             "final": "\uFB9B",
19156             "initial": "\uFB9C",
19157             "medial": "\uFB9D"
19158           },
19159           "gueh": {
19160             "normal": ["\u06B3"],
19161             "isolated": "\uFB96",
19162             "final": "\uFB97",
19163             "initial": "\uFB98",
19164             "medial": "\uFB99"
19165           },
19166           "noon ghunna": {
19167             "normal": ["\u06BA"],
19168             "isolated": "\uFB9E",
19169             "final": "\uFB9F"
19170           },
19171           "rnoon": {
19172             "normal": ["\u06BB"],
19173             "isolated": "\uFBA0",
19174             "final": "\uFBA1",
19175             "initial": "\uFBA2",
19176             "medial": "\uFBA3"
19177           },
19178           "heh doachashmee": {
19179             "normal": ["\u06BE"],
19180             "isolated": "\uFBAA",
19181             "final": "\uFBAB",
19182             "initial": "\uFBAC",
19183             "medial": "\uFBAD"
19184           },
19185           "heh goal": {
19186             "normal": ["\u06C1"],
19187             "hamza_above": ["\u06C1\u0654", "\u06C2"],
19188             "isolated": "\uFBA6",
19189             "final": "\uFBA7",
19190             "initial": "\uFBA8",
19191             "medial": "\uFBA9"
19192           },
19193           "teh marbuta goal": {
19194             "normal": ["\u06C3"]
19195           },
19196           "kirghiz oe": {
19197             "normal": ["\u06C5"],
19198             "isolated": "\uFBE0",
19199             "final": "\uFBE1"
19200           },
19201           "oe": {
19202             "normal": ["\u06C6"],
19203             "isolated": "\uFBD9",
19204             "final": "\uFBDA"
19205           },
19206           "u": {
19207             "normal": ["\u06C7"],
19208             "hamza_above": {
19209               "normal": ["\u0677", "\u06C7\u0674"],
19210               "isolated": "\uFBDD"
19211             },
19212             "isolated": "\uFBD7",
19213             "final": "\uFBD8"
19214           },
19215           "yu": {
19216             "normal": ["\u06C8"],
19217             "isolated": "\uFBDB",
19218             "final": "\uFBDC"
19219           },
19220           "kirghiz yu": {
19221             "normal": ["\u06C9"],
19222             "isolated": "\uFBE2",
19223             "final": "\uFBE3"
19224           },
19225           "ve": {
19226             "normal": ["\u06CB"],
19227             "isolated": "\uFBDE",
19228             "final": "\uFBDF"
19229           },
19230           "farsi yeh": {
19231             "normal": ["\u06CC"],
19232             "indic_two_above": ["\u0775"],
19233             "indic_three_above": ["\u0776"],
19234             "indic_four_above": ["\u0777"],
19235             "isolated": "\uFBFC",
19236             "final": "\uFBFD",
19237             "initial": "\uFBFE",
19238             "medial": "\uFBFF"
19239           },
19240           "e": {
19241             "normal": ["\u06D0"],
19242             "isolated": "\uFBE4",
19243             "final": "\uFBE5",
19244             "initial": "\uFBE6",
19245             "medial": "\uFBE7"
19246           },
19247           "yeh barree": {
19248             "normal": ["\u06D2"],
19249             "hamza_above": {
19250               "normal": ["\u06D2\u0654", "\u06D3"],
19251               "isolated": "\uFBB0",
19252               "final": "\uFBB1"
19253             },
19254             "indic_two_above": ["\u077A"],
19255             "indic_three_above": ["\u077B"],
19256             "isolated": "\uFBAE",
19257             "final": "\uFBAF"
19258           },
19259           "ae": {
19260             "normal": ["\u06D5"],
19261             "isolated": "\u06D5",
19262             "final": "\uFEEA",
19263             "yeh_above": {
19264               "normal": ["\u06C0", "\u06D5\u0654"],
19265               "isolated": "\uFBA4",
19266               "final": "\uFBA5"
19267             }
19268           },
19269           "rohingya yeh": {
19270             "normal": ["\u08AC"]
19271           },
19272           "low alef": {
19273             "normal": ["\u08AD"]
19274           },
19275           "straight waw": {
19276             "normal": ["\u08B1"]
19277           },
19278           "african feh": {
19279             "normal": ["\u08BB"]
19280           },
19281           "african qaf": {
19282             "normal": ["\u08BC"]
19283           },
19284           "african noon": {
19285             "normal": ["\u08BD"]
19286           }
19287         };
19288
19289         unicodeArabic["default"] = arabicReference;
19290
19291         var unicodeLigatures = {};
19292
19293         Object.defineProperty(unicodeLigatures, "__esModule", {
19294           value: true
19295         });
19296         var ligatureReference = {
19297           "\u0626\u0627": {
19298             "isolated": "\uFBEA",
19299             "final": "\uFBEB"
19300           },
19301           "\u0626\u06D5": {
19302             "isolated": "\uFBEC",
19303             "final": "\uFBED"
19304           },
19305           "\u0626\u0648": {
19306             "isolated": "\uFBEE",
19307             "final": "\uFBEF"
19308           },
19309           "\u0626\u06C7": {
19310             "isolated": "\uFBF0",
19311             "final": "\uFBF1"
19312           },
19313           "\u0626\u06C6": {
19314             "isolated": "\uFBF2",
19315             "final": "\uFBF3"
19316           },
19317           "\u0626\u06C8": {
19318             "isolated": "\uFBF4",
19319             "final": "\uFBF5"
19320           },
19321           "\u0626\u06D0": {
19322             "isolated": "\uFBF6",
19323             "final": "\uFBF7",
19324             "initial": "\uFBF8"
19325           },
19326           "\u0626\u0649": {
19327             "uighur_kirghiz": {
19328               "isolated": "\uFBF9",
19329               "final": "\uFBFA",
19330               "initial": "\uFBFB"
19331             },
19332             "isolated": "\uFC03",
19333             "final": "\uFC68"
19334           },
19335           "\u0626\u062C": {
19336             "isolated": "\uFC00",
19337             "initial": "\uFC97"
19338           },
19339           "\u0626\u062D": {
19340             "isolated": "\uFC01",
19341             "initial": "\uFC98"
19342           },
19343           "\u0626\u0645": {
19344             "isolated": "\uFC02",
19345             "final": "\uFC66",
19346             "initial": "\uFC9A",
19347             "medial": "\uFCDF"
19348           },
19349           "\u0626\u064A": {
19350             "isolated": "\uFC04",
19351             "final": "\uFC69"
19352           },
19353           "\u0628\u062C": {
19354             "isolated": "\uFC05",
19355             "initial": "\uFC9C"
19356           },
19357           "\u0628\u062D": {
19358             "isolated": "\uFC06",
19359             "initial": "\uFC9D"
19360           },
19361           "\u0628\u062E": {
19362             "isolated": "\uFC07",
19363             "initial": "\uFC9E"
19364           },
19365           "\u0628\u0645": {
19366             "isolated": "\uFC08",
19367             "final": "\uFC6C",
19368             "initial": "\uFC9F",
19369             "medial": "\uFCE1"
19370           },
19371           "\u0628\u0649": {
19372             "isolated": "\uFC09",
19373             "final": "\uFC6E"
19374           },
19375           "\u0628\u064A": {
19376             "isolated": "\uFC0A",
19377             "final": "\uFC6F"
19378           },
19379           "\u062A\u062C": {
19380             "isolated": "\uFC0B",
19381             "initial": "\uFCA1"
19382           },
19383           "\u062A\u062D": {
19384             "isolated": "\uFC0C",
19385             "initial": "\uFCA2"
19386           },
19387           "\u062A\u062E": {
19388             "isolated": "\uFC0D",
19389             "initial": "\uFCA3"
19390           },
19391           "\u062A\u0645": {
19392             "isolated": "\uFC0E",
19393             "final": "\uFC72",
19394             "initial": "\uFCA4",
19395             "medial": "\uFCE3"
19396           },
19397           "\u062A\u0649": {
19398             "isolated": "\uFC0F",
19399             "final": "\uFC74"
19400           },
19401           "\u062A\u064A": {
19402             "isolated": "\uFC10",
19403             "final": "\uFC75"
19404           },
19405           "\u062B\u062C": {
19406             "isolated": "\uFC11"
19407           },
19408           "\u062B\u0645": {
19409             "isolated": "\uFC12",
19410             "final": "\uFC78",
19411             "initial": "\uFCA6",
19412             "medial": "\uFCE5"
19413           },
19414           "\u062B\u0649": {
19415             "isolated": "\uFC13",
19416             "final": "\uFC7A"
19417           },
19418           "\u062B\u0648": {
19419             "isolated": "\uFC14"
19420           },
19421           "\u062C\u062D": {
19422             "isolated": "\uFC15",
19423             "initial": "\uFCA7"
19424           },
19425           "\u062C\u0645": {
19426             "isolated": "\uFC16",
19427             "initial": "\uFCA8"
19428           },
19429           "\u062D\u062C": {
19430             "isolated": "\uFC17",
19431             "initial": "\uFCA9"
19432           },
19433           "\u062D\u0645": {
19434             "isolated": "\uFC18",
19435             "initial": "\uFCAA"
19436           },
19437           "\u062E\u062C": {
19438             "isolated": "\uFC19",
19439             "initial": "\uFCAB"
19440           },
19441           "\u062E\u062D": {
19442             "isolated": "\uFC1A"
19443           },
19444           "\u062E\u0645": {
19445             "isolated": "\uFC1B",
19446             "initial": "\uFCAC"
19447           },
19448           "\u0633\u062C": {
19449             "isolated": "\uFC1C",
19450             "initial": "\uFCAD",
19451             "medial": "\uFD34"
19452           },
19453           "\u0633\u062D": {
19454             "isolated": "\uFC1D",
19455             "initial": "\uFCAE",
19456             "medial": "\uFD35"
19457           },
19458           "\u0633\u062E": {
19459             "isolated": "\uFC1E",
19460             "initial": "\uFCAF",
19461             "medial": "\uFD36"
19462           },
19463           "\u0633\u0645": {
19464             "isolated": "\uFC1F",
19465             "initial": "\uFCB0",
19466             "medial": "\uFCE7"
19467           },
19468           "\u0635\u062D": {
19469             "isolated": "\uFC20",
19470             "initial": "\uFCB1"
19471           },
19472           "\u0635\u0645": {
19473             "isolated": "\uFC21",
19474             "initial": "\uFCB3"
19475           },
19476           "\u0636\u062C": {
19477             "isolated": "\uFC22",
19478             "initial": "\uFCB4"
19479           },
19480           "\u0636\u062D": {
19481             "isolated": "\uFC23",
19482             "initial": "\uFCB5"
19483           },
19484           "\u0636\u062E": {
19485             "isolated": "\uFC24",
19486             "initial": "\uFCB6"
19487           },
19488           "\u0636\u0645": {
19489             "isolated": "\uFC25",
19490             "initial": "\uFCB7"
19491           },
19492           "\u0637\u062D": {
19493             "isolated": "\uFC26",
19494             "initial": "\uFCB8"
19495           },
19496           "\u0637\u0645": {
19497             "isolated": "\uFC27",
19498             "initial": "\uFD33",
19499             "medial": "\uFD3A"
19500           },
19501           "\u0638\u0645": {
19502             "isolated": "\uFC28",
19503             "initial": "\uFCB9",
19504             "medial": "\uFD3B"
19505           },
19506           "\u0639\u062C": {
19507             "isolated": "\uFC29",
19508             "initial": "\uFCBA"
19509           },
19510           "\u0639\u0645": {
19511             "isolated": "\uFC2A",
19512             "initial": "\uFCBB"
19513           },
19514           "\u063A\u062C": {
19515             "isolated": "\uFC2B",
19516             "initial": "\uFCBC"
19517           },
19518           "\u063A\u0645": {
19519             "isolated": "\uFC2C",
19520             "initial": "\uFCBD"
19521           },
19522           "\u0641\u062C": {
19523             "isolated": "\uFC2D",
19524             "initial": "\uFCBE"
19525           },
19526           "\u0641\u062D": {
19527             "isolated": "\uFC2E",
19528             "initial": "\uFCBF"
19529           },
19530           "\u0641\u062E": {
19531             "isolated": "\uFC2F",
19532             "initial": "\uFCC0"
19533           },
19534           "\u0641\u0645": {
19535             "isolated": "\uFC30",
19536             "initial": "\uFCC1"
19537           },
19538           "\u0641\u0649": {
19539             "isolated": "\uFC31",
19540             "final": "\uFC7C"
19541           },
19542           "\u0641\u064A": {
19543             "isolated": "\uFC32",
19544             "final": "\uFC7D"
19545           },
19546           "\u0642\u062D": {
19547             "isolated": "\uFC33",
19548             "initial": "\uFCC2"
19549           },
19550           "\u0642\u0645": {
19551             "isolated": "\uFC34",
19552             "initial": "\uFCC3"
19553           },
19554           "\u0642\u0649": {
19555             "isolated": "\uFC35",
19556             "final": "\uFC7E"
19557           },
19558           "\u0642\u064A": {
19559             "isolated": "\uFC36",
19560             "final": "\uFC7F"
19561           },
19562           "\u0643\u0627": {
19563             "isolated": "\uFC37",
19564             "final": "\uFC80"
19565           },
19566           "\u0643\u062C": {
19567             "isolated": "\uFC38",
19568             "initial": "\uFCC4"
19569           },
19570           "\u0643\u062D": {
19571             "isolated": "\uFC39",
19572             "initial": "\uFCC5"
19573           },
19574           "\u0643\u062E": {
19575             "isolated": "\uFC3A",
19576             "initial": "\uFCC6"
19577           },
19578           "\u0643\u0644": {
19579             "isolated": "\uFC3B",
19580             "final": "\uFC81",
19581             "initial": "\uFCC7",
19582             "medial": "\uFCEB"
19583           },
19584           "\u0643\u0645": {
19585             "isolated": "\uFC3C",
19586             "final": "\uFC82",
19587             "initial": "\uFCC8",
19588             "medial": "\uFCEC"
19589           },
19590           "\u0643\u0649": {
19591             "isolated": "\uFC3D",
19592             "final": "\uFC83"
19593           },
19594           "\u0643\u064A": {
19595             "isolated": "\uFC3E",
19596             "final": "\uFC84"
19597           },
19598           "\u0644\u062C": {
19599             "isolated": "\uFC3F",
19600             "initial": "\uFCC9"
19601           },
19602           "\u0644\u062D": {
19603             "isolated": "\uFC40",
19604             "initial": "\uFCCA"
19605           },
19606           "\u0644\u062E": {
19607             "isolated": "\uFC41",
19608             "initial": "\uFCCB"
19609           },
19610           "\u0644\u0645": {
19611             "isolated": "\uFC42",
19612             "final": "\uFC85",
19613             "initial": "\uFCCC",
19614             "medial": "\uFCED"
19615           },
19616           "\u0644\u0649": {
19617             "isolated": "\uFC43",
19618             "final": "\uFC86"
19619           },
19620           "\u0644\u064A": {
19621             "isolated": "\uFC44",
19622             "final": "\uFC87"
19623           },
19624           "\u0645\u062C": {
19625             "isolated": "\uFC45",
19626             "initial": "\uFCCE"
19627           },
19628           "\u0645\u062D": {
19629             "isolated": "\uFC46",
19630             "initial": "\uFCCF"
19631           },
19632           "\u0645\u062E": {
19633             "isolated": "\uFC47",
19634             "initial": "\uFCD0"
19635           },
19636           "\u0645\u0645": {
19637             "isolated": "\uFC48",
19638             "final": "\uFC89",
19639             "initial": "\uFCD1"
19640           },
19641           "\u0645\u0649": {
19642             "isolated": "\uFC49"
19643           },
19644           "\u0645\u064A": {
19645             "isolated": "\uFC4A"
19646           },
19647           "\u0646\u062C": {
19648             "isolated": "\uFC4B",
19649             "initial": "\uFCD2"
19650           },
19651           "\u0646\u062D": {
19652             "isolated": "\uFC4C",
19653             "initial": "\uFCD3"
19654           },
19655           "\u0646\u062E": {
19656             "isolated": "\uFC4D",
19657             "initial": "\uFCD4"
19658           },
19659           "\u0646\u0645": {
19660             "isolated": "\uFC4E",
19661             "final": "\uFC8C",
19662             "initial": "\uFCD5",
19663             "medial": "\uFCEE"
19664           },
19665           "\u0646\u0649": {
19666             "isolated": "\uFC4F",
19667             "final": "\uFC8E"
19668           },
19669           "\u0646\u064A": {
19670             "isolated": "\uFC50",
19671             "final": "\uFC8F"
19672           },
19673           "\u0647\u062C": {
19674             "isolated": "\uFC51",
19675             "initial": "\uFCD7"
19676           },
19677           "\u0647\u0645": {
19678             "isolated": "\uFC52",
19679             "initial": "\uFCD8"
19680           },
19681           "\u0647\u0649": {
19682             "isolated": "\uFC53"
19683           },
19684           "\u0647\u064A": {
19685             "isolated": "\uFC54"
19686           },
19687           "\u064A\u062C": {
19688             "isolated": "\uFC55",
19689             "initial": "\uFCDA"
19690           },
19691           "\u064A\u062D": {
19692             "isolated": "\uFC56",
19693             "initial": "\uFCDB"
19694           },
19695           "\u064A\u062E": {
19696             "isolated": "\uFC57",
19697             "initial": "\uFCDC"
19698           },
19699           "\u064A\u0645": {
19700             "isolated": "\uFC58",
19701             "final": "\uFC93",
19702             "initial": "\uFCDD",
19703             "medial": "\uFCF0"
19704           },
19705           "\u064A\u0649": {
19706             "isolated": "\uFC59",
19707             "final": "\uFC95"
19708           },
19709           "\u064A\u064A": {
19710             "isolated": "\uFC5A",
19711             "final": "\uFC96"
19712           },
19713           "\u0630\u0670": {
19714             "isolated": "\uFC5B"
19715           },
19716           "\u0631\u0670": {
19717             "isolated": "\uFC5C"
19718           },
19719           "\u0649\u0670": {
19720             "isolated": "\uFC5D",
19721             "final": "\uFC90"
19722           },
19723           "\u064C\u0651": {
19724             "isolated": "\uFC5E"
19725           },
19726           "\u064D\u0651": {
19727             "isolated": "\uFC5F"
19728           },
19729           "\u064E\u0651": {
19730             "isolated": "\uFC60"
19731           },
19732           "\u064F\u0651": {
19733             "isolated": "\uFC61"
19734           },
19735           "\u0650\u0651": {
19736             "isolated": "\uFC62"
19737           },
19738           "\u0651\u0670": {
19739             "isolated": "\uFC63"
19740           },
19741           "\u0626\u0631": {
19742             "final": "\uFC64"
19743           },
19744           "\u0626\u0632": {
19745             "final": "\uFC65"
19746           },
19747           "\u0626\u0646": {
19748             "final": "\uFC67"
19749           },
19750           "\u0628\u0631": {
19751             "final": "\uFC6A"
19752           },
19753           "\u0628\u0632": {
19754             "final": "\uFC6B"
19755           },
19756           "\u0628\u0646": {
19757             "final": "\uFC6D"
19758           },
19759           "\u062A\u0631": {
19760             "final": "\uFC70"
19761           },
19762           "\u062A\u0632": {
19763             "final": "\uFC71"
19764           },
19765           "\u062A\u0646": {
19766             "final": "\uFC73"
19767           },
19768           "\u062B\u0631": {
19769             "final": "\uFC76"
19770           },
19771           "\u062B\u0632": {
19772             "final": "\uFC77"
19773           },
19774           "\u062B\u0646": {
19775             "final": "\uFC79"
19776           },
19777           "\u062B\u064A": {
19778             "final": "\uFC7B"
19779           },
19780           "\u0645\u0627": {
19781             "final": "\uFC88"
19782           },
19783           "\u0646\u0631": {
19784             "final": "\uFC8A"
19785           },
19786           "\u0646\u0632": {
19787             "final": "\uFC8B"
19788           },
19789           "\u0646\u0646": {
19790             "final": "\uFC8D"
19791           },
19792           "\u064A\u0631": {
19793             "final": "\uFC91"
19794           },
19795           "\u064A\u0632": {
19796             "final": "\uFC92"
19797           },
19798           "\u064A\u0646": {
19799             "final": "\uFC94"
19800           },
19801           "\u0626\u062E": {
19802             "initial": "\uFC99"
19803           },
19804           "\u0626\u0647": {
19805             "initial": "\uFC9B",
19806             "medial": "\uFCE0"
19807           },
19808           "\u0628\u0647": {
19809             "initial": "\uFCA0",
19810             "medial": "\uFCE2"
19811           },
19812           "\u062A\u0647": {
19813             "initial": "\uFCA5",
19814             "medial": "\uFCE4"
19815           },
19816           "\u0635\u062E": {
19817             "initial": "\uFCB2"
19818           },
19819           "\u0644\u0647": {
19820             "initial": "\uFCCD"
19821           },
19822           "\u0646\u0647": {
19823             "initial": "\uFCD6",
19824             "medial": "\uFCEF"
19825           },
19826           "\u0647\u0670": {
19827             "initial": "\uFCD9"
19828           },
19829           "\u064A\u0647": {
19830             "initial": "\uFCDE",
19831             "medial": "\uFCF1"
19832           },
19833           "\u062B\u0647": {
19834             "medial": "\uFCE6"
19835           },
19836           "\u0633\u0647": {
19837             "medial": "\uFCE8",
19838             "initial": "\uFD31"
19839           },
19840           "\u0634\u0645": {
19841             "medial": "\uFCE9",
19842             "isolated": "\uFD0C",
19843             "final": "\uFD28",
19844             "initial": "\uFD30"
19845           },
19846           "\u0634\u0647": {
19847             "medial": "\uFCEA",
19848             "initial": "\uFD32"
19849           },
19850           "\u0640\u064E\u0651": {
19851             "medial": "\uFCF2"
19852           },
19853           "\u0640\u064F\u0651": {
19854             "medial": "\uFCF3"
19855           },
19856           "\u0640\u0650\u0651": {
19857             "medial": "\uFCF4"
19858           },
19859           "\u0637\u0649": {
19860             "isolated": "\uFCF5",
19861             "final": "\uFD11"
19862           },
19863           "\u0637\u064A": {
19864             "isolated": "\uFCF6",
19865             "final": "\uFD12"
19866           },
19867           "\u0639\u0649": {
19868             "isolated": "\uFCF7",
19869             "final": "\uFD13"
19870           },
19871           "\u0639\u064A": {
19872             "isolated": "\uFCF8",
19873             "final": "\uFD14"
19874           },
19875           "\u063A\u0649": {
19876             "isolated": "\uFCF9",
19877             "final": "\uFD15"
19878           },
19879           "\u063A\u064A": {
19880             "isolated": "\uFCFA",
19881             "final": "\uFD16"
19882           },
19883           "\u0633\u0649": {
19884             "isolated": "\uFCFB"
19885           },
19886           "\u0633\u064A": {
19887             "isolated": "\uFCFC",
19888             "final": "\uFD18"
19889           },
19890           "\u0634\u0649": {
19891             "isolated": "\uFCFD",
19892             "final": "\uFD19"
19893           },
19894           "\u0634\u064A": {
19895             "isolated": "\uFCFE",
19896             "final": "\uFD1A"
19897           },
19898           "\u062D\u0649": {
19899             "isolated": "\uFCFF",
19900             "final": "\uFD1B"
19901           },
19902           "\u062D\u064A": {
19903             "isolated": "\uFD00",
19904             "final": "\uFD1C"
19905           },
19906           "\u062C\u0649": {
19907             "isolated": "\uFD01",
19908             "final": "\uFD1D"
19909           },
19910           "\u062C\u064A": {
19911             "isolated": "\uFD02",
19912             "final": "\uFD1E"
19913           },
19914           "\u062E\u0649": {
19915             "isolated": "\uFD03",
19916             "final": "\uFD1F"
19917           },
19918           "\u062E\u064A": {
19919             "isolated": "\uFD04",
19920             "final": "\uFD20"
19921           },
19922           "\u0635\u0649": {
19923             "isolated": "\uFD05",
19924             "final": "\uFD21"
19925           },
19926           "\u0635\u064A": {
19927             "isolated": "\uFD06",
19928             "final": "\uFD22"
19929           },
19930           "\u0636\u0649": {
19931             "isolated": "\uFD07",
19932             "final": "\uFD23"
19933           },
19934           "\u0636\u064A": {
19935             "isolated": "\uFD08",
19936             "final": "\uFD24"
19937           },
19938           "\u0634\u062C": {
19939             "isolated": "\uFD09",
19940             "final": "\uFD25",
19941             "initial": "\uFD2D",
19942             "medial": "\uFD37"
19943           },
19944           "\u0634\u062D": {
19945             "isolated": "\uFD0A",
19946             "final": "\uFD26",
19947             "initial": "\uFD2E",
19948             "medial": "\uFD38"
19949           },
19950           "\u0634\u062E": {
19951             "isolated": "\uFD0B",
19952             "final": "\uFD27",
19953             "initial": "\uFD2F",
19954             "medial": "\uFD39"
19955           },
19956           "\u0634\u0631": {
19957             "isolated": "\uFD0D",
19958             "final": "\uFD29"
19959           },
19960           "\u0633\u0631": {
19961             "isolated": "\uFD0E",
19962             "final": "\uFD2A"
19963           },
19964           "\u0635\u0631": {
19965             "isolated": "\uFD0F",
19966             "final": "\uFD2B"
19967           },
19968           "\u0636\u0631": {
19969             "isolated": "\uFD10",
19970             "final": "\uFD2C"
19971           },
19972           "\u0633\u0639": {
19973             "final": "\uFD17"
19974           },
19975           "\u062A\u062C\u0645": {
19976             "initial": "\uFD50"
19977           },
19978           "\u062A\u062D\u062C": {
19979             "final": "\uFD51",
19980             "initial": "\uFD52"
19981           },
19982           "\u062A\u062D\u0645": {
19983             "initial": "\uFD53"
19984           },
19985           "\u062A\u062E\u0645": {
19986             "initial": "\uFD54"
19987           },
19988           "\u062A\u0645\u062C": {
19989             "initial": "\uFD55"
19990           },
19991           "\u062A\u0645\u062D": {
19992             "initial": "\uFD56"
19993           },
19994           "\u062A\u0645\u062E": {
19995             "initial": "\uFD57"
19996           },
19997           "\u062C\u0645\u062D": {
19998             "final": "\uFD58",
19999             "initial": "\uFD59"
20000           },
20001           "\u062D\u0645\u064A": {
20002             "final": "\uFD5A"
20003           },
20004           "\u062D\u0645\u0649": {
20005             "final": "\uFD5B"
20006           },
20007           "\u0633\u062D\u062C": {
20008             "initial": "\uFD5C"
20009           },
20010           "\u0633\u062C\u062D": {
20011             "initial": "\uFD5D"
20012           },
20013           "\u0633\u062C\u0649": {
20014             "final": "\uFD5E"
20015           },
20016           "\u0633\u0645\u062D": {
20017             "final": "\uFD5F",
20018             "initial": "\uFD60"
20019           },
20020           "\u0633\u0645\u062C": {
20021             "initial": "\uFD61"
20022           },
20023           "\u0633\u0645\u0645": {
20024             "final": "\uFD62",
20025             "initial": "\uFD63"
20026           },
20027           "\u0635\u062D\u062D": {
20028             "final": "\uFD64",
20029             "initial": "\uFD65"
20030           },
20031           "\u0635\u0645\u0645": {
20032             "final": "\uFD66",
20033             "initial": "\uFDC5"
20034           },
20035           "\u0634\u062D\u0645": {
20036             "final": "\uFD67",
20037             "initial": "\uFD68"
20038           },
20039           "\u0634\u062C\u064A": {
20040             "final": "\uFD69"
20041           },
20042           "\u0634\u0645\u062E": {
20043             "final": "\uFD6A",
20044             "initial": "\uFD6B"
20045           },
20046           "\u0634\u0645\u0645": {
20047             "final": "\uFD6C",
20048             "initial": "\uFD6D"
20049           },
20050           "\u0636\u062D\u0649": {
20051             "final": "\uFD6E"
20052           },
20053           "\u0636\u062E\u0645": {
20054             "final": "\uFD6F",
20055             "initial": "\uFD70"
20056           },
20057           "\u0636\u0645\u062D": {
20058             "final": "\uFD71"
20059           },
20060           "\u0637\u0645\u062D": {
20061             "initial": "\uFD72"
20062           },
20063           "\u0637\u0645\u0645": {
20064             "initial": "\uFD73"
20065           },
20066           "\u0637\u0645\u064A": {
20067             "final": "\uFD74"
20068           },
20069           "\u0639\u062C\u0645": {
20070             "final": "\uFD75",
20071             "initial": "\uFDC4"
20072           },
20073           "\u0639\u0645\u0645": {
20074             "final": "\uFD76",
20075             "initial": "\uFD77"
20076           },
20077           "\u0639\u0645\u0649": {
20078             "final": "\uFD78"
20079           },
20080           "\u063A\u0645\u0645": {
20081             "final": "\uFD79"
20082           },
20083           "\u063A\u0645\u064A": {
20084             "final": "\uFD7A"
20085           },
20086           "\u063A\u0645\u0649": {
20087             "final": "\uFD7B"
20088           },
20089           "\u0641\u062E\u0645": {
20090             "final": "\uFD7C",
20091             "initial": "\uFD7D"
20092           },
20093           "\u0642\u0645\u062D": {
20094             "final": "\uFD7E",
20095             "initial": "\uFDB4"
20096           },
20097           "\u0642\u0645\u0645": {
20098             "final": "\uFD7F"
20099           },
20100           "\u0644\u062D\u0645": {
20101             "final": "\uFD80",
20102             "initial": "\uFDB5"
20103           },
20104           "\u0644\u062D\u064A": {
20105             "final": "\uFD81"
20106           },
20107           "\u0644\u062D\u0649": {
20108             "final": "\uFD82"
20109           },
20110           "\u0644\u062C\u062C": {
20111             "initial": "\uFD83",
20112             "final": "\uFD84"
20113           },
20114           "\u0644\u062E\u0645": {
20115             "final": "\uFD85",
20116             "initial": "\uFD86"
20117           },
20118           "\u0644\u0645\u062D": {
20119             "final": "\uFD87",
20120             "initial": "\uFD88"
20121           },
20122           "\u0645\u062D\u062C": {
20123             "initial": "\uFD89"
20124           },
20125           "\u0645\u062D\u0645": {
20126             "initial": "\uFD8A"
20127           },
20128           "\u0645\u062D\u064A": {
20129             "final": "\uFD8B"
20130           },
20131           "\u0645\u062C\u062D": {
20132             "initial": "\uFD8C"
20133           },
20134           "\u0645\u062C\u0645": {
20135             "initial": "\uFD8D"
20136           },
20137           "\u0645\u062E\u062C": {
20138             "initial": "\uFD8E"
20139           },
20140           "\u0645\u062E\u0645": {
20141             "initial": "\uFD8F"
20142           },
20143           "\u0645\u062C\u062E": {
20144             "initial": "\uFD92"
20145           },
20146           "\u0647\u0645\u062C": {
20147             "initial": "\uFD93"
20148           },
20149           "\u0647\u0645\u0645": {
20150             "initial": "\uFD94"
20151           },
20152           "\u0646\u062D\u0645": {
20153             "initial": "\uFD95"
20154           },
20155           "\u0646\u062D\u0649": {
20156             "final": "\uFD96"
20157           },
20158           "\u0646\u062C\u0645": {
20159             "final": "\uFD97",
20160             "initial": "\uFD98"
20161           },
20162           "\u0646\u062C\u0649": {
20163             "final": "\uFD99"
20164           },
20165           "\u0646\u0645\u064A": {
20166             "final": "\uFD9A"
20167           },
20168           "\u0646\u0645\u0649": {
20169             "final": "\uFD9B"
20170           },
20171           "\u064A\u0645\u0645": {
20172             "final": "\uFD9C",
20173             "initial": "\uFD9D"
20174           },
20175           "\u0628\u062E\u064A": {
20176             "final": "\uFD9E"
20177           },
20178           "\u062A\u062C\u064A": {
20179             "final": "\uFD9F"
20180           },
20181           "\u062A\u062C\u0649": {
20182             "final": "\uFDA0"
20183           },
20184           "\u062A\u062E\u064A": {
20185             "final": "\uFDA1"
20186           },
20187           "\u062A\u062E\u0649": {
20188             "final": "\uFDA2"
20189           },
20190           "\u062A\u0645\u064A": {
20191             "final": "\uFDA3"
20192           },
20193           "\u062A\u0645\u0649": {
20194             "final": "\uFDA4"
20195           },
20196           "\u062C\u0645\u064A": {
20197             "final": "\uFDA5"
20198           },
20199           "\u062C\u062D\u0649": {
20200             "final": "\uFDA6"
20201           },
20202           "\u062C\u0645\u0649": {
20203             "final": "\uFDA7"
20204           },
20205           "\u0633\u062E\u0649": {
20206             "final": "\uFDA8"
20207           },
20208           "\u0635\u062D\u064A": {
20209             "final": "\uFDA9"
20210           },
20211           "\u0634\u062D\u064A": {
20212             "final": "\uFDAA"
20213           },
20214           "\u0636\u062D\u064A": {
20215             "final": "\uFDAB"
20216           },
20217           "\u0644\u062C\u064A": {
20218             "final": "\uFDAC"
20219           },
20220           "\u0644\u0645\u064A": {
20221             "final": "\uFDAD"
20222           },
20223           "\u064A\u062D\u064A": {
20224             "final": "\uFDAE"
20225           },
20226           "\u064A\u062C\u064A": {
20227             "final": "\uFDAF"
20228           },
20229           "\u064A\u0645\u064A": {
20230             "final": "\uFDB0"
20231           },
20232           "\u0645\u0645\u064A": {
20233             "final": "\uFDB1"
20234           },
20235           "\u0642\u0645\u064A": {
20236             "final": "\uFDB2"
20237           },
20238           "\u0646\u062D\u064A": {
20239             "final": "\uFDB3"
20240           },
20241           "\u0639\u0645\u064A": {
20242             "final": "\uFDB6"
20243           },
20244           "\u0643\u0645\u064A": {
20245             "final": "\uFDB7"
20246           },
20247           "\u0646\u062C\u062D": {
20248             "initial": "\uFDB8",
20249             "final": "\uFDBD"
20250           },
20251           "\u0645\u062E\u064A": {
20252             "final": "\uFDB9"
20253           },
20254           "\u0644\u062C\u0645": {
20255             "initial": "\uFDBA",
20256             "final": "\uFDBC"
20257           },
20258           "\u0643\u0645\u0645": {
20259             "final": "\uFDBB",
20260             "initial": "\uFDC3"
20261           },
20262           "\u062C\u062D\u064A": {
20263             "final": "\uFDBE"
20264           },
20265           "\u062D\u062C\u064A": {
20266             "final": "\uFDBF"
20267           },
20268           "\u0645\u062C\u064A": {
20269             "final": "\uFDC0"
20270           },
20271           "\u0641\u0645\u064A": {
20272             "final": "\uFDC1"
20273           },
20274           "\u0628\u062D\u064A": {
20275             "final": "\uFDC2"
20276           },
20277           "\u0633\u062E\u064A": {
20278             "final": "\uFDC6"
20279           },
20280           "\u0646\u062C\u064A": {
20281             "final": "\uFDC7"
20282           },
20283           "\u0644\u0622": {
20284             "isolated": "\uFEF5",
20285             "final": "\uFEF6"
20286           },
20287           "\u0644\u0623": {
20288             "isolated": "\uFEF7",
20289             "final": "\uFEF8"
20290           },
20291           "\u0644\u0625": {
20292             "isolated": "\uFEF9",
20293             "final": "\uFEFA"
20294           },
20295           "\u0644\u0627": {
20296             "isolated": "\uFEFB",
20297             "final": "\uFEFC"
20298           },
20299           "words": {
20300             "\u0635\u0644\u06D2": "\uFDF0",
20301             "\u0642\u0644\u06D2": "\uFDF1",
20302             "\u0627\u0644\u0644\u0647": "\uFDF2",
20303             "\u0627\u0643\u0628\u0631": "\uFDF3",
20304             "\u0645\u062D\u0645\u062F": "\uFDF4",
20305             "\u0635\u0644\u0639\u0645": "\uFDF5",
20306             "\u0631\u0633\u0648\u0644": "\uFDF6",
20307             "\u0639\u0644\u064A\u0647": "\uFDF7",
20308             "\u0648\u0633\u0644\u0645": "\uFDF8",
20309             "\u0635\u0644\u0649": "\uFDF9",
20310             "\u0635\u0644\u0649\u0627\u0644\u0644\u0647\u0639\u0644\u064A\u0647\u0648\u0633\u0644\u0645": "\uFDFA",
20311             "\u062C\u0644\u062C\u0644\u0627\u0644\u0647": "\uFDFB",
20312             "\u0631\u06CC\u0627\u0644": "\uFDFC"
20313           }
20314         };
20315
20316         unicodeLigatures["default"] = ligatureReference;
20317
20318         Object.defineProperty(reference, "__esModule", {
20319           value: true
20320         });
20321         var unicode_arabic_1$3 = unicodeArabic;
20322         var unicode_ligatures_1$2 = unicodeLigatures;
20323         var letterList = Object.keys(unicode_arabic_1$3["default"]);
20324         reference.letterList = letterList;
20325         var ligatureList = Object.keys(unicode_ligatures_1$2["default"]);
20326         reference.ligatureList = ligatureList;
20327         var ligatureWordList = Object.keys(unicode_ligatures_1$2["default"].words);
20328         reference.ligatureWordList = ligatureWordList;
20329         var lams = "\u0644\u06B5\u06B6\u06B7\u06B8";
20330         reference.lams = lams;
20331         var alefs = "\u0627\u0622\u0623\u0625\u0671\u0672\u0673\u0675\u0773\u0774";
20332         reference.alefs = alefs; // for (var l = 1; l < lams.length; l++) {
20333         //   console.log('-');
20334         //   for (var a = 0; a < alefs.length; a++) {
20335         //     console.log(a + ': ' + lams[l] + alefs[a]);
20336         //   }
20337         // }
20338
20339         var tashkeel = "\u0605\u0640\u0670\u0674\u06DF\u06E7\u06E8";
20340         reference.tashkeel = tashkeel;
20341
20342         function addToTashkeel(start, finish) {
20343           for (var i = start; i <= finish; i++) {
20344             reference.tashkeel = tashkeel += String.fromCharCode(i);
20345           }
20346         }
20347
20348         addToTashkeel(0x0610, 0x061A);
20349         addToTashkeel(0x064B, 0x065F);
20350         addToTashkeel(0x06D6, 0x06DC);
20351         addToTashkeel(0x06E0, 0x06E4);
20352         addToTashkeel(0x06EA, 0x06ED);
20353         addToTashkeel(0x08D3, 0x08E1);
20354         addToTashkeel(0x08E3, 0x08FF);
20355         addToTashkeel(0xFE70, 0xFE7F);
20356         var lineBreakers = "\u0627\u0629\u0648\u06C0\u06CF\u06FD\u06FE\u076B\u076C\u0771\u0773\u0774\u0778\u0779\u08E2\u08B1\u08B2\u08B9";
20357         reference.lineBreakers = lineBreakers;
20358
20359         function addToLineBreakers(start, finish) {
20360           for (var i = start; i <= finish; i++) {
20361             reference.lineBreakers = lineBreakers += String.fromCharCode(i);
20362           }
20363         }
20364
20365         addToLineBreakers(0x0600, 0x061F); // it's OK to include tashkeel in this range as it is ignored
20366
20367         addToLineBreakers(0x0621, 0x0625);
20368         addToLineBreakers(0x062F, 0x0632);
20369         addToLineBreakers(0x0660, 0x066D); // numerals, math
20370
20371         addToLineBreakers(0x0671, 0x0677);
20372         addToLineBreakers(0x0688, 0x0699);
20373         addToLineBreakers(0x06C3, 0x06CB);
20374         addToLineBreakers(0x06D2, 0x06F9);
20375         addToLineBreakers(0x0759, 0x075B);
20376         addToLineBreakers(0x08AA, 0x08AE);
20377         addToLineBreakers(0xFB50, 0xFDFD); // presentation forms look like they could connect, but never do
20378         // Presentation Forms A includes diacritics but they are meant to stand alone
20379
20380         addToLineBreakers(0xFE80, 0xFEFC); // presentation forms look like they could connect, but never do
20381         // numerals, math
20382
20383         addToLineBreakers(0x10E60, 0x10E7F);
20384         addToLineBreakers(0x1EC70, 0x1ECBF);
20385         addToLineBreakers(0x1EE00, 0x1EEFF);
20386
20387         Object.defineProperty(GlyphSplitter$1, "__esModule", {
20388           value: true
20389         });
20390         var isArabic_1$6 = isArabic$1;
20391         var reference_1$5 = reference;
20392
20393         function GlyphSplitter(word) {
20394           var letters = [];
20395           var lastLetter = '';
20396           word.split('').forEach(function (letter) {
20397             if (isArabic_1$6.isArabic(letter)) {
20398               if (reference_1$5.tashkeel.indexOf(letter) > -1) {
20399                 letters[letters.length - 1] += letter;
20400               } else if (lastLetter.length && (reference_1$5.lams.indexOf(lastLetter) === 0 && reference_1$5.alefs.indexOf(letter) > -1 || reference_1$5.lams.indexOf(lastLetter) > 0 && reference_1$5.alefs.indexOf(letter) === 0)) {
20401                 // valid LA forms
20402                 letters[letters.length - 1] += letter;
20403               } else {
20404                 letters.push(letter);
20405               }
20406             } else {
20407               letters.push(letter);
20408             }
20409
20410             if (reference_1$5.tashkeel.indexOf(letter) === -1) {
20411               lastLetter = letter;
20412             }
20413           });
20414           return letters;
20415         }
20416
20417         GlyphSplitter$1.GlyphSplitter = GlyphSplitter;
20418
20419         var BaselineSplitter$1 = {};
20420
20421         Object.defineProperty(BaselineSplitter$1, "__esModule", {
20422           value: true
20423         });
20424         var isArabic_1$5 = isArabic$1;
20425         var reference_1$4 = reference;
20426
20427         function BaselineSplitter(word) {
20428           var letters = [];
20429           var lastLetter = '';
20430           word.split('').forEach(function (letter) {
20431             if (isArabic_1$5.isArabic(letter) && isArabic_1$5.isArabic(lastLetter)) {
20432               if (lastLetter.length && reference_1$4.tashkeel.indexOf(letter) > -1) {
20433                 letters[letters.length - 1] += letter;
20434               } else if (reference_1$4.lineBreakers.indexOf(lastLetter) > -1) {
20435                 letters.push(letter);
20436               } else {
20437                 letters[letters.length - 1] += letter;
20438               }
20439             } else {
20440               letters.push(letter);
20441             }
20442
20443             if (reference_1$4.tashkeel.indexOf(letter) === -1) {
20444               // don't allow tashkeel to hide line break
20445               lastLetter = letter;
20446             }
20447           });
20448           return letters;
20449         }
20450
20451         BaselineSplitter$1.BaselineSplitter = BaselineSplitter;
20452
20453         var Normalization = {};
20454
20455         Object.defineProperty(Normalization, "__esModule", {
20456           value: true
20457         });
20458         var unicode_arabic_1$2 = unicodeArabic;
20459         var unicode_ligatures_1$1 = unicodeLigatures;
20460         var isArabic_1$4 = isArabic$1;
20461         var reference_1$3 = reference;
20462
20463         function Normal(word, breakPresentationForm) {
20464           // default is to turn initial/isolated/medial/final presentation form to generic
20465           if (typeof breakPresentationForm === 'undefined') {
20466             breakPresentationForm = true;
20467           }
20468
20469           var returnable = '';
20470           word.split('').forEach(function (letter) {
20471             if (!isArabic_1$4.isArabic(letter)) {
20472               returnable += letter;
20473               return;
20474             }
20475
20476             for (var w = 0; w < reference_1$3.letterList.length; w++) {
20477               // ok so we are checking this potential lettertron
20478               var letterForms = unicode_arabic_1$2["default"][reference_1$3.letterList[w]];
20479               var versions = Object.keys(letterForms);
20480
20481               for (var v = 0; v < versions.length; v++) {
20482                 var localVersion = letterForms[versions[v]];
20483
20484                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20485                   // look at this embedded object
20486                   var embeddedForms = Object.keys(localVersion);
20487
20488                   for (var ef = 0; ef < embeddedForms.length; ef++) {
20489                     var form = localVersion[embeddedForms[ef]];
20490
20491                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20492                       // match
20493                       // console.log('embedded match');
20494                       if (form === letter) {
20495                         // match exact
20496                         if (breakPresentationForm && localVersion['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(embeddedForms[ef]) > -1) {
20497                           // replace presentation form
20498                           // console.log('keeping normal form of the letter');
20499                           if (_typeof(localVersion['normal']) === 'object') {
20500                             returnable += localVersion['normal'][0];
20501                           } else {
20502                             returnable += localVersion['normal'];
20503                           }
20504
20505                           return;
20506                         } // console.log('keeping this letter');
20507
20508
20509                         returnable += letter;
20510                         return;
20511                       } else if (_typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20512                         // match
20513                         returnable += form[0]; // console.log('added the first letter from the same array');
20514
20515                         return;
20516                       }
20517                     }
20518                   }
20519                 } else if (localVersion === letter) {
20520                   // match exact
20521                   if (breakPresentationForm && letterForms['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(versions[v]) > -1) {
20522                     // replace presentation form
20523                     // console.log('keeping normal form of the letter');
20524                     if (_typeof(letterForms['normal']) === 'object') {
20525                       returnable += letterForms['normal'][0];
20526                     } else {
20527                       returnable += letterForms['normal'];
20528                     }
20529
20530                     return;
20531                   } // console.log('keeping this letter');
20532
20533
20534                   returnable += letter;
20535                   return;
20536                 } else if (_typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20537                   // match
20538                   returnable += localVersion[0]; // console.log('added the first letter from the same array');
20539
20540                   return;
20541                 }
20542               }
20543             } // try ligatures
20544
20545
20546             for (var v2 = 0; v2 < reference_1$3.ligatureList.length; v2++) {
20547               var normalForm = reference_1$3.ligatureList[v2];
20548
20549               if (normalForm !== 'words') {
20550                 var ligForms = Object.keys(unicode_ligatures_1$1["default"][normalForm]);
20551
20552                 for (var f = 0; f < ligForms.length; f++) {
20553                   if (unicode_ligatures_1$1["default"][normalForm][ligForms[f]] === letter) {
20554                     returnable += normalForm;
20555                     return;
20556                   }
20557                 }
20558               }
20559             } // try words ligatures
20560
20561
20562             for (var v3 = 0; v3 < reference_1$3.ligatureWordList.length; v3++) {
20563               var _normalForm = reference_1$3.ligatureWordList[v3];
20564
20565               if (unicode_ligatures_1$1["default"].words[_normalForm] === letter) {
20566                 returnable += _normalForm;
20567                 return;
20568               }
20569             }
20570
20571             returnable += letter; // console.log('kept the letter')
20572           });
20573           return returnable;
20574         }
20575
20576         Normalization.Normal = Normal;
20577
20578         var CharShaper$1 = {};
20579
20580         Object.defineProperty(CharShaper$1, "__esModule", {
20581           value: true
20582         });
20583         var unicode_arabic_1$1 = unicodeArabic;
20584         var isArabic_1$3 = isArabic$1;
20585         var reference_1$2 = reference;
20586
20587         function CharShaper(letter, form) {
20588           if (!isArabic_1$3.isArabic(letter)) {
20589             // fail not Arabic
20590             throw new Error('Not Arabic');
20591           }
20592
20593           if (letter === "\u0621") {
20594             // hamza alone
20595             return "\u0621";
20596           }
20597
20598           for (var w = 0; w < reference_1$2.letterList.length; w++) {
20599             // ok so we are checking this potential lettertron
20600             var letterForms = unicode_arabic_1$1["default"][reference_1$2.letterList[w]];
20601             var versions = Object.keys(letterForms);
20602
20603             for (var v = 0; v < versions.length; v++) {
20604               var localVersion = letterForms[versions[v]];
20605
20606               if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20607                 if (versions.indexOf(form) > -1) {
20608                   return letterForms[form];
20609                 }
20610               } else if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20611                 // check embedded
20612                 var embeddedVersions = Object.keys(localVersion);
20613
20614                 for (var ev = 0; ev < embeddedVersions.length; ev++) {
20615                   if (localVersion[embeddedVersions[ev]] === letter || _typeof(localVersion[embeddedVersions[ev]]) === 'object' && localVersion[embeddedVersions[ev]].indexOf && localVersion[embeddedVersions[ev]].indexOf(letter) > -1) {
20616                     if (embeddedVersions.indexOf(form) > -1) {
20617                       return localVersion[form];
20618                     }
20619                   }
20620                 }
20621               }
20622             }
20623           }
20624         }
20625
20626         CharShaper$1.CharShaper = CharShaper;
20627
20628         var WordShaper$2 = {};
20629
20630         Object.defineProperty(WordShaper$2, "__esModule", {
20631           value: true
20632         });
20633         var isArabic_1$2 = isArabic$1;
20634         var reference_1$1 = reference;
20635         var CharShaper_1$1 = CharShaper$1;
20636         var unicode_ligatures_1 = unicodeLigatures;
20637
20638         function WordShaper$1(word) {
20639           var state = 'initial';
20640           var output = '';
20641
20642           for (var w = 0; w < word.length; w++) {
20643             var nextLetter = ' ';
20644
20645             for (var nxw = w + 1; nxw < word.length; nxw++) {
20646               if (!isArabic_1$2.isArabic(word[nxw])) {
20647                 break;
20648               }
20649
20650               if (reference_1$1.tashkeel.indexOf(word[nxw]) === -1) {
20651                 nextLetter = word[nxw];
20652                 break;
20653               }
20654             }
20655
20656             if (!isArabic_1$2.isArabic(word[w]) || isArabic_1$2.isMath(word[w])) {
20657               // space or other non-Arabic
20658               output += word[w];
20659               state = 'initial';
20660             } else if (reference_1$1.tashkeel.indexOf(word[w]) > -1) {
20661               // tashkeel - add without changing state
20662               output += word[w];
20663             } else if (nextLetter === ' ' || // last Arabic letter in this word
20664             reference_1$1.lineBreakers.indexOf(word[w]) > -1) {
20665               // the current letter is known to break lines
20666               output += CharShaper_1$1.CharShaper(word[w], state === 'initial' ? 'isolated' : 'final');
20667               state = 'initial';
20668             } else if (reference_1$1.lams.indexOf(word[w]) > -1 && reference_1$1.alefs.indexOf(nextLetter) > -1) {
20669               // LA letters - advance an additional letter after this
20670               output += unicode_ligatures_1["default"][word[w] + nextLetter][state === 'initial' ? 'isolated' : 'final'];
20671
20672               while (word[w] !== nextLetter) {
20673                 w++;
20674               }
20675
20676               state = 'initial';
20677             } else {
20678               output += CharShaper_1$1.CharShaper(word[w], state);
20679               state = 'medial';
20680             }
20681           }
20682
20683           return output;
20684         }
20685
20686         WordShaper$2.WordShaper = WordShaper$1;
20687
20688         var ParentLetter$1 = {};
20689
20690         Object.defineProperty(ParentLetter$1, "__esModule", {
20691           value: true
20692         });
20693         var unicode_arabic_1 = unicodeArabic;
20694         var isArabic_1$1 = isArabic$1;
20695         var reference_1 = reference;
20696
20697         function ParentLetter(letter) {
20698           if (!isArabic_1$1.isArabic(letter)) {
20699             throw new Error('Not an Arabic letter');
20700           }
20701
20702           for (var w = 0; w < reference_1.letterList.length; w++) {
20703             // ok so we are checking this potential lettertron
20704             var letterForms = unicode_arabic_1["default"][reference_1.letterList[w]];
20705             var versions = Object.keys(letterForms);
20706
20707             for (var v = 0; v < versions.length; v++) {
20708               var localVersion = letterForms[versions[v]];
20709
20710               if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20711                 // look at this embedded object
20712                 var embeddedForms = Object.keys(localVersion);
20713
20714                 for (var ef = 0; ef < embeddedForms.length; ef++) {
20715                   var form = localVersion[embeddedForms[ef]];
20716
20717                   if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20718                     // match
20719                     return localVersion;
20720                   }
20721                 }
20722               } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20723                 // match
20724                 return letterForms;
20725               }
20726             }
20727
20728             return null;
20729           }
20730         }
20731
20732         ParentLetter$1.ParentLetter = ParentLetter;
20733
20734         function GrandparentLetter(letter) {
20735           if (!isArabic_1$1.isArabic(letter)) {
20736             throw new Error('Not an Arabic letter');
20737           }
20738
20739           for (var w = 0; w < reference_1.letterList.length; w++) {
20740             // ok so we are checking this potential lettertron
20741             var letterForms = unicode_arabic_1["default"][reference_1.letterList[w]];
20742             var versions = Object.keys(letterForms);
20743
20744             for (var v = 0; v < versions.length; v++) {
20745               var localVersion = letterForms[versions[v]];
20746
20747               if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20748                 // look at this embedded object
20749                 var embeddedForms = Object.keys(localVersion);
20750
20751                 for (var ef = 0; ef < embeddedForms.length; ef++) {
20752                   var form = localVersion[embeddedForms[ef]];
20753
20754                   if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20755                     // match
20756                     return letterForms;
20757                   }
20758                 }
20759               } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20760                 // match
20761                 return letterForms;
20762               }
20763             }
20764
20765             return null;
20766           }
20767         }
20768
20769         ParentLetter$1.GrandparentLetter = GrandparentLetter;
20770
20771         Object.defineProperty(lib, "__esModule", {
20772           value: true
20773         });
20774         var isArabic_1 = isArabic$1;
20775         lib.isArabic = isArabic_1.isArabic;
20776         var GlyphSplitter_1 = GlyphSplitter$1;
20777         lib.GlyphSplitter = GlyphSplitter_1.GlyphSplitter;
20778         var BaselineSplitter_1 = BaselineSplitter$1;
20779         lib.BaselineSplitter = BaselineSplitter_1.BaselineSplitter;
20780         var Normalization_1 = Normalization;
20781         lib.Normal = Normalization_1.Normal;
20782         var CharShaper_1 = CharShaper$1;
20783         lib.CharShaper = CharShaper_1.CharShaper;
20784         var WordShaper_1 = WordShaper$2;
20785         var WordShaper = lib.WordShaper = WordShaper_1.WordShaper;
20786         var ParentLetter_1 = ParentLetter$1;
20787         lib.ParentLetter = ParentLetter_1.ParentLetter;
20788         lib.GrandparentLetter = ParentLetter_1.GrandparentLetter;
20789
20790         var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u07BF\u08A0–\u08BF]/;
20791         function fixRTLTextForSvg(inputText) {
20792           var ret = '',
20793               rtlBuffer = [];
20794           var arabicRegex = /[\u0600-\u06FF]/g;
20795           var arabicDiacritics = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06ED]/g;
20796           var arabicMath = /[\u0660-\u066C\u06F0-\u06F9]+/g;
20797           var thaanaVowel = /[\u07A6-\u07B0]/;
20798           var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/; // Arabic word shaping
20799
20800           if (arabicRegex.test(inputText)) {
20801             inputText = WordShaper(inputText);
20802           }
20803
20804           for (var n = 0; n < inputText.length; n++) {
20805             var c = inputText[n];
20806
20807             if (arabicMath.test(c)) {
20808               // Arabic numbers go LTR
20809               ret += rtlBuffer.reverse().join('');
20810               rtlBuffer = [c];
20811             } else {
20812               if (rtlBuffer.length && arabicMath.test(rtlBuffer[rtlBuffer.length - 1])) {
20813                 ret += rtlBuffer.reverse().join('');
20814                 rtlBuffer = [];
20815               }
20816
20817               if ((thaanaVowel.test(c) || hebrewSign.test(c) || arabicDiacritics.test(c)) && rtlBuffer.length) {
20818                 rtlBuffer[rtlBuffer.length - 1] += c;
20819               } else if (rtlRegex.test(c) // include Arabic presentation forms
20820               || c.charCodeAt(0) >= 64336 && c.charCodeAt(0) <= 65023 || c.charCodeAt(0) >= 65136 && c.charCodeAt(0) <= 65279) {
20821                 rtlBuffer.push(c);
20822               } else if (c === ' ' && rtlBuffer.length) {
20823                 // whitespace within RTL text
20824                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
20825               } else {
20826                 // non-RTL character
20827                 ret += rtlBuffer.reverse().join('') + c;
20828                 rtlBuffer = [];
20829               }
20830             }
20831           }
20832
20833           ret += rtlBuffer.reverse().join('');
20834           return ret;
20835         }
20836
20837         var DESCRIPTORS$1 = descriptors;
20838         var objectKeys = objectKeys$4;
20839         var toIndexedObject = toIndexedObject$b;
20840         var propertyIsEnumerable = objectPropertyIsEnumerable.f;
20841
20842         // `Object.{ entries, values }` methods implementation
20843         var createMethod$1 = function (TO_ENTRIES) {
20844           return function (it) {
20845             var O = toIndexedObject(it);
20846             var keys = objectKeys(O);
20847             var length = keys.length;
20848             var i = 0;
20849             var result = [];
20850             var key;
20851             while (length > i) {
20852               key = keys[i++];
20853               if (!DESCRIPTORS$1 || propertyIsEnumerable.call(O, key)) {
20854                 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
20855               }
20856             }
20857             return result;
20858           };
20859         };
20860
20861         var objectToArray = {
20862           // `Object.entries` method
20863           // https://tc39.es/ecma262/#sec-object.entries
20864           entries: createMethod$1(true),
20865           // `Object.values` method
20866           // https://tc39.es/ecma262/#sec-object.values
20867           values: createMethod$1(false)
20868         };
20869
20870         var $$k = _export;
20871         var $values = objectToArray.values;
20872
20873         // `Object.values` method
20874         // https://tc39.es/ecma262/#sec-object.values
20875         $$k({ target: 'Object', stat: true }, {
20876           values: function values(O) {
20877             return $values(O);
20878           }
20879         });
20880
20881         // https://github.com/openstreetmap/iD/issues/772
20882         // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
20883         var _storage;
20884
20885         try {
20886           _storage = localStorage;
20887         } catch (e) {} // eslint-disable-line no-empty
20888
20889
20890         _storage = _storage || function () {
20891           var s = {};
20892           return {
20893             getItem: function getItem(k) {
20894               return s[k];
20895             },
20896             setItem: function setItem(k, v) {
20897               return s[k] = v;
20898             },
20899             removeItem: function removeItem(k) {
20900               return delete s[k];
20901             }
20902           };
20903         }(); //
20904         // corePreferences is an interface for persisting basic key-value strings
20905         // within and between iD sessions on the same site.
20906         //
20907
20908         /**
20909          * @param {string} k
20910          * @param {string?} v
20911          * @returns {boolean} true if the action succeeded
20912          */
20913
20914
20915         function corePreferences(k, v) {
20916           try {
20917             if (arguments.length === 1) return _storage.getItem(k);else if (v === null) _storage.removeItem(k);else _storage.setItem(k, v);
20918             return true;
20919           } catch (e) {
20920             /* eslint-disable no-console */
20921             if (typeof console !== 'undefined') {
20922               console.error('localStorage quota exceeded');
20923             }
20924             /* eslint-enable no-console */
20925
20926
20927             return false;
20928           }
20929         }
20930
20931         var vparse = {exports: {}};
20932
20933         (function (module) {
20934           (function (window) {
20935
20936             function parseVersion(v) {
20937               var m = v.replace(/[^0-9.]/g, '').match(/[0-9]*\.|[0-9]+/g) || [];
20938               v = {
20939                 major: +m[0] || 0,
20940                 minor: +m[1] || 0,
20941                 patch: +m[2] || 0,
20942                 build: +m[3] || 0
20943               };
20944               v.isEmpty = !v.major && !v.minor && !v.patch && !v.build;
20945               v.parsed = [v.major, v.minor, v.patch, v.build];
20946               v.text = v.parsed.join('.');
20947               v.compare = compare;
20948               return v;
20949             }
20950
20951             function compare(v) {
20952               if (typeof v === 'string') {
20953                 v = parseVersion(v);
20954               }
20955
20956               for (var i = 0; i < 4; i++) {
20957                 if (this.parsed[i] !== v.parsed[i]) {
20958                   return this.parsed[i] > v.parsed[i] ? 1 : -1;
20959                 }
20960               }
20961
20962               return 0;
20963             }
20964             /* istanbul ignore next */
20965
20966
20967             if (module && 'object' === 'object') {
20968               module.exports = parseVersion;
20969             } else {
20970               window.parseVersion = parseVersion;
20971             }
20972           })(commonjsGlobal);
20973         })(vparse);
20974
20975         var parseVersion = vparse.exports;
20976
20977         var name = "iD";
20978         var version = "2.20.2";
20979         var description = "A friendly editor for OpenStreetMap";
20980         var main = "dist/iD.min.js";
20981         var repository = "github:openstreetmap/iD";
20982         var homepage = "https://github.com/openstreetmap/iD";
20983         var bugs = "https://github.com/openstreetmap/iD/issues";
20984         var keywords = ["editor","openstreetmap"];
20985         var license = "ISC";
20986         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"};
20987         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/vector-tile":"^1.3.1","@tmcw/togeojson":"^4.5.0","@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",pbf:"^3.2.1","polygon-clipping":"~0.15.1",rbush:"3.0.1","whatwg-fetch":"^3.4.1","which-polygon":"2.2.0"};
20988         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":"^21.0.0","@rollup/plugin-json":"^4.0.1","@rollup/plugin-node-resolve":"~13.0.5",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.1","uglify-js":"~3.13.0",vparse:"~1.1.0"};
20989         var engines = {node:">=10"};
20990         var browserslist = ["> 0.2%, last 6 major versions, Firefox ESR, IE 11, maintained node versions"];
20991         var packageJSON = {
20992         name: name,
20993         version: version,
20994         description: description,
20995         main: main,
20996         repository: repository,
20997         homepage: homepage,
20998         bugs: bugs,
20999         keywords: keywords,
21000         license: license,
21001         scripts: scripts,
21002         dependencies: dependencies,
21003         devDependencies: devDependencies,
21004         engines: engines,
21005         browserslist: browserslist
21006         };
21007
21008         var _mainFileFetcher = coreFileFetcher(); // singleton
21009         // coreFileFetcher asynchronously fetches data from JSON files
21010         //
21011
21012         function coreFileFetcher() {
21013           var ociVersion = packageJSON.devDependencies['osm-community-index'];
21014           var v = parseVersion(ociVersion);
21015           var vMinor = "".concat(v.major, ".").concat(v.minor);
21016           var _this = {};
21017           var _inflight = {};
21018           var _fileMap = {
21019             'address_formats': 'data/address_formats.min.json',
21020             'deprecated': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/deprecated.min.json',
21021             'discarded': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/discarded.min.json',
21022             'imagery': 'data/imagery.min.json',
21023             'intro_graph': 'data/intro_graph.min.json',
21024             'keepRight': 'data/keepRight.min.json',
21025             'languages': 'data/languages.min.json',
21026             'locales': 'locales/index.min.json',
21027             'oci_defaults': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/defaults.min.json"),
21028             'oci_features': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/featureCollection.min.json"),
21029             'oci_resources': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/resources.min.json"),
21030             'preset_categories': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_categories.min.json',
21031             'preset_defaults': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_defaults.min.json',
21032             'preset_fields': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/fields.min.json',
21033             'preset_presets': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/presets.min.json',
21034             'phone_formats': 'data/phone_formats.min.json',
21035             'qa_data': 'data/qa_data.min.json',
21036             'shortcuts': 'data/shortcuts.min.json',
21037             'territory_languages': 'data/territory_languages.min.json',
21038             'wmf_sitematrix': 'https://cdn.jsdelivr.net/npm/wmf-sitematrix@0.1/wikipedia.min.json'
21039           };
21040           var _cachedData = {}; // expose the cache; useful for tests
21041
21042           _this.cache = function () {
21043             return _cachedData;
21044           }; // Returns a Promise to fetch data
21045           // (resolved with the data if we have it already)
21046
21047
21048           _this.get = function (which) {
21049             if (_cachedData[which]) {
21050               return Promise.resolve(_cachedData[which]);
21051             }
21052
21053             var file = _fileMap[which];
21054
21055             var url = file && _this.asset(file);
21056
21057             if (!url) {
21058               return Promise.reject("Unknown data file for \"".concat(which, "\""));
21059             }
21060
21061             var prom = _inflight[url];
21062
21063             if (!prom) {
21064               _inflight[url] = prom = fetch(url).then(function (response) {
21065                 // fetch in PhantomJS tests may return ok=false and status=0 even if it's okay
21066                 if (!response.ok && response.status !== 0 || !response.json) {
21067                   throw new Error(response.status + ' ' + response.statusText);
21068                 }
21069
21070                 if (response.status === 204 || response.status === 205) return; // No Content, Reset Content
21071
21072                 return response.json();
21073               }).then(function (result) {
21074                 delete _inflight[url];
21075
21076                 if (!result) {
21077                   throw new Error("No data loaded for \"".concat(which, "\""));
21078                 }
21079
21080                 _cachedData[which] = result;
21081                 return result;
21082               })["catch"](function (err) {
21083                 delete _inflight[url];
21084                 throw err;
21085               });
21086             }
21087
21088             return prom;
21089           }; // Accessor for the file map
21090
21091
21092           _this.fileMap = function (val) {
21093             if (!arguments.length) return _fileMap;
21094             _fileMap = val;
21095             return _this;
21096           };
21097
21098           var _assetPath = '';
21099
21100           _this.assetPath = function (val) {
21101             if (!arguments.length) return _assetPath;
21102             _assetPath = val;
21103             return _this;
21104           };
21105
21106           var _assetMap = {};
21107
21108           _this.assetMap = function (val) {
21109             if (!arguments.length) return _assetMap;
21110             _assetMap = val;
21111             return _this;
21112           };
21113
21114           _this.asset = function (val) {
21115             if (/^http(s)?:\/\//i.test(val)) return val;
21116             var filename = _assetPath + val;
21117             return _assetMap[filename] || filename;
21118           };
21119
21120           return _this;
21121         }
21122
21123         var classof = classofRaw$1;
21124
21125         // `thisNumberValue` abstract operation
21126         // https://tc39.es/ecma262/#sec-thisnumbervalue
21127         var thisNumberValue$2 = function (value) {
21128           if (typeof value != 'number' && classof(value) != 'Number') {
21129             throw TypeError('Incorrect invocation');
21130           }
21131           return +value;
21132         };
21133
21134         var toInteger$1 = toInteger$b;
21135         var requireObjectCoercible$6 = requireObjectCoercible$e;
21136
21137         // `String.prototype.repeat` method implementation
21138         // https://tc39.es/ecma262/#sec-string.prototype.repeat
21139         var stringRepeat = function repeat(count) {
21140           var str = String(requireObjectCoercible$6(this));
21141           var result = '';
21142           var n = toInteger$1(count);
21143           if (n < 0 || n == Infinity) throw RangeError('Wrong number of repetitions');
21144           for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;
21145           return result;
21146         };
21147
21148         var $$j = _export;
21149         var toInteger = toInteger$b;
21150         var thisNumberValue$1 = thisNumberValue$2;
21151         var repeat$2 = stringRepeat;
21152         var fails$7 = fails$N;
21153
21154         var nativeToFixed = 1.0.toFixed;
21155         var floor = Math.floor;
21156
21157         var pow = function (x, n, acc) {
21158           return n === 0 ? acc : n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc);
21159         };
21160
21161         var log = function (x) {
21162           var n = 0;
21163           var x2 = x;
21164           while (x2 >= 4096) {
21165             n += 12;
21166             x2 /= 4096;
21167           }
21168           while (x2 >= 2) {
21169             n += 1;
21170             x2 /= 2;
21171           } return n;
21172         };
21173
21174         var multiply = function (data, n, c) {
21175           var index = -1;
21176           var c2 = c;
21177           while (++index < 6) {
21178             c2 += n * data[index];
21179             data[index] = c2 % 1e7;
21180             c2 = floor(c2 / 1e7);
21181           }
21182         };
21183
21184         var divide = function (data, n) {
21185           var index = 6;
21186           var c = 0;
21187           while (--index >= 0) {
21188             c += data[index];
21189             data[index] = floor(c / n);
21190             c = (c % n) * 1e7;
21191           }
21192         };
21193
21194         var dataToString = function (data) {
21195           var index = 6;
21196           var s = '';
21197           while (--index >= 0) {
21198             if (s !== '' || index === 0 || data[index] !== 0) {
21199               var t = String(data[index]);
21200               s = s === '' ? t : s + repeat$2.call('0', 7 - t.length) + t;
21201             }
21202           } return s;
21203         };
21204
21205         var FORCED$4 = nativeToFixed && (
21206           0.00008.toFixed(3) !== '0.000' ||
21207           0.9.toFixed(0) !== '1' ||
21208           1.255.toFixed(2) !== '1.25' ||
21209           1000000000000000128.0.toFixed(0) !== '1000000000000000128'
21210         ) || !fails$7(function () {
21211           // V8 ~ Android 4.3-
21212           nativeToFixed.call({});
21213         });
21214
21215         // `Number.prototype.toFixed` method
21216         // https://tc39.es/ecma262/#sec-number.prototype.tofixed
21217         $$j({ target: 'Number', proto: true, forced: FORCED$4 }, {
21218           toFixed: function toFixed(fractionDigits) {
21219             var number = thisNumberValue$1(this);
21220             var fractDigits = toInteger(fractionDigits);
21221             var data = [0, 0, 0, 0, 0, 0];
21222             var sign = '';
21223             var result = '0';
21224             var e, z, j, k;
21225
21226             if (fractDigits < 0 || fractDigits > 20) throw RangeError('Incorrect fraction digits');
21227             // eslint-disable-next-line no-self-compare -- NaN check
21228             if (number != number) return 'NaN';
21229             if (number <= -1e21 || number >= 1e21) return String(number);
21230             if (number < 0) {
21231               sign = '-';
21232               number = -number;
21233             }
21234             if (number > 1e-21) {
21235               e = log(number * pow(2, 69, 1)) - 69;
21236               z = e < 0 ? number * pow(2, -e, 1) : number / pow(2, e, 1);
21237               z *= 0x10000000000000;
21238               e = 52 - e;
21239               if (e > 0) {
21240                 multiply(data, 0, z);
21241                 j = fractDigits;
21242                 while (j >= 7) {
21243                   multiply(data, 1e7, 0);
21244                   j -= 7;
21245                 }
21246                 multiply(data, pow(10, j, 1), 0);
21247                 j = e - 1;
21248                 while (j >= 23) {
21249                   divide(data, 1 << 23);
21250                   j -= 23;
21251                 }
21252                 divide(data, 1 << j);
21253                 multiply(data, 1, 1);
21254                 divide(data, 2);
21255                 result = dataToString(data);
21256               } else {
21257                 multiply(data, 0, z);
21258                 multiply(data, 1 << -e, 0);
21259                 result = dataToString(data) + repeat$2.call('0', fractDigits);
21260               }
21261             }
21262             if (fractDigits > 0) {
21263               k = result.length;
21264               result = sign + (k <= fractDigits
21265                 ? '0.' + repeat$2.call('0', fractDigits - k) + result
21266                 : result.slice(0, k - fractDigits) + '.' + result.slice(k - fractDigits));
21267             } else {
21268               result = sign + result;
21269             } return result;
21270           }
21271         });
21272
21273         var global$1 = global$F;
21274
21275         var globalIsFinite = global$1.isFinite;
21276
21277         // `Number.isFinite` method
21278         // https://tc39.es/ecma262/#sec-number.isfinite
21279         // eslint-disable-next-line es/no-number-isfinite -- safe
21280         var numberIsFinite$1 = Number.isFinite || function isFinite(it) {
21281           return typeof it == 'number' && globalIsFinite(it);
21282         };
21283
21284         var $$i = _export;
21285         var numberIsFinite = numberIsFinite$1;
21286
21287         // `Number.isFinite` method
21288         // https://tc39.es/ecma262/#sec-number.isfinite
21289         $$i({ target: 'Number', stat: true }, { isFinite: numberIsFinite });
21290
21291         var $$h = _export;
21292         var toAbsoluteIndex = toAbsoluteIndex$8;
21293
21294         var fromCharCode = String.fromCharCode;
21295         // eslint-disable-next-line es/no-string-fromcodepoint -- required for testing
21296         var $fromCodePoint = String.fromCodePoint;
21297
21298         // length should be 1, old FF problem
21299         var INCORRECT_LENGTH = !!$fromCodePoint && $fromCodePoint.length != 1;
21300
21301         // `String.fromCodePoint` method
21302         // https://tc39.es/ecma262/#sec-string.fromcodepoint
21303         $$h({ target: 'String', stat: true, forced: INCORRECT_LENGTH }, {
21304           // eslint-disable-next-line no-unused-vars -- required for `.length`
21305           fromCodePoint: function fromCodePoint(x) {
21306             var elements = [];
21307             var length = arguments.length;
21308             var i = 0;
21309             var code;
21310             while (length > i) {
21311               code = +arguments[i++];
21312               if (toAbsoluteIndex(code, 0x10FFFF) !== code) throw RangeError(code + ' is not a valid code point');
21313               elements.push(code < 0x10000
21314                 ? fromCharCode(code)
21315                 : fromCharCode(((code -= 0x10000) >> 10) + 0xD800, code % 0x400 + 0xDC00)
21316               );
21317             } return elements.join('');
21318           }
21319         });
21320
21321         var fixRegExpWellKnownSymbolLogic = fixRegexpWellKnownSymbolLogic;
21322         var anObject = anObject$m;
21323         var requireObjectCoercible$5 = requireObjectCoercible$e;
21324         var sameValue = sameValue$1;
21325         var regExpExec = regexpExecAbstract;
21326
21327         // @@search logic
21328         fixRegExpWellKnownSymbolLogic('search', function (SEARCH, nativeSearch, maybeCallNative) {
21329           return [
21330             // `String.prototype.search` method
21331             // https://tc39.es/ecma262/#sec-string.prototype.search
21332             function search(regexp) {
21333               var O = requireObjectCoercible$5(this);
21334               var searcher = regexp == undefined ? undefined : regexp[SEARCH];
21335               return searcher !== undefined ? searcher.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
21336             },
21337             // `RegExp.prototype[@@search]` method
21338             // https://tc39.es/ecma262/#sec-regexp.prototype-@@search
21339             function (string) {
21340               var res = maybeCallNative(nativeSearch, this, string);
21341               if (res.done) return res.value;
21342
21343               var rx = anObject(this);
21344               var S = String(string);
21345
21346               var previousLastIndex = rx.lastIndex;
21347               if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;
21348               var result = regExpExec(rx, S);
21349               if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;
21350               return result === null ? -1 : result.index;
21351             }
21352           ];
21353         });
21354
21355         var rbush$2 = {exports: {}};
21356
21357         var quickselect$2 = {exports: {}};
21358
21359         (function (module, exports) {
21360           (function (global, factory) {
21361             module.exports = factory() ;
21362           })(commonjsGlobal, function () {
21363
21364             function quickselect(arr, k, left, right, compare) {
21365               quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
21366             }
21367
21368             function quickselectStep(arr, k, left, right, compare) {
21369               while (right > left) {
21370                 if (right - left > 600) {
21371                   var n = right - left + 1;
21372                   var m = k - left + 1;
21373                   var z = Math.log(n);
21374                   var s = 0.5 * Math.exp(2 * z / 3);
21375                   var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
21376                   var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
21377                   var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
21378                   quickselectStep(arr, k, newLeft, newRight, compare);
21379                 }
21380
21381                 var t = arr[k];
21382                 var i = left;
21383                 var j = right;
21384                 swap(arr, left, k);
21385                 if (compare(arr[right], t) > 0) swap(arr, left, right);
21386
21387                 while (i < j) {
21388                   swap(arr, i, j);
21389                   i++;
21390                   j--;
21391
21392                   while (compare(arr[i], t) < 0) {
21393                     i++;
21394                   }
21395
21396                   while (compare(arr[j], t) > 0) {
21397                     j--;
21398                   }
21399                 }
21400
21401                 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
21402                   j++;
21403                   swap(arr, j, right);
21404                 }
21405                 if (j <= k) left = j + 1;
21406                 if (k <= j) right = j - 1;
21407               }
21408             }
21409
21410             function swap(arr, i, j) {
21411               var tmp = arr[i];
21412               arr[i] = arr[j];
21413               arr[j] = tmp;
21414             }
21415
21416             function defaultCompare(a, b) {
21417               return a < b ? -1 : a > b ? 1 : 0;
21418             }
21419
21420             return quickselect;
21421           });
21422         })(quickselect$2);
21423
21424         rbush$2.exports = rbush$1;
21425
21426         rbush$2.exports["default"] = rbush$1;
21427
21428         var quickselect$1 = quickselect$2.exports;
21429
21430         function rbush$1(maxEntries, format) {
21431           if (!(this instanceof rbush$1)) return new rbush$1(maxEntries, format); // max entries in a node is 9 by default; min node fill is 40% for best performance
21432
21433           this._maxEntries = Math.max(4, maxEntries || 9);
21434           this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
21435
21436           if (format) {
21437             this._initFormat(format);
21438           }
21439
21440           this.clear();
21441         }
21442
21443         rbush$1.prototype = {
21444           all: function all() {
21445             return this._all(this.data, []);
21446           },
21447           search: function search(bbox) {
21448             var node = this.data,
21449                 result = [],
21450                 toBBox = this.toBBox;
21451             if (!intersects$1(bbox, node)) return result;
21452             var nodesToSearch = [],
21453                 i,
21454                 len,
21455                 child,
21456                 childBBox;
21457
21458             while (node) {
21459               for (i = 0, len = node.children.length; i < len; i++) {
21460                 child = node.children[i];
21461                 childBBox = node.leaf ? toBBox(child) : child;
21462
21463                 if (intersects$1(bbox, childBBox)) {
21464                   if (node.leaf) result.push(child);else if (contains$1(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
21465                 }
21466               }
21467
21468               node = nodesToSearch.pop();
21469             }
21470
21471             return result;
21472           },
21473           collides: function collides(bbox) {
21474             var node = this.data,
21475                 toBBox = this.toBBox;
21476             if (!intersects$1(bbox, node)) return false;
21477             var nodesToSearch = [],
21478                 i,
21479                 len,
21480                 child,
21481                 childBBox;
21482
21483             while (node) {
21484               for (i = 0, len = node.children.length; i < len; i++) {
21485                 child = node.children[i];
21486                 childBBox = node.leaf ? toBBox(child) : child;
21487
21488                 if (intersects$1(bbox, childBBox)) {
21489                   if (node.leaf || contains$1(bbox, childBBox)) return true;
21490                   nodesToSearch.push(child);
21491                 }
21492               }
21493
21494               node = nodesToSearch.pop();
21495             }
21496
21497             return false;
21498           },
21499           load: function load(data) {
21500             if (!(data && data.length)) return this;
21501
21502             if (data.length < this._minEntries) {
21503               for (var i = 0, len = data.length; i < len; i++) {
21504                 this.insert(data[i]);
21505               }
21506
21507               return this;
21508             } // recursively build the tree with the given data from scratch using OMT algorithm
21509
21510
21511             var node = this._build(data.slice(), 0, data.length - 1, 0);
21512
21513             if (!this.data.children.length) {
21514               // save as is if tree is empty
21515               this.data = node;
21516             } else if (this.data.height === node.height) {
21517               // split root if trees have the same height
21518               this._splitRoot(this.data, node);
21519             } else {
21520               if (this.data.height < node.height) {
21521                 // swap trees if inserted one is bigger
21522                 var tmpNode = this.data;
21523                 this.data = node;
21524                 node = tmpNode;
21525               } // insert the small tree into the large tree at appropriate level
21526
21527
21528               this._insert(node, this.data.height - node.height - 1, true);
21529             }
21530
21531             return this;
21532           },
21533           insert: function insert(item) {
21534             if (item) this._insert(item, this.data.height - 1);
21535             return this;
21536           },
21537           clear: function clear() {
21538             this.data = createNode$1([]);
21539             return this;
21540           },
21541           remove: function remove(item, equalsFn) {
21542             if (!item) return this;
21543             var node = this.data,
21544                 bbox = this.toBBox(item),
21545                 path = [],
21546                 indexes = [],
21547                 i,
21548                 parent,
21549                 index,
21550                 goingUp; // depth-first iterative tree traversal
21551
21552             while (node || path.length) {
21553               if (!node) {
21554                 // go up
21555                 node = path.pop();
21556                 parent = path[path.length - 1];
21557                 i = indexes.pop();
21558                 goingUp = true;
21559               }
21560
21561               if (node.leaf) {
21562                 // check current node
21563                 index = findItem$1(item, node.children, equalsFn);
21564
21565                 if (index !== -1) {
21566                   // item found, remove the item and condense tree upwards
21567                   node.children.splice(index, 1);
21568                   path.push(node);
21569
21570                   this._condense(path);
21571
21572                   return this;
21573                 }
21574               }
21575
21576               if (!goingUp && !node.leaf && contains$1(node, bbox)) {
21577                 // go down
21578                 path.push(node);
21579                 indexes.push(i);
21580                 i = 0;
21581                 parent = node;
21582                 node = node.children[0];
21583               } else if (parent) {
21584                 // go right
21585                 i++;
21586                 node = parent.children[i];
21587                 goingUp = false;
21588               } else node = null; // nothing found
21589
21590             }
21591
21592             return this;
21593           },
21594           toBBox: function toBBox(item) {
21595             return item;
21596           },
21597           compareMinX: compareNodeMinX$1,
21598           compareMinY: compareNodeMinY$1,
21599           toJSON: function toJSON() {
21600             return this.data;
21601           },
21602           fromJSON: function fromJSON(data) {
21603             this.data = data;
21604             return this;
21605           },
21606           _all: function _all(node, result) {
21607             var nodesToSearch = [];
21608
21609             while (node) {
21610               if (node.leaf) result.push.apply(result, node.children);else nodesToSearch.push.apply(nodesToSearch, node.children);
21611               node = nodesToSearch.pop();
21612             }
21613
21614             return result;
21615           },
21616           _build: function _build(items, left, right, height) {
21617             var N = right - left + 1,
21618                 M = this._maxEntries,
21619                 node;
21620
21621             if (N <= M) {
21622               // reached leaf level; return leaf
21623               node = createNode$1(items.slice(left, right + 1));
21624               calcBBox$1(node, this.toBBox);
21625               return node;
21626             }
21627
21628             if (!height) {
21629               // target height of the bulk-loaded tree
21630               height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
21631
21632               M = Math.ceil(N / Math.pow(M, height - 1));
21633             }
21634
21635             node = createNode$1([]);
21636             node.leaf = false;
21637             node.height = height; // split the items into M mostly square tiles
21638
21639             var N2 = Math.ceil(N / M),
21640                 N1 = N2 * Math.ceil(Math.sqrt(M)),
21641                 i,
21642                 j,
21643                 right2,
21644                 right3;
21645             multiSelect$1(items, left, right, N1, this.compareMinX);
21646
21647             for (i = left; i <= right; i += N1) {
21648               right2 = Math.min(i + N1 - 1, right);
21649               multiSelect$1(items, i, right2, N2, this.compareMinY);
21650
21651               for (j = i; j <= right2; j += N2) {
21652                 right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
21653
21654                 node.children.push(this._build(items, j, right3, height - 1));
21655               }
21656             }
21657
21658             calcBBox$1(node, this.toBBox);
21659             return node;
21660           },
21661           _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
21662             var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
21663
21664             while (true) {
21665               path.push(node);
21666               if (node.leaf || path.length - 1 === level) break;
21667               minArea = minEnlargement = Infinity;
21668
21669               for (i = 0, len = node.children.length; i < len; i++) {
21670                 child = node.children[i];
21671                 area = bboxArea$1(child);
21672                 enlargement = enlargedArea$1(bbox, child) - area; // choose entry with the least area enlargement
21673
21674                 if (enlargement < minEnlargement) {
21675                   minEnlargement = enlargement;
21676                   minArea = area < minArea ? area : minArea;
21677                   targetNode = child;
21678                 } else if (enlargement === minEnlargement) {
21679                   // otherwise choose one with the smallest area
21680                   if (area < minArea) {
21681                     minArea = area;
21682                     targetNode = child;
21683                   }
21684                 }
21685               }
21686
21687               node = targetNode || node.children[0];
21688             }
21689
21690             return node;
21691           },
21692           _insert: function _insert(item, level, isNode) {
21693             var toBBox = this.toBBox,
21694                 bbox = isNode ? item : toBBox(item),
21695                 insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
21696
21697             var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
21698
21699
21700             node.children.push(item);
21701             extend$2(node, bbox); // split on node overflow; propagate upwards if necessary
21702
21703             while (level >= 0) {
21704               if (insertPath[level].children.length > this._maxEntries) {
21705                 this._split(insertPath, level);
21706
21707                 level--;
21708               } else break;
21709             } // adjust bboxes along the insertion path
21710
21711
21712             this._adjustParentBBoxes(bbox, insertPath, level);
21713           },
21714           // split overflowed node into two
21715           _split: function _split(insertPath, level) {
21716             var node = insertPath[level],
21717                 M = node.children.length,
21718                 m = this._minEntries;
21719
21720             this._chooseSplitAxis(node, m, M);
21721
21722             var splitIndex = this._chooseSplitIndex(node, m, M);
21723
21724             var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
21725             newNode.height = node.height;
21726             newNode.leaf = node.leaf;
21727             calcBBox$1(node, this.toBBox);
21728             calcBBox$1(newNode, this.toBBox);
21729             if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
21730           },
21731           _splitRoot: function _splitRoot(node, newNode) {
21732             // split root node
21733             this.data = createNode$1([node, newNode]);
21734             this.data.height = node.height + 1;
21735             this.data.leaf = false;
21736             calcBBox$1(this.data, this.toBBox);
21737           },
21738           _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
21739             var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
21740             minOverlap = minArea = Infinity;
21741
21742             for (i = m; i <= M - m; i++) {
21743               bbox1 = distBBox$1(node, 0, i, this.toBBox);
21744               bbox2 = distBBox$1(node, i, M, this.toBBox);
21745               overlap = intersectionArea$1(bbox1, bbox2);
21746               area = bboxArea$1(bbox1) + bboxArea$1(bbox2); // choose distribution with minimum overlap
21747
21748               if (overlap < minOverlap) {
21749                 minOverlap = overlap;
21750                 index = i;
21751                 minArea = area < minArea ? area : minArea;
21752               } else if (overlap === minOverlap) {
21753                 // otherwise choose distribution with minimum area
21754                 if (area < minArea) {
21755                   minArea = area;
21756                   index = i;
21757                 }
21758               }
21759             }
21760
21761             return index;
21762           },
21763           // sorts node children by the best axis for split
21764           _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
21765             var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
21766                 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
21767                 xMargin = this._allDistMargin(node, m, M, compareMinX),
21768                 yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
21769             // otherwise it's already sorted by minY
21770
21771
21772             if (xMargin < yMargin) node.children.sort(compareMinX);
21773           },
21774           // total margin of all possible split distributions where each node is at least m full
21775           _allDistMargin: function _allDistMargin(node, m, M, compare) {
21776             node.children.sort(compare);
21777             var toBBox = this.toBBox,
21778                 leftBBox = distBBox$1(node, 0, m, toBBox),
21779                 rightBBox = distBBox$1(node, M - m, M, toBBox),
21780                 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
21781                 i,
21782                 child;
21783
21784             for (i = m; i < M - m; i++) {
21785               child = node.children[i];
21786               extend$2(leftBBox, node.leaf ? toBBox(child) : child);
21787               margin += bboxMargin$1(leftBBox);
21788             }
21789
21790             for (i = M - m - 1; i >= m; i--) {
21791               child = node.children[i];
21792               extend$2(rightBBox, node.leaf ? toBBox(child) : child);
21793               margin += bboxMargin$1(rightBBox);
21794             }
21795
21796             return margin;
21797           },
21798           _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
21799             // adjust bboxes along the given tree path
21800             for (var i = level; i >= 0; i--) {
21801               extend$2(path[i], bbox);
21802             }
21803           },
21804           _condense: function _condense(path) {
21805             // go through the path, removing empty nodes and updating bboxes
21806             for (var i = path.length - 1, siblings; i >= 0; i--) {
21807               if (path[i].children.length === 0) {
21808                 if (i > 0) {
21809                   siblings = path[i - 1].children;
21810                   siblings.splice(siblings.indexOf(path[i]), 1);
21811                 } else this.clear();
21812               } else calcBBox$1(path[i], this.toBBox);
21813             }
21814           },
21815           _initFormat: function _initFormat(format) {
21816             // data format (minX, minY, maxX, maxY accessors)
21817             // uses eval-type function compilation instead of just accepting a toBBox function
21818             // because the algorithms are very sensitive to sorting functions performance,
21819             // so they should be dead simple and without inner calls
21820             var compareArr = ['return a', ' - b', ';'];
21821             this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
21822             this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
21823             this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
21824           }
21825         };
21826
21827         function findItem$1(item, items, equalsFn) {
21828           if (!equalsFn) return items.indexOf(item);
21829
21830           for (var i = 0; i < items.length; i++) {
21831             if (equalsFn(item, items[i])) return i;
21832           }
21833
21834           return -1;
21835         } // calculate node's bbox from bboxes of its children
21836
21837
21838         function calcBBox$1(node, toBBox) {
21839           distBBox$1(node, 0, node.children.length, toBBox, node);
21840         } // min bounding rectangle of node children from k to p-1
21841
21842
21843         function distBBox$1(node, k, p, toBBox, destNode) {
21844           if (!destNode) destNode = createNode$1(null);
21845           destNode.minX = Infinity;
21846           destNode.minY = Infinity;
21847           destNode.maxX = -Infinity;
21848           destNode.maxY = -Infinity;
21849
21850           for (var i = k, child; i < p; i++) {
21851             child = node.children[i];
21852             extend$2(destNode, node.leaf ? toBBox(child) : child);
21853           }
21854
21855           return destNode;
21856         }
21857
21858         function extend$2(a, b) {
21859           a.minX = Math.min(a.minX, b.minX);
21860           a.minY = Math.min(a.minY, b.minY);
21861           a.maxX = Math.max(a.maxX, b.maxX);
21862           a.maxY = Math.max(a.maxY, b.maxY);
21863           return a;
21864         }
21865
21866         function compareNodeMinX$1(a, b) {
21867           return a.minX - b.minX;
21868         }
21869
21870         function compareNodeMinY$1(a, b) {
21871           return a.minY - b.minY;
21872         }
21873
21874         function bboxArea$1(a) {
21875           return (a.maxX - a.minX) * (a.maxY - a.minY);
21876         }
21877
21878         function bboxMargin$1(a) {
21879           return a.maxX - a.minX + (a.maxY - a.minY);
21880         }
21881
21882         function enlargedArea$1(a, b) {
21883           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));
21884         }
21885
21886         function intersectionArea$1(a, b) {
21887           var minX = Math.max(a.minX, b.minX),
21888               minY = Math.max(a.minY, b.minY),
21889               maxX = Math.min(a.maxX, b.maxX),
21890               maxY = Math.min(a.maxY, b.maxY);
21891           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
21892         }
21893
21894         function contains$1(a, b) {
21895           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
21896         }
21897
21898         function intersects$1(a, b) {
21899           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
21900         }
21901
21902         function createNode$1(children) {
21903           return {
21904             children: children,
21905             height: 1,
21906             leaf: true,
21907             minX: Infinity,
21908             minY: Infinity,
21909             maxX: -Infinity,
21910             maxY: -Infinity
21911           };
21912         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
21913         // combines selection algorithm with binary divide & conquer approach
21914
21915
21916         function multiSelect$1(arr, left, right, n, compare) {
21917           var stack = [left, right],
21918               mid;
21919
21920           while (stack.length) {
21921             right = stack.pop();
21922             left = stack.pop();
21923             if (right - left <= n) continue;
21924             mid = left + Math.ceil((right - left) / n / 2) * n;
21925             quickselect$1(arr, mid, left, right, compare);
21926             stack.push(left, mid, mid, right);
21927           }
21928         }
21929
21930         var lineclip_1 = lineclip$2;
21931         lineclip$2.polyline = lineclip$2;
21932         lineclip$2.polygon = polygonclip$1; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
21933         // handle polylines rather than just segments
21934
21935         function lineclip$2(points, bbox, result) {
21936           var len = points.length,
21937               codeA = bitCode$1(points[0], bbox),
21938               part = [],
21939               i,
21940               a,
21941               b,
21942               codeB,
21943               lastCode;
21944           if (!result) result = [];
21945
21946           for (i = 1; i < len; i++) {
21947             a = points[i - 1];
21948             b = points[i];
21949             codeB = lastCode = bitCode$1(b, bbox);
21950
21951             while (true) {
21952               if (!(codeA | codeB)) {
21953                 // accept
21954                 part.push(a);
21955
21956                 if (codeB !== lastCode) {
21957                   // segment went outside
21958                   part.push(b);
21959
21960                   if (i < len - 1) {
21961                     // start a new line
21962                     result.push(part);
21963                     part = [];
21964                   }
21965                 } else if (i === len - 1) {
21966                   part.push(b);
21967                 }
21968
21969                 break;
21970               } else if (codeA & codeB) {
21971                 // trivial reject
21972                 break;
21973               } else if (codeA) {
21974                 // a outside, intersect with clip edge
21975                 a = intersect$1(a, b, codeA, bbox);
21976                 codeA = bitCode$1(a, bbox);
21977               } else {
21978                 // b outside
21979                 b = intersect$1(a, b, codeB, bbox);
21980                 codeB = bitCode$1(b, bbox);
21981               }
21982             }
21983
21984             codeA = lastCode;
21985           }
21986
21987           if (part.length) result.push(part);
21988           return result;
21989         } // Sutherland-Hodgeman polygon clipping algorithm
21990
21991
21992         function polygonclip$1(points, bbox) {
21993           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
21994
21995           for (edge = 1; edge <= 8; edge *= 2) {
21996             result = [];
21997             prev = points[points.length - 1];
21998             prevInside = !(bitCode$1(prev, bbox) & edge);
21999
22000             for (i = 0; i < points.length; i++) {
22001               p = points[i];
22002               inside = !(bitCode$1(p, bbox) & edge); // if segment goes through the clip window, add an intersection
22003
22004               if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
22005               if (inside) result.push(p); // add a point if it's inside
22006
22007               prev = p;
22008               prevInside = inside;
22009             }
22010
22011             points = result;
22012             if (!points.length) break;
22013           }
22014
22015           return result;
22016         } // intersect a segment against one of the 4 lines that make up the bbox
22017
22018
22019         function intersect$1(a, b, edge, bbox) {
22020           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
22021           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
22022           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
22023           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
22024           null;
22025         } // bit code reflects the point position relative to the bbox:
22026         //         left  mid  right
22027         //    top  1001  1000  1010
22028         //    mid  0001  0000  0010
22029         // bottom  0101  0100  0110
22030
22031
22032         function bitCode$1(p, bbox) {
22033           var code = 0;
22034           if (p[0] < bbox[0]) code |= 1; // left
22035           else if (p[0] > bbox[2]) code |= 2; // right
22036
22037           if (p[1] < bbox[1]) code |= 4; // bottom
22038           else if (p[1] > bbox[3]) code |= 8; // top
22039
22040           return code;
22041         }
22042
22043         var rbush = rbush$2.exports;
22044         var lineclip$1 = lineclip_1;
22045         var whichPolygon_1 = whichPolygon;
22046
22047         function whichPolygon(data) {
22048           var bboxes = [];
22049
22050           for (var i = 0; i < data.features.length; i++) {
22051             var feature = data.features[i];
22052             var coords = feature.geometry.coordinates;
22053
22054             if (feature.geometry.type === 'Polygon') {
22055               bboxes.push(treeItem(coords, feature.properties));
22056             } else if (feature.geometry.type === 'MultiPolygon') {
22057               for (var j = 0; j < coords.length; j++) {
22058                 bboxes.push(treeItem(coords[j], feature.properties));
22059               }
22060             }
22061           }
22062
22063           var tree = rbush().load(bboxes);
22064
22065           function query(p, multi) {
22066             var output = [],
22067                 result = tree.search({
22068               minX: p[0],
22069               minY: p[1],
22070               maxX: p[0],
22071               maxY: p[1]
22072             });
22073
22074             for (var i = 0; i < result.length; i++) {
22075               if (insidePolygon(result[i].coords, p)) {
22076                 if (multi) output.push(result[i].props);else return result[i].props;
22077               }
22078             }
22079
22080             return multi && output.length ? output : null;
22081           }
22082
22083           query.tree = tree;
22084
22085           query.bbox = function queryBBox(bbox) {
22086             var output = [];
22087             var result = tree.search({
22088               minX: bbox[0],
22089               minY: bbox[1],
22090               maxX: bbox[2],
22091               maxY: bbox[3]
22092             });
22093
22094             for (var i = 0; i < result.length; i++) {
22095               if (polygonIntersectsBBox(result[i].coords, bbox)) {
22096                 output.push(result[i].props);
22097               }
22098             }
22099
22100             return output;
22101           };
22102
22103           return query;
22104         }
22105
22106         function polygonIntersectsBBox(polygon, bbox) {
22107           var bboxCenter = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
22108           if (insidePolygon(polygon, bboxCenter)) return true;
22109
22110           for (var i = 0; i < polygon.length; i++) {
22111             if (lineclip$1(polygon[i], bbox).length > 0) return true;
22112           }
22113
22114           return false;
22115         } // ray casting algorithm for detecting if point is in polygon
22116
22117
22118         function insidePolygon(rings, p) {
22119           var inside = false;
22120
22121           for (var i = 0, len = rings.length; i < len; i++) {
22122             var ring = rings[i];
22123
22124             for (var j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
22125               if (rayIntersect(p, ring[j], ring[k])) inside = !inside;
22126             }
22127           }
22128
22129           return inside;
22130         }
22131
22132         function rayIntersect(p, p1, p2) {
22133           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];
22134         }
22135
22136         function treeItem(coords, props) {
22137           var item = {
22138             minX: Infinity,
22139             minY: Infinity,
22140             maxX: -Infinity,
22141             maxY: -Infinity,
22142             coords: coords,
22143             props: props
22144           };
22145
22146           for (var i = 0; i < coords[0].length; i++) {
22147             var p = coords[0][i];
22148             item.minX = Math.min(item.minX, p[0]);
22149             item.minY = Math.min(item.minY, p[1]);
22150             item.maxX = Math.max(item.maxX, p[0]);
22151             item.maxY = Math.max(item.maxY, p[1]);
22152           }
22153
22154           return item;
22155         }
22156
22157         var type = "FeatureCollection";
22158         var features = [{
22159           type: "Feature",
22160           properties: {
22161             wikidata: "Q21",
22162             nameEn: "England",
22163             aliases: ["GB-ENG"],
22164             country: "GB",
22165             groups: ["Q23666", "Q3336843", "154", "150", "UN"],
22166             driveSide: "left",
22167             roadSpeedUnit: "mph",
22168             roadHeightUnit: "ft",
22169             callingCodes: ["44"]
22170           },
22171           geometry: {
22172             type: "MultiPolygon",
22173             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]]]]
22174           }
22175         }, {
22176           type: "Feature",
22177           properties: {
22178             wikidata: "Q22",
22179             nameEn: "Scotland",
22180             aliases: ["GB-SCT"],
22181             country: "GB",
22182             groups: ["Q23666", "Q3336843", "154", "150", "UN"],
22183             driveSide: "left",
22184             roadSpeedUnit: "mph",
22185             roadHeightUnit: "ft",
22186             callingCodes: ["44"]
22187           },
22188           geometry: {
22189             type: "MultiPolygon",
22190             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]]]]
22191           }
22192         }, {
22193           type: "Feature",
22194           properties: {
22195             wikidata: "Q25",
22196             nameEn: "Wales",
22197             aliases: ["GB-WLS"],
22198             country: "GB",
22199             groups: ["Q23666", "Q3336843", "154", "150", "UN"],
22200             driveSide: "left",
22201             roadSpeedUnit: "mph",
22202             roadHeightUnit: "ft",
22203             callingCodes: ["44"]
22204           },
22205           geometry: {
22206             type: "MultiPolygon",
22207             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]]]]
22208           }
22209         }, {
22210           type: "Feature",
22211           properties: {
22212             wikidata: "Q26",
22213             nameEn: "Northern Ireland",
22214             aliases: ["GB-NIR"],
22215             country: "GB",
22216             groups: ["Q22890", "Q3336843", "154", "150", "UN"],
22217             driveSide: "left",
22218             roadSpeedUnit: "mph",
22219             roadHeightUnit: "ft",
22220             callingCodes: ["44"]
22221           },
22222           geometry: {
22223             type: "MultiPolygon",
22224             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]]]]
22225           }
22226         }, {
22227           type: "Feature",
22228           properties: {
22229             wikidata: "Q35",
22230             nameEn: "Denmark",
22231             country: "DK",
22232             groups: ["EU", "154", "150", "UN"],
22233             callingCodes: ["45"]
22234           },
22235           geometry: {
22236             type: "MultiPolygon",
22237             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]]]]
22238           }
22239         }, {
22240           type: "Feature",
22241           properties: {
22242             wikidata: "Q55",
22243             nameEn: "Netherlands",
22244             country: "NL",
22245             groups: ["EU", "155", "150", "UN"],
22246             callingCodes: ["31"]
22247           },
22248           geometry: {
22249             type: "MultiPolygon",
22250             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]]]]
22251           }
22252         }, {
22253           type: "Feature",
22254           properties: {
22255             wikidata: "Q782",
22256             nameEn: "Hawaii",
22257             aliases: ["US-HI"],
22258             country: "US",
22259             groups: ["Q35657", "061", "009", "UN"],
22260             roadSpeedUnit: "mph",
22261             roadHeightUnit: "ft",
22262             callingCodes: ["1"]
22263           },
22264           geometry: {
22265             type: "MultiPolygon",
22266             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]]]]
22267           }
22268         }, {
22269           type: "Feature",
22270           properties: {
22271             wikidata: "Q797",
22272             nameEn: "Alaska",
22273             aliases: ["US-AK"],
22274             country: "US",
22275             groups: ["Q35657", "021", "003", "019", "UN"],
22276             roadSpeedUnit: "mph",
22277             roadHeightUnit: "ft",
22278             callingCodes: ["1"]
22279           },
22280           geometry: {
22281             type: "MultiPolygon",
22282             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]]]]
22283           }
22284         }, {
22285           type: "Feature",
22286           properties: {
22287             wikidata: "Q3492",
22288             nameEn: "Sumatra",
22289             aliases: ["ID-SM"],
22290             country: "ID",
22291             groups: ["035", "142", "UN"],
22292             driveSide: "left",
22293             callingCodes: ["62"]
22294           },
22295           geometry: {
22296             type: "MultiPolygon",
22297             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]]]]
22298           }
22299         }, {
22300           type: "Feature",
22301           properties: {
22302             wikidata: "Q3757",
22303             nameEn: "Java",
22304             aliases: ["ID-JW"],
22305             country: "ID",
22306             groups: ["035", "142", "UN"],
22307             driveSide: "left",
22308             callingCodes: ["62"]
22309           },
22310           geometry: {
22311             type: "MultiPolygon",
22312             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]]]]
22313           }
22314         }, {
22315           type: "Feature",
22316           properties: {
22317             wikidata: "Q3795",
22318             nameEn: "Kalimantan",
22319             aliases: ["ID-KA"],
22320             country: "ID",
22321             groups: ["Q36117", "035", "142", "UN"],
22322             driveSide: "left",
22323             callingCodes: ["62"]
22324           },
22325           geometry: {
22326             type: "MultiPolygon",
22327             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]]]]
22328           }
22329         }, {
22330           type: "Feature",
22331           properties: {
22332             wikidata: "Q3803",
22333             nameEn: "Lesser Sunda Islands",
22334             aliases: ["ID-NU"],
22335             country: "ID",
22336             groups: ["035", "142", "UN"],
22337             driveSide: "left",
22338             callingCodes: ["62"]
22339           },
22340           geometry: {
22341             type: "MultiPolygon",
22342             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]]]]
22343           }
22344         }, {
22345           type: "Feature",
22346           properties: {
22347             wikidata: "Q3812",
22348             nameEn: "Sulawesi",
22349             aliases: ["ID-SL"],
22350             country: "ID",
22351             groups: ["035", "142", "UN"],
22352             driveSide: "left",
22353             callingCodes: ["62"]
22354           },
22355           geometry: {
22356             type: "MultiPolygon",
22357             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]]]]
22358           }
22359         }, {
22360           type: "Feature",
22361           properties: {
22362             wikidata: "Q3827",
22363             nameEn: "Maluku Islands",
22364             aliases: ["ID-ML"],
22365             country: "ID",
22366             groups: ["035", "142", "UN"],
22367             driveSide: "left",
22368             callingCodes: ["62"]
22369           },
22370           geometry: {
22371             type: "MultiPolygon",
22372             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]]]]
22373           }
22374         }, {
22375           type: "Feature",
22376           properties: {
22377             wikidata: "Q3845",
22378             nameEn: "Western New Guinea",
22379             aliases: ["ID-PP"],
22380             country: "ID",
22381             groups: ["035", "142", "UN"],
22382             driveSide: "left",
22383             callingCodes: ["62"]
22384           },
22385           geometry: {
22386             type: "MultiPolygon",
22387             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]]]]
22388           }
22389         }, {
22390           type: "Feature",
22391           properties: {
22392             wikidata: "Q5765",
22393             nameEn: "Balearic Islands",
22394             aliases: ["ES-IB"],
22395             country: "ES",
22396             groups: ["EU", "039", "150", "UN"],
22397             callingCodes: ["34 971"]
22398           },
22399           geometry: {
22400             type: "MultiPolygon",
22401             coordinates: [[[[-2.27707, 35.35051], [5.10072, 39.89531], [3.75438, 42.33445], [-2.27707, 35.35051]]]]
22402           }
22403         }, {
22404           type: "Feature",
22405           properties: {
22406             wikidata: "Q5823",
22407             nameEn: "Ceuta",
22408             aliases: ["ES-CE"],
22409             country: "ES",
22410             groups: ["EA", "EU", "015", "002", "UN"],
22411             level: "subterritory",
22412             callingCodes: ["34"]
22413           },
22414           geometry: {
22415             type: "MultiPolygon",
22416             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]]]]
22417           }
22418         }, {
22419           type: "Feature",
22420           properties: {
22421             wikidata: "Q5831",
22422             nameEn: "Melilla",
22423             aliases: ["ES-ML"],
22424             country: "ES",
22425             groups: ["EA", "EU", "015", "002", "UN"],
22426             level: "subterritory",
22427             callingCodes: ["34"]
22428           },
22429           geometry: {
22430             type: "MultiPolygon",
22431             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]]]]
22432           }
22433         }, {
22434           type: "Feature",
22435           properties: {
22436             wikidata: "Q7835",
22437             nameEn: "Crimea",
22438             country: "RU",
22439             groups: ["151", "150", "UN"],
22440             level: "subterritory",
22441             callingCodes: ["7"]
22442           },
22443           geometry: {
22444             type: "MultiPolygon",
22445             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]]]]
22446           }
22447         }, {
22448           type: "Feature",
22449           properties: {
22450             wikidata: "Q12837",
22451             nameEn: "Iberia",
22452             level: "sharedLandform"
22453           },
22454           geometry: null
22455         }, {
22456           type: "Feature",
22457           properties: {
22458             wikidata: "Q14056",
22459             nameEn: "Jan Mayen",
22460             aliases: ["NO-22"],
22461             country: "NO",
22462             groups: ["SJ", "154", "150", "UN"],
22463             level: "subterritory"
22464           },
22465           geometry: {
22466             type: "MultiPolygon",
22467             coordinates: [[[[-9.18243, 72.23144], [-10.71459, 70.09565], [-5.93364, 70.76368], [-9.18243, 72.23144]]]]
22468           }
22469         }, {
22470           type: "Feature",
22471           properties: {
22472             wikidata: "Q19188",
22473             nameEn: "Mainland China",
22474             country: "CN",
22475             groups: ["030", "142", "UN"],
22476             callingCodes: ["86"]
22477           },
22478           geometry: {
22479             type: "MultiPolygon",
22480             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]]]]
22481           }
22482         }, {
22483           type: "Feature",
22484           properties: {
22485             wikidata: "Q22890",
22486             nameEn: "Ireland",
22487             level: "sharedLandform"
22488           },
22489           geometry: null
22490         }, {
22491           type: "Feature",
22492           properties: {
22493             wikidata: "Q23666",
22494             nameEn: "Great Britain",
22495             country: "GB",
22496             level: "sharedLandform"
22497           },
22498           geometry: null
22499         }, {
22500           type: "Feature",
22501           properties: {
22502             wikidata: "Q23681",
22503             nameEn: "Northern Cyprus",
22504             groups: ["Q644636", "145", "142"],
22505             driveSide: "left",
22506             callingCodes: ["90 392"]
22507           },
22508           geometry: {
22509             type: "MultiPolygon",
22510             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]]]]
22511           }
22512         }, {
22513           type: "Feature",
22514           properties: {
22515             wikidata: "Q25231",
22516             nameEn: "Svalbard",
22517             aliases: ["NO-21"],
22518             country: "NO",
22519             groups: ["SJ", "154", "150", "UN"],
22520             level: "subterritory",
22521             callingCodes: ["47 79"]
22522           },
22523           geometry: {
22524             type: "MultiPolygon",
22525             coordinates: [[[[-7.49892, 77.24208], [32.07813, 72.01005], [36.85549, 84.09565], [-7.49892, 77.24208]]]]
22526           }
22527         }, {
22528           type: "Feature",
22529           properties: {
22530             wikidata: "Q25263",
22531             nameEn: "Azores",
22532             aliases: ["PT-20"],
22533             country: "PT",
22534             groups: ["Q3320166", "Q2914565", "Q105472", "EU", "039", "150", "UN"],
22535             callingCodes: ["351"]
22536           },
22537           geometry: {
22538             type: "MultiPolygon",
22539             coordinates: [[[[-23.12984, 40.26428], [-36.43765, 41.39418], [-22.54767, 33.34416], [-23.12984, 40.26428]]]]
22540           }
22541         }, {
22542           type: "Feature",
22543           properties: {
22544             wikidata: "Q25359",
22545             nameEn: "Navassa Island",
22546             aliases: ["UM-76"],
22547             country: "US",
22548             groups: ["UM", "Q1352230", "029", "003", "419", "019", "UN"],
22549             level: "subterritory",
22550             roadSpeedUnit: "mph",
22551             roadHeightUnit: "ft"
22552           },
22553           geometry: {
22554             type: "MultiPolygon",
22555             coordinates: [[[[-74.7289, 18.71009], [-75.71816, 18.46438], [-74.76465, 18.06252], [-74.7289, 18.71009]]]]
22556           }
22557         }, {
22558           type: "Feature",
22559           properties: {
22560             wikidata: "Q25396",
22561             nameEn: "Bonaire",
22562             aliases: ["BQ-BO", "NL-BQ1"],
22563             country: "NL",
22564             groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
22565             level: "subterritory",
22566             callingCodes: ["599 7"]
22567           },
22568           geometry: {
22569             type: "MultiPolygon",
22570             coordinates: [[[[-67.89186, 12.4116], [-68.90012, 12.62309], [-68.33524, 11.78151], [-68.01417, 11.77722], [-67.89186, 12.4116]]]]
22571           }
22572         }, {
22573           type: "Feature",
22574           properties: {
22575             wikidata: "Q25528",
22576             nameEn: "Saba",
22577             aliases: ["BQ-SA", "NL-BQ2"],
22578             country: "NL",
22579             groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
22580             level: "subterritory",
22581             callingCodes: ["599 4"]
22582           },
22583           geometry: {
22584             type: "MultiPolygon",
22585             coordinates: [[[[-63.07669, 17.79659], [-63.81314, 17.95045], [-63.22932, 17.32592], [-63.07669, 17.79659]]]]
22586           }
22587         }, {
22588           type: "Feature",
22589           properties: {
22590             wikidata: "Q26180",
22591             nameEn: "Sint Eustatius",
22592             aliases: ["BQ-SE", "NL-BQ3"],
22593             country: "NL",
22594             groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
22595             level: "subterritory",
22596             callingCodes: ["599 3"]
22597           },
22598           geometry: {
22599             type: "MultiPolygon",
22600             coordinates: [[[[-63.07669, 17.79659], [-63.34999, 16.94218], [-62.76692, 17.64353], [-63.07669, 17.79659]]]]
22601           }
22602         }, {
22603           type: "Feature",
22604           properties: {
22605             wikidata: "Q26253",
22606             nameEn: "Madeira",
22607             aliases: ["PT-30"],
22608             country: "PT",
22609             groups: ["Q3320166", "Q2914565", "Q105472", "EU", "039", "150", "UN"],
22610             callingCodes: ["351"]
22611           },
22612           geometry: {
22613             type: "MultiPolygon",
22614             coordinates: [[[[-19.30302, 33.65304], [-16.04789, 29.65076], [-11.68307, 33.12333], [-19.30302, 33.65304]]]]
22615           }
22616         }, {
22617           type: "Feature",
22618           properties: {
22619             wikidata: "Q26927",
22620             nameEn: "Lakshadweep",
22621             aliases: ["IN-LD"],
22622             country: "IN",
22623             groups: ["034", "142", "UN"],
22624             driveSide: "left",
22625             callingCodes: ["91"]
22626           },
22627           geometry: {
22628             type: "MultiPolygon",
22629             coordinates: [[[[67.64074, 11.57295], [76.59015, 5.591], [72.67494, 13.58102], [67.64074, 11.57295]]]]
22630           }
22631         }, {
22632           type: "Feature",
22633           properties: {
22634             wikidata: "Q27329",
22635             nameEn: "Asian Russia",
22636             country: "RU",
22637             groups: ["142", "UN"],
22638             callingCodes: ["7"]
22639           },
22640           geometry: {
22641             type: "MultiPolygon",
22642             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]]]]
22643           }
22644         }, {
22645           type: "Feature",
22646           properties: {
22647             wikidata: "Q34366",
22648             nameEn: "Tasmania",
22649             aliases: ["AU-TAS"],
22650             country: "AU",
22651             groups: ["053", "009", "UN"],
22652             driveSide: "left",
22653             callingCodes: ["61"]
22654           },
22655           geometry: {
22656             type: "MultiPolygon",
22657             coordinates: [[[[123.64533, -39.13605], [159.69067, -56.28945], [159.74028, -39.1978], [123.64533, -39.13605]]]]
22658           }
22659         }, {
22660           type: "Feature",
22661           properties: {
22662             wikidata: "Q34497",
22663             nameEn: "Saint Helena",
22664             aliases: ["SH-HL"],
22665             country: "GB",
22666             groups: ["SH", "BOTS", "011", "202", "002", "UN"],
22667             level: "subterritory",
22668             driveSide: "left",
22669             roadSpeedUnit: "mph",
22670             roadHeightUnit: "ft",
22671             callingCodes: ["290"]
22672           },
22673           geometry: {
22674             type: "MultiPolygon",
22675             coordinates: [[[[-8.3824, -13.9131], [-6.17428, -19.07236], [-3.29308, -15.22647], [-8.3824, -13.9131]]]]
22676           }
22677         }, {
22678           type: "Feature",
22679           properties: {
22680             wikidata: "Q35657",
22681             nameEn: "US States",
22682             country: "US",
22683             level: "subcountryGroup"
22684           },
22685           geometry: null
22686         }, {
22687           type: "Feature",
22688           properties: {
22689             wikidata: "Q36117",
22690             nameEn: "Borneo",
22691             level: "sharedLandform"
22692           },
22693           geometry: null
22694         }, {
22695           type: "Feature",
22696           properties: {
22697             wikidata: "Q36678",
22698             nameEn: "West Bank",
22699             country: "PS",
22700             groups: ["145", "142"],
22701             callingCodes: ["970"]
22702           },
22703           geometry: {
22704             type: "MultiPolygon",
22705             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]]]]
22706           }
22707         }, {
22708           type: "Feature",
22709           properties: {
22710             wikidata: "Q37362",
22711             nameEn: "Akrotiri and Dhekelia",
22712             aliases: ["SBA"],
22713             country: "GB"
22714           },
22715           geometry: null
22716         }, {
22717           type: "Feature",
22718           properties: {
22719             wikidata: "Q38095",
22720             nameEn: "Gal\xE1pagos Islands",
22721             aliases: ["EC-W"],
22722             country: "EC",
22723             groups: ["005", "419", "019", "UN"],
22724             callingCodes: ["593"]
22725           },
22726           geometry: {
22727             type: "MultiPolygon",
22728             coordinates: [[[[-93.12365, 2.64343], [-92.46744, -2.52874], [-87.07749, -0.8849], [-93.12365, 2.64343]]]]
22729           }
22730         }, {
22731           type: "Feature",
22732           properties: {
22733             wikidata: "Q39760",
22734             nameEn: "Gaza Strip",
22735             country: "PS",
22736             groups: ["145", "142"],
22737             callingCodes: ["970"]
22738           },
22739           geometry: {
22740             type: "MultiPolygon",
22741             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]]]]
22742           }
22743         }, {
22744           type: "Feature",
22745           properties: {
22746             wikidata: "Q40888",
22747             nameEn: "Andaman and Nicobar Islands",
22748             aliases: ["IN-AN"],
22749             country: "IN",
22750             groups: ["034", "142", "UN"],
22751             driveSide: "left",
22752             callingCodes: ["91"]
22753           },
22754           geometry: {
22755             type: "MultiPolygon",
22756             coordinates: [[[[94.42132, 5.96581], [94.6371, 13.81803], [86.7822, 13.41052], [94.42132, 5.96581]]]]
22757           }
22758         }, {
22759           type: "Feature",
22760           properties: {
22761             wikidata: "Q41684",
22762             nameEn: "Stewart Island",
22763             country: "NZ",
22764             groups: ["053", "009", "UN"],
22765             driveSide: "left",
22766             callingCodes: ["64"]
22767           },
22768           geometry: {
22769             type: "MultiPolygon",
22770             coordinates: [[[[166.59185, -47.61313], [169.70504, -47.56021], [167.52103, -46.41337], [166.59185, -47.61313]]]]
22771           }
22772         }, {
22773           type: "Feature",
22774           properties: {
22775             wikidata: "Q43296",
22776             nameEn: "Wake Island",
22777             aliases: ["WK", "WAK", "WKUM", "872", "UM-79"],
22778             country: "US",
22779             groups: ["UM", "Q1352230", "057", "009", "UN"],
22780             level: "subterritory",
22781             roadSpeedUnit: "mph",
22782             roadHeightUnit: "ft",
22783             callingCodes: ["1"]
22784           },
22785           geometry: {
22786             type: "MultiPolygon",
22787             coordinates: [[[[167.34779, 18.97692], [166.67967, 20.14834], [165.82549, 18.97692], [167.34779, 18.97692]]]]
22788           }
22789         }, {
22790           type: "Feature",
22791           properties: {
22792             wikidata: "Q46275",
22793             nameEn: "New Zealand Subantarctic Islands",
22794             country: "NZ",
22795             groups: ["Q851132", "053", "009", "UN"],
22796             driveSide: "left"
22797           },
22798           geometry: {
22799             type: "MultiPolygon",
22800             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]]]]
22801           }
22802         }, {
22803           type: "Feature",
22804           properties: {
22805             wikidata: "Q46395",
22806             nameEn: "British Overseas Territories",
22807             aliases: ["BOTS", "UKOTS"],
22808             country: "GB",
22809             level: "subcountryGroup"
22810           },
22811           geometry: null
22812         }, {
22813           type: "Feature",
22814           properties: {
22815             wikidata: "Q46772",
22816             nameEn: "Kerguelen Islands",
22817             country: "FR",
22818             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
22819             level: "subterritory"
22820           },
22821           geometry: {
22822             type: "MultiPolygon",
22823             coordinates: [[[[61.9216, -49.39746], [70.67507, -51.14192], [74.25129, -45.45074], [61.9216, -49.39746]]]]
22824           }
22825         }, {
22826           type: "Feature",
22827           properties: {
22828             wikidata: "Q46879",
22829             nameEn: "Baker Island",
22830             aliases: ["UM-81"],
22831             country: "US",
22832             groups: ["UM", "Q1352230", "061", "009", "UN"],
22833             level: "subterritory",
22834             roadSpeedUnit: "mph",
22835             roadHeightUnit: "ft"
22836           },
22837           geometry: {
22838             type: "MultiPolygon",
22839             coordinates: [[[[-175.33482, -1.40631], [-175.31323, 0.5442], [-177.91421, 0.39582], [-175.33482, -1.40631]]]]
22840           }
22841         }, {
22842           type: "Feature",
22843           properties: {
22844             wikidata: "Q47863",
22845             nameEn: "Midway Atoll",
22846             aliases: ["MI", "MID", "MIUM", "488", "UM-71"],
22847             country: "US",
22848             groups: ["UM", "Q1352230", "061", "009", "UN"],
22849             level: "subterritory",
22850             roadSpeedUnit: "mph",
22851             roadHeightUnit: "ft",
22852             callingCodes: ["1"]
22853           },
22854           geometry: {
22855             type: "MultiPolygon",
22856             coordinates: [[[[-176.29741, 29.09786], [-177.77531, 29.29793], [-177.5224, 27.7635], [-176.29741, 29.09786]]]]
22857           }
22858         }, {
22859           type: "Feature",
22860           properties: {
22861             wikidata: "Q62218",
22862             nameEn: "Jarvis Island",
22863             aliases: ["UM-86"],
22864             country: "US",
22865             groups: ["UM", "Q1352230", "061", "009", "UN"],
22866             level: "subterritory",
22867             roadSpeedUnit: "mph",
22868             roadHeightUnit: "ft"
22869           },
22870           geometry: {
22871             type: "MultiPolygon",
22872             coordinates: [[[[-160.42921, -1.4364], [-159.12443, 0.19975], [-160.38779, 0.30331], [-160.42921, -1.4364]]]]
22873           }
22874         }, {
22875           type: "Feature",
22876           properties: {
22877             wikidata: "Q105472",
22878             nameEn: "Macaronesia",
22879             level: "sharedLandform"
22880           },
22881           geometry: null
22882         }, {
22883           type: "Feature",
22884           properties: {
22885             wikidata: "Q114935",
22886             nameEn: "Kermadec Islands",
22887             country: "NZ",
22888             groups: ["Q851132", "053", "009", "UN"],
22889             driveSide: "left",
22890             callingCodes: ["64"]
22891           },
22892           geometry: {
22893             type: "MultiPolygon",
22894             coordinates: [[[[-174.40891, -29.09438], [-180, -24.21376], [-179.96512, -35.00791], [-174.40891, -29.09438]]]]
22895           }
22896         }, {
22897           type: "Feature",
22898           properties: {
22899             wikidata: "Q115459",
22900             nameEn: "Chatham Islands",
22901             aliases: ["NZ-CIT"],
22902             country: "NZ",
22903             groups: ["Q851132", "053", "009", "UN"],
22904             driveSide: "left",
22905             callingCodes: ["64"]
22906           },
22907           geometry: {
22908             type: "MultiPolygon",
22909             coordinates: [[[[-179.93224, -45.18423], [-172.47015, -45.17912], [-176.30998, -41.38382], [-179.93224, -45.18423]]]]
22910           }
22911         }, {
22912           type: "Feature",
22913           properties: {
22914             wikidata: "Q118863",
22915             nameEn: "North Island",
22916             country: "NZ",
22917             groups: ["053", "009", "UN"],
22918             driveSide: "left",
22919             callingCodes: ["64"]
22920           },
22921           geometry: {
22922             type: "MultiPolygon",
22923             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]]]]
22924           }
22925         }, {
22926           type: "Feature",
22927           properties: {
22928             wikidata: "Q120755",
22929             nameEn: "South Island",
22930             country: "NZ",
22931             groups: ["053", "009", "UN"],
22932             driveSide: "left",
22933             callingCodes: ["64"]
22934           },
22935           geometry: {
22936             type: "MultiPolygon",
22937             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]]]]
22938           }
22939         }, {
22940           type: "Feature",
22941           properties: {
22942             wikidata: "Q123076",
22943             nameEn: "Palmyra Atoll",
22944             aliases: ["UM-95"],
22945             country: "US",
22946             groups: ["UM", "Q1352230", "061", "009", "UN"],
22947             level: "subterritory",
22948             roadSpeedUnit: "mph",
22949             roadHeightUnit: "ft",
22950             callingCodes: ["1"]
22951           },
22952           geometry: {
22953             type: "MultiPolygon",
22954             coordinates: [[[[-161.06795, 5.2462], [-161.0731, 7.1291], [-163.24478, 5.24198], [-161.06795, 5.2462]]]]
22955           }
22956         }, {
22957           type: "Feature",
22958           properties: {
22959             wikidata: "Q130574",
22960             nameEn: "Chafarinas Islands",
22961             country: "ES",
22962             groups: ["EU", "Q191011", "015", "002", "UN"],
22963             level: "subterritory"
22964           },
22965           geometry: {
22966             type: "MultiPolygon",
22967             coordinates: [[[[-2.40316, 35.16893], [-2.43262, 35.20652], [-2.45965, 35.16527], [-2.40316, 35.16893]]]]
22968           }
22969         }, {
22970           type: "Feature",
22971           properties: {
22972             wikidata: "Q130895",
22973             nameEn: "Kingman Reef",
22974             aliases: ["UM-89"],
22975             country: "US",
22976             groups: ["UM", "Q1352230", "061", "009", "UN"],
22977             level: "subterritory",
22978             roadSpeedUnit: "mph",
22979             roadHeightUnit: "ft"
22980           },
22981           geometry: {
22982             type: "MultiPolygon",
22983             coordinates: [[[[-161.0731, 7.1291], [-163.16627, 7.15036], [-163.24478, 5.24198], [-161.0731, 7.1291]]]]
22984           }
22985         }, {
22986           type: "Feature",
22987           properties: {
22988             wikidata: "Q131008",
22989             nameEn: "Johnston Atoll",
22990             aliases: ["JT", "JTN", "JTUM", "396", "UM-67"],
22991             country: "US",
22992             groups: ["UM", "Q1352230", "061", "009", "UN"],
22993             level: "subterritory",
22994             roadSpeedUnit: "mph",
22995             roadHeightUnit: "ft",
22996             callingCodes: ["1"]
22997           },
22998           geometry: {
22999             type: "MultiPolygon",
23000             coordinates: [[[[-170.65691, 16.57199], [-168.87689, 16.01159], [-169.2329, 17.4933], [-170.65691, 16.57199]]]]
23001           }
23002         }, {
23003           type: "Feature",
23004           properties: {
23005             wikidata: "Q131305",
23006             nameEn: "Howland Island",
23007             aliases: ["UM-84"],
23008             country: "US",
23009             groups: ["UM", "Q1352230", "061", "009", "UN"],
23010             level: "subterritory",
23011             roadSpeedUnit: "mph",
23012             roadHeightUnit: "ft"
23013           },
23014           geometry: {
23015             type: "MultiPolygon",
23016             coordinates: [[[[-177.91421, 0.39582], [-175.31323, 0.5442], [-176.74464, 2.28109], [-177.91421, 0.39582]]]]
23017           }
23018         }, {
23019           type: "Feature",
23020           properties: {
23021             wikidata: "Q133888",
23022             nameEn: "Ashmore and Cartier Islands",
23023             country: "AU",
23024             groups: ["053", "009", "UN"],
23025             driveSide: "left",
23026             callingCodes: ["61"]
23027           },
23028           geometry: {
23029             type: "MultiPolygon",
23030             coordinates: [[[[123.7463, -11.1783], [120.6877, -13.59408], [125.29076, -12.33139], [123.7463, -11.1783]]]]
23031           }
23032         }, {
23033           type: "Feature",
23034           properties: {
23035             wikidata: "Q153732",
23036             nameEn: "Mariana Islands",
23037             level: "sharedLandform"
23038           },
23039           geometry: null
23040         }, {
23041           type: "Feature",
23042           properties: {
23043             wikidata: "Q172216",
23044             nameEn: "Coral Sea Islands",
23045             country: "AU",
23046             groups: ["053", "009", "UN"],
23047             driveSide: "left",
23048             callingCodes: ["61"]
23049           },
23050           geometry: {
23051             type: "MultiPolygon",
23052             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]]]]
23053           }
23054         }, {
23055           type: "Feature",
23056           properties: {
23057             wikidata: "Q179313",
23058             nameEn: "Alderney",
23059             country: "GB",
23060             groups: ["GG", "830", "Q185086", "154", "150", "UN"],
23061             level: "subterritory",
23062             driveSide: "left",
23063             roadSpeedUnit: "mph",
23064             roadHeightUnit: "ft",
23065             callingCodes: ["44 01481"]
23066           },
23067           geometry: {
23068             type: "MultiPolygon",
23069             coordinates: [[[[-2.36485, 49.48223], [-2.09454, 49.46288], [-2.02963, 49.91866], [-2.49556, 49.79012], [-2.36485, 49.48223]]]]
23070           }
23071         }, {
23072           type: "Feature",
23073           properties: {
23074             wikidata: "Q185086",
23075             nameEn: "Crown Dependencies",
23076             country: "GB",
23077             level: "subcountryGroup"
23078           },
23079           geometry: null
23080         }, {
23081           type: "Feature",
23082           properties: {
23083             wikidata: "Q190571",
23084             nameEn: "Scattered Islands",
23085             country: "FR",
23086             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
23087             level: "subterritory"
23088           },
23089           geometry: {
23090             type: "MultiPolygon",
23091             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]]]]
23092           }
23093         }, {
23094           type: "Feature",
23095           properties: {
23096             wikidata: "Q191011",
23097             nameEn: "Plazas de soberan\xEDa",
23098             country: "ES"
23099           },
23100           geometry: null
23101         }, {
23102           type: "Feature",
23103           properties: {
23104             wikidata: "Q191146",
23105             nameEn: "Pe\xF1\xF3n de V\xE9lez de la Gomera",
23106             country: "ES",
23107             groups: ["EU", "Q191011", "015", "002", "UN"],
23108             level: "subterritory"
23109           },
23110           geometry: {
23111             type: "MultiPolygon",
23112             coordinates: [[[[-4.30191, 35.17419], [-4.30112, 35.17058], [-4.29436, 35.17149], [-4.30191, 35.17419]]]]
23113           }
23114         }, {
23115           type: "Feature",
23116           properties: {
23117             wikidata: "Q201698",
23118             nameEn: "Crozet Islands",
23119             country: "FR",
23120             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
23121             level: "subterritory"
23122           },
23123           geometry: {
23124             type: "MultiPolygon",
23125             coordinates: [[[[55.03425, -43.65017], [46.31615, -46.28749], [54.5587, -47.93013], [55.03425, -43.65017]]]]
23126           }
23127         }, {
23128           type: "Feature",
23129           properties: {
23130             wikidata: "Q578170",
23131             nameEn: "Contiguous United States",
23132             aliases: ["CONUS"],
23133             country: "US",
23134             groups: ["Q35657", "021", "003", "019", "UN"],
23135             roadSpeedUnit: "mph",
23136             roadHeightUnit: "ft",
23137             callingCodes: ["1"]
23138           },
23139           geometry: {
23140             type: "MultiPolygon",
23141             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]]]]
23142           }
23143         }, {
23144           type: "Feature",
23145           properties: {
23146             wikidata: "Q620634",
23147             nameEn: "Bir Tawil",
23148             groups: ["015", "002"],
23149             level: "territory"
23150           },
23151           geometry: {
23152             type: "MultiPolygon",
23153             coordinates: [[[[33.17563, 22.00405], [33.57251, 21.72406], [33.99686, 21.76784], [34.0765, 22.00501], [33.17563, 22.00405]]]]
23154           }
23155         }, {
23156           type: "Feature",
23157           properties: {
23158             wikidata: "Q639185",
23159             nameEn: "Peros Banhos",
23160             country: "GB",
23161             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23162             level: "subterritory"
23163           },
23164           geometry: {
23165             type: "MultiPolygon",
23166             coordinates: [[[[72.12587, -4.02588], [70.1848, -6.37445], [72.09518, -5.61768], [72.12587, -4.02588]]]]
23167           }
23168         }, {
23169           type: "Feature",
23170           properties: {
23171             wikidata: "Q644636",
23172             nameEn: "Cyprus",
23173             level: "sharedLandform"
23174           },
23175           geometry: null
23176         }, {
23177           type: "Feature",
23178           properties: {
23179             wikidata: "Q851132",
23180             nameEn: "New Zealand Outlying Islands",
23181             country: "NZ",
23182             level: "subcountryGroup"
23183           },
23184           geometry: null
23185         }, {
23186           type: "Feature",
23187           properties: {
23188             wikidata: "Q875134",
23189             nameEn: "European Russia",
23190             country: "RU",
23191             groups: ["151", "150", "UN"],
23192             callingCodes: ["7"]
23193           },
23194           geometry: {
23195             type: "MultiPolygon",
23196             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]]]]
23197           }
23198         }, {
23199           type: "Feature",
23200           properties: {
23201             wikidata: "Q1083368",
23202             nameEn: "Mainland Finland",
23203             country: "FI",
23204             groups: ["EU", "154", "150", "UN"],
23205             callingCodes: ["358"]
23206           },
23207           geometry: {
23208             type: "MultiPolygon",
23209             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]]]]
23210           }
23211         }, {
23212           type: "Feature",
23213           properties: {
23214             wikidata: "Q1184963",
23215             nameEn: "Alhucemas Islands",
23216             country: "ES",
23217             groups: ["EU", "Q191011", "015", "002", "UN"],
23218             level: "subterritory"
23219           },
23220           geometry: {
23221             type: "MultiPolygon",
23222             coordinates: [[[[-3.90602, 35.21494], [-3.88372, 35.20767], [-3.89343, 35.22728], [-3.90602, 35.21494]]]]
23223           }
23224         }, {
23225           type: "Feature",
23226           properties: {
23227             wikidata: "Q1298289",
23228             nameEn: "Egmont Islands",
23229             country: "GB",
23230             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23231             level: "subterritory"
23232           },
23233           geometry: {
23234             type: "MultiPolygon",
23235             coordinates: [[[[70.1848, -6.37445], [70.67958, -8.2663], [72.17991, -6.68509], [70.1848, -6.37445]]]]
23236           }
23237         }, {
23238           type: "Feature",
23239           properties: {
23240             wikidata: "Q1352230",
23241             nameEn: "US Territories",
23242             country: "US",
23243             level: "subcountryGroup"
23244           },
23245           geometry: null
23246         }, {
23247           type: "Feature",
23248           properties: {
23249             wikidata: "Q1451600",
23250             nameEn: "Overseas Countries and Territories of the EU",
23251             aliases: ["OCT"],
23252             level: "subunion"
23253           },
23254           geometry: null
23255         }, {
23256           type: "Feature",
23257           properties: {
23258             wikidata: "Q1544253",
23259             nameEn: "Great Chagos Bank",
23260             country: "GB",
23261             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23262             level: "subterritory"
23263           },
23264           geometry: {
23265             type: "MultiPolygon",
23266             coordinates: [[[[70.1848, -6.37445], [72.17991, -6.68509], [73.20573, -5.20727], [70.1848, -6.37445]]]]
23267           }
23268         }, {
23269           type: "Feature",
23270           properties: {
23271             wikidata: "Q1585511",
23272             nameEn: "Salomon Atoll",
23273             country: "GB",
23274             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23275             level: "subterritory"
23276           },
23277           geometry: {
23278             type: "MultiPolygon",
23279             coordinates: [[[[72.09518, -5.61768], [73.20573, -5.20727], [72.12587, -4.02588], [72.09518, -5.61768]]]]
23280           }
23281         }, {
23282           type: "Feature",
23283           properties: {
23284             wikidata: "Q1681727",
23285             nameEn: "Saint-Paul and Amsterdam",
23286             country: "FR",
23287             groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
23288             level: "subterritory"
23289           },
23290           geometry: {
23291             type: "MultiPolygon",
23292             coordinates: [[[[76.31747, -42.16264], [80.15867, -36.04977], [71.22311, -38.75287], [76.31747, -42.16264]]]]
23293           }
23294         }, {
23295           type: "Feature",
23296           properties: {
23297             wikidata: "Q1901211",
23298             nameEn: "East Malaysia",
23299             country: "MY",
23300             groups: ["Q36117", "035", "142", "UN"],
23301             driveSide: "left",
23302             callingCodes: ["60"]
23303           },
23304           geometry: {
23305             type: "MultiPolygon",
23306             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]]]]
23307           }
23308         }, {
23309           type: "Feature",
23310           properties: {
23311             wikidata: "Q1973345",
23312             nameEn: "Peninsular Malaysia",
23313             country: "MY",
23314             groups: ["035", "142", "UN"],
23315             driveSide: "left",
23316             callingCodes: ["60"]
23317           },
23318           geometry: {
23319             type: "MultiPolygon",
23320             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]]]]
23321           }
23322         }, {
23323           type: "Feature",
23324           properties: {
23325             wikidata: "Q2093907",
23326             nameEn: "Three Kings Islands",
23327             country: "NZ",
23328             groups: ["Q851132", "053", "009", "UN"],
23329             driveSide: "left"
23330           },
23331           geometry: {
23332             type: "MultiPolygon",
23333             coordinates: [[[[174.17679, -32.62487], [170.93268, -32.97889], [171.97383, -34.64644], [174.17679, -32.62487]]]]
23334           }
23335         }, {
23336           type: "Feature",
23337           properties: {
23338             wikidata: "Q2298216",
23339             nameEn: "Solander Islands",
23340             country: "NZ",
23341             groups: ["Q851132", "053", "009", "UN"],
23342             driveSide: "left"
23343           },
23344           geometry: {
23345             type: "MultiPolygon",
23346             coordinates: [[[[167.39068, -46.49187], [166.5534, -46.39484], [166.84561, -46.84889], [167.39068, -46.49187]]]]
23347           }
23348         }, {
23349           type: "Feature",
23350           properties: {
23351             wikidata: "Q2872203",
23352             nameEn: "Mainland Australia",
23353             country: "AU",
23354             groups: ["053", "009", "UN"],
23355             level: "subcountryGroup",
23356             driveSide: "left",
23357             callingCodes: ["61"]
23358           },
23359           geometry: {
23360             type: "MultiPolygon",
23361             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]]]]
23362           }
23363         }, {
23364           type: "Feature",
23365           properties: {
23366             wikidata: "Q2914565",
23367             nameEn: "Autonomous Regions of Portugal",
23368             country: "PT",
23369             level: "subcountryGroup"
23370           },
23371           geometry: null
23372         }, {
23373           type: "Feature",
23374           properties: {
23375             wikidata: "Q2915956",
23376             nameEn: "Mainland Portugal",
23377             country: "PT",
23378             groups: ["Q12837", "EU", "039", "150", "UN"],
23379             level: "subcountryGroup",
23380             callingCodes: ["351"]
23381           },
23382           geometry: {
23383             type: "MultiPolygon",
23384             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]]]]
23385           }
23386         }, {
23387           type: "Feature",
23388           properties: {
23389             wikidata: "Q3311985",
23390             nameEn: "Guernsey",
23391             country: "GB",
23392             groups: ["GG", "830", "Q185086", "154", "150", "UN"],
23393             level: "subterritory",
23394             driveSide: "left",
23395             roadSpeedUnit: "mph",
23396             roadHeightUnit: "ft",
23397             callingCodes: ["44 01481"]
23398           },
23399           geometry: {
23400             type: "MultiPolygon",
23401             coordinates: [[[[-2.49556, 49.79012], [-3.28154, 49.57329], [-2.65349, 49.15373], [-2.36485, 49.48223], [-2.49556, 49.79012]]]]
23402           }
23403         }, {
23404           type: "Feature",
23405           properties: {
23406             wikidata: "Q3320166",
23407             nameEn: "Outermost Regions of the EU",
23408             aliases: ["OMR"],
23409             level: "subunion"
23410           },
23411           geometry: null
23412         }, {
23413           type: "Feature",
23414           properties: {
23415             wikidata: "Q3336843",
23416             nameEn: "Countries of the United Kingdom",
23417             country: "GB",
23418             level: "subcountryGroup"
23419           },
23420           geometry: null
23421         }, {
23422           type: "Feature",
23423           properties: {
23424             wikidata: "Q6736667",
23425             nameEn: "Mainland India",
23426             country: "IN",
23427             groups: ["034", "142", "UN"],
23428             driveSide: "left",
23429             callingCodes: ["91"]
23430           },
23431           geometry: {
23432             type: "MultiPolygon",
23433             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]]]]
23434           }
23435         }, {
23436           type: "Feature",
23437           properties: {
23438             wikidata: "Q9143535",
23439             nameEn: "Akrotiri",
23440             country: "GB",
23441             groups: ["Q644636", "Q37362", "BOTS", "145", "142", "UN"],
23442             level: "subterritory",
23443             driveSide: "left",
23444             callingCodes: ["357"]
23445           },
23446           geometry: {
23447             type: "MultiPolygon",
23448             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]]]]
23449           }
23450         }, {
23451           type: "Feature",
23452           properties: {
23453             wikidata: "Q9206745",
23454             nameEn: "Dhekelia",
23455             country: "GB",
23456             groups: ["Q644636", "Q37362", "BOTS", "145", "142", "UN"],
23457             level: "subterritory",
23458             driveSide: "left",
23459             callingCodes: ["357"]
23460           },
23461           geometry: {
23462             type: "MultiPolygon",
23463             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]]]]
23464           }
23465         }, {
23466           type: "Feature",
23467           properties: {
23468             wikidata: "Q16390686",
23469             nameEn: "Peninsular Spain",
23470             country: "ES",
23471             groups: ["Q12837", "EU", "039", "150", "UN"],
23472             callingCodes: ["34"]
23473           },
23474           geometry: {
23475             type: "MultiPolygon",
23476             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]]]]
23477           }
23478         }, {
23479           type: "Feature",
23480           properties: {
23481             wikidata: "Q98059339",
23482             nameEn: "Mainland Norway",
23483             country: "NO",
23484             groups: ["154", "150", "UN"],
23485             callingCodes: ["47"]
23486           },
23487           geometry: {
23488             type: "MultiPolygon",
23489             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]]]]
23490           }
23491         }, {
23492           type: "Feature",
23493           properties: {
23494             wikidata: "Q98543636",
23495             nameEn: "Mainland Ecuador",
23496             country: "EC",
23497             groups: ["005", "419", "019", "UN"],
23498             callingCodes: ["593"]
23499           },
23500           geometry: {
23501             type: "MultiPolygon",
23502             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]]]]
23503           }
23504         }, {
23505           type: "Feature",
23506           properties: {
23507             m49: "001",
23508             wikidata: "Q2",
23509             nameEn: "World",
23510             aliases: ["Earth", "Planet"],
23511             level: "world"
23512           },
23513           geometry: null
23514         }, {
23515           type: "Feature",
23516           properties: {
23517             m49: "002",
23518             wikidata: "Q15",
23519             nameEn: "Africa",
23520             level: "region"
23521           },
23522           geometry: null
23523         }, {
23524           type: "Feature",
23525           properties: {
23526             m49: "003",
23527             wikidata: "Q49",
23528             nameEn: "North America",
23529             level: "subregion"
23530           },
23531           geometry: null
23532         }, {
23533           type: "Feature",
23534           properties: {
23535             m49: "005",
23536             wikidata: "Q18",
23537             nameEn: "South America",
23538             level: "intermediateRegion"
23539           },
23540           geometry: null
23541         }, {
23542           type: "Feature",
23543           properties: {
23544             m49: "009",
23545             wikidata: "Q538",
23546             nameEn: "Oceania",
23547             level: "region"
23548           },
23549           geometry: null
23550         }, {
23551           type: "Feature",
23552           properties: {
23553             m49: "011",
23554             wikidata: "Q4412",
23555             nameEn: "Western Africa",
23556             level: "intermediateRegion"
23557           },
23558           geometry: null
23559         }, {
23560           type: "Feature",
23561           properties: {
23562             m49: "013",
23563             wikidata: "Q27611",
23564             nameEn: "Central America",
23565             level: "intermediateRegion"
23566           },
23567           geometry: null
23568         }, {
23569           type: "Feature",
23570           properties: {
23571             m49: "014",
23572             wikidata: "Q27407",
23573             nameEn: "Eastern Africa",
23574             level: "intermediateRegion"
23575           },
23576           geometry: null
23577         }, {
23578           type: "Feature",
23579           properties: {
23580             m49: "015",
23581             wikidata: "Q27381",
23582             nameEn: "Northern Africa",
23583             level: "subregion"
23584           },
23585           geometry: null
23586         }, {
23587           type: "Feature",
23588           properties: {
23589             m49: "017",
23590             wikidata: "Q27433",
23591             nameEn: "Middle Africa",
23592             level: "intermediateRegion"
23593           },
23594           geometry: null
23595         }, {
23596           type: "Feature",
23597           properties: {
23598             m49: "018",
23599             wikidata: "Q27394",
23600             nameEn: "Southern Africa",
23601             level: "intermediateRegion"
23602           },
23603           geometry: null
23604         }, {
23605           type: "Feature",
23606           properties: {
23607             m49: "019",
23608             wikidata: "Q828",
23609             nameEn: "Americas",
23610             level: "region"
23611           },
23612           geometry: null
23613         }, {
23614           type: "Feature",
23615           properties: {
23616             m49: "021",
23617             wikidata: "Q2017699",
23618             nameEn: "Northern America",
23619             level: "subregion"
23620           },
23621           geometry: null
23622         }, {
23623           type: "Feature",
23624           properties: {
23625             m49: "029",
23626             wikidata: "Q664609",
23627             nameEn: "Caribbean",
23628             level: "intermediateRegion"
23629           },
23630           geometry: null
23631         }, {
23632           type: "Feature",
23633           properties: {
23634             m49: "030",
23635             wikidata: "Q27231",
23636             nameEn: "Eastern Asia",
23637             level: "subregion"
23638           },
23639           geometry: null
23640         }, {
23641           type: "Feature",
23642           properties: {
23643             m49: "034",
23644             wikidata: "Q771405",
23645             nameEn: "Southern Asia",
23646             level: "subregion"
23647           },
23648           geometry: null
23649         }, {
23650           type: "Feature",
23651           properties: {
23652             m49: "035",
23653             wikidata: "Q11708",
23654             nameEn: "South-eastern Asia",
23655             level: "subregion"
23656           },
23657           geometry: null
23658         }, {
23659           type: "Feature",
23660           properties: {
23661             m49: "039",
23662             wikidata: "Q27449",
23663             nameEn: "Southern Europe",
23664             level: "subregion"
23665           },
23666           geometry: null
23667         }, {
23668           type: "Feature",
23669           properties: {
23670             m49: "053",
23671             wikidata: "Q45256",
23672             nameEn: "Australia and New Zealand",
23673             aliases: ["Australasia"],
23674             level: "subregion"
23675           },
23676           geometry: null
23677         }, {
23678           type: "Feature",
23679           properties: {
23680             m49: "054",
23681             wikidata: "Q37394",
23682             nameEn: "Melanesia",
23683             level: "subregion"
23684           },
23685           geometry: null
23686         }, {
23687           type: "Feature",
23688           properties: {
23689             m49: "057",
23690             wikidata: "Q3359409",
23691             nameEn: "Micronesia",
23692             level: "subregion"
23693           },
23694           geometry: null
23695         }, {
23696           type: "Feature",
23697           properties: {
23698             m49: "061",
23699             wikidata: "Q35942",
23700             nameEn: "Polynesia",
23701             level: "subregion"
23702           },
23703           geometry: null
23704         }, {
23705           type: "Feature",
23706           properties: {
23707             m49: "142",
23708             wikidata: "Q48",
23709             nameEn: "Asia",
23710             level: "region"
23711           },
23712           geometry: null
23713         }, {
23714           type: "Feature",
23715           properties: {
23716             m49: "143",
23717             wikidata: "Q27275",
23718             nameEn: "Central Asia",
23719             level: "subregion"
23720           },
23721           geometry: null
23722         }, {
23723           type: "Feature",
23724           properties: {
23725             m49: "145",
23726             wikidata: "Q27293",
23727             nameEn: "Western Asia",
23728             level: "subregion"
23729           },
23730           geometry: null
23731         }, {
23732           type: "Feature",
23733           properties: {
23734             m49: "150",
23735             wikidata: "Q46",
23736             nameEn: "Europe",
23737             level: "region"
23738           },
23739           geometry: null
23740         }, {
23741           type: "Feature",
23742           properties: {
23743             m49: "151",
23744             wikidata: "Q27468",
23745             nameEn: "Eastern Europe",
23746             level: "subregion"
23747           },
23748           geometry: null
23749         }, {
23750           type: "Feature",
23751           properties: {
23752             m49: "154",
23753             wikidata: "Q27479",
23754             nameEn: "Northern Europe",
23755             level: "subregion"
23756           },
23757           geometry: null
23758         }, {
23759           type: "Feature",
23760           properties: {
23761             m49: "155",
23762             wikidata: "Q27496",
23763             nameEn: "Western Europe",
23764             level: "subregion"
23765           },
23766           geometry: null
23767         }, {
23768           type: "Feature",
23769           properties: {
23770             m49: "202",
23771             wikidata: "Q132959",
23772             nameEn: "Sub-Saharan Africa",
23773             level: "subregion"
23774           },
23775           geometry: null
23776         }, {
23777           type: "Feature",
23778           properties: {
23779             m49: "419",
23780             wikidata: "Q72829598",
23781             nameEn: "Latin America and the Caribbean",
23782             level: "subregion"
23783           },
23784           geometry: null
23785         }, {
23786           type: "Feature",
23787           properties: {
23788             m49: "680",
23789             wikidata: "Q3405693",
23790             nameEn: "Sark",
23791             country: "GB",
23792             groups: ["GG", "830", "Q185086", "154", "150", "UN"],
23793             level: "subterritory",
23794             driveSide: "left",
23795             roadSpeedUnit: "mph",
23796             roadHeightUnit: "ft",
23797             callingCodes: ["44 01481"]
23798           },
23799           geometry: {
23800             type: "MultiPolygon",
23801             coordinates: [[[[-2.36485, 49.48223], [-2.65349, 49.15373], [-2.09454, 49.46288], [-2.36485, 49.48223]]]]
23802           }
23803         }, {
23804           type: "Feature",
23805           properties: {
23806             m49: "830",
23807             wikidata: "Q42314",
23808             nameEn: "Channel Islands",
23809             level: "intermediateRegion"
23810           },
23811           geometry: null
23812         }, {
23813           type: "Feature",
23814           properties: {
23815             iso1A2: "AC",
23816             iso1A3: "ASC",
23817             wikidata: "Q46197",
23818             nameEn: "Ascension Island",
23819             aliases: ["SH-AC"],
23820             country: "GB",
23821             groups: ["SH", "BOTS", "011", "202", "002", "UN"],
23822             isoStatus: "excRes",
23823             driveSide: "left",
23824             roadSpeedUnit: "mph",
23825             roadHeightUnit: "ft",
23826             callingCodes: ["247"]
23827           },
23828           geometry: {
23829             type: "MultiPolygon",
23830             coordinates: [[[[-14.82771, -8.70814], [-13.33271, -8.07391], [-14.91926, -6.63386], [-14.82771, -8.70814]]]]
23831           }
23832         }, {
23833           type: "Feature",
23834           properties: {
23835             iso1A2: "AD",
23836             iso1A3: "AND",
23837             iso1N3: "020",
23838             wikidata: "Q228",
23839             nameEn: "Andorra",
23840             groups: ["Q12837", "039", "150", "UN"],
23841             callingCodes: ["376"]
23842           },
23843           geometry: {
23844             type: "MultiPolygon",
23845             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]]]]
23846           }
23847         }, {
23848           type: "Feature",
23849           properties: {
23850             iso1A2: "AE",
23851             iso1A3: "ARE",
23852             iso1N3: "784",
23853             wikidata: "Q878",
23854             nameEn: "United Arab Emirates",
23855             groups: ["145", "142", "UN"],
23856             callingCodes: ["971"]
23857           },
23858           geometry: {
23859             type: "MultiPolygon",
23860             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]]]]
23861           }
23862         }, {
23863           type: "Feature",
23864           properties: {
23865             iso1A2: "AF",
23866             iso1A3: "AFG",
23867             iso1N3: "004",
23868             wikidata: "Q889",
23869             nameEn: "Afghanistan",
23870             groups: ["034", "142", "UN"],
23871             callingCodes: ["93"]
23872           },
23873           geometry: {
23874             type: "MultiPolygon",
23875             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]]]]
23876           }
23877         }, {
23878           type: "Feature",
23879           properties: {
23880             iso1A2: "AG",
23881             iso1A3: "ATG",
23882             iso1N3: "028",
23883             wikidata: "Q781",
23884             nameEn: "Antigua and Barbuda",
23885             groups: ["029", "003", "419", "019", "UN"],
23886             driveSide: "left",
23887             roadSpeedUnit: "mph",
23888             callingCodes: ["1 268"]
23889           },
23890           geometry: {
23891             type: "MultiPolygon",
23892             coordinates: [[[[-61.66959, 18.6782], [-62.58307, 16.68909], [-62.1023, 16.97277], [-61.23098, 16.62484], [-61.66959, 18.6782]]]]
23893           }
23894         }, {
23895           type: "Feature",
23896           properties: {
23897             iso1A2: "AI",
23898             iso1A3: "AIA",
23899             iso1N3: "660",
23900             wikidata: "Q25228",
23901             nameEn: "Anguilla",
23902             country: "GB",
23903             groups: ["BOTS", "029", "003", "419", "019", "UN"],
23904             driveSide: "left",
23905             roadSpeedUnit: "mph",
23906             callingCodes: ["1 264"]
23907           },
23908           geometry: {
23909             type: "MultiPolygon",
23910             coordinates: [[[[-63.79029, 19.11219], [-63.35989, 18.06012], [-62.62718, 18.26185], [-63.79029, 19.11219]]]]
23911           }
23912         }, {
23913           type: "Feature",
23914           properties: {
23915             iso1A2: "AL",
23916             iso1A3: "ALB",
23917             iso1N3: "008",
23918             wikidata: "Q222",
23919             nameEn: "Albania",
23920             groups: ["039", "150", "UN"],
23921             callingCodes: ["355"]
23922           },
23923           geometry: {
23924             type: "MultiPolygon",
23925             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]]]]
23926           }
23927         }, {
23928           type: "Feature",
23929           properties: {
23930             iso1A2: "AM",
23931             iso1A3: "ARM",
23932             iso1N3: "051",
23933             wikidata: "Q399",
23934             nameEn: "Armenia",
23935             groups: ["145", "142", "UN"],
23936             callingCodes: ["374"]
23937           },
23938           geometry: {
23939             type: "MultiPolygon",
23940             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]]]]
23941           }
23942         }, {
23943           type: "Feature",
23944           properties: {
23945             iso1A2: "AO",
23946             iso1A3: "AGO",
23947             iso1N3: "024",
23948             wikidata: "Q916",
23949             nameEn: "Angola",
23950             groups: ["017", "202", "002", "UN"],
23951             callingCodes: ["244"]
23952           },
23953           geometry: {
23954             type: "MultiPolygon",
23955             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]]]]
23956           }
23957         }, {
23958           type: "Feature",
23959           properties: {
23960             iso1A2: "AQ",
23961             iso1A3: "ATA",
23962             iso1N3: "010",
23963             wikidata: "Q51",
23964             nameEn: "Antarctica",
23965             level: "region",
23966             callingCodes: ["672"]
23967           },
23968           geometry: {
23969             type: "MultiPolygon",
23970             coordinates: [[[[180, -60], [-180, -60], [-180, -90], [180, -90], [180, -60]]]]
23971           }
23972         }, {
23973           type: "Feature",
23974           properties: {
23975             iso1A2: "AR",
23976             iso1A3: "ARG",
23977             iso1N3: "032",
23978             wikidata: "Q414",
23979             nameEn: "Argentina",
23980             aliases: ["RA"],
23981             groups: ["005", "419", "019", "UN"],
23982             callingCodes: ["54"]
23983           },
23984           geometry: {
23985             type: "MultiPolygon",
23986             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]]]]
23987           }
23988         }, {
23989           type: "Feature",
23990           properties: {
23991             iso1A2: "AS",
23992             iso1A3: "ASM",
23993             iso1N3: "016",
23994             wikidata: "Q16641",
23995             nameEn: "American Samoa",
23996             aliases: ["US-AS"],
23997             country: "US",
23998             groups: ["Q1352230", "061", "009", "UN"],
23999             roadSpeedUnit: "mph",
24000             roadHeightUnit: "ft",
24001             callingCodes: ["1 684"]
24002           },
24003           geometry: {
24004             type: "MultiPolygon",
24005             coordinates: [[[[-171.39864, -10.21587], [-170.99605, -15.1275], [-166.32598, -15.26169], [-171.39864, -10.21587]]]]
24006           }
24007         }, {
24008           type: "Feature",
24009           properties: {
24010             iso1A2: "AT",
24011             iso1A3: "AUT",
24012             iso1N3: "040",
24013             wikidata: "Q40",
24014             nameEn: "Austria",
24015             groups: ["EU", "155", "150", "UN"],
24016             callingCodes: ["43"]
24017           },
24018           geometry: {
24019             type: "MultiPolygon",
24020             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]]]]
24021           }
24022         }, {
24023           type: "Feature",
24024           properties: {
24025             iso1A2: "AU",
24026             iso1A3: "AUS",
24027             iso1N3: "036",
24028             wikidata: "Q408",
24029             nameEn: "Australia"
24030           },
24031           geometry: null
24032         }, {
24033           type: "Feature",
24034           properties: {
24035             iso1A2: "AW",
24036             iso1A3: "ABW",
24037             iso1N3: "533",
24038             wikidata: "Q21203",
24039             nameEn: "Aruba",
24040             aliases: ["NL-AW"],
24041             country: "NL",
24042             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
24043             callingCodes: ["297"]
24044           },
24045           geometry: {
24046             type: "MultiPolygon",
24047             coordinates: [[[[-70.00823, 12.98375], [-70.35625, 12.58277], [-69.60231, 12.17], [-70.00823, 12.98375]]]]
24048           }
24049         }, {
24050           type: "Feature",
24051           properties: {
24052             iso1A2: "AX",
24053             iso1A3: "ALA",
24054             iso1N3: "248",
24055             wikidata: "Q5689",
24056             nameEn: "\xC5land Islands",
24057             country: "FI",
24058             groups: ["EU", "154", "150", "UN"],
24059             callingCodes: ["358 18", "358 457"]
24060           },
24061           geometry: {
24062             type: "MultiPolygon",
24063             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]]]]
24064           }
24065         }, {
24066           type: "Feature",
24067           properties: {
24068             iso1A2: "AZ",
24069             iso1A3: "AZE",
24070             iso1N3: "031",
24071             wikidata: "Q227",
24072             nameEn: "Azerbaijan",
24073             groups: ["145", "142", "UN"],
24074             callingCodes: ["994"]
24075           },
24076           geometry: {
24077             type: "MultiPolygon",
24078             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]]]]
24079           }
24080         }, {
24081           type: "Feature",
24082           properties: {
24083             iso1A2: "BA",
24084             iso1A3: "BIH",
24085             iso1N3: "070",
24086             wikidata: "Q225",
24087             nameEn: "Bosnia and Herzegovina",
24088             groups: ["039", "150", "UN"],
24089             callingCodes: ["387"]
24090           },
24091           geometry: {
24092             type: "MultiPolygon",
24093             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]]]]
24094           }
24095         }, {
24096           type: "Feature",
24097           properties: {
24098             iso1A2: "BB",
24099             iso1A3: "BRB",
24100             iso1N3: "052",
24101             wikidata: "Q244",
24102             nameEn: "Barbados",
24103             groups: ["029", "003", "419", "019", "UN"],
24104             driveSide: "left",
24105             callingCodes: ["1 246"]
24106           },
24107           geometry: {
24108             type: "MultiPolygon",
24109             coordinates: [[[[-58.56442, 13.24471], [-59.80731, 13.87556], [-59.82929, 12.70644], [-58.56442, 13.24471]]]]
24110           }
24111         }, {
24112           type: "Feature",
24113           properties: {
24114             iso1A2: "BD",
24115             iso1A3: "BGD",
24116             iso1N3: "050",
24117             wikidata: "Q902",
24118             nameEn: "Bangladesh",
24119             groups: ["034", "142", "UN"],
24120             driveSide: "left",
24121             callingCodes: ["880"]
24122           },
24123           geometry: {
24124             type: "MultiPolygon",
24125             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]]]]
24126           }
24127         }, {
24128           type: "Feature",
24129           properties: {
24130             iso1A2: "BE",
24131             iso1A3: "BEL",
24132             iso1N3: "056",
24133             wikidata: "Q31",
24134             nameEn: "Belgium",
24135             groups: ["EU", "155", "150", "UN"],
24136             callingCodes: ["32"]
24137           },
24138           geometry: {
24139             type: "MultiPolygon",
24140             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]]]]
24141           }
24142         }, {
24143           type: "Feature",
24144           properties: {
24145             iso1A2: "BF",
24146             iso1A3: "BFA",
24147             iso1N3: "854",
24148             wikidata: "Q965",
24149             nameEn: "Burkina Faso",
24150             groups: ["011", "202", "002", "UN"],
24151             callingCodes: ["226"]
24152           },
24153           geometry: {
24154             type: "MultiPolygon",
24155             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]]]]
24156           }
24157         }, {
24158           type: "Feature",
24159           properties: {
24160             iso1A2: "BG",
24161             iso1A3: "BGR",
24162             iso1N3: "100",
24163             wikidata: "Q219",
24164             nameEn: "Bulgaria",
24165             groups: ["EU", "151", "150", "UN"],
24166             callingCodes: ["359"]
24167           },
24168           geometry: {
24169             type: "MultiPolygon",
24170             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]]]]
24171           }
24172         }, {
24173           type: "Feature",
24174           properties: {
24175             iso1A2: "BH",
24176             iso1A3: "BHR",
24177             iso1N3: "048",
24178             wikidata: "Q398",
24179             nameEn: "Bahrain",
24180             groups: ["145", "142", "UN"],
24181             callingCodes: ["973"]
24182           },
24183           geometry: {
24184             type: "MultiPolygon",
24185             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]]]]
24186           }
24187         }, {
24188           type: "Feature",
24189           properties: {
24190             iso1A2: "BI",
24191             iso1A3: "BDI",
24192             iso1N3: "108",
24193             wikidata: "Q967",
24194             nameEn: "Burundi",
24195             groups: ["014", "202", "002", "UN"],
24196             callingCodes: ["257"]
24197           },
24198           geometry: {
24199             type: "MultiPolygon",
24200             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]]]]
24201           }
24202         }, {
24203           type: "Feature",
24204           properties: {
24205             iso1A2: "BJ",
24206             iso1A3: "BEN",
24207             iso1N3: "204",
24208             wikidata: "Q962",
24209             nameEn: "Benin",
24210             aliases: ["DY"],
24211             groups: ["011", "202", "002", "UN"],
24212             callingCodes: ["229"]
24213           },
24214           geometry: {
24215             type: "MultiPolygon",
24216             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]]]]
24217           }
24218         }, {
24219           type: "Feature",
24220           properties: {
24221             iso1A2: "BL",
24222             iso1A3: "BLM",
24223             iso1N3: "652",
24224             wikidata: "Q25362",
24225             nameEn: "Saint-Barth\xE9lemy",
24226             country: "FR",
24227             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
24228             callingCodes: ["590"]
24229           },
24230           geometry: {
24231             type: "MultiPolygon",
24232             coordinates: [[[[-62.62718, 18.26185], [-63.1055, 17.86651], [-62.34423, 17.49165], [-62.62718, 18.26185]]]]
24233           }
24234         }, {
24235           type: "Feature",
24236           properties: {
24237             iso1A2: "BM",
24238             iso1A3: "BMU",
24239             iso1N3: "060",
24240             wikidata: "Q23635",
24241             nameEn: "Bermuda",
24242             country: "GB",
24243             groups: ["BOTS", "021", "003", "019", "UN"],
24244             driveSide: "left",
24245             callingCodes: ["1 441"]
24246           },
24247           geometry: {
24248             type: "MultiPolygon",
24249             coordinates: [[[[-63.20987, 32.6953], [-65.31453, 32.68437], [-65.63955, 31.43417], [-63.20987, 32.6953]]]]
24250           }
24251         }, {
24252           type: "Feature",
24253           properties: {
24254             iso1A2: "BN",
24255             iso1A3: "BRN",
24256             iso1N3: "096",
24257             wikidata: "Q921",
24258             nameEn: "Brunei",
24259             groups: ["Q36117", "035", "142", "UN"],
24260             driveSide: "left",
24261             callingCodes: ["673"]
24262           },
24263           geometry: {
24264             type: "MultiPolygon",
24265             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]]]]
24266           }
24267         }, {
24268           type: "Feature",
24269           properties: {
24270             iso1A2: "BO",
24271             iso1A3: "BOL",
24272             iso1N3: "068",
24273             wikidata: "Q750",
24274             nameEn: "Bolivia",
24275             groups: ["005", "419", "019", "UN"],
24276             callingCodes: ["591"]
24277           },
24278           geometry: {
24279             type: "MultiPolygon",
24280             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]]]]
24281           }
24282         }, {
24283           type: "Feature",
24284           properties: {
24285             iso1A2: "BQ",
24286             iso1A3: "BES",
24287             iso1N3: "535",
24288             wikidata: "Q27561",
24289             nameEn: "Caribbean Netherlands",
24290             country: "NL"
24291           },
24292           geometry: null
24293         }, {
24294           type: "Feature",
24295           properties: {
24296             iso1A2: "BR",
24297             iso1A3: "BRA",
24298             iso1N3: "076",
24299             wikidata: "Q155",
24300             nameEn: "Brazil",
24301             groups: ["005", "419", "019", "UN"],
24302             callingCodes: ["55"]
24303           },
24304           geometry: {
24305             type: "MultiPolygon",
24306             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]]]]
24307           }
24308         }, {
24309           type: "Feature",
24310           properties: {
24311             iso1A2: "BS",
24312             iso1A3: "BHS",
24313             iso1N3: "044",
24314             wikidata: "Q778",
24315             nameEn: "The Bahamas",
24316             groups: ["029", "003", "419", "019", "UN"],
24317             driveSide: "left",
24318             roadSpeedUnit: "mph",
24319             callingCodes: ["1 242"]
24320           },
24321           geometry: {
24322             type: "MultiPolygon",
24323             coordinates: [[[[-72.98446, 20.4801], [-71.70065, 25.7637], [-78.91214, 27.76553], [-80.65727, 23.71953], [-72.98446, 20.4801]]]]
24324           }
24325         }, {
24326           type: "Feature",
24327           properties: {
24328             iso1A2: "BT",
24329             iso1A3: "BTN",
24330             iso1N3: "064",
24331             wikidata: "Q917",
24332             nameEn: "Bhutan",
24333             groups: ["034", "142", "UN"],
24334             driveSide: "left",
24335             callingCodes: ["975"]
24336           },
24337           geometry: {
24338             type: "MultiPolygon",
24339             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]]]]
24340           }
24341         }, {
24342           type: "Feature",
24343           properties: {
24344             iso1A2: "BV",
24345             iso1A3: "BVT",
24346             iso1N3: "074",
24347             wikidata: "Q23408",
24348             nameEn: "Bouvet Island",
24349             country: "NO",
24350             groups: ["005", "419", "019", "UN"]
24351           },
24352           geometry: {
24353             type: "MultiPolygon",
24354             coordinates: [[[[4.54042, -54.0949], [2.28941, -54.13089], [3.35353, -55.17558], [4.54042, -54.0949]]]]
24355           }
24356         }, {
24357           type: "Feature",
24358           properties: {
24359             iso1A2: "BW",
24360             iso1A3: "BWA",
24361             iso1N3: "072",
24362             wikidata: "Q963",
24363             nameEn: "Botswana",
24364             groups: ["018", "202", "002", "UN"],
24365             driveSide: "left",
24366             callingCodes: ["267"]
24367           },
24368           geometry: {
24369             type: "MultiPolygon",
24370             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]]]]
24371           }
24372         }, {
24373           type: "Feature",
24374           properties: {
24375             iso1A2: "BY",
24376             iso1A3: "BLR",
24377             iso1N3: "112",
24378             wikidata: "Q184",
24379             nameEn: "Belarus",
24380             groups: ["151", "150", "UN"],
24381             callingCodes: ["375"]
24382           },
24383           geometry: {
24384             type: "MultiPolygon",
24385             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]]]]
24386           }
24387         }, {
24388           type: "Feature",
24389           properties: {
24390             iso1A2: "BZ",
24391             iso1A3: "BLZ",
24392             iso1N3: "084",
24393             wikidata: "Q242",
24394             nameEn: "Belize",
24395             groups: ["013", "003", "419", "019", "UN"],
24396             roadSpeedUnit: "mph",
24397             callingCodes: ["501"]
24398           },
24399           geometry: {
24400             type: "MultiPolygon",
24401             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]]]]
24402           }
24403         }, {
24404           type: "Feature",
24405           properties: {
24406             iso1A2: "CA",
24407             iso1A3: "CAN",
24408             iso1N3: "124",
24409             wikidata: "Q16",
24410             nameEn: "Canada",
24411             groups: ["021", "003", "019", "UN"],
24412             callingCodes: ["1"]
24413           },
24414           geometry: {
24415             type: "MultiPolygon",
24416             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]]]]
24417           }
24418         }, {
24419           type: "Feature",
24420           properties: {
24421             iso1A2: "CC",
24422             iso1A3: "CCK",
24423             iso1N3: "166",
24424             wikidata: "Q36004",
24425             nameEn: "Cocos (Keeling) Islands",
24426             country: "AU",
24427             groups: ["053", "009", "UN"],
24428             driveSide: "left",
24429             callingCodes: ["61"]
24430           },
24431           geometry: {
24432             type: "MultiPolygon",
24433             coordinates: [[[[96.61846, -10.82438], [96.02343, -12.68334], [97.93979, -12.33309], [96.61846, -10.82438]]]]
24434           }
24435         }, {
24436           type: "Feature",
24437           properties: {
24438             iso1A2: "CD",
24439             iso1A3: "COD",
24440             iso1N3: "180",
24441             wikidata: "Q974",
24442             nameEn: "Democratic Republic of the Congo",
24443             aliases: ["ZR"],
24444             groups: ["017", "202", "002", "UN"],
24445             callingCodes: ["243"]
24446           },
24447           geometry: {
24448             type: "MultiPolygon",
24449             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]]]]
24450           }
24451         }, {
24452           type: "Feature",
24453           properties: {
24454             iso1A2: "CF",
24455             iso1A3: "CAF",
24456             iso1N3: "140",
24457             wikidata: "Q929",
24458             nameEn: "Central African Republic",
24459             groups: ["017", "202", "002", "UN"],
24460             callingCodes: ["236"]
24461           },
24462           geometry: {
24463             type: "MultiPolygon",
24464             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]]]]
24465           }
24466         }, {
24467           type: "Feature",
24468           properties: {
24469             iso1A2: "CG",
24470             iso1A3: "COG",
24471             iso1N3: "178",
24472             wikidata: "Q971",
24473             nameEn: "Republic of the Congo",
24474             groups: ["017", "202", "002", "UN"],
24475             callingCodes: ["242"]
24476           },
24477           geometry: {
24478             type: "MultiPolygon",
24479             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]]]]
24480           }
24481         }, {
24482           type: "Feature",
24483           properties: {
24484             iso1A2: "CH",
24485             iso1A3: "CHE",
24486             iso1N3: "756",
24487             wikidata: "Q39",
24488             nameEn: "Switzerland",
24489             groups: ["155", "150", "UN"],
24490             callingCodes: ["41"]
24491           },
24492           geometry: {
24493             type: "MultiPolygon",
24494             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]]]]
24495           }
24496         }, {
24497           type: "Feature",
24498           properties: {
24499             iso1A2: "CI",
24500             iso1A3: "CIV",
24501             iso1N3: "384",
24502             wikidata: "Q1008",
24503             nameEn: "C\xF4te d'Ivoire",
24504             groups: ["011", "202", "002", "UN"],
24505             callingCodes: ["225"]
24506           },
24507           geometry: {
24508             type: "MultiPolygon",
24509             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]]]]
24510           }
24511         }, {
24512           type: "Feature",
24513           properties: {
24514             iso1A2: "CK",
24515             iso1A3: "COK",
24516             iso1N3: "184",
24517             wikidata: "Q26988",
24518             nameEn: "Cook Islands",
24519             country: "NZ",
24520             groups: ["061", "009", "UN"],
24521             driveSide: "left",
24522             callingCodes: ["682"]
24523           },
24524           geometry: {
24525             type: "MultiPolygon",
24526             coordinates: [[[[-168.15106, -10.26955], [-156.45576, -31.75456], [-156.48634, -15.52824], [-156.50903, -7.4975], [-168.15106, -10.26955]]]]
24527           }
24528         }, {
24529           type: "Feature",
24530           properties: {
24531             iso1A2: "CL",
24532             iso1A3: "CHL",
24533             iso1N3: "152",
24534             wikidata: "Q298",
24535             nameEn: "Chile",
24536             groups: ["005", "419", "019", "UN"],
24537             callingCodes: ["56"]
24538           },
24539           geometry: {
24540             type: "MultiPolygon",
24541             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]]]]
24542           }
24543         }, {
24544           type: "Feature",
24545           properties: {
24546             iso1A2: "CM",
24547             iso1A3: "CMR",
24548             iso1N3: "120",
24549             wikidata: "Q1009",
24550             nameEn: "Cameroon",
24551             groups: ["017", "202", "002", "UN"],
24552             callingCodes: ["237"]
24553           },
24554           geometry: {
24555             type: "MultiPolygon",
24556             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]]]]
24557           }
24558         }, {
24559           type: "Feature",
24560           properties: {
24561             iso1A2: "CN",
24562             iso1A3: "CHN",
24563             iso1N3: "156",
24564             wikidata: "Q148",
24565             nameEn: "People's Republic of China"
24566           },
24567           geometry: null
24568         }, {
24569           type: "Feature",
24570           properties: {
24571             iso1A2: "CO",
24572             iso1A3: "COL",
24573             iso1N3: "170",
24574             wikidata: "Q739",
24575             nameEn: "Colombia",
24576             groups: ["005", "419", "019", "UN"],
24577             callingCodes: ["57"]
24578           },
24579           geometry: {
24580             type: "MultiPolygon",
24581             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]]]]
24582           }
24583         }, {
24584           type: "Feature",
24585           properties: {
24586             iso1A2: "CP",
24587             iso1A3: "CPT",
24588             wikidata: "Q161258",
24589             nameEn: "Clipperton Island",
24590             country: "FR",
24591             groups: ["013", "003", "019", "UN"],
24592             isoStatus: "excRes"
24593           },
24594           geometry: {
24595             type: "MultiPolygon",
24596             coordinates: [[[[-110.36279, 9.79626], [-108.755, 9.84085], [-109.04145, 11.13245], [-110.36279, 9.79626]]]]
24597           }
24598         }, {
24599           type: "Feature",
24600           properties: {
24601             iso1A2: "CR",
24602             iso1A3: "CRI",
24603             iso1N3: "188",
24604             wikidata: "Q800",
24605             nameEn: "Costa Rica",
24606             groups: ["013", "003", "419", "019", "UN"],
24607             callingCodes: ["506"]
24608           },
24609           geometry: {
24610             type: "MultiPolygon",
24611             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]]]]
24612           }
24613         }, {
24614           type: "Feature",
24615           properties: {
24616             iso1A2: "CU",
24617             iso1A3: "CUB",
24618             iso1N3: "192",
24619             wikidata: "Q241",
24620             nameEn: "Cuba",
24621             groups: ["029", "003", "419", "019", "UN"],
24622             callingCodes: ["53"]
24623           },
24624           geometry: {
24625             type: "MultiPolygon",
24626             coordinates: [[[[-73.62304, 20.6935], [-82.02215, 24.23074], [-85.77883, 21.92705], [-74.81171, 18.82201], [-73.62304, 20.6935]]]]
24627           }
24628         }, {
24629           type: "Feature",
24630           properties: {
24631             iso1A2: "CV",
24632             iso1A3: "CPV",
24633             iso1N3: "132",
24634             wikidata: "Q1011",
24635             nameEn: "Cape Verde",
24636             groups: ["Q105472", "011", "202", "002", "UN"],
24637             callingCodes: ["238"]
24638           },
24639           geometry: {
24640             type: "MultiPolygon",
24641             coordinates: [[[[-28.81604, 14.57305], [-20.39702, 14.12816], [-23.37101, 19.134], [-28.81604, 14.57305]]]]
24642           }
24643         }, {
24644           type: "Feature",
24645           properties: {
24646             iso1A2: "CW",
24647             iso1A3: "CUW",
24648             iso1N3: "531",
24649             wikidata: "Q25279",
24650             nameEn: "Cura\xE7ao",
24651             aliases: ["NL-CW"],
24652             country: "NL",
24653             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
24654             callingCodes: ["599"]
24655           },
24656           geometry: {
24657             type: "MultiPolygon",
24658             coordinates: [[[[-68.90012, 12.62309], [-69.59009, 12.46019], [-68.99639, 11.79035], [-68.33524, 11.78151], [-68.90012, 12.62309]]]]
24659           }
24660         }, {
24661           type: "Feature",
24662           properties: {
24663             iso1A2: "CX",
24664             iso1A3: "CXR",
24665             iso1N3: "162",
24666             wikidata: "Q31063",
24667             nameEn: "Christmas Island",
24668             country: "AU",
24669             groups: ["053", "009", "UN"],
24670             driveSide: "left",
24671             callingCodes: ["61"]
24672           },
24673           geometry: {
24674             type: "MultiPolygon",
24675             coordinates: [[[[105.66835, -9.31927], [104.67494, -11.2566], [106.66176, -11.14349], [105.66835, -9.31927]]]]
24676           }
24677         }, {
24678           type: "Feature",
24679           properties: {
24680             iso1A2: "CY",
24681             iso1A3: "CYP",
24682             iso1N3: "196",
24683             wikidata: "Q229",
24684             nameEn: "Republic of Cyprus",
24685             groups: ["Q644636", "EU", "145", "142", "UN"],
24686             driveSide: "left",
24687             callingCodes: ["357"]
24688           },
24689           geometry: {
24690             type: "MultiPolygon",
24691             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]]]]
24692           }
24693         }, {
24694           type: "Feature",
24695           properties: {
24696             iso1A2: "CZ",
24697             iso1A3: "CZE",
24698             iso1N3: "203",
24699             wikidata: "Q213",
24700             nameEn: "Czechia",
24701             groups: ["EU", "151", "150", "UN"],
24702             callingCodes: ["420"]
24703           },
24704           geometry: {
24705             type: "MultiPolygon",
24706             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]]]]
24707           }
24708         }, {
24709           type: "Feature",
24710           properties: {
24711             iso1A2: "DE",
24712             iso1A3: "DEU",
24713             iso1N3: "276",
24714             wikidata: "Q183",
24715             nameEn: "Germany",
24716             groups: ["EU", "155", "150", "UN"],
24717             callingCodes: ["49"]
24718           },
24719           geometry: {
24720             type: "MultiPolygon",
24721             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]]]]
24722           }
24723         }, {
24724           type: "Feature",
24725           properties: {
24726             iso1A2: "DG",
24727             iso1A3: "DGA",
24728             wikidata: "Q184851",
24729             nameEn: "Diego Garcia",
24730             country: "GB",
24731             groups: ["IO", "BOTS", "014", "202", "002", "UN"],
24732             isoStatus: "excRes",
24733             callingCodes: ["246"]
24734           },
24735           geometry: {
24736             type: "MultiPolygon",
24737             coordinates: [[[[73.14823, -7.76302], [73.09982, -6.07324], [71.43792, -7.73904], [73.14823, -7.76302]]]]
24738           }
24739         }, {
24740           type: "Feature",
24741           properties: {
24742             iso1A2: "DJ",
24743             iso1A3: "DJI",
24744             iso1N3: "262",
24745             wikidata: "Q977",
24746             nameEn: "Djibouti",
24747             groups: ["014", "202", "002", "UN"],
24748             callingCodes: ["253"]
24749           },
24750           geometry: {
24751             type: "MultiPolygon",
24752             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]]]]
24753           }
24754         }, {
24755           type: "Feature",
24756           properties: {
24757             iso1A2: "DK",
24758             iso1A3: "DNK",
24759             iso1N3: "208",
24760             wikidata: "Q756617",
24761             nameEn: "Kingdom of Denmark"
24762           },
24763           geometry: null
24764         }, {
24765           type: "Feature",
24766           properties: {
24767             iso1A2: "DM",
24768             iso1A3: "DMA",
24769             iso1N3: "212",
24770             wikidata: "Q784",
24771             nameEn: "Dominica",
24772             groups: ["029", "003", "419", "019", "UN"],
24773             driveSide: "left",
24774             roadSpeedUnit: "mph",
24775             callingCodes: ["1 767"]
24776           },
24777           geometry: {
24778             type: "MultiPolygon",
24779             coordinates: [[[[-61.32485, 14.91445], [-60.86656, 15.82603], [-61.95646, 15.5094], [-61.32485, 14.91445]]]]
24780           }
24781         }, {
24782           type: "Feature",
24783           properties: {
24784             iso1A2: "DO",
24785             iso1A3: "DOM",
24786             iso1N3: "214",
24787             wikidata: "Q786",
24788             nameEn: "Dominican Republic",
24789             groups: ["029", "003", "419", "019", "UN"],
24790             callingCodes: ["1 809", "1 829", "1 849"]
24791           },
24792           geometry: {
24793             type: "MultiPolygon",
24794             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]]]]
24795           }
24796         }, {
24797           type: "Feature",
24798           properties: {
24799             iso1A2: "DZ",
24800             iso1A3: "DZA",
24801             iso1N3: "012",
24802             wikidata: "Q262",
24803             nameEn: "Algeria",
24804             groups: ["015", "002", "UN"],
24805             callingCodes: ["213"]
24806           },
24807           geometry: {
24808             type: "MultiPolygon",
24809             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]]]]
24810           }
24811         }, {
24812           type: "Feature",
24813           properties: {
24814             iso1A2: "EA",
24815             wikidata: "Q28868874",
24816             nameEn: "Ceuta, Melilla",
24817             country: "ES",
24818             level: "territory",
24819             isoStatus: "excRes"
24820           },
24821           geometry: null
24822         }, {
24823           type: "Feature",
24824           properties: {
24825             iso1A2: "EC",
24826             iso1A3: "ECU",
24827             iso1N3: "218",
24828             wikidata: "Q736",
24829             nameEn: "Ecuador"
24830           },
24831           geometry: null
24832         }, {
24833           type: "Feature",
24834           properties: {
24835             iso1A2: "EE",
24836             iso1A3: "EST",
24837             iso1N3: "233",
24838             wikidata: "Q191",
24839             nameEn: "Estonia",
24840             aliases: ["EW"],
24841             groups: ["EU", "154", "150", "UN"],
24842             callingCodes: ["372"]
24843           },
24844           geometry: {
24845             type: "MultiPolygon",
24846             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]]]]
24847           }
24848         }, {
24849           type: "Feature",
24850           properties: {
24851             iso1A2: "EG",
24852             iso1A3: "EGY",
24853             iso1N3: "818",
24854             wikidata: "Q79",
24855             nameEn: "Egypt",
24856             groups: ["015", "002", "UN"],
24857             callingCodes: ["20"]
24858           },
24859           geometry: {
24860             type: "MultiPolygon",
24861             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]]]]
24862           }
24863         }, {
24864           type: "Feature",
24865           properties: {
24866             iso1A2: "EH",
24867             iso1A3: "ESH",
24868             iso1N3: "732",
24869             wikidata: "Q6250",
24870             nameEn: "Western Sahara",
24871             groups: ["015", "002"],
24872             callingCodes: ["212"]
24873           },
24874           geometry: {
24875             type: "MultiPolygon",
24876             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]]]]
24877           }
24878         }, {
24879           type: "Feature",
24880           properties: {
24881             iso1A2: "ER",
24882             iso1A3: "ERI",
24883             iso1N3: "232",
24884             wikidata: "Q986",
24885             nameEn: "Eritrea",
24886             groups: ["014", "202", "002", "UN"],
24887             callingCodes: ["291"]
24888           },
24889           geometry: {
24890             type: "MultiPolygon",
24891             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]]]]
24892           }
24893         }, {
24894           type: "Feature",
24895           properties: {
24896             iso1A2: "ES",
24897             iso1A3: "ESP",
24898             iso1N3: "724",
24899             wikidata: "Q29",
24900             nameEn: "Spain"
24901           },
24902           geometry: null
24903         }, {
24904           type: "Feature",
24905           properties: {
24906             iso1A2: "ET",
24907             iso1A3: "ETH",
24908             iso1N3: "231",
24909             wikidata: "Q115",
24910             nameEn: "Ethiopia",
24911             groups: ["014", "202", "002", "UN"],
24912             callingCodes: ["251"]
24913           },
24914           geometry: {
24915             type: "MultiPolygon",
24916             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]]]]
24917           }
24918         }, {
24919           type: "Feature",
24920           properties: {
24921             iso1A2: "EU",
24922             iso1A3: "EUE",
24923             wikidata: "Q458",
24924             nameEn: "European Union",
24925             level: "union",
24926             isoStatus: "excRes"
24927           },
24928           geometry: null
24929         }, {
24930           type: "Feature",
24931           properties: {
24932             iso1A2: "FI",
24933             iso1A3: "FIN",
24934             iso1N3: "246",
24935             wikidata: "Q33",
24936             nameEn: "Finland",
24937             aliases: ["SF"]
24938           },
24939           geometry: null
24940         }, {
24941           type: "Feature",
24942           properties: {
24943             iso1A2: "FJ",
24944             iso1A3: "FJI",
24945             iso1N3: "242",
24946             wikidata: "Q712",
24947             nameEn: "Fiji",
24948             groups: ["054", "009", "UN"],
24949             driveSide: "left",
24950             callingCodes: ["679"]
24951           },
24952           geometry: {
24953             type: "MultiPolygon",
24954             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]]]]
24955           }
24956         }, {
24957           type: "Feature",
24958           properties: {
24959             iso1A2: "FK",
24960             iso1A3: "FLK",
24961             iso1N3: "238",
24962             wikidata: "Q9648",
24963             nameEn: "Falkland Islands",
24964             country: "GB",
24965             groups: ["BOTS", "005", "419", "019", "UN"],
24966             driveSide: "left",
24967             roadSpeedUnit: "mph",
24968             roadHeightUnit: "ft",
24969             callingCodes: ["500"]
24970           },
24971           geometry: {
24972             type: "MultiPolygon",
24973             coordinates: [[[[-63.67376, -55.11859], [-54.56126, -51.26248], [-61.26735, -50.63919], [-63.67376, -55.11859]]]]
24974           }
24975         }, {
24976           type: "Feature",
24977           properties: {
24978             iso1A2: "FM",
24979             iso1A3: "FSM",
24980             iso1N3: "583",
24981             wikidata: "Q702",
24982             nameEn: "Federated States of Micronesia",
24983             groups: ["057", "009", "UN"],
24984             roadSpeedUnit: "mph",
24985             roadHeightUnit: "ft",
24986             callingCodes: ["691"]
24987           },
24988           geometry: {
24989             type: "MultiPolygon",
24990             coordinates: [[[[138.20583, 13.3783], [136.27107, 6.73747], [156.88247, -1.39237], [165.19726, 6.22546], [138.20583, 13.3783]]]]
24991           }
24992         }, {
24993           type: "Feature",
24994           properties: {
24995             iso1A2: "FO",
24996             iso1A3: "FRO",
24997             iso1N3: "234",
24998             wikidata: "Q4628",
24999             nameEn: "Faroe Islands",
25000             country: "DK",
25001             groups: ["154", "150", "UN"],
25002             callingCodes: ["298"]
25003           },
25004           geometry: {
25005             type: "MultiPolygon",
25006             coordinates: [[[[-8.51774, 62.35338], [-6.51083, 60.95272], [-5.70102, 62.77194], [-8.51774, 62.35338]]]]
25007           }
25008         }, {
25009           type: "Feature",
25010           properties: {
25011             iso1A2: "FR",
25012             iso1A3: "FRA",
25013             iso1N3: "250",
25014             wikidata: "Q142",
25015             nameEn: "France"
25016           },
25017           geometry: null
25018         }, {
25019           type: "Feature",
25020           properties: {
25021             iso1A2: "FX",
25022             iso1A3: "FXX",
25023             iso1N3: "249",
25024             wikidata: "Q212429",
25025             nameEn: "Metropolitan France",
25026             country: "FR",
25027             groups: ["EU", "155", "150", "UN"],
25028             isoStatus: "excRes",
25029             callingCodes: ["33"]
25030           },
25031           geometry: {
25032             type: "MultiPolygon",
25033             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]]]]
25034           }
25035         }, {
25036           type: "Feature",
25037           properties: {
25038             iso1A2: "GA",
25039             iso1A3: "GAB",
25040             iso1N3: "266",
25041             wikidata: "Q1000",
25042             nameEn: "Gabon",
25043             groups: ["017", "202", "002", "UN"],
25044             callingCodes: ["241"]
25045           },
25046           geometry: {
25047             type: "MultiPolygon",
25048             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]]]]
25049           }
25050         }, {
25051           type: "Feature",
25052           properties: {
25053             iso1A2: "GB",
25054             iso1A3: "GBR",
25055             iso1N3: "826",
25056             wikidata: "Q145",
25057             ccTLD: ".uk",
25058             nameEn: "United Kingdom",
25059             aliases: ["UK"]
25060           },
25061           geometry: null
25062         }, {
25063           type: "Feature",
25064           properties: {
25065             iso1A2: "GD",
25066             iso1A3: "GRD",
25067             iso1N3: "308",
25068             wikidata: "Q769",
25069             nameEn: "Grenada",
25070             aliases: ["WG"],
25071             groups: ["029", "003", "419", "019", "UN"],
25072             driveSide: "left",
25073             roadSpeedUnit: "mph",
25074             callingCodes: ["1 473"]
25075           },
25076           geometry: {
25077             type: "MultiPolygon",
25078             coordinates: [[[[-62.64026, 12.69984], [-61.77886, 11.36496], [-59.94058, 12.34011], [-62.64026, 12.69984]]]]
25079           }
25080         }, {
25081           type: "Feature",
25082           properties: {
25083             iso1A2: "GE",
25084             iso1A3: "GEO",
25085             iso1N3: "268",
25086             wikidata: "Q230",
25087             nameEn: "Georgia",
25088             groups: ["145", "142", "UN"],
25089             callingCodes: ["995"]
25090           },
25091           geometry: {
25092             type: "MultiPolygon",
25093             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]]]]
25094           }
25095         }, {
25096           type: "Feature",
25097           properties: {
25098             iso1A2: "GF",
25099             iso1A3: "GUF",
25100             iso1N3: "254",
25101             wikidata: "Q3769",
25102             nameEn: "French Guiana",
25103             country: "FR",
25104             groups: ["Q3320166", "EU", "005", "419", "019", "UN"],
25105             callingCodes: ["594"]
25106           },
25107           geometry: {
25108             type: "MultiPolygon",
25109             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]]]]
25110           }
25111         }, {
25112           type: "Feature",
25113           properties: {
25114             iso1A2: "GG",
25115             iso1A3: "GGY",
25116             iso1N3: "831",
25117             wikidata: "Q25230",
25118             nameEn: "Bailiwick of Guernsey",
25119             country: "GB"
25120           },
25121           geometry: null
25122         }, {
25123           type: "Feature",
25124           properties: {
25125             iso1A2: "GH",
25126             iso1A3: "GHA",
25127             iso1N3: "288",
25128             wikidata: "Q117",
25129             nameEn: "Ghana",
25130             groups: ["011", "202", "002", "UN"],
25131             callingCodes: ["233"]
25132           },
25133           geometry: {
25134             type: "MultiPolygon",
25135             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]]]]
25136           }
25137         }, {
25138           type: "Feature",
25139           properties: {
25140             iso1A2: "GI",
25141             iso1A3: "GIB",
25142             iso1N3: "292",
25143             wikidata: "Q1410",
25144             nameEn: "Gibraltar",
25145             country: "GB",
25146             groups: ["Q12837", "BOTS", "039", "150", "UN"],
25147             callingCodes: ["350"]
25148           },
25149           geometry: {
25150             type: "MultiPolygon",
25151             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]]]]
25152           }
25153         }, {
25154           type: "Feature",
25155           properties: {
25156             iso1A2: "GL",
25157             iso1A3: "GRL",
25158             iso1N3: "304",
25159             wikidata: "Q223",
25160             nameEn: "Greenland",
25161             country: "DK",
25162             groups: ["Q1451600", "021", "003", "019", "UN"],
25163             callingCodes: ["299"]
25164           },
25165           geometry: {
25166             type: "MultiPolygon",
25167             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]]]]
25168           }
25169         }, {
25170           type: "Feature",
25171           properties: {
25172             iso1A2: "GM",
25173             iso1A3: "GMB",
25174             iso1N3: "270",
25175             wikidata: "Q1005",
25176             nameEn: "The Gambia",
25177             groups: ["011", "202", "002", "UN"],
25178             callingCodes: ["220"]
25179           },
25180           geometry: {
25181             type: "MultiPolygon",
25182             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]]]]
25183           }
25184         }, {
25185           type: "Feature",
25186           properties: {
25187             iso1A2: "GN",
25188             iso1A3: "GIN",
25189             iso1N3: "324",
25190             wikidata: "Q1006",
25191             nameEn: "Guinea",
25192             groups: ["011", "202", "002", "UN"],
25193             callingCodes: ["224"]
25194           },
25195           geometry: {
25196             type: "MultiPolygon",
25197             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]]]]
25198           }
25199         }, {
25200           type: "Feature",
25201           properties: {
25202             iso1A2: "GP",
25203             iso1A3: "GLP",
25204             iso1N3: "312",
25205             wikidata: "Q17012",
25206             nameEn: "Guadeloupe",
25207             country: "FR",
25208             groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
25209             callingCodes: ["590"]
25210           },
25211           geometry: {
25212             type: "MultiPolygon",
25213             coordinates: [[[[-60.03183, 16.1129], [-61.60296, 16.73066], [-63.00549, 15.26166], [-60.03183, 16.1129]]]]
25214           }
25215         }, {
25216           type: "Feature",
25217           properties: {
25218             iso1A2: "GQ",
25219             iso1A3: "GNQ",
25220             iso1N3: "226",
25221             wikidata: "Q983",
25222             nameEn: "Equatorial Guinea",
25223             groups: ["017", "202", "002", "UN"],
25224             callingCodes: ["240"]
25225           },
25226           geometry: {
25227             type: "MultiPolygon",
25228             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]]]]
25229           }
25230         }, {
25231           type: "Feature",
25232           properties: {
25233             iso1A2: "GR",
25234             iso1A3: "GRC",
25235             iso1N3: "300",
25236             wikidata: "Q41",
25237             nameEn: "Greece",
25238             aliases: ["EL"],
25239             groups: ["EU", "039", "150", "UN"],
25240             callingCodes: ["30"]
25241           },
25242           geometry: {
25243             type: "MultiPolygon",
25244             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]]]]
25245           }
25246         }, {
25247           type: "Feature",
25248           properties: {
25249             iso1A2: "GS",
25250             iso1A3: "SGS",
25251             iso1N3: "239",
25252             wikidata: "Q35086",
25253             nameEn: "South Georgia and South Sandwich Islands",
25254             country: "GB",
25255             groups: ["BOTS", "005", "419", "019", "UN"],
25256             driveSide: "left",
25257             roadSpeedUnit: "mph",
25258             roadHeightUnit: "ft",
25259             callingCodes: ["500"]
25260           },
25261           geometry: {
25262             type: "MultiPolygon",
25263             coordinates: [[[[-35.26394, -43.68272], [-53.39656, -59.87088], [-22.31757, -59.85974], [-35.26394, -43.68272]]]]
25264           }
25265         }, {
25266           type: "Feature",
25267           properties: {
25268             iso1A2: "GT",
25269             iso1A3: "GTM",
25270             iso1N3: "320",
25271             wikidata: "Q774",
25272             nameEn: "Guatemala",
25273             groups: ["013", "003", "419", "019", "UN"],
25274             callingCodes: ["502"]
25275           },
25276           geometry: {
25277             type: "MultiPolygon",
25278             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]]]]
25279           }
25280         }, {
25281           type: "Feature",
25282           properties: {
25283             iso1A2: "GU",
25284             iso1A3: "GUM",
25285             iso1N3: "316",
25286             wikidata: "Q16635",
25287             nameEn: "Guam",
25288             aliases: ["US-GU"],
25289             country: "US",
25290             groups: ["Q1352230", "Q153732", "057", "009", "UN"],
25291             roadSpeedUnit: "mph",
25292             roadHeightUnit: "ft",
25293             callingCodes: ["1 671"]
25294           },
25295           geometry: {
25296             type: "MultiPolygon",
25297             coordinates: [[[[146.25931, 13.85876], [143.82485, 13.92273], [144.61642, 12.82462], [146.25931, 13.85876]]]]
25298           }
25299         }, {
25300           type: "Feature",
25301           properties: {
25302             iso1A2: "GW",
25303             iso1A3: "GNB",
25304             iso1N3: "624",
25305             wikidata: "Q1007",
25306             nameEn: "Guinea-Bissau",
25307             groups: ["011", "202", "002", "UN"],
25308             callingCodes: ["245"]
25309           },
25310           geometry: {
25311             type: "MultiPolygon",
25312             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]]]]
25313           }
25314         }, {
25315           type: "Feature",
25316           properties: {
25317             iso1A2: "GY",
25318             iso1A3: "GUY",
25319             iso1N3: "328",
25320             wikidata: "Q734",
25321             nameEn: "Guyana",
25322             groups: ["005", "419", "019", "UN"],
25323             driveSide: "left",
25324             callingCodes: ["592"]
25325           },
25326           geometry: {
25327             type: "MultiPolygon",
25328             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]]]]
25329           }
25330         }, {
25331           type: "Feature",
25332           properties: {
25333             iso1A2: "HK",
25334             iso1A3: "HKG",
25335             iso1N3: "344",
25336             wikidata: "Q8646",
25337             nameEn: "Hong Kong",
25338             country: "CN",
25339             groups: ["030", "142", "UN"],
25340             driveSide: "left",
25341             callingCodes: ["852"]
25342           },
25343           geometry: {
25344             type: "MultiPolygon",
25345             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]]]]
25346           }
25347         }, {
25348           type: "Feature",
25349           properties: {
25350             iso1A2: "HM",
25351             iso1A3: "HMD",
25352             iso1N3: "334",
25353             wikidata: "Q131198",
25354             nameEn: "Heard Island and McDonald Islands",
25355             country: "AU",
25356             groups: ["053", "009", "UN"],
25357             driveSide: "left"
25358           },
25359           geometry: {
25360             type: "MultiPolygon",
25361             coordinates: [[[[71.08716, -53.87687], [75.44182, -53.99822], [72.87012, -51.48322], [71.08716, -53.87687]]]]
25362           }
25363         }, {
25364           type: "Feature",
25365           properties: {
25366             iso1A2: "HN",
25367             iso1A3: "HND",
25368             iso1N3: "340",
25369             wikidata: "Q783",
25370             nameEn: "Honduras",
25371             groups: ["013", "003", "419", "019", "UN"],
25372             callingCodes: ["504"]
25373           },
25374           geometry: {
25375             type: "MultiPolygon",
25376             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]]]]
25377           }
25378         }, {
25379           type: "Feature",
25380           properties: {
25381             iso1A2: "HR",
25382             iso1A3: "HRV",
25383             iso1N3: "191",
25384             wikidata: "Q224",
25385             nameEn: "Croatia",
25386             groups: ["EU", "039", "150", "UN"],
25387             callingCodes: ["385"]
25388           },
25389           geometry: {
25390             type: "MultiPolygon",
25391             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]]]]
25392           }
25393         }, {
25394           type: "Feature",
25395           properties: {
25396             iso1A2: "HT",
25397             iso1A3: "HTI",
25398             iso1N3: "332",
25399             wikidata: "Q790",
25400             nameEn: "Haiti",
25401             aliases: ["RH"],
25402             groups: ["029", "003", "419", "019", "UN"],
25403             callingCodes: ["509"]
25404           },
25405           geometry: {
25406             type: "MultiPolygon",
25407             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]]]]
25408           }
25409         }, {
25410           type: "Feature",
25411           properties: {
25412             iso1A2: "HU",
25413             iso1A3: "HUN",
25414             iso1N3: "348",
25415             wikidata: "Q28",
25416             nameEn: "Hungary",
25417             groups: ["EU", "151", "150", "UN"],
25418             callingCodes: ["36"]
25419           },
25420           geometry: {
25421             type: "MultiPolygon",
25422             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]]]]
25423           }
25424         }, {
25425           type: "Feature",
25426           properties: {
25427             iso1A2: "IC",
25428             wikidata: "Q5813",
25429             nameEn: "Canary Islands",
25430             country: "ES",
25431             groups: ["Q3320166", "Q105472", "EU", "039", "150", "UN"],
25432             isoStatus: "excRes",
25433             callingCodes: ["34"]
25434           },
25435           geometry: {
25436             type: "MultiPolygon",
25437             coordinates: [[[[-12.00985, 30.24121], [-25.3475, 27.87574], [-14.43883, 27.02969], [-12.00985, 30.24121]]]]
25438           }
25439         }, {
25440           type: "Feature",
25441           properties: {
25442             iso1A2: "ID",
25443             iso1A3: "IDN",
25444             iso1N3: "360",
25445             wikidata: "Q252",
25446             nameEn: "Indonesia",
25447             aliases: ["RI"]
25448           },
25449           geometry: null
25450         }, {
25451           type: "Feature",
25452           properties: {
25453             iso1A2: "IE",
25454             iso1A3: "IRL",
25455             iso1N3: "372",
25456             wikidata: "Q27",
25457             nameEn: "Republic of Ireland",
25458             groups: ["EU", "Q22890", "154", "150", "UN"],
25459             driveSide: "left",
25460             callingCodes: ["353"]
25461           },
25462           geometry: {
25463             type: "MultiPolygon",
25464             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]]]]
25465           }
25466         }, {
25467           type: "Feature",
25468           properties: {
25469             iso1A2: "IL",
25470             iso1A3: "ISR",
25471             iso1N3: "376",
25472             wikidata: "Q801",
25473             nameEn: "Israel",
25474             groups: ["145", "142", "UN"],
25475             callingCodes: ["972"]
25476           },
25477           geometry: {
25478             type: "MultiPolygon",
25479             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]]]]
25480           }
25481         }, {
25482           type: "Feature",
25483           properties: {
25484             iso1A2: "IM",
25485             iso1A3: "IMN",
25486             iso1N3: "833",
25487             wikidata: "Q9676",
25488             nameEn: "Isle of Man",
25489             country: "GB",
25490             groups: ["Q185086", "154", "150", "UN"],
25491             driveSide: "left",
25492             roadSpeedUnit: "mph",
25493             roadHeightUnit: "ft",
25494             callingCodes: ["44 01624", "44 07624", "44 07524", "44 07924"]
25495           },
25496           geometry: {
25497             type: "MultiPolygon",
25498             coordinates: [[[[-3.98763, 54.07351], [-4.1819, 54.57861], [-5.6384, 53.81157], [-3.98763, 54.07351]]]]
25499           }
25500         }, {
25501           type: "Feature",
25502           properties: {
25503             iso1A2: "IN",
25504             iso1A3: "IND",
25505             iso1N3: "356",
25506             wikidata: "Q668",
25507             nameEn: "India"
25508           },
25509           geometry: null
25510         }, {
25511           type: "Feature",
25512           properties: {
25513             iso1A2: "IO",
25514             iso1A3: "IOT",
25515             iso1N3: "086",
25516             wikidata: "Q43448",
25517             nameEn: "British Indian Ocean Territory",
25518             country: "GB"
25519           },
25520           geometry: null
25521         }, {
25522           type: "Feature",
25523           properties: {
25524             iso1A2: "IQ",
25525             iso1A3: "IRQ",
25526             iso1N3: "368",
25527             wikidata: "Q796",
25528             nameEn: "Iraq",
25529             groups: ["145", "142", "UN"],
25530             callingCodes: ["964"]
25531           },
25532           geometry: {
25533             type: "MultiPolygon",
25534             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]]]]
25535           }
25536         }, {
25537           type: "Feature",
25538           properties: {
25539             iso1A2: "IR",
25540             iso1A3: "IRN",
25541             iso1N3: "364",
25542             wikidata: "Q794",
25543             nameEn: "Iran",
25544             groups: ["034", "142", "UN"],
25545             callingCodes: ["98"]
25546           },
25547           geometry: {
25548             type: "MultiPolygon",
25549             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]]]]
25550           }
25551         }, {
25552           type: "Feature",
25553           properties: {
25554             iso1A2: "IS",
25555             iso1A3: "ISL",
25556             iso1N3: "352",
25557             wikidata: "Q189",
25558             nameEn: "Iceland",
25559             groups: ["154", "150", "UN"],
25560             callingCodes: ["354"]
25561           },
25562           geometry: {
25563             type: "MultiPolygon",
25564             coordinates: [[[[-33.15676, 62.62995], [-8.25539, 63.0423], [-15.70914, 69.67442], [-33.15676, 62.62995]]]]
25565           }
25566         }, {
25567           type: "Feature",
25568           properties: {
25569             iso1A2: "IT",
25570             iso1A3: "ITA",
25571             iso1N3: "380",
25572             wikidata: "Q38",
25573             nameEn: "Italy",
25574             groups: ["EU", "039", "150", "UN"],
25575             callingCodes: ["39"]
25576           },
25577           geometry: {
25578             type: "MultiPolygon",
25579             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]]]]
25580           }
25581         }, {
25582           type: "Feature",
25583           properties: {
25584             iso1A2: "JE",
25585             iso1A3: "JEY",
25586             iso1N3: "832",
25587             wikidata: "Q785",
25588             nameEn: "Bailiwick of Jersey",
25589             country: "GB",
25590             groups: ["830", "Q185086", "154", "150", "UN"],
25591             driveSide: "left",
25592             roadSpeedUnit: "mph",
25593             roadHeightUnit: "ft",
25594             callingCodes: ["44 01534"]
25595           },
25596           geometry: {
25597             type: "MultiPolygon",
25598             coordinates: [[[[-2.00491, 48.86706], [-1.83944, 49.23037], [-2.09454, 49.46288], [-2.65349, 49.15373], [-2.00491, 48.86706]]]]
25599           }
25600         }, {
25601           type: "Feature",
25602           properties: {
25603             iso1A2: "JM",
25604             iso1A3: "JAM",
25605             iso1N3: "388",
25606             wikidata: "Q766",
25607             nameEn: "Jamaica",
25608             aliases: ["JA"],
25609             groups: ["029", "003", "419", "019", "UN"],
25610             driveSide: "left",
25611             callingCodes: ["1 876", "1 658"]
25612           },
25613           geometry: {
25614             type: "MultiPolygon",
25615             coordinates: [[[[-74.09729, 17.36817], [-78.9741, 19.59515], [-78.34606, 16.57862], [-74.09729, 17.36817]]]]
25616           }
25617         }, {
25618           type: "Feature",
25619           properties: {
25620             iso1A2: "JO",
25621             iso1A3: "JOR",
25622             iso1N3: "400",
25623             wikidata: "Q810",
25624             nameEn: "Jordan",
25625             groups: ["145", "142", "UN"],
25626             callingCodes: ["962"]
25627           },
25628           geometry: {
25629             type: "MultiPolygon",
25630             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]]]]
25631           }
25632         }, {
25633           type: "Feature",
25634           properties: {
25635             iso1A2: "JP",
25636             iso1A3: "JPN",
25637             iso1N3: "392",
25638             wikidata: "Q17",
25639             nameEn: "Japan",
25640             groups: ["030", "142", "UN"],
25641             driveSide: "left",
25642             callingCodes: ["81"]
25643           },
25644           geometry: {
25645             type: "MultiPolygon",
25646             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]]]]
25647           }
25648         }, {
25649           type: "Feature",
25650           properties: {
25651             iso1A2: "KE",
25652             iso1A3: "KEN",
25653             iso1N3: "404",
25654             wikidata: "Q114",
25655             nameEn: "Kenya",
25656             groups: ["014", "202", "002", "UN"],
25657             driveSide: "left",
25658             callingCodes: ["254"]
25659           },
25660           geometry: {
25661             type: "MultiPolygon",
25662             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]]]]
25663           }
25664         }, {
25665           type: "Feature",
25666           properties: {
25667             iso1A2: "KG",
25668             iso1A3: "KGZ",
25669             iso1N3: "417",
25670             wikidata: "Q813",
25671             nameEn: "Kyrgyzstan",
25672             groups: ["143", "142", "UN"],
25673             callingCodes: ["996"]
25674           },
25675           geometry: {
25676             type: "MultiPolygon",
25677             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]]]]
25678           }
25679         }, {
25680           type: "Feature",
25681           properties: {
25682             iso1A2: "KH",
25683             iso1A3: "KHM",
25684             iso1N3: "116",
25685             wikidata: "Q424",
25686             nameEn: "Cambodia",
25687             groups: ["035", "142", "UN"],
25688             callingCodes: ["855"]
25689           },
25690           geometry: {
25691             type: "MultiPolygon",
25692             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]]]]
25693           }
25694         }, {
25695           type: "Feature",
25696           properties: {
25697             iso1A2: "KI",
25698             iso1A3: "KIR",
25699             iso1N3: "296",
25700             wikidata: "Q710",
25701             nameEn: "Kiribati",
25702             groups: ["057", "009", "UN"],
25703             driveSide: "left",
25704             callingCodes: ["686"]
25705           },
25706           geometry: {
25707             type: "MultiPolygon",
25708             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]]]]
25709           }
25710         }, {
25711           type: "Feature",
25712           properties: {
25713             iso1A2: "KM",
25714             iso1A3: "COM",
25715             iso1N3: "174",
25716             wikidata: "Q970",
25717             nameEn: "Comoros",
25718             groups: ["014", "202", "002", "UN"],
25719             callingCodes: ["269"]
25720           },
25721           geometry: {
25722             type: "MultiPolygon",
25723             coordinates: [[[[42.63904, -10.02522], [43.28731, -13.97126], [45.4971, -11.75965], [42.63904, -10.02522]]]]
25724           }
25725         }, {
25726           type: "Feature",
25727           properties: {
25728             iso1A2: "KN",
25729             iso1A3: "KNA",
25730             iso1N3: "659",
25731             wikidata: "Q763",
25732             nameEn: "St. Kitts and Nevis",
25733             groups: ["029", "003", "419", "019", "UN"],
25734             driveSide: "left",
25735             roadSpeedUnit: "mph",
25736             callingCodes: ["1 869"]
25737           },
25738           geometry: {
25739             type: "MultiPolygon",
25740             coordinates: [[[[-62.29333, 17.43155], [-62.76692, 17.64353], [-63.09677, 17.21372], [-62.63813, 16.65446], [-62.29333, 17.43155]]]]
25741           }
25742         }, {
25743           type: "Feature",
25744           properties: {
25745             iso1A2: "KP",
25746             iso1A3: "PRK",
25747             iso1N3: "408",
25748             wikidata: "Q423",
25749             nameEn: "North Korea",
25750             groups: ["030", "142", "UN"],
25751             callingCodes: ["850"]
25752           },
25753           geometry: {
25754             type: "MultiPolygon",
25755             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]]]]
25756           }
25757         }, {
25758           type: "Feature",
25759           properties: {
25760             iso1A2: "KR",
25761             iso1A3: "KOR",
25762             iso1N3: "410",
25763             wikidata: "Q884",
25764             nameEn: "South Korea",
25765             groups: ["030", "142", "UN"],
25766             callingCodes: ["82"]
25767           },
25768           geometry: {
25769             type: "MultiPolygon",
25770             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]]]]
25771           }
25772         }, {
25773           type: "Feature",
25774           properties: {
25775             iso1A2: "KW",
25776             iso1A3: "KWT",
25777             iso1N3: "414",
25778             wikidata: "Q817",
25779             nameEn: "Kuwait",
25780             groups: ["145", "142", "UN"],
25781             callingCodes: ["965"]
25782           },
25783           geometry: {
25784             type: "MultiPolygon",
25785             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]]]]
25786           }
25787         }, {
25788           type: "Feature",
25789           properties: {
25790             iso1A2: "KY",
25791             iso1A3: "CYM",
25792             iso1N3: "136",
25793             wikidata: "Q5785",
25794             nameEn: "Cayman Islands",
25795             country: "GB",
25796             groups: ["BOTS", "029", "003", "419", "019", "UN"],
25797             driveSide: "left",
25798             roadSpeedUnit: "mph",
25799             roadHeightUnit: "ft",
25800             callingCodes: ["1 345"]
25801           },
25802           geometry: {
25803             type: "MultiPolygon",
25804             coordinates: [[[[-82.11509, 19.60401], [-80.36068, 18.11751], [-79.32727, 20.06742], [-82.11509, 19.60401]]]]
25805           }
25806         }, {
25807           type: "Feature",
25808           properties: {
25809             iso1A2: "KZ",
25810             iso1A3: "KAZ",
25811             iso1N3: "398",
25812             wikidata: "Q232",
25813             nameEn: "Kazakhstan",
25814             groups: ["143", "142", "UN"],
25815             callingCodes: ["7"]
25816           },
25817           geometry: {
25818             type: "MultiPolygon",
25819             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]]]]
25820           }
25821         }, {
25822           type: "Feature",
25823           properties: {
25824             iso1A2: "LA",
25825             iso1A3: "LAO",
25826             iso1N3: "418",
25827             wikidata: "Q819",
25828             nameEn: "Laos",
25829             groups: ["035", "142", "UN"],
25830             callingCodes: ["856"]
25831           },
25832           geometry: {
25833             type: "MultiPolygon",
25834             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]]]]
25835           }
25836         }, {
25837           type: "Feature",
25838           properties: {
25839             iso1A2: "LB",
25840             iso1A3: "LBN",
25841             iso1N3: "422",
25842             wikidata: "Q822",
25843             nameEn: "Lebanon",
25844             aliases: ["RL"],
25845             groups: ["145", "142", "UN"],
25846             callingCodes: ["961"]
25847           },
25848           geometry: {
25849             type: "MultiPolygon",
25850             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]]]]
25851           }
25852         }, {
25853           type: "Feature",
25854           properties: {
25855             iso1A2: "LC",
25856             iso1A3: "LCA",
25857             iso1N3: "662",
25858             wikidata: "Q760",
25859             nameEn: "St. Lucia",
25860             aliases: ["WL"],
25861             groups: ["029", "003", "419", "019", "UN"],
25862             driveSide: "left",
25863             roadSpeedUnit: "mph",
25864             callingCodes: ["1 758"]
25865           },
25866           geometry: {
25867             type: "MultiPolygon",
25868             coordinates: [[[[-59.95997, 14.20285], [-61.69315, 14.26451], [-59.94058, 12.34011], [-59.95997, 14.20285]]]]
25869           }
25870         }, {
25871           type: "Feature",
25872           properties: {
25873             iso1A2: "LI",
25874             iso1A3: "LIE",
25875             iso1N3: "438",
25876             wikidata: "Q347",
25877             nameEn: "Liechtenstein",
25878             aliases: ["FL"],
25879             groups: ["155", "150", "UN"],
25880             callingCodes: ["423"]
25881           },
25882           geometry: {
25883             type: "MultiPolygon",
25884             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]]]]
25885           }
25886         }, {
25887           type: "Feature",
25888           properties: {
25889             iso1A2: "LK",
25890             iso1A3: "LKA",
25891             iso1N3: "144",
25892             wikidata: "Q854",
25893             nameEn: "Sri Lanka",
25894             groups: ["034", "142", "UN"],
25895             driveSide: "left",
25896             callingCodes: ["94"]
25897           },
25898           geometry: {
25899             type: "MultiPolygon",
25900             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]]]]
25901           }
25902         }, {
25903           type: "Feature",
25904           properties: {
25905             iso1A2: "LR",
25906             iso1A3: "LBR",
25907             iso1N3: "430",
25908             wikidata: "Q1014",
25909             nameEn: "Liberia",
25910             groups: ["011", "202", "002", "UN"],
25911             callingCodes: ["231"]
25912           },
25913           geometry: {
25914             type: "MultiPolygon",
25915             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]]]]
25916           }
25917         }, {
25918           type: "Feature",
25919           properties: {
25920             iso1A2: "LS",
25921             iso1A3: "LSO",
25922             iso1N3: "426",
25923             wikidata: "Q1013",
25924             nameEn: "Lesotho",
25925             groups: ["018", "202", "002", "UN"],
25926             driveSide: "left",
25927             callingCodes: ["266"]
25928           },
25929           geometry: {
25930             type: "MultiPolygon",
25931             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]]]]
25932           }
25933         }, {
25934           type: "Feature",
25935           properties: {
25936             iso1A2: "LT",
25937             iso1A3: "LTU",
25938             iso1N3: "440",
25939             wikidata: "Q37",
25940             nameEn: "Lithuania",
25941             groups: ["EU", "154", "150", "UN"],
25942             callingCodes: ["370"]
25943           },
25944           geometry: {
25945             type: "MultiPolygon",
25946             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]]]]
25947           }
25948         }, {
25949           type: "Feature",
25950           properties: {
25951             iso1A2: "LU",
25952             iso1A3: "LUX",
25953             iso1N3: "442",
25954             wikidata: "Q32",
25955             nameEn: "Luxembourg",
25956             groups: ["EU", "155", "150", "UN"],
25957             callingCodes: ["352"]
25958           },
25959           geometry: {
25960             type: "MultiPolygon",
25961             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]]]]
25962           }
25963         }, {
25964           type: "Feature",
25965           properties: {
25966             iso1A2: "LV",
25967             iso1A3: "LVA",
25968             iso1N3: "428",
25969             wikidata: "Q211",
25970             nameEn: "Latvia",
25971             groups: ["EU", "154", "150", "UN"],
25972             callingCodes: ["371"]
25973           },
25974           geometry: {
25975             type: "MultiPolygon",
25976             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]]]]
25977           }
25978         }, {
25979           type: "Feature",
25980           properties: {
25981             iso1A2: "LY",
25982             iso1A3: "LBY",
25983             iso1N3: "434",
25984             wikidata: "Q1016",
25985             nameEn: "Libya",
25986             groups: ["015", "002", "UN"],
25987             callingCodes: ["218"]
25988           },
25989           geometry: {
25990             type: "MultiPolygon",
25991             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]]]]
25992           }
25993         }, {
25994           type: "Feature",
25995           properties: {
25996             iso1A2: "MA",
25997             iso1A3: "MAR",
25998             iso1N3: "504",
25999             wikidata: "Q1028",
26000             nameEn: "Morocco",
26001             groups: ["015", "002", "UN"],
26002             callingCodes: ["212"]
26003           },
26004           geometry: {
26005             type: "MultiPolygon",
26006             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]]]]
26007           }
26008         }, {
26009           type: "Feature",
26010           properties: {
26011             iso1A2: "MC",
26012             iso1A3: "MCO",
26013             iso1N3: "492",
26014             wikidata: "Q235",
26015             nameEn: "Monaco",
26016             groups: ["155", "150", "UN"],
26017             callingCodes: ["377"]
26018           },
26019           geometry: {
26020             type: "MultiPolygon",
26021             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]]]]
26022           }
26023         }, {
26024           type: "Feature",
26025           properties: {
26026             iso1A2: "MD",
26027             iso1A3: "MDA",
26028             iso1N3: "498",
26029             wikidata: "Q217",
26030             nameEn: "Moldova",
26031             groups: ["151", "150", "UN"],
26032             callingCodes: ["373"]
26033           },
26034           geometry: {
26035             type: "MultiPolygon",
26036             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]]]]
26037           }
26038         }, {
26039           type: "Feature",
26040           properties: {
26041             iso1A2: "ME",
26042             iso1A3: "MNE",
26043             iso1N3: "499",
26044             wikidata: "Q236",
26045             nameEn: "Montenegro",
26046             groups: ["039", "150", "UN"],
26047             callingCodes: ["382"]
26048           },
26049           geometry: {
26050             type: "MultiPolygon",
26051             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]]]]
26052           }
26053         }, {
26054           type: "Feature",
26055           properties: {
26056             iso1A2: "MF",
26057             iso1A3: "MAF",
26058             iso1N3: "663",
26059             wikidata: "Q126125",
26060             nameEn: "Saint-Martin",
26061             country: "FR",
26062             groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
26063             callingCodes: ["590"]
26064           },
26065           geometry: {
26066             type: "MultiPolygon",
26067             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]]]]
26068           }
26069         }, {
26070           type: "Feature",
26071           properties: {
26072             iso1A2: "MG",
26073             iso1A3: "MDG",
26074             iso1N3: "450",
26075             wikidata: "Q1019",
26076             nameEn: "Madagascar",
26077             aliases: ["RM"],
26078             groups: ["014", "202", "002", "UN"],
26079             callingCodes: ["261"]
26080           },
26081           geometry: {
26082             type: "MultiPolygon",
26083             coordinates: [[[[51.93891, -10.85085], [45.84651, -12.77177], [42.14681, -19.63341], [45.80092, -33.00974], [51.93891, -10.85085]]]]
26084           }
26085         }, {
26086           type: "Feature",
26087           properties: {
26088             iso1A2: "MH",
26089             iso1A3: "MHL",
26090             iso1N3: "584",
26091             wikidata: "Q709",
26092             nameEn: "Marshall Islands",
26093             groups: ["057", "009", "UN"],
26094             roadSpeedUnit: "mph",
26095             callingCodes: ["692"]
26096           },
26097           geometry: {
26098             type: "MultiPolygon",
26099             coordinates: [[[[169, 3.9], [173.53711, 5.70687], [169.29099, 15.77133], [159.04653, 10.59067], [169, 3.9]]]]
26100           }
26101         }, {
26102           type: "Feature",
26103           properties: {
26104             iso1A2: "MK",
26105             iso1A3: "MKD",
26106             iso1N3: "807",
26107             wikidata: "Q221",
26108             nameEn: "North Macedonia",
26109             groups: ["039", "150", "UN"],
26110             callingCodes: ["389"]
26111           },
26112           geometry: {
26113             type: "MultiPolygon",
26114             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]]]]
26115           }
26116         }, {
26117           type: "Feature",
26118           properties: {
26119             iso1A2: "ML",
26120             iso1A3: "MLI",
26121             iso1N3: "466",
26122             wikidata: "Q912",
26123             nameEn: "Mali",
26124             groups: ["011", "202", "002", "UN"],
26125             callingCodes: ["223"]
26126           },
26127           geometry: {
26128             type: "MultiPolygon",
26129             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]]]]
26130           }
26131         }, {
26132           type: "Feature",
26133           properties: {
26134             iso1A2: "MM",
26135             iso1A3: "MMR",
26136             iso1N3: "104",
26137             wikidata: "Q836",
26138             nameEn: "Myanmar",
26139             aliases: ["Burma", "BU"],
26140             groups: ["035", "142", "UN"],
26141             callingCodes: ["95"]
26142           },
26143           geometry: {
26144             type: "MultiPolygon",
26145             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]]]]
26146           }
26147         }, {
26148           type: "Feature",
26149           properties: {
26150             iso1A2: "MN",
26151             iso1A3: "MNG",
26152             iso1N3: "496",
26153             wikidata: "Q711",
26154             nameEn: "Mongolia",
26155             groups: ["030", "142", "UN"],
26156             callingCodes: ["976"]
26157           },
26158           geometry: {
26159             type: "MultiPolygon",
26160             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]]]]
26161           }
26162         }, {
26163           type: "Feature",
26164           properties: {
26165             iso1A2: "MO",
26166             iso1A3: "MAC",
26167             iso1N3: "446",
26168             wikidata: "Q14773",
26169             nameEn: "Macau",
26170             aliases: ["Macao"],
26171             country: "CN",
26172             groups: ["030", "142", "UN"],
26173             driveSide: "left",
26174             callingCodes: ["853"]
26175           },
26176           geometry: {
26177             type: "MultiPolygon",
26178             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]]]]
26179           }
26180         }, {
26181           type: "Feature",
26182           properties: {
26183             iso1A2: "MP",
26184             iso1A3: "MNP",
26185             iso1N3: "580",
26186             wikidata: "Q16644",
26187             nameEn: "Northern Mariana Islands",
26188             aliases: ["US-MP"],
26189             country: "US",
26190             groups: ["Q1352230", "Q153732", "057", "009", "UN"],
26191             roadSpeedUnit: "mph",
26192             callingCodes: ["1 670"]
26193           },
26194           geometry: {
26195             type: "MultiPolygon",
26196             coordinates: [[[[135.52896, 14.32623], [152.19114, 13.63487], [145.05972, 21.28731], [135.52896, 14.32623]]]]
26197           }
26198         }, {
26199           type: "Feature",
26200           properties: {
26201             iso1A2: "MQ",
26202             iso1A3: "MTQ",
26203             iso1N3: "474",
26204             wikidata: "Q17054",
26205             nameEn: "Martinique",
26206             country: "FR",
26207             groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
26208             callingCodes: ["596"]
26209           },
26210           geometry: {
26211             type: "MultiPolygon",
26212             coordinates: [[[[-59.95997, 14.20285], [-61.07821, 15.25109], [-61.69315, 14.26451], [-59.95997, 14.20285]]]]
26213           }
26214         }, {
26215           type: "Feature",
26216           properties: {
26217             iso1A2: "MR",
26218             iso1A3: "MRT",
26219             iso1N3: "478",
26220             wikidata: "Q1025",
26221             nameEn: "Mauritania",
26222             groups: ["011", "202", "002", "UN"],
26223             callingCodes: ["222"]
26224           },
26225           geometry: {
26226             type: "MultiPolygon",
26227             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]]]]
26228           }
26229         }, {
26230           type: "Feature",
26231           properties: {
26232             iso1A2: "MS",
26233             iso1A3: "MSR",
26234             iso1N3: "500",
26235             wikidata: "Q13353",
26236             nameEn: "Montserrat",
26237             country: "GB",
26238             groups: ["BOTS", "029", "003", "419", "019", "UN"],
26239             driveSide: "left",
26240             roadSpeedUnit: "mph",
26241             roadHeightUnit: "ft",
26242             callingCodes: ["1 664"]
26243           },
26244           geometry: {
26245             type: "MultiPolygon",
26246             coordinates: [[[[-61.91508, 16.51165], [-62.1023, 16.97277], [-62.58307, 16.68909], [-61.91508, 16.51165]]]]
26247           }
26248         }, {
26249           type: "Feature",
26250           properties: {
26251             iso1A2: "MT",
26252             iso1A3: "MLT",
26253             iso1N3: "470",
26254             wikidata: "Q233",
26255             nameEn: "Malta",
26256             groups: ["EU", "039", "150", "UN"],
26257             driveSide: "left",
26258             callingCodes: ["356"]
26259           },
26260           geometry: {
26261             type: "MultiPolygon",
26262             coordinates: [[[[15.70991, 35.79901], [14.07544, 36.41525], [13.27636, 35.20764], [15.70991, 35.79901]]]]
26263           }
26264         }, {
26265           type: "Feature",
26266           properties: {
26267             iso1A2: "MU",
26268             iso1A3: "MUS",
26269             iso1N3: "480",
26270             wikidata: "Q1027",
26271             nameEn: "Mauritius",
26272             groups: ["014", "202", "002", "UN"],
26273             driveSide: "left",
26274             callingCodes: ["230"]
26275           },
26276           geometry: {
26277             type: "MultiPolygon",
26278             coordinates: [[[[56.09755, -9.55401], [57.50644, -31.92637], [68.4673, -19.15185], [56.09755, -9.55401]]]]
26279           }
26280         }, {
26281           type: "Feature",
26282           properties: {
26283             iso1A2: "MV",
26284             iso1A3: "MDV",
26285             iso1N3: "462",
26286             wikidata: "Q826",
26287             nameEn: "Maldives",
26288             groups: ["034", "142", "UN"],
26289             driveSide: "left",
26290             callingCodes: ["960"]
26291           },
26292           geometry: {
26293             type: "MultiPolygon",
26294             coordinates: [[[[71.9161, 8.55531], [72.57428, -3.7623], [76.59015, 5.591], [71.9161, 8.55531]]]]
26295           }
26296         }, {
26297           type: "Feature",
26298           properties: {
26299             iso1A2: "MW",
26300             iso1A3: "MWI",
26301             iso1N3: "454",
26302             wikidata: "Q1020",
26303             nameEn: "Malawi",
26304             groups: ["014", "202", "002", "UN"],
26305             driveSide: "left",
26306             callingCodes: ["265"]
26307           },
26308           geometry: {
26309             type: "MultiPolygon",
26310             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]]]]
26311           }
26312         }, {
26313           type: "Feature",
26314           properties: {
26315             iso1A2: "MX",
26316             iso1A3: "MEX",
26317             iso1N3: "484",
26318             wikidata: "Q96",
26319             nameEn: "Mexico",
26320             groups: ["013", "003", "419", "019", "UN"],
26321             callingCodes: ["52"]
26322           },
26323           geometry: {
26324             type: "MultiPolygon",
26325             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]]]]
26326           }
26327         }, {
26328           type: "Feature",
26329           properties: {
26330             iso1A2: "MY",
26331             iso1A3: "MYS",
26332             iso1N3: "458",
26333             wikidata: "Q833",
26334             nameEn: "Malaysia"
26335           },
26336           geometry: null
26337         }, {
26338           type: "Feature",
26339           properties: {
26340             iso1A2: "MZ",
26341             iso1A3: "MOZ",
26342             iso1N3: "508",
26343             wikidata: "Q1029",
26344             nameEn: "Mozambique",
26345             groups: ["014", "202", "002", "UN"],
26346             driveSide: "left",
26347             callingCodes: ["258"]
26348           },
26349           geometry: {
26350             type: "MultiPolygon",
26351             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]]]]
26352           }
26353         }, {
26354           type: "Feature",
26355           properties: {
26356             iso1A2: "NA",
26357             iso1A3: "NAM",
26358             iso1N3: "516",
26359             wikidata: "Q1030",
26360             nameEn: "Namibia",
26361             groups: ["018", "202", "002", "UN"],
26362             driveSide: "left",
26363             callingCodes: ["264"]
26364           },
26365           geometry: {
26366             type: "MultiPolygon",
26367             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]]]]
26368           }
26369         }, {
26370           type: "Feature",
26371           properties: {
26372             iso1A2: "NC",
26373             iso1A3: "NCL",
26374             iso1N3: "540",
26375             wikidata: "Q33788",
26376             nameEn: "New Caledonia",
26377             country: "FR",
26378             groups: ["Q1451600", "054", "009", "UN"],
26379             callingCodes: ["687"]
26380           },
26381           geometry: {
26382             type: "MultiPolygon",
26383             coordinates: [[[[159.77159, -28.41151], [174.245, -23.1974], [156.73836, -14.50464], [159.77159, -28.41151]]]]
26384           }
26385         }, {
26386           type: "Feature",
26387           properties: {
26388             iso1A2: "NE",
26389             iso1A3: "NER",
26390             iso1N3: "562",
26391             wikidata: "Q1032",
26392             nameEn: "Niger",
26393             aliases: ["RN"],
26394             groups: ["011", "202", "002", "UN"],
26395             callingCodes: ["227"]
26396           },
26397           geometry: {
26398             type: "MultiPolygon",
26399             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]]]]
26400           }
26401         }, {
26402           type: "Feature",
26403           properties: {
26404             iso1A2: "NF",
26405             iso1A3: "NFK",
26406             iso1N3: "574",
26407             wikidata: "Q31057",
26408             nameEn: "Norfolk Island",
26409             country: "AU",
26410             groups: ["053", "009", "UN"],
26411             driveSide: "left",
26412             callingCodes: ["672 3"]
26413           },
26414           geometry: {
26415             type: "MultiPolygon",
26416             coordinates: [[[[169.82316, -28.16667], [166.29505, -28.29175], [167.94076, -30.60745], [169.82316, -28.16667]]]]
26417           }
26418         }, {
26419           type: "Feature",
26420           properties: {
26421             iso1A2: "NG",
26422             iso1A3: "NGA",
26423             iso1N3: "566",
26424             wikidata: "Q1033",
26425             nameEn: "Nigeria",
26426             groups: ["011", "202", "002", "UN"],
26427             callingCodes: ["234"]
26428           },
26429           geometry: {
26430             type: "MultiPolygon",
26431             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]]]]
26432           }
26433         }, {
26434           type: "Feature",
26435           properties: {
26436             iso1A2: "NI",
26437             iso1A3: "NIC",
26438             iso1N3: "558",
26439             wikidata: "Q811",
26440             nameEn: "Nicaragua",
26441             groups: ["013", "003", "419", "019", "UN"],
26442             callingCodes: ["505"]
26443           },
26444           geometry: {
26445             type: "MultiPolygon",
26446             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]]]]
26447           }
26448         }, {
26449           type: "Feature",
26450           properties: {
26451             iso1A2: "NL",
26452             iso1A3: "NLD",
26453             iso1N3: "528",
26454             wikidata: "Q29999",
26455             nameEn: "Kingdom of the Netherlands"
26456           },
26457           geometry: null
26458         }, {
26459           type: "Feature",
26460           properties: {
26461             iso1A2: "NO",
26462             iso1A3: "NOR",
26463             iso1N3: "578",
26464             wikidata: "Q20",
26465             nameEn: "Norway"
26466           },
26467           geometry: null
26468         }, {
26469           type: "Feature",
26470           properties: {
26471             iso1A2: "NP",
26472             iso1A3: "NPL",
26473             iso1N3: "524",
26474             wikidata: "Q837",
26475             nameEn: "Nepal",
26476             groups: ["034", "142", "UN"],
26477             driveSide: "left",
26478             callingCodes: ["977"]
26479           },
26480           geometry: {
26481             type: "MultiPolygon",
26482             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]]]]
26483           }
26484         }, {
26485           type: "Feature",
26486           properties: {
26487             iso1A2: "NR",
26488             iso1A3: "NRU",
26489             iso1N3: "520",
26490             wikidata: "Q697",
26491             nameEn: "Nauru",
26492             groups: ["057", "009", "UN"],
26493             driveSide: "left",
26494             callingCodes: ["674"]
26495           },
26496           geometry: {
26497             type: "MultiPolygon",
26498             coordinates: [[[[166.95155, 0.14829], [166.21778, -0.7977], [167.60042, -0.88259], [166.95155, 0.14829]]]]
26499           }
26500         }, {
26501           type: "Feature",
26502           properties: {
26503             iso1A2: "NU",
26504             iso1A3: "NIU",
26505             iso1N3: "570",
26506             wikidata: "Q34020",
26507             nameEn: "Niue",
26508             country: "NZ",
26509             groups: ["061", "009", "UN"],
26510             driveSide: "left",
26511             callingCodes: ["683"]
26512           },
26513           geometry: {
26514             type: "MultiPolygon",
26515             coordinates: [[[[-170.83899, -18.53439], [-170.82274, -20.44429], [-168.63096, -18.60489], [-170.83899, -18.53439]]]]
26516           }
26517         }, {
26518           type: "Feature",
26519           properties: {
26520             iso1A2: "NZ",
26521             iso1A3: "NZL",
26522             iso1N3: "554",
26523             wikidata: "Q664",
26524             nameEn: "New Zealand"
26525           },
26526           geometry: null
26527         }, {
26528           type: "Feature",
26529           properties: {
26530             iso1A2: "OM",
26531             iso1A3: "OMN",
26532             iso1N3: "512",
26533             wikidata: "Q842",
26534             nameEn: "Oman",
26535             groups: ["145", "142", "UN"],
26536             callingCodes: ["968"]
26537           },
26538           geometry: {
26539             type: "MultiPolygon",
26540             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]]]]
26541           }
26542         }, {
26543           type: "Feature",
26544           properties: {
26545             iso1A2: "PA",
26546             iso1A3: "PAN",
26547             iso1N3: "591",
26548             wikidata: "Q804",
26549             nameEn: "Panama",
26550             groups: ["013", "003", "419", "019", "UN"],
26551             callingCodes: ["507"]
26552           },
26553           geometry: {
26554             type: "MultiPolygon",
26555             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]]]]
26556           }
26557         }, {
26558           type: "Feature",
26559           properties: {
26560             iso1A2: "PE",
26561             iso1A3: "PER",
26562             iso1N3: "604",
26563             wikidata: "Q419",
26564             nameEn: "Peru",
26565             groups: ["005", "419", "019", "UN"],
26566             callingCodes: ["51"]
26567           },
26568           geometry: {
26569             type: "MultiPolygon",
26570             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]]]]
26571           }
26572         }, {
26573           type: "Feature",
26574           properties: {
26575             iso1A2: "PF",
26576             iso1A3: "PYF",
26577             iso1N3: "258",
26578             wikidata: "Q30971",
26579             nameEn: "French Polynesia",
26580             country: "FR",
26581             groups: ["Q1451600", "061", "009", "UN"],
26582             callingCodes: ["689"]
26583           },
26584           geometry: {
26585             type: "MultiPolygon",
26586             coordinates: [[[[-135.59706, -4.70473], [-156.48634, -15.52824], [-156.45576, -31.75456], [-133.59543, -28.4709], [-135.59706, -4.70473]]]]
26587           }
26588         }, {
26589           type: "Feature",
26590           properties: {
26591             iso1A2: "PG",
26592             iso1A3: "PNG",
26593             iso1N3: "598",
26594             wikidata: "Q691",
26595             nameEn: "Papua New Guinea",
26596             groups: ["054", "009", "UN"],
26597             driveSide: "left",
26598             callingCodes: ["675"]
26599           },
26600           geometry: {
26601             type: "MultiPolygon",
26602             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]]]]
26603           }
26604         }, {
26605           type: "Feature",
26606           properties: {
26607             iso1A2: "PH",
26608             iso1A3: "PHL",
26609             iso1N3: "608",
26610             wikidata: "Q928",
26611             nameEn: "Philippines",
26612             aliases: ["PI", "RP"],
26613             groups: ["035", "142", "UN"],
26614             callingCodes: ["63"]
26615           },
26616           geometry: {
26617             type: "MultiPolygon",
26618             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]]]]
26619           }
26620         }, {
26621           type: "Feature",
26622           properties: {
26623             iso1A2: "PK",
26624             iso1A3: "PAK",
26625             iso1N3: "586",
26626             wikidata: "Q843",
26627             nameEn: "Pakistan",
26628             groups: ["034", "142", "UN"],
26629             driveSide: "left",
26630             callingCodes: ["92"]
26631           },
26632           geometry: {
26633             type: "MultiPolygon",
26634             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]]]]
26635           }
26636         }, {
26637           type: "Feature",
26638           properties: {
26639             iso1A2: "PL",
26640             iso1A3: "POL",
26641             iso1N3: "616",
26642             wikidata: "Q36",
26643             nameEn: "Poland",
26644             groups: ["EU", "151", "150", "UN"],
26645             callingCodes: ["48"]
26646           },
26647           geometry: {
26648             type: "MultiPolygon",
26649             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]]]]
26650           }
26651         }, {
26652           type: "Feature",
26653           properties: {
26654             iso1A2: "PM",
26655             iso1A3: "SPM",
26656             iso1N3: "666",
26657             wikidata: "Q34617",
26658             nameEn: "Saint Pierre and Miquelon",
26659             country: "FR",
26660             groups: ["Q1451600", "021", "003", "019", "UN"],
26661             callingCodes: ["508"]
26662           },
26663           geometry: {
26664             type: "MultiPolygon",
26665             coordinates: [[[[-56.72993, 46.65575], [-55.90758, 46.6223], [-56.27503, 47.39728], [-56.72993, 46.65575]]]]
26666           }
26667         }, {
26668           type: "Feature",
26669           properties: {
26670             iso1A2: "PN",
26671             iso1A3: "PCN",
26672             iso1N3: "612",
26673             wikidata: "Q35672",
26674             nameEn: "Pitcairn Islands",
26675             country: "GB",
26676             groups: ["BOTS", "061", "009", "UN"],
26677             driveSide: "left",
26678             callingCodes: ["64"]
26679           },
26680           geometry: {
26681             type: "MultiPolygon",
26682             coordinates: [[[[-133.59543, -28.4709], [-122.0366, -24.55017], [-133.61511, -21.93325], [-133.59543, -28.4709]]]]
26683           }
26684         }, {
26685           type: "Feature",
26686           properties: {
26687             iso1A2: "PR",
26688             iso1A3: "PRI",
26689             iso1N3: "630",
26690             wikidata: "Q1183",
26691             nameEn: "Puerto Rico",
26692             aliases: ["US-PR"],
26693             country: "US",
26694             groups: ["Q1352230", "029", "003", "419", "019", "UN"],
26695             roadSpeedUnit: "mph",
26696             callingCodes: ["1 787", "1 939"]
26697           },
26698           geometry: {
26699             type: "MultiPolygon",
26700             coordinates: [[[[-65.27974, 17.56928], [-65.02435, 18.73231], [-67.99519, 18.97186], [-68.23894, 17.84663], [-65.27974, 17.56928]]]]
26701           }
26702         }, {
26703           type: "Feature",
26704           properties: {
26705             iso1A2: "PS",
26706             iso1A3: "PSE",
26707             iso1N3: "275",
26708             wikidata: "Q219060",
26709             nameEn: "Palestine"
26710           },
26711           geometry: null
26712         }, {
26713           type: "Feature",
26714           properties: {
26715             iso1A2: "PT",
26716             iso1A3: "PRT",
26717             iso1N3: "620",
26718             wikidata: "Q45",
26719             nameEn: "Portugal"
26720           },
26721           geometry: null
26722         }, {
26723           type: "Feature",
26724           properties: {
26725             iso1A2: "PW",
26726             iso1A3: "PLW",
26727             iso1N3: "585",
26728             wikidata: "Q695",
26729             nameEn: "Palau",
26730             groups: ["057", "009", "UN"],
26731             roadSpeedUnit: "mph",
26732             callingCodes: ["680"]
26733           },
26734           geometry: {
26735             type: "MultiPolygon",
26736             coordinates: [[[[128.97621, 3.08804], [136.39296, 1.54187], [136.04605, 12.45908], [128.97621, 3.08804]]]]
26737           }
26738         }, {
26739           type: "Feature",
26740           properties: {
26741             iso1A2: "PY",
26742             iso1A3: "PRY",
26743             iso1N3: "600",
26744             wikidata: "Q733",
26745             nameEn: "Paraguay",
26746             groups: ["005", "419", "019", "UN"],
26747             callingCodes: ["595"]
26748           },
26749           geometry: {
26750             type: "MultiPolygon",
26751             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]]]]
26752           }
26753         }, {
26754           type: "Feature",
26755           properties: {
26756             iso1A2: "QA",
26757             iso1A3: "QAT",
26758             iso1N3: "634",
26759             wikidata: "Q846",
26760             nameEn: "Qatar",
26761             groups: ["145", "142", "UN"],
26762             callingCodes: ["974"]
26763           },
26764           geometry: {
26765             type: "MultiPolygon",
26766             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]]]]
26767           }
26768         }, {
26769           type: "Feature",
26770           properties: {
26771             iso1A2: "RE",
26772             iso1A3: "REU",
26773             iso1N3: "638",
26774             wikidata: "Q17070",
26775             nameEn: "R\xE9union",
26776             country: "FR",
26777             groups: ["Q3320166", "EU", "014", "202", "002", "UN"],
26778             callingCodes: ["262"]
26779           },
26780           geometry: {
26781             type: "MultiPolygon",
26782             coordinates: [[[[53.37984, -21.23941], [56.73473, -21.9174], [56.62373, -20.2711], [53.37984, -21.23941]]]]
26783           }
26784         }, {
26785           type: "Feature",
26786           properties: {
26787             iso1A2: "RO",
26788             iso1A3: "ROU",
26789             iso1N3: "642",
26790             wikidata: "Q218",
26791             nameEn: "Romania",
26792             groups: ["EU", "151", "150", "UN"],
26793             callingCodes: ["40"]
26794           },
26795           geometry: {
26796             type: "MultiPolygon",
26797             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]]]]
26798           }
26799         }, {
26800           type: "Feature",
26801           properties: {
26802             iso1A2: "RS",
26803             iso1A3: "SRB",
26804             iso1N3: "688",
26805             wikidata: "Q403",
26806             nameEn: "Serbia",
26807             groups: ["039", "150", "UN"],
26808             callingCodes: ["381"]
26809           },
26810           geometry: {
26811             type: "MultiPolygon",
26812             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]]]]
26813           }
26814         }, {
26815           type: "Feature",
26816           properties: {
26817             iso1A2: "RU",
26818             iso1A3: "RUS",
26819             iso1N3: "643",
26820             wikidata: "Q159",
26821             nameEn: "Russia"
26822           },
26823           geometry: null
26824         }, {
26825           type: "Feature",
26826           properties: {
26827             iso1A2: "RW",
26828             iso1A3: "RWA",
26829             iso1N3: "646",
26830             wikidata: "Q1037",
26831             nameEn: "Rwanda",
26832             groups: ["014", "202", "002", "UN"],
26833             callingCodes: ["250"]
26834           },
26835           geometry: {
26836             type: "MultiPolygon",
26837             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]]]]
26838           }
26839         }, {
26840           type: "Feature",
26841           properties: {
26842             iso1A2: "SA",
26843             iso1A3: "SAU",
26844             iso1N3: "682",
26845             wikidata: "Q851",
26846             nameEn: "Saudi Arabia",
26847             groups: ["145", "142", "UN"],
26848             callingCodes: ["966"]
26849           },
26850           geometry: {
26851             type: "MultiPolygon",
26852             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]]]]
26853           }
26854         }, {
26855           type: "Feature",
26856           properties: {
26857             iso1A2: "SB",
26858             iso1A3: "SLB",
26859             iso1N3: "090",
26860             wikidata: "Q685",
26861             nameEn: "Solomon Islands",
26862             groups: ["054", "009", "UN"],
26863             driveSide: "left",
26864             callingCodes: ["677"]
26865           },
26866           geometry: {
26867             type: "MultiPolygon",
26868             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]]]]
26869           }
26870         }, {
26871           type: "Feature",
26872           properties: {
26873             iso1A2: "SC",
26874             iso1A3: "SYC",
26875             iso1N3: "690",
26876             wikidata: "Q1042",
26877             nameEn: "Seychelles",
26878             groups: ["014", "202", "002", "UN"],
26879             driveSide: "left",
26880             callingCodes: ["248"]
26881           },
26882           geometry: {
26883             type: "MultiPolygon",
26884             coordinates: [[[[43.75112, -10.38913], [54.83239, -10.93575], [66.3222, 5.65313], [43.75112, -10.38913]]]]
26885           }
26886         }, {
26887           type: "Feature",
26888           properties: {
26889             iso1A2: "SD",
26890             iso1A3: "SDN",
26891             iso1N3: "729",
26892             wikidata: "Q1049",
26893             nameEn: "Sudan",
26894             groups: ["015", "002", "UN"],
26895             callingCodes: ["249"]
26896           },
26897           geometry: {
26898             type: "MultiPolygon",
26899             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]]]]
26900           }
26901         }, {
26902           type: "Feature",
26903           properties: {
26904             iso1A2: "SE",
26905             iso1A3: "SWE",
26906             iso1N3: "752",
26907             wikidata: "Q34",
26908             nameEn: "Sweden",
26909             groups: ["EU", "154", "150", "UN"],
26910             callingCodes: ["46"]
26911           },
26912           geometry: {
26913             type: "MultiPolygon",
26914             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]]]]
26915           }
26916         }, {
26917           type: "Feature",
26918           properties: {
26919             iso1A2: "SG",
26920             iso1A3: "SGP",
26921             iso1N3: "702",
26922             wikidata: "Q334",
26923             nameEn: "Singapore",
26924             groups: ["035", "142", "UN"],
26925             driveSide: "left",
26926             callingCodes: ["65"]
26927           },
26928           geometry: {
26929             type: "MultiPolygon",
26930             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]]]]
26931           }
26932         }, {
26933           type: "Feature",
26934           properties: {
26935             iso1A2: "SH",
26936             iso1A3: "SHN",
26937             iso1N3: "654",
26938             wikidata: "Q192184",
26939             nameEn: "Saint Helena, Ascension and Tristan da Cunha",
26940             country: "GB"
26941           },
26942           geometry: null
26943         }, {
26944           type: "Feature",
26945           properties: {
26946             iso1A2: "SI",
26947             iso1A3: "SVN",
26948             iso1N3: "705",
26949             wikidata: "Q215",
26950             nameEn: "Slovenia",
26951             groups: ["EU", "039", "150", "UN"],
26952             callingCodes: ["386"]
26953           },
26954           geometry: {
26955             type: "MultiPolygon",
26956             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]]]]
26957           }
26958         }, {
26959           type: "Feature",
26960           properties: {
26961             iso1A2: "SJ",
26962             iso1A3: "SJM",
26963             iso1N3: "744",
26964             wikidata: "Q842829",
26965             nameEn: "Svalbard and Jan Mayen",
26966             country: "NO"
26967           },
26968           geometry: null
26969         }, {
26970           type: "Feature",
26971           properties: {
26972             iso1A2: "SK",
26973             iso1A3: "SVK",
26974             iso1N3: "703",
26975             wikidata: "Q214",
26976             nameEn: "Slovakia",
26977             groups: ["EU", "151", "150", "UN"],
26978             callingCodes: ["421"]
26979           },
26980           geometry: {
26981             type: "MultiPolygon",
26982             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]]]]
26983           }
26984         }, {
26985           type: "Feature",
26986           properties: {
26987             iso1A2: "SL",
26988             iso1A3: "SLE",
26989             iso1N3: "694",
26990             wikidata: "Q1044",
26991             nameEn: "Sierra Leone",
26992             groups: ["011", "202", "002", "UN"],
26993             callingCodes: ["232"]
26994           },
26995           geometry: {
26996             type: "MultiPolygon",
26997             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]]]]
26998           }
26999         }, {
27000           type: "Feature",
27001           properties: {
27002             iso1A2: "SM",
27003             iso1A3: "SMR",
27004             iso1N3: "674",
27005             wikidata: "Q238",
27006             nameEn: "San Marino",
27007             groups: ["039", "150", "UN"],
27008             callingCodes: ["378"]
27009           },
27010           geometry: {
27011             type: "MultiPolygon",
27012             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]]]]
27013           }
27014         }, {
27015           type: "Feature",
27016           properties: {
27017             iso1A2: "SN",
27018             iso1A3: "SEN",
27019             iso1N3: "686",
27020             wikidata: "Q1041",
27021             nameEn: "Senegal",
27022             groups: ["011", "202", "002", "UN"],
27023             callingCodes: ["221"]
27024           },
27025           geometry: {
27026             type: "MultiPolygon",
27027             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]]]]
27028           }
27029         }, {
27030           type: "Feature",
27031           properties: {
27032             iso1A2: "SO",
27033             iso1A3: "SOM",
27034             iso1N3: "706",
27035             wikidata: "Q1045",
27036             nameEn: "Somalia",
27037             groups: ["014", "202", "002", "UN"],
27038             callingCodes: ["252"]
27039           },
27040           geometry: {
27041             type: "MultiPolygon",
27042             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]]]]
27043           }
27044         }, {
27045           type: "Feature",
27046           properties: {
27047             iso1A2: "SR",
27048             iso1A3: "SUR",
27049             iso1N3: "740",
27050             wikidata: "Q730",
27051             nameEn: "Suriname",
27052             groups: ["005", "419", "019", "UN"],
27053             driveSide: "left",
27054             callingCodes: ["597"]
27055           },
27056           geometry: {
27057             type: "MultiPolygon",
27058             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]]]]
27059           }
27060         }, {
27061           type: "Feature",
27062           properties: {
27063             iso1A2: "SS",
27064             iso1A3: "SSD",
27065             iso1N3: "728",
27066             wikidata: "Q958",
27067             nameEn: "South Sudan",
27068             groups: ["014", "202", "002", "UN"],
27069             callingCodes: ["211"]
27070           },
27071           geometry: {
27072             type: "MultiPolygon",
27073             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]]]]
27074           }
27075         }, {
27076           type: "Feature",
27077           properties: {
27078             iso1A2: "ST",
27079             iso1A3: "STP",
27080             iso1N3: "678",
27081             wikidata: "Q1039",
27082             nameEn: "S\xE3o Tom\xE9 and Principe",
27083             groups: ["017", "202", "002", "UN"],
27084             callingCodes: ["239"]
27085           },
27086           geometry: {
27087             type: "MultiPolygon",
27088             coordinates: [[[[4.34149, 1.91417], [6.6507, -0.28606], [7.9035, 1.92304], [4.34149, 1.91417]]]]
27089           }
27090         }, {
27091           type: "Feature",
27092           properties: {
27093             iso1A2: "SV",
27094             iso1A3: "SLV",
27095             iso1N3: "222",
27096             wikidata: "Q792",
27097             nameEn: "El Salvador",
27098             groups: ["013", "003", "419", "019", "UN"],
27099             callingCodes: ["503"]
27100           },
27101           geometry: {
27102             type: "MultiPolygon",
27103             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]]]]
27104           }
27105         }, {
27106           type: "Feature",
27107           properties: {
27108             iso1A2: "SX",
27109             iso1A3: "SXM",
27110             iso1N3: "534",
27111             wikidata: "Q26273",
27112             nameEn: "Sint Maarten",
27113             aliases: ["NL-SX"],
27114             country: "NL",
27115             groups: ["Q1451600", "029", "003", "419", "019", "UN"],
27116             callingCodes: ["1 721"]
27117           },
27118           geometry: {
27119             type: "MultiPolygon",
27120             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]]]]
27121           }
27122         }, {
27123           type: "Feature",
27124           properties: {
27125             iso1A2: "SY",
27126             iso1A3: "SYR",
27127             iso1N3: "760",
27128             wikidata: "Q858",
27129             nameEn: "Syria",
27130             groups: ["145", "142", "UN"],
27131             callingCodes: ["963"]
27132           },
27133           geometry: {
27134             type: "MultiPolygon",
27135             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]]]]
27136           }
27137         }, {
27138           type: "Feature",
27139           properties: {
27140             iso1A2: "SZ",
27141             iso1A3: "SWZ",
27142             iso1N3: "748",
27143             wikidata: "Q1050",
27144             nameEn: "Eswatini",
27145             aliases: ["Swaziland"],
27146             groups: ["018", "202", "002", "UN"],
27147             driveSide: "left",
27148             callingCodes: ["268"]
27149           },
27150           geometry: {
27151             type: "MultiPolygon",
27152             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]]]]
27153           }
27154         }, {
27155           type: "Feature",
27156           properties: {
27157             iso1A2: "TA",
27158             iso1A3: "TAA",
27159             wikidata: "Q220982",
27160             nameEn: "Tristan da Cunha",
27161             aliases: ["SH-TA"],
27162             country: "GB",
27163             groups: ["SH", "BOTS", "011", "202", "002", "UN"],
27164             isoStatus: "excRes",
27165             driveSide: "left",
27166             roadSpeedUnit: "mph",
27167             roadHeightUnit: "ft",
27168             callingCodes: ["290 8", "44 20"]
27169           },
27170           geometry: {
27171             type: "MultiPolygon",
27172             coordinates: [[[[-13.38232, -34.07258], [-16.67337, -41.9188], [-5.88482, -41.4829], [-13.38232, -34.07258]]]]
27173           }
27174         }, {
27175           type: "Feature",
27176           properties: {
27177             iso1A2: "TC",
27178             iso1A3: "TCA",
27179             iso1N3: "796",
27180             wikidata: "Q18221",
27181             nameEn: "Turks and Caicos Islands",
27182             country: "GB",
27183             groups: ["BOTS", "029", "003", "419", "019", "UN"],
27184             driveSide: "left",
27185             roadSpeedUnit: "mph",
27186             roadHeightUnit: "ft",
27187             callingCodes: ["1 649"]
27188           },
27189           geometry: {
27190             type: "MultiPolygon",
27191             coordinates: [[[[-71.70065, 25.7637], [-72.98446, 20.4801], [-69.80718, 21.35956], [-71.70065, 25.7637]]]]
27192           }
27193         }, {
27194           type: "Feature",
27195           properties: {
27196             iso1A2: "TD",
27197             iso1A3: "TCD",
27198             iso1N3: "148",
27199             wikidata: "Q657",
27200             nameEn: "Chad",
27201             groups: ["017", "202", "002", "UN"],
27202             callingCodes: ["235"]
27203           },
27204           geometry: {
27205             type: "MultiPolygon",
27206             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]]]]
27207           }
27208         }, {
27209           type: "Feature",
27210           properties: {
27211             iso1A2: "TF",
27212             iso1A3: "ATF",
27213             iso1N3: "260",
27214             wikidata: "Q129003",
27215             nameEn: "French Southern Territories",
27216             country: "FR"
27217           },
27218           geometry: null
27219         }, {
27220           type: "Feature",
27221           properties: {
27222             iso1A2: "TG",
27223             iso1A3: "TGO",
27224             iso1N3: "768",
27225             wikidata: "Q945",
27226             nameEn: "Togo",
27227             groups: ["011", "202", "002", "UN"],
27228             callingCodes: ["228"]
27229           },
27230           geometry: {
27231             type: "MultiPolygon",
27232             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]]]]
27233           }
27234         }, {
27235           type: "Feature",
27236           properties: {
27237             iso1A2: "TH",
27238             iso1A3: "THA",
27239             iso1N3: "764",
27240             wikidata: "Q869",
27241             nameEn: "Thailand",
27242             groups: ["035", "142", "UN"],
27243             driveSide: "left",
27244             callingCodes: ["66"]
27245           },
27246           geometry: {
27247             type: "MultiPolygon",
27248             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]]]]
27249           }
27250         }, {
27251           type: "Feature",
27252           properties: {
27253             iso1A2: "TJ",
27254             iso1A3: "TJK",
27255             iso1N3: "762",
27256             wikidata: "Q863",
27257             nameEn: "Tajikistan",
27258             groups: ["143", "142", "UN"],
27259             callingCodes: ["992"]
27260           },
27261           geometry: {
27262             type: "MultiPolygon",
27263             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]]]]
27264           }
27265         }, {
27266           type: "Feature",
27267           properties: {
27268             iso1A2: "TK",
27269             iso1A3: "TKL",
27270             iso1N3: "772",
27271             wikidata: "Q36823",
27272             nameEn: "Tokelau",
27273             country: "NZ",
27274             groups: ["061", "009", "UN"],
27275             driveSide: "left",
27276             callingCodes: ["690"]
27277           },
27278           geometry: {
27279             type: "MultiPolygon",
27280             coordinates: [[[[-168.251, -9.44289], [-174.18635, -7.80441], [-174.17993, -10.13616], [-168.251, -9.44289]]]]
27281           }
27282         }, {
27283           type: "Feature",
27284           properties: {
27285             iso1A2: "TL",
27286             iso1A3: "TLS",
27287             iso1N3: "626",
27288             wikidata: "Q574",
27289             nameEn: "East Timor",
27290             aliases: ["Timor-Leste", "TP"],
27291             groups: ["035", "142", "UN"],
27292             driveSide: "left",
27293             callingCodes: ["670"]
27294           },
27295           geometry: {
27296             type: "MultiPolygon",
27297             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]]]]
27298           }
27299         }, {
27300           type: "Feature",
27301           properties: {
27302             iso1A2: "TM",
27303             iso1A3: "TKM",
27304             iso1N3: "795",
27305             wikidata: "Q874",
27306             nameEn: "Turkmenistan",
27307             groups: ["143", "142", "UN"],
27308             callingCodes: ["993"]
27309           },
27310           geometry: {
27311             type: "MultiPolygon",
27312             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]]]]
27313           }
27314         }, {
27315           type: "Feature",
27316           properties: {
27317             iso1A2: "TN",
27318             iso1A3: "TUN",
27319             iso1N3: "788",
27320             wikidata: "Q948",
27321             nameEn: "Tunisia",
27322             groups: ["015", "002", "UN"],
27323             callingCodes: ["216"]
27324           },
27325           geometry: {
27326             type: "MultiPolygon",
27327             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]]]]
27328           }
27329         }, {
27330           type: "Feature",
27331           properties: {
27332             iso1A2: "TO",
27333             iso1A3: "TON",
27334             iso1N3: "776",
27335             wikidata: "Q678",
27336             nameEn: "Tonga",
27337             groups: ["061", "009", "UN"],
27338             driveSide: "left",
27339             callingCodes: ["676"]
27340           },
27341           geometry: {
27342             type: "MultiPolygon",
27343             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]]]]
27344           }
27345         }, {
27346           type: "Feature",
27347           properties: {
27348             iso1A2: "TR",
27349             iso1A3: "TUR",
27350             iso1N3: "792",
27351             wikidata: "Q43",
27352             nameEn: "Turkey",
27353             groups: ["145", "142", "UN"],
27354             callingCodes: ["90"]
27355           },
27356           geometry: {
27357             type: "MultiPolygon",
27358             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]]]]
27359           }
27360         }, {
27361           type: "Feature",
27362           properties: {
27363             iso1A2: "TT",
27364             iso1A3: "TTO",
27365             iso1N3: "780",
27366             wikidata: "Q754",
27367             nameEn: "Trinidad and Tobago",
27368             groups: ["029", "003", "419", "019", "UN"],
27369             driveSide: "left",
27370             callingCodes: ["1 868"]
27371           },
27372           geometry: {
27373             type: "MultiPolygon",
27374             coordinates: [[[[-61.62505, 11.18974], [-62.08693, 10.04435], [-60.89962, 9.81445], [-60.07172, 11.77667], [-61.62505, 11.18974]]]]
27375           }
27376         }, {
27377           type: "Feature",
27378           properties: {
27379             iso1A2: "TV",
27380             iso1A3: "TUV",
27381             iso1N3: "798",
27382             wikidata: "Q672",
27383             nameEn: "Tuvalu",
27384             groups: ["061", "009", "UN"],
27385             driveSide: "left",
27386             callingCodes: ["688"]
27387           },
27388           geometry: {
27389             type: "MultiPolygon",
27390             coordinates: [[[[174, -5], [174, -11.5], [179.99999, -11.5], [179.99999, -5], [174, -5]]]]
27391           }
27392         }, {
27393           type: "Feature",
27394           properties: {
27395             iso1A2: "TW",
27396             iso1A3: "TWN",
27397             iso1N3: "158",
27398             wikidata: "Q865",
27399             nameEn: "Taiwan",
27400             aliases: ["RC"],
27401             groups: ["030", "142"],
27402             callingCodes: ["886"]
27403           },
27404           geometry: {
27405             type: "MultiPolygon",
27406             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]]]]
27407           }
27408         }, {
27409           type: "Feature",
27410           properties: {
27411             iso1A2: "TZ",
27412             iso1A3: "TZA",
27413             iso1N3: "834",
27414             wikidata: "Q924",
27415             nameEn: "Tanzania",
27416             groups: ["014", "202", "002", "UN"],
27417             driveSide: "left",
27418             callingCodes: ["255"]
27419           },
27420           geometry: {
27421             type: "MultiPolygon",
27422             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]]]]
27423           }
27424         }, {
27425           type: "Feature",
27426           properties: {
27427             iso1A2: "UA",
27428             iso1A3: "UKR",
27429             iso1N3: "804",
27430             wikidata: "Q212",
27431             nameEn: "Ukraine",
27432             groups: ["151", "150", "UN"],
27433             callingCodes: ["380"]
27434           },
27435           geometry: {
27436             type: "MultiPolygon",
27437             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]]]]
27438           }
27439         }, {
27440           type: "Feature",
27441           properties: {
27442             iso1A2: "UG",
27443             iso1A3: "UGA",
27444             iso1N3: "800",
27445             wikidata: "Q1036",
27446             nameEn: "Uganda",
27447             groups: ["014", "202", "002", "UN"],
27448             driveSide: "left",
27449             callingCodes: ["256"]
27450           },
27451           geometry: {
27452             type: "MultiPolygon",
27453             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]]]]
27454           }
27455         }, {
27456           type: "Feature",
27457           properties: {
27458             iso1A2: "UM",
27459             iso1A3: "UMI",
27460             iso1N3: "581",
27461             wikidata: "Q16645",
27462             nameEn: "United States Minor Outlying Islands",
27463             country: "US"
27464           },
27465           geometry: null
27466         }, {
27467           type: "Feature",
27468           properties: {
27469             iso1A2: "UN",
27470             wikidata: "Q1065",
27471             nameEn: "United Nations",
27472             level: "unitedNations",
27473             isoStatus: "excRes"
27474           },
27475           geometry: null
27476         }, {
27477           type: "Feature",
27478           properties: {
27479             iso1A2: "US",
27480             iso1A3: "USA",
27481             iso1N3: "840",
27482             wikidata: "Q30",
27483             nameEn: "United States of America"
27484           },
27485           geometry: null
27486         }, {
27487           type: "Feature",
27488           properties: {
27489             iso1A2: "UY",
27490             iso1A3: "URY",
27491             iso1N3: "858",
27492             wikidata: "Q77",
27493             nameEn: "Uruguay",
27494             groups: ["005", "419", "019", "UN"],
27495             callingCodes: ["598"]
27496           },
27497           geometry: {
27498             type: "MultiPolygon",
27499             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]]]]
27500           }
27501         }, {
27502           type: "Feature",
27503           properties: {
27504             iso1A2: "UZ",
27505             iso1A3: "UZB",
27506             iso1N3: "860",
27507             wikidata: "Q265",
27508             nameEn: "Uzbekistan",
27509             groups: ["143", "142", "UN"],
27510             callingCodes: ["998"]
27511           },
27512           geometry: {
27513             type: "MultiPolygon",
27514             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]]]]
27515           }
27516         }, {
27517           type: "Feature",
27518           properties: {
27519             iso1A2: "VA",
27520             iso1A3: "VAT",
27521             iso1N3: "336",
27522             wikidata: "Q237",
27523             nameEn: "Vatican City",
27524             aliases: ["Holy See"],
27525             groups: ["039", "150"],
27526             callingCodes: ["379", "39 06"]
27527           },
27528           geometry: {
27529             type: "MultiPolygon",
27530             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]]]]
27531           }
27532         }, {
27533           type: "Feature",
27534           properties: {
27535             iso1A2: "VC",
27536             iso1A3: "VCT",
27537             iso1N3: "670",
27538             wikidata: "Q757",
27539             nameEn: "St. Vincent and the Grenadines",
27540             aliases: ["WV"],
27541             groups: ["029", "003", "419", "019", "UN"],
27542             driveSide: "left",
27543             roadSpeedUnit: "mph",
27544             callingCodes: ["1 784"]
27545           },
27546           geometry: {
27547             type: "MultiPolygon",
27548             coordinates: [[[[-62.64026, 12.69984], [-59.94058, 12.34011], [-61.69315, 14.26451], [-62.64026, 12.69984]]]]
27549           }
27550         }, {
27551           type: "Feature",
27552           properties: {
27553             iso1A2: "VE",
27554             iso1A3: "VEN",
27555             iso1N3: "862",
27556             wikidata: "Q717",
27557             nameEn: "Venezuela",
27558             aliases: ["YV"],
27559             groups: ["005", "419", "019", "UN"],
27560             callingCodes: ["58"]
27561           },
27562           geometry: {
27563             type: "MultiPolygon",
27564             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]]]]
27565           }
27566         }, {
27567           type: "Feature",
27568           properties: {
27569             iso1A2: "VG",
27570             iso1A3: "VGB",
27571             iso1N3: "092",
27572             wikidata: "Q25305",
27573             nameEn: "British Virgin Islands",
27574             country: "GB",
27575             groups: ["BOTS", "029", "003", "419", "019", "UN"],
27576             driveSide: "left",
27577             roadSpeedUnit: "mph",
27578             roadHeightUnit: "ft",
27579             callingCodes: ["1 284"]
27580           },
27581           geometry: {
27582             type: "MultiPolygon",
27583             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]]]]
27584           }
27585         }, {
27586           type: "Feature",
27587           properties: {
27588             iso1A2: "VI",
27589             iso1A3: "VIR",
27590             iso1N3: "850",
27591             wikidata: "Q11703",
27592             nameEn: "United States Virgin Islands",
27593             aliases: ["US-VI"],
27594             country: "US",
27595             groups: ["Q1352230", "029", "003", "419", "019", "UN"],
27596             driveSide: "left",
27597             roadSpeedUnit: "mph",
27598             roadHeightUnit: "ft",
27599             callingCodes: ["1 340"]
27600           },
27601           geometry: {
27602             type: "MultiPolygon",
27603             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]]]]
27604           }
27605         }, {
27606           type: "Feature",
27607           properties: {
27608             iso1A2: "VN",
27609             iso1A3: "VNM",
27610             iso1N3: "704",
27611             wikidata: "Q881",
27612             nameEn: "Vietnam",
27613             groups: ["035", "142", "UN"],
27614             callingCodes: ["84"]
27615           },
27616           geometry: {
27617             type: "MultiPolygon",
27618             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]]]]
27619           }
27620         }, {
27621           type: "Feature",
27622           properties: {
27623             iso1A2: "VU",
27624             iso1A3: "VUT",
27625             iso1N3: "548",
27626             wikidata: "Q686",
27627             nameEn: "Vanuatu",
27628             groups: ["054", "009", "UN"],
27629             callingCodes: ["678"]
27630           },
27631           geometry: {
27632             type: "MultiPolygon",
27633             coordinates: [[[[156.73836, -14.50464], [174.245, -23.1974], [172.71443, -12.01327], [156.73836, -14.50464]]]]
27634           }
27635         }, {
27636           type: "Feature",
27637           properties: {
27638             iso1A2: "WF",
27639             iso1A3: "WLF",
27640             iso1N3: "876",
27641             wikidata: "Q35555",
27642             nameEn: "Wallis and Futuna",
27643             country: "FR",
27644             groups: ["Q1451600", "061", "009", "UN"],
27645             callingCodes: ["681"]
27646           },
27647           geometry: {
27648             type: "MultiPolygon",
27649             coordinates: [[[[-178.66551, -14.32452], [-176.76826, -14.95183], [-175.59809, -12.61507], [-178.66551, -14.32452]]]]
27650           }
27651         }, {
27652           type: "Feature",
27653           properties: {
27654             iso1A2: "WS",
27655             iso1A3: "WSM",
27656             iso1N3: "882",
27657             wikidata: "Q683",
27658             nameEn: "Samoa",
27659             groups: ["061", "009", "UN"],
27660             driveSide: "left",
27661             callingCodes: ["685"]
27662           },
27663           geometry: {
27664             type: "MultiPolygon",
27665             coordinates: [[[[-173.74402, -14.26669], [-170.99605, -15.1275], [-171.39864, -10.21587], [-173.74402, -14.26669]]]]
27666           }
27667         }, {
27668           type: "Feature",
27669           properties: {
27670             iso1A2: "XK",
27671             iso1A3: "XKX",
27672             wikidata: "Q1246",
27673             nameEn: "Kosovo",
27674             aliases: ["KV"],
27675             groups: ["039", "150"],
27676             isoStatus: "usrAssn",
27677             callingCodes: ["383"]
27678           },
27679           geometry: {
27680             type: "MultiPolygon",
27681             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]]]]
27682           }
27683         }, {
27684           type: "Feature",
27685           properties: {
27686             iso1A2: "YE",
27687             iso1A3: "YEM",
27688             iso1N3: "887",
27689             wikidata: "Q805",
27690             nameEn: "Yemen",
27691             groups: ["145", "142", "UN"],
27692             callingCodes: ["967"]
27693           },
27694           geometry: {
27695             type: "MultiPolygon",
27696             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]]]]
27697           }
27698         }, {
27699           type: "Feature",
27700           properties: {
27701             iso1A2: "YT",
27702             iso1A3: "MYT",
27703             iso1N3: "175",
27704             wikidata: "Q17063",
27705             nameEn: "Mayotte",
27706             country: "FR",
27707             groups: ["Q3320166", "EU", "014", "202", "002", "UN"],
27708             callingCodes: ["262"]
27709           },
27710           geometry: {
27711             type: "MultiPolygon",
27712             coordinates: [[[[43.28731, -13.97126], [45.54824, -13.22353], [45.4971, -11.75965], [43.28731, -13.97126]]]]
27713           }
27714         }, {
27715           type: "Feature",
27716           properties: {
27717             iso1A2: "ZA",
27718             iso1A3: "ZAF",
27719             iso1N3: "710",
27720             wikidata: "Q258",
27721             nameEn: "South Africa",
27722             groups: ["018", "202", "002", "UN"],
27723             driveSide: "left",
27724             callingCodes: ["27"]
27725           },
27726           geometry: {
27727             type: "MultiPolygon",
27728             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]]]]
27729           }
27730         }, {
27731           type: "Feature",
27732           properties: {
27733             iso1A2: "ZM",
27734             iso1A3: "ZMB",
27735             iso1N3: "894",
27736             wikidata: "Q953",
27737             nameEn: "Zambia",
27738             groups: ["014", "202", "002", "UN"],
27739             driveSide: "left",
27740             callingCodes: ["260"]
27741           },
27742           geometry: {
27743             type: "MultiPolygon",
27744             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]]]]
27745           }
27746         }, {
27747           type: "Feature",
27748           properties: {
27749             iso1A2: "ZW",
27750             iso1A3: "ZWE",
27751             iso1N3: "716",
27752             wikidata: "Q954",
27753             nameEn: "Zimbabwe",
27754             groups: ["014", "202", "002", "UN"],
27755             driveSide: "left",
27756             callingCodes: ["263"]
27757           },
27758           geometry: {
27759             type: "MultiPolygon",
27760             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]]]]
27761           }
27762         }];
27763         var borders_default = {
27764           type: type,
27765           features: features
27766         }; // src/country-coder.ts
27767
27768         var borders = borders_default;
27769         var whichPolygonGetter = {};
27770         var featuresByCode = {};
27771         var idFilterRegex = /(?=(?!^(and|the|of|el|la|de)$))(\b(and|the|of|el|la|de)\b)|[-_ .,'()&[\]/]/gi;
27772
27773         function canonicalID(id) {
27774           var s = id || "";
27775
27776           if (s.charAt(0) === ".") {
27777             return s.toUpperCase();
27778           } else {
27779             return s.replace(idFilterRegex, "").toUpperCase();
27780           }
27781         }
27782
27783         var levels = ["subterritory", "territory", "subcountryGroup", "country", "sharedLandform", "intermediateRegion", "subregion", "region", "subunion", "union", "unitedNations", "world"];
27784         loadDerivedDataAndCaches(borders);
27785
27786         function loadDerivedDataAndCaches(borders2) {
27787           var identifierProps = ["iso1A2", "iso1A3", "m49", "wikidata", "emojiFlag", "ccTLD", "nameEn"];
27788           var geometryFeatures = [];
27789
27790           for (var i in borders2.features) {
27791             var feature2 = borders2.features[i];
27792             feature2.properties.id = feature2.properties.iso1A2 || feature2.properties.m49 || feature2.properties.wikidata;
27793             loadM49(feature2);
27794             loadTLD(feature2);
27795             loadIsoStatus(feature2);
27796             loadLevel(feature2);
27797             loadGroups(feature2);
27798             loadFlag(feature2);
27799             cacheFeatureByIDs(feature2);
27800             if (feature2.geometry) geometryFeatures.push(feature2);
27801           }
27802
27803           for (var _i in borders2.features) {
27804             var _feature = borders2.features[_i];
27805             _feature.properties.groups = _feature.properties.groups.map(function (groupID) {
27806               return featuresByCode[groupID].properties.id;
27807             });
27808             loadMembersForGroupsOf(_feature);
27809           }
27810
27811           for (var _i2 in borders2.features) {
27812             var _feature2 = borders2.features[_i2];
27813             loadRoadSpeedUnit(_feature2);
27814             loadRoadHeightUnit(_feature2);
27815             loadDriveSide(_feature2);
27816             loadCallingCodes(_feature2);
27817             loadGroupGroups(_feature2);
27818           }
27819
27820           for (var _i3 in borders2.features) {
27821             var _feature3 = borders2.features[_i3];
27822
27823             _feature3.properties.groups.sort(function (groupID1, groupID2) {
27824               return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
27825             });
27826
27827             if (_feature3.properties.members) _feature3.properties.members.sort(function (id1, id2) {
27828               var diff = levels.indexOf(featuresByCode[id1].properties.level) - levels.indexOf(featuresByCode[id2].properties.level);
27829
27830               if (diff === 0) {
27831                 return borders2.features.indexOf(featuresByCode[id1]) - borders2.features.indexOf(featuresByCode[id2]);
27832               }
27833
27834               return diff;
27835             });
27836           }
27837
27838           var geometryOnlyCollection = {
27839             type: "FeatureCollection",
27840             features: geometryFeatures
27841           };
27842           whichPolygonGetter = whichPolygon_1(geometryOnlyCollection);
27843
27844           function loadGroups(feature2) {
27845             var props = feature2.properties;
27846
27847             if (!props.groups) {
27848               props.groups = [];
27849             }
27850
27851             if (feature2.geometry && props.country) {
27852               props.groups.push(props.country);
27853             }
27854
27855             if (props.m49 !== "001") {
27856               props.groups.push("001");
27857             }
27858           }
27859
27860           function loadM49(feature2) {
27861             var props = feature2.properties;
27862
27863             if (!props.m49 && props.iso1N3) {
27864               props.m49 = props.iso1N3;
27865             }
27866           }
27867
27868           function loadTLD(feature2) {
27869             var props = feature2.properties;
27870             if (props.level === "unitedNations") return;
27871
27872             if (!props.ccTLD && props.iso1A2) {
27873               props.ccTLD = "." + props.iso1A2.toLowerCase();
27874             }
27875           }
27876
27877           function loadIsoStatus(feature2) {
27878             var props = feature2.properties;
27879
27880             if (!props.isoStatus && props.iso1A2) {
27881               props.isoStatus = "official";
27882             }
27883           }
27884
27885           function loadLevel(feature2) {
27886             var props = feature2.properties;
27887             if (props.level) return;
27888
27889             if (!props.country) {
27890               props.level = "country";
27891             } else if (!props.iso1A2 || props.isoStatus === "official") {
27892               props.level = "territory";
27893             } else {
27894               props.level = "subterritory";
27895             }
27896           }
27897
27898           function loadGroupGroups(feature2) {
27899             var props = feature2.properties;
27900             if (feature2.geometry || !props.members) return;
27901             var featureLevelIndex = levels.indexOf(props.level);
27902             var sharedGroups = [];
27903
27904             var _loop = function _loop(_i4) {
27905               var memberID = props.members[_i4];
27906               var member = featuresByCode[memberID];
27907               var memberGroups = member.properties.groups.filter(function (groupID) {
27908                 return groupID !== feature2.properties.id && featureLevelIndex < levels.indexOf(featuresByCode[groupID].properties.level);
27909               });
27910
27911               if (_i4 === "0") {
27912                 sharedGroups = memberGroups;
27913               } else {
27914                 sharedGroups = sharedGroups.filter(function (groupID) {
27915                   return memberGroups.indexOf(groupID) !== -1;
27916                 });
27917               }
27918             };
27919
27920             for (var _i4 in props.members) {
27921               _loop(_i4);
27922             }
27923
27924             props.groups = props.groups.concat(sharedGroups.filter(function (groupID) {
27925               return props.groups.indexOf(groupID) === -1;
27926             }));
27927
27928             for (var j in sharedGroups) {
27929               var groupFeature = featuresByCode[sharedGroups[j]];
27930
27931               if (groupFeature.properties.members.indexOf(props.id) === -1) {
27932                 groupFeature.properties.members.push(props.id);
27933               }
27934             }
27935           }
27936
27937           function loadRoadSpeedUnit(feature2) {
27938             var props = feature2.properties;
27939
27940             if (feature2.geometry) {
27941               if (!props.roadSpeedUnit) props.roadSpeedUnit = "km/h";
27942             } else if (props.members) {
27943               var vals = Array.from(new Set(props.members.map(function (id) {
27944                 var member = featuresByCode[id];
27945                 if (member.geometry) return member.properties.roadSpeedUnit || "km/h";
27946               }).filter(Boolean)));
27947               if (vals.length === 1) props.roadSpeedUnit = vals[0];
27948             }
27949           }
27950
27951           function loadRoadHeightUnit(feature2) {
27952             var props = feature2.properties;
27953
27954             if (feature2.geometry) {
27955               if (!props.roadHeightUnit) props.roadHeightUnit = "m";
27956             } else if (props.members) {
27957               var vals = Array.from(new Set(props.members.map(function (id) {
27958                 var member = featuresByCode[id];
27959                 if (member.geometry) return member.properties.roadHeightUnit || "m";
27960               }).filter(Boolean)));
27961               if (vals.length === 1) props.roadHeightUnit = vals[0];
27962             }
27963           }
27964
27965           function loadDriveSide(feature2) {
27966             var props = feature2.properties;
27967
27968             if (feature2.geometry) {
27969               if (!props.driveSide) props.driveSide = "right";
27970             } else if (props.members) {
27971               var vals = Array.from(new Set(props.members.map(function (id) {
27972                 var member = featuresByCode[id];
27973                 if (member.geometry) return member.properties.driveSide || "right";
27974               }).filter(Boolean)));
27975               if (vals.length === 1) props.driveSide = vals[0];
27976             }
27977           }
27978
27979           function loadCallingCodes(feature2) {
27980             var props = feature2.properties;
27981
27982             if (!feature2.geometry && props.members) {
27983               props.callingCodes = Array.from(new Set(props.members.reduce(function (array, id) {
27984                 var member = featuresByCode[id];
27985                 if (member.geometry && member.properties.callingCodes) return array.concat(member.properties.callingCodes);
27986                 return array;
27987               }, [])));
27988             }
27989           }
27990
27991           function loadFlag(feature2) {
27992             if (!feature2.properties.iso1A2) return;
27993             var flag = feature2.properties.iso1A2.replace(/./g, function (_char) {
27994               return String.fromCodePoint(_char.charCodeAt(0) + 127397);
27995             });
27996             feature2.properties.emojiFlag = flag;
27997           }
27998
27999           function loadMembersForGroupsOf(feature2) {
28000             for (var j in feature2.properties.groups) {
28001               var groupID = feature2.properties.groups[j];
28002               var groupFeature = featuresByCode[groupID];
28003               if (!groupFeature.properties.members) groupFeature.properties.members = [];
28004               groupFeature.properties.members.push(feature2.properties.id);
28005             }
28006           }
28007
28008           function cacheFeatureByIDs(feature2) {
28009             var ids = [];
28010
28011             for (var k in identifierProps) {
28012               var prop = identifierProps[k];
28013               var id = feature2.properties[prop];
28014               if (id) ids.push(id);
28015             }
28016
28017             if (feature2.properties.aliases) {
28018               for (var j in feature2.properties.aliases) {
28019                 ids.push(feature2.properties.aliases[j]);
28020               }
28021             }
28022
28023             for (var _i5 in ids) {
28024               var _id = canonicalID(ids[_i5]);
28025
28026               featuresByCode[_id] = feature2;
28027             }
28028           }
28029         }
28030
28031         function locArray(loc) {
28032           if (Array.isArray(loc)) {
28033             return loc;
28034           } else if (loc.coordinates) {
28035             return loc.coordinates;
28036           }
28037
28038           return loc.geometry.coordinates;
28039         }
28040
28041         function smallestFeature(loc) {
28042           var query = locArray(loc);
28043           var featureProperties = whichPolygonGetter(query);
28044           if (!featureProperties) return null;
28045           return featuresByCode[featureProperties.id];
28046         }
28047
28048         function countryFeature(loc) {
28049           var feature2 = smallestFeature(loc);
28050           if (!feature2) return null;
28051           var countryCode = feature2.properties.country || feature2.properties.iso1A2;
28052           return featuresByCode[countryCode] || null;
28053         }
28054
28055         var defaultOpts = {
28056           level: void 0,
28057           maxLevel: void 0,
28058           withProp: void 0
28059         };
28060
28061         function featureForLoc(loc, opts) {
28062           var targetLevel = opts.level || "country";
28063           var maxLevel = opts.maxLevel || "world";
28064           var withProp = opts.withProp;
28065           var targetLevelIndex = levels.indexOf(targetLevel);
28066           if (targetLevelIndex === -1) return null;
28067           var maxLevelIndex = levels.indexOf(maxLevel);
28068           if (maxLevelIndex === -1) return null;
28069           if (maxLevelIndex < targetLevelIndex) return null;
28070
28071           if (targetLevel === "country") {
28072             var fastFeature = countryFeature(loc);
28073
28074             if (fastFeature) {
28075               if (!withProp || fastFeature.properties[withProp]) {
28076                 return fastFeature;
28077               }
28078             }
28079           }
28080
28081           var features2 = featuresContaining(loc);
28082
28083           for (var i in features2) {
28084             var feature2 = features2[i];
28085             var levelIndex = levels.indexOf(feature2.properties.level);
28086
28087             if (feature2.properties.level === targetLevel || levelIndex > targetLevelIndex && levelIndex <= maxLevelIndex) {
28088               if (!withProp || feature2.properties[withProp]) {
28089                 return feature2;
28090               }
28091             }
28092           }
28093
28094           return null;
28095         }
28096
28097         function featureForID(id) {
28098           var stringID;
28099
28100           if (typeof id === "number") {
28101             stringID = id.toString();
28102
28103             if (stringID.length === 1) {
28104               stringID = "00" + stringID;
28105             } else if (stringID.length === 2) {
28106               stringID = "0" + stringID;
28107             }
28108           } else {
28109             stringID = canonicalID(id);
28110           }
28111
28112           return featuresByCode[stringID] || null;
28113         }
28114
28115         function smallestFeaturesForBbox(bbox) {
28116           return whichPolygonGetter.bbox(bbox).map(function (props) {
28117             return featuresByCode[props.id];
28118           });
28119         }
28120
28121         function smallestOrMatchingFeature(query) {
28122           if (_typeof(query) === "object") {
28123             return smallestFeature(query);
28124           }
28125
28126           return featureForID(query);
28127         }
28128
28129         function feature$1(query) {
28130           var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts;
28131
28132           if (_typeof(query) === "object") {
28133             return featureForLoc(query, opts);
28134           }
28135
28136           return featureForID(query);
28137         }
28138
28139         function iso1A2Code(query) {
28140           var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts;
28141           opts.withProp = "iso1A2";
28142           var match = feature$1(query, opts);
28143           if (!match) return null;
28144           return match.properties.iso1A2 || null;
28145         }
28146
28147         function featuresContaining(query, strict) {
28148           var matchingFeatures;
28149
28150           if (Array.isArray(query) && query.length === 4) {
28151             matchingFeatures = smallestFeaturesForBbox(query);
28152           } else {
28153             var smallestOrMatching = smallestOrMatchingFeature(query);
28154             matchingFeatures = smallestOrMatching ? [smallestOrMatching] : [];
28155           }
28156
28157           if (!matchingFeatures.length) return [];
28158           var returnFeatures;
28159
28160           if (!strict || _typeof(query) === "object") {
28161             returnFeatures = matchingFeatures.slice();
28162           } else {
28163             returnFeatures = [];
28164           }
28165
28166           for (var j in matchingFeatures) {
28167             var properties = matchingFeatures[j].properties;
28168
28169             for (var i in properties.groups) {
28170               var groupID = properties.groups[i];
28171               var groupFeature = featuresByCode[groupID];
28172
28173               if (returnFeatures.indexOf(groupFeature) === -1) {
28174                 returnFeatures.push(groupFeature);
28175               }
28176             }
28177           }
28178
28179           return returnFeatures;
28180         }
28181
28182         function featuresIn(id, strict) {
28183           var feature2 = featureForID(id);
28184           if (!feature2) return [];
28185           var features2 = [];
28186
28187           if (!strict) {
28188             features2.push(feature2);
28189           }
28190
28191           var properties = feature2.properties;
28192
28193           if (properties.members) {
28194             for (var i in properties.members) {
28195               var memberID = properties.members[i];
28196               features2.push(featuresByCode[memberID]);
28197             }
28198           }
28199
28200           return features2;
28201         }
28202
28203         function aggregateFeature(id) {
28204           var features2 = featuresIn(id, false);
28205           if (features2.length === 0) return null;
28206           var aggregateCoordinates = [];
28207
28208           for (var i in features2) {
28209             var feature2 = features2[i];
28210
28211             if (feature2.geometry && feature2.geometry.type === "MultiPolygon" && feature2.geometry.coordinates) {
28212               aggregateCoordinates = aggregateCoordinates.concat(feature2.geometry.coordinates);
28213             }
28214           }
28215
28216           return {
28217             type: "Feature",
28218             properties: features2[0].properties,
28219             geometry: {
28220               type: "MultiPolygon",
28221               coordinates: aggregateCoordinates
28222             }
28223           };
28224         }
28225
28226         function roadSpeedUnit(query) {
28227           var feature2 = smallestOrMatchingFeature(query);
28228           return feature2 && feature2.properties.roadSpeedUnit || null;
28229         }
28230
28231         function roadHeightUnit(query) {
28232           var feature2 = smallestOrMatchingFeature(query);
28233           return feature2 && feature2.properties.roadHeightUnit || null;
28234         }
28235
28236         var geojsonArea = {};
28237
28238         var wgs84$1 = {};
28239
28240         wgs84$1.RADIUS = 6378137;
28241         wgs84$1.FLATTENING = 1 / 298.257223563;
28242         wgs84$1.POLAR_RADIUS = 6356752.3142;
28243
28244         var wgs84 = wgs84$1;
28245         geojsonArea.geometry = geometry;
28246         geojsonArea.ring = ringArea;
28247
28248         function geometry(_) {
28249           var area = 0,
28250               i;
28251
28252           switch (_.type) {
28253             case 'Polygon':
28254               return polygonArea(_.coordinates);
28255
28256             case 'MultiPolygon':
28257               for (i = 0; i < _.coordinates.length; i++) {
28258                 area += polygonArea(_.coordinates[i]);
28259               }
28260
28261               return area;
28262
28263             case 'Point':
28264             case 'MultiPoint':
28265             case 'LineString':
28266             case 'MultiLineString':
28267               return 0;
28268
28269             case 'GeometryCollection':
28270               for (i = 0; i < _.geometries.length; i++) {
28271                 area += geometry(_.geometries[i]);
28272               }
28273
28274               return area;
28275           }
28276         }
28277
28278         function polygonArea(coords) {
28279           var area = 0;
28280
28281           if (coords && coords.length > 0) {
28282             area += Math.abs(ringArea(coords[0]));
28283
28284             for (var i = 1; i < coords.length; i++) {
28285               area -= Math.abs(ringArea(coords[i]));
28286             }
28287           }
28288
28289           return area;
28290         }
28291         /**
28292          * Calculate the approximate area of the polygon were it projected onto
28293          *     the earth.  Note that this area will be positive if ring is oriented
28294          *     clockwise, otherwise it will be negative.
28295          *
28296          * Reference:
28297          * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
28298          *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
28299          *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
28300          *
28301          * Returns:
28302          * {float} The approximate signed geodesic area of the polygon in square
28303          *     meters.
28304          */
28305
28306
28307         function ringArea(coords) {
28308           var p1,
28309               p2,
28310               p3,
28311               lowerIndex,
28312               middleIndex,
28313               upperIndex,
28314               i,
28315               area = 0,
28316               coordsLength = coords.length;
28317
28318           if (coordsLength > 2) {
28319             for (i = 0; i < coordsLength; i++) {
28320               if (i === coordsLength - 2) {
28321                 // i = N-2
28322                 lowerIndex = coordsLength - 2;
28323                 middleIndex = coordsLength - 1;
28324                 upperIndex = 0;
28325               } else if (i === coordsLength - 1) {
28326                 // i = N-1
28327                 lowerIndex = coordsLength - 1;
28328                 middleIndex = 0;
28329                 upperIndex = 1;
28330               } else {
28331                 // i = 0 to N-3
28332                 lowerIndex = i;
28333                 middleIndex = i + 1;
28334                 upperIndex = i + 2;
28335               }
28336
28337               p1 = coords[lowerIndex];
28338               p2 = coords[middleIndex];
28339               p3 = coords[upperIndex];
28340               area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
28341             }
28342
28343             area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
28344           }
28345
28346           return area;
28347         }
28348
28349         function rad(_) {
28350           return _ * Math.PI / 180;
28351         }
28352
28353         var inputValidation = {};
28354
28355         var $$g = _export;
28356         var $includes = arrayIncludes.includes;
28357         var addToUnscopables$1 = addToUnscopables$5;
28358
28359         // `Array.prototype.includes` method
28360         // https://tc39.es/ecma262/#sec-array.prototype.includes
28361         $$g({ target: 'Array', proto: true }, {
28362           includes: function includes(el /* , fromIndex = 0 */) {
28363             return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
28364           }
28365         });
28366
28367         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
28368         addToUnscopables$1('includes');
28369
28370         var validateCenter$1 = {};
28371
28372         validateCenter$1.validateCenter = function validateCenter(center) {
28373           var validCenterLengths = [2, 3];
28374
28375           if (!Array.isArray(center) || !validCenterLengths.includes(center.length)) {
28376             throw new Error("ERROR! Center has to be an array of length two or three");
28377           }
28378
28379           var _center = _slicedToArray(center, 2),
28380               lng = _center[0],
28381               lat = _center[1];
28382
28383           if (typeof lng !== "number" || typeof lat !== "number") {
28384             throw new Error("ERROR! Longitude and Latitude has to be numbers but where ".concat(_typeof(lng), " and ").concat(_typeof(lat)));
28385           }
28386
28387           if (lng > 180 || lng < -180) {
28388             throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
28389           }
28390
28391           if (lat > 90 || lat < -90) {
28392             throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
28393           }
28394         };
28395
28396         var validateRadius$1 = {};
28397
28398         validateRadius$1.validateRadius = function validateRadius(radius) {
28399           if (typeof radius !== "number") {
28400             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(_typeof(radius)));
28401           }
28402
28403           if (radius <= 0) {
28404             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
28405           }
28406         };
28407
28408         var validateNumberOfEdges$1 = {};
28409
28410         validateNumberOfEdges$1.validateNumberOfEdges = function validateNumberOfEdges(numberOfEdges) {
28411           if (typeof numberOfEdges !== "number") {
28412             var ARGUMENT_TYPE = Array.isArray(numberOfEdges) ? "array" : _typeof(numberOfEdges);
28413             throw new Error("ERROR! Number of edges has to be a number but was: ".concat(ARGUMENT_TYPE));
28414           }
28415
28416           if (numberOfEdges < 3) {
28417             throw new Error("ERROR! Number of edges has to be at least 3 but was: ".concat(numberOfEdges));
28418           }
28419         };
28420
28421         var validateEarthRadius$1 = {};
28422
28423         validateEarthRadius$1.validateEarthRadius = function validateEarthRadius(earthRadius) {
28424           if (typeof earthRadius !== "number") {
28425             var ARGUMENT_TYPE = Array.isArray(earthRadius) ? "array" : _typeof(earthRadius);
28426             throw new Error("ERROR! Earth radius has to be a number but was: ".concat(ARGUMENT_TYPE));
28427           }
28428
28429           if (earthRadius <= 0) {
28430             throw new Error("ERROR! Earth radius has to be a positive number but was: ".concat(earthRadius));
28431           }
28432         };
28433
28434         var validateBearing$1 = {};
28435
28436         validateBearing$1.validateBearing = function validateBearing(bearing) {
28437           if (typeof bearing !== "number") {
28438             var ARGUMENT_TYPE = Array.isArray(bearing) ? "array" : _typeof(bearing);
28439             throw new Error("ERROR! Bearing has to be a number but was: ".concat(ARGUMENT_TYPE));
28440           }
28441         };
28442
28443         var validateCenter = validateCenter$1.validateCenter;
28444         var validateRadius = validateRadius$1.validateRadius;
28445         var validateNumberOfEdges = validateNumberOfEdges$1.validateNumberOfEdges;
28446         var validateEarthRadius = validateEarthRadius$1.validateEarthRadius;
28447         var validateBearing = validateBearing$1.validateBearing;
28448
28449         function validateInput$1(_ref) {
28450           var center = _ref.center,
28451               radius = _ref.radius,
28452               numberOfEdges = _ref.numberOfEdges,
28453               earthRadius = _ref.earthRadius,
28454               bearing = _ref.bearing;
28455           validateCenter(center);
28456           validateRadius(radius);
28457           validateNumberOfEdges(numberOfEdges);
28458           validateEarthRadius(earthRadius);
28459           validateBearing(bearing);
28460         }
28461
28462         inputValidation.validateCenter = validateCenter;
28463         inputValidation.validateRadius = validateRadius;
28464         inputValidation.validateNumberOfEdges = validateNumberOfEdges;
28465         inputValidation.validateEarthRadius = validateEarthRadius;
28466         inputValidation.validateBearing = validateBearing;
28467         inputValidation.validateInput = validateInput$1;
28468
28469         var validateInput = inputValidation.validateInput;
28470         var defaultEarthRadius = 6378137; // equatorial Earth radius
28471
28472         function toRadians(angleInDegrees) {
28473           return angleInDegrees * Math.PI / 180;
28474         }
28475
28476         function toDegrees(angleInRadians) {
28477           return angleInRadians * 180 / Math.PI;
28478         }
28479
28480         function offset(c1, distance, earthRadius, bearing) {
28481           var lat1 = toRadians(c1[1]);
28482           var lon1 = toRadians(c1[0]);
28483           var dByR = distance / earthRadius;
28484           var lat = Math.asin(Math.sin(lat1) * Math.cos(dByR) + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
28485           var lon = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
28486           return [toDegrees(lon), toDegrees(lat)];
28487         }
28488
28489         var circleToPolygon = function circleToPolygon(center, radius, options) {
28490           var n = getNumberOfEdges(options);
28491           var earthRadius = getEarthRadius(options);
28492           var bearing = getBearing(options);
28493           var direction = getDirection(options); // validateInput() throws error on invalid input and do nothing on valid input
28494
28495           validateInput({
28496             center: center,
28497             radius: radius,
28498             numberOfEdges: n,
28499             earthRadius: earthRadius,
28500             bearing: bearing
28501           });
28502           var start = toRadians(bearing);
28503           var coordinates = [];
28504
28505           for (var i = 0; i < n; ++i) {
28506             coordinates.push(offset(center, radius, earthRadius, start + direction * 2 * Math.PI * -i / n));
28507           }
28508
28509           coordinates.push(coordinates[0]);
28510           return {
28511             type: "Polygon",
28512             coordinates: [coordinates]
28513           };
28514         };
28515
28516         function getNumberOfEdges(options) {
28517           if (isUndefinedOrNull(options)) {
28518             return 32;
28519           } else if (isObjectNotArray(options)) {
28520             var numberOfEdges = options.numberOfEdges;
28521             return numberOfEdges === undefined ? 32 : numberOfEdges;
28522           }
28523
28524           return options;
28525         }
28526
28527         function getEarthRadius(options) {
28528           if (isUndefinedOrNull(options)) {
28529             return defaultEarthRadius;
28530           } else if (isObjectNotArray(options)) {
28531             var earthRadius = options.earthRadius;
28532             return earthRadius === undefined ? defaultEarthRadius : earthRadius;
28533           }
28534
28535           return defaultEarthRadius;
28536         }
28537
28538         function getDirection(options) {
28539           if (isObjectNotArray(options) && options.rightHandRule) {
28540             return -1;
28541           }
28542
28543           return 1;
28544         }
28545
28546         function getBearing(options) {
28547           if (isUndefinedOrNull(options)) {
28548             return 0;
28549           } else if (isObjectNotArray(options)) {
28550             var bearing = options.bearing;
28551             return bearing === undefined ? 0 : bearing;
28552           }
28553
28554           return 0;
28555         }
28556
28557         function isObjectNotArray(argument) {
28558           return argument !== null && _typeof(argument) === "object" && !Array.isArray(argument);
28559         }
28560
28561         function isUndefinedOrNull(argument) {
28562           return argument === null || argument === undefined;
28563         }
28564
28565         var $$f = _export;
28566
28567         // `Number.EPSILON` constant
28568         // https://tc39.es/ecma262/#sec-number.epsilon
28569         $$f({ target: 'Number', stat: true }, {
28570           EPSILON: Math.pow(2, -52)
28571         });
28572
28573         var requireObjectCoercible$4 = requireObjectCoercible$e;
28574
28575         var quot = /"/g;
28576
28577         // `CreateHTML` abstract operation
28578         // https://tc39.es/ecma262/#sec-createhtml
28579         var createHtml = function (string, tag, attribute, value) {
28580           var S = String(requireObjectCoercible$4(string));
28581           var p1 = '<' + tag;
28582           if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
28583           return p1 + '>' + S + '</' + tag + '>';
28584         };
28585
28586         var fails$6 = fails$N;
28587
28588         // check the existence of a method, lowercase
28589         // of a tag and escaping quotes in arguments
28590         var stringHtmlForced = function (METHOD_NAME) {
28591           return fails$6(function () {
28592             var test = ''[METHOD_NAME]('"');
28593             return test !== test.toLowerCase() || test.split('"').length > 3;
28594           });
28595         };
28596
28597         var $$e = _export;
28598         var createHTML = createHtml;
28599         var forcedStringHTMLMethod = stringHtmlForced;
28600
28601         // `String.prototype.link` method
28602         // https://tc39.es/ecma262/#sec-string.prototype.link
28603         $$e({ target: 'String', proto: true, forced: forcedStringHTMLMethod('link') }, {
28604           link: function link(url) {
28605             return createHTML(this, 'a', 'href', url);
28606           }
28607         });
28608
28609         /**
28610          * splaytree v3.1.0
28611          * Fast Splay tree for Node and browser
28612          *
28613          * @author Alexander Milevski <info@w8r.name>
28614          * @license MIT
28615          * @preserve
28616          */
28617         var Node =
28618         /** @class */
28619         function () {
28620           function Node(key, data) {
28621             this.next = null;
28622             this.key = key;
28623             this.data = data;
28624             this.left = null;
28625             this.right = null;
28626           }
28627
28628           return Node;
28629         }();
28630         /* follows "An implementation of top-down splaying"
28631          * by D. Sleator <sleator@cs.cmu.edu> March 1992
28632          */
28633
28634
28635         function DEFAULT_COMPARE(a, b) {
28636           return a > b ? 1 : a < b ? -1 : 0;
28637         }
28638         /**
28639          * Simple top down splay, not requiring i to be in the tree t.
28640          */
28641
28642
28643         function splay(i, t, comparator) {
28644           var N = new Node(null, null);
28645           var l = N;
28646           var r = N;
28647
28648           while (true) {
28649             var cmp = comparator(i, t.key); //if (i < t.key) {
28650
28651             if (cmp < 0) {
28652               if (t.left === null) break; //if (i < t.left.key) {
28653
28654               if (comparator(i, t.left.key) < 0) {
28655                 var y = t.left;
28656                 /* rotate right */
28657
28658                 t.left = y.right;
28659                 y.right = t;
28660                 t = y;
28661                 if (t.left === null) break;
28662               }
28663
28664               r.left = t;
28665               /* link right */
28666
28667               r = t;
28668               t = t.left; //} else if (i > t.key) {
28669             } else if (cmp > 0) {
28670               if (t.right === null) break; //if (i > t.right.key) {
28671
28672               if (comparator(i, t.right.key) > 0) {
28673                 var y = t.right;
28674                 /* rotate left */
28675
28676                 t.right = y.left;
28677                 y.left = t;
28678                 t = y;
28679                 if (t.right === null) break;
28680               }
28681
28682               l.right = t;
28683               /* link left */
28684
28685               l = t;
28686               t = t.right;
28687             } else break;
28688           }
28689           /* assemble */
28690
28691
28692           l.right = t.left;
28693           r.left = t.right;
28694           t.left = N.right;
28695           t.right = N.left;
28696           return t;
28697         }
28698
28699         function insert(i, data, t, comparator) {
28700           var node = new Node(i, data);
28701
28702           if (t === null) {
28703             node.left = node.right = null;
28704             return node;
28705           }
28706
28707           t = splay(i, t, comparator);
28708           var cmp = comparator(i, t.key);
28709
28710           if (cmp < 0) {
28711             node.left = t.left;
28712             node.right = t;
28713             t.left = null;
28714           } else if (cmp >= 0) {
28715             node.right = t.right;
28716             node.left = t;
28717             t.right = null;
28718           }
28719
28720           return node;
28721         }
28722
28723         function split(key, v, comparator) {
28724           var left = null;
28725           var right = null;
28726
28727           if (v) {
28728             v = splay(key, v, comparator);
28729             var cmp = comparator(v.key, key);
28730
28731             if (cmp === 0) {
28732               left = v.left;
28733               right = v.right;
28734             } else if (cmp < 0) {
28735               right = v.right;
28736               v.right = null;
28737               left = v;
28738             } else {
28739               left = v.left;
28740               v.left = null;
28741               right = v;
28742             }
28743           }
28744
28745           return {
28746             left: left,
28747             right: right
28748           };
28749         }
28750
28751         function merge$3(left, right, comparator) {
28752           if (right === null) return left;
28753           if (left === null) return right;
28754           right = splay(left.key, right, comparator);
28755           right.left = left;
28756           return right;
28757         }
28758         /**
28759          * Prints level of the tree
28760          */
28761
28762
28763         function printRow(root, prefix, isTail, out, printNode) {
28764           if (root) {
28765             out("" + prefix + (isTail ? '└── ' : '├── ') + printNode(root) + "\n");
28766             var indent = prefix + (isTail ? '    ' : '│   ');
28767             if (root.left) printRow(root.left, indent, false, out, printNode);
28768             if (root.right) printRow(root.right, indent, true, out, printNode);
28769           }
28770         }
28771
28772         var Tree =
28773         /** @class */
28774         function () {
28775           function Tree(comparator) {
28776             if (comparator === void 0) {
28777               comparator = DEFAULT_COMPARE;
28778             }
28779
28780             this._root = null;
28781             this._size = 0;
28782             this._comparator = comparator;
28783           }
28784           /**
28785            * Inserts a key, allows duplicates
28786            */
28787
28788
28789           Tree.prototype.insert = function (key, data) {
28790             this._size++;
28791             return this._root = insert(key, data, this._root, this._comparator);
28792           };
28793           /**
28794            * Adds a key, if it is not present in the tree
28795            */
28796
28797
28798           Tree.prototype.add = function (key, data) {
28799             var node = new Node(key, data);
28800
28801             if (this._root === null) {
28802               node.left = node.right = null;
28803               this._size++;
28804               this._root = node;
28805             }
28806
28807             var comparator = this._comparator;
28808             var t = splay(key, this._root, comparator);
28809             var cmp = comparator(key, t.key);
28810             if (cmp === 0) this._root = t;else {
28811               if (cmp < 0) {
28812                 node.left = t.left;
28813                 node.right = t;
28814                 t.left = null;
28815               } else if (cmp > 0) {
28816                 node.right = t.right;
28817                 node.left = t;
28818                 t.right = null;
28819               }
28820
28821               this._size++;
28822               this._root = node;
28823             }
28824             return this._root;
28825           };
28826           /**
28827            * @param  {Key} key
28828            * @return {Node|null}
28829            */
28830
28831
28832           Tree.prototype.remove = function (key) {
28833             this._root = this._remove(key, this._root, this._comparator);
28834           };
28835           /**
28836            * Deletes i from the tree if it's there
28837            */
28838
28839
28840           Tree.prototype._remove = function (i, t, comparator) {
28841             var x;
28842             if (t === null) return null;
28843             t = splay(i, t, comparator);
28844             var cmp = comparator(i, t.key);
28845
28846             if (cmp === 0) {
28847               /* found it */
28848               if (t.left === null) {
28849                 x = t.right;
28850               } else {
28851                 x = splay(i, t.left, comparator);
28852                 x.right = t.right;
28853               }
28854
28855               this._size--;
28856               return x;
28857             }
28858
28859             return t;
28860             /* It wasn't there */
28861           };
28862           /**
28863            * Removes and returns the node with smallest key
28864            */
28865
28866
28867           Tree.prototype.pop = function () {
28868             var node = this._root;
28869
28870             if (node) {
28871               while (node.left) {
28872                 node = node.left;
28873               }
28874
28875               this._root = splay(node.key, this._root, this._comparator);
28876               this._root = this._remove(node.key, this._root, this._comparator);
28877               return {
28878                 key: node.key,
28879                 data: node.data
28880               };
28881             }
28882
28883             return null;
28884           };
28885           /**
28886            * Find without splaying
28887            */
28888
28889
28890           Tree.prototype.findStatic = function (key) {
28891             var current = this._root;
28892             var compare = this._comparator;
28893
28894             while (current) {
28895               var cmp = compare(key, current.key);
28896               if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
28897             }
28898
28899             return null;
28900           };
28901
28902           Tree.prototype.find = function (key) {
28903             if (this._root) {
28904               this._root = splay(key, this._root, this._comparator);
28905               if (this._comparator(key, this._root.key) !== 0) return null;
28906             }
28907
28908             return this._root;
28909           };
28910
28911           Tree.prototype.contains = function (key) {
28912             var current = this._root;
28913             var compare = this._comparator;
28914
28915             while (current) {
28916               var cmp = compare(key, current.key);
28917               if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
28918             }
28919
28920             return false;
28921           };
28922
28923           Tree.prototype.forEach = function (visitor, ctx) {
28924             var current = this._root;
28925             var Q = [];
28926             /* Initialize stack s */
28927
28928             var done = false;
28929
28930             while (!done) {
28931               if (current !== null) {
28932                 Q.push(current);
28933                 current = current.left;
28934               } else {
28935                 if (Q.length !== 0) {
28936                   current = Q.pop();
28937                   visitor.call(ctx, current);
28938                   current = current.right;
28939                 } else done = true;
28940               }
28941             }
28942
28943             return this;
28944           };
28945           /**
28946            * Walk key range from `low` to `high`. Stops if `fn` returns a value.
28947            */
28948
28949
28950           Tree.prototype.range = function (low, high, fn, ctx) {
28951             var Q = [];
28952             var compare = this._comparator;
28953             var node = this._root;
28954             var cmp;
28955
28956             while (Q.length !== 0 || node) {
28957               if (node) {
28958                 Q.push(node);
28959                 node = node.left;
28960               } else {
28961                 node = Q.pop();
28962                 cmp = compare(node.key, high);
28963
28964                 if (cmp > 0) {
28965                   break;
28966                 } else if (compare(node.key, low) >= 0) {
28967                   if (fn.call(ctx, node)) return this; // stop if smth is returned
28968                 }
28969
28970                 node = node.right;
28971               }
28972             }
28973
28974             return this;
28975           };
28976           /**
28977            * Returns array of keys
28978            */
28979
28980
28981           Tree.prototype.keys = function () {
28982             var keys = [];
28983             this.forEach(function (_a) {
28984               var key = _a.key;
28985               return keys.push(key);
28986             });
28987             return keys;
28988           };
28989           /**
28990            * Returns array of all the data in the nodes
28991            */
28992
28993
28994           Tree.prototype.values = function () {
28995             var values = [];
28996             this.forEach(function (_a) {
28997               var data = _a.data;
28998               return values.push(data);
28999             });
29000             return values;
29001           };
29002
29003           Tree.prototype.min = function () {
29004             if (this._root) return this.minNode(this._root).key;
29005             return null;
29006           };
29007
29008           Tree.prototype.max = function () {
29009             if (this._root) return this.maxNode(this._root).key;
29010             return null;
29011           };
29012
29013           Tree.prototype.minNode = function (t) {
29014             if (t === void 0) {
29015               t = this._root;
29016             }
29017
29018             if (t) while (t.left) {
29019               t = t.left;
29020             }
29021             return t;
29022           };
29023
29024           Tree.prototype.maxNode = function (t) {
29025             if (t === void 0) {
29026               t = this._root;
29027             }
29028
29029             if (t) while (t.right) {
29030               t = t.right;
29031             }
29032             return t;
29033           };
29034           /**
29035            * Returns node at given index
29036            */
29037
29038
29039           Tree.prototype.at = function (index) {
29040             var current = this._root;
29041             var done = false;
29042             var i = 0;
29043             var Q = [];
29044
29045             while (!done) {
29046               if (current) {
29047                 Q.push(current);
29048                 current = current.left;
29049               } else {
29050                 if (Q.length > 0) {
29051                   current = Q.pop();
29052                   if (i === index) return current;
29053                   i++;
29054                   current = current.right;
29055                 } else done = true;
29056               }
29057             }
29058
29059             return null;
29060           };
29061
29062           Tree.prototype.next = function (d) {
29063             var root = this._root;
29064             var successor = null;
29065
29066             if (d.right) {
29067               successor = d.right;
29068
29069               while (successor.left) {
29070                 successor = successor.left;
29071               }
29072
29073               return successor;
29074             }
29075
29076             var comparator = this._comparator;
29077
29078             while (root) {
29079               var cmp = comparator(d.key, root.key);
29080               if (cmp === 0) break;else if (cmp < 0) {
29081                 successor = root;
29082                 root = root.left;
29083               } else root = root.right;
29084             }
29085
29086             return successor;
29087           };
29088
29089           Tree.prototype.prev = function (d) {
29090             var root = this._root;
29091             var predecessor = null;
29092
29093             if (d.left !== null) {
29094               predecessor = d.left;
29095
29096               while (predecessor.right) {
29097                 predecessor = predecessor.right;
29098               }
29099
29100               return predecessor;
29101             }
29102
29103             var comparator = this._comparator;
29104
29105             while (root) {
29106               var cmp = comparator(d.key, root.key);
29107               if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
29108                 predecessor = root;
29109                 root = root.right;
29110               }
29111             }
29112
29113             return predecessor;
29114           };
29115
29116           Tree.prototype.clear = function () {
29117             this._root = null;
29118             this._size = 0;
29119             return this;
29120           };
29121
29122           Tree.prototype.toList = function () {
29123             return toList(this._root);
29124           };
29125           /**
29126            * Bulk-load items. Both array have to be same size
29127            */
29128
29129
29130           Tree.prototype.load = function (keys, values, presort) {
29131             if (values === void 0) {
29132               values = [];
29133             }
29134
29135             if (presort === void 0) {
29136               presort = false;
29137             }
29138
29139             var size = keys.length;
29140             var comparator = this._comparator; // sort if needed
29141
29142             if (presort) sort(keys, values, 0, size - 1, comparator);
29143
29144             if (this._root === null) {
29145               // empty tree
29146               this._root = loadRecursive(keys, values, 0, size);
29147               this._size = size;
29148             } else {
29149               // that re-builds the whole tree from two in-order traversals
29150               var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
29151               size = this._size + size;
29152               this._root = sortedListToBST({
29153                 head: mergedList
29154               }, 0, size);
29155             }
29156
29157             return this;
29158           };
29159
29160           Tree.prototype.isEmpty = function () {
29161             return this._root === null;
29162           };
29163
29164           Object.defineProperty(Tree.prototype, "size", {
29165             get: function get() {
29166               return this._size;
29167             },
29168             enumerable: true,
29169             configurable: true
29170           });
29171           Object.defineProperty(Tree.prototype, "root", {
29172             get: function get() {
29173               return this._root;
29174             },
29175             enumerable: true,
29176             configurable: true
29177           });
29178
29179           Tree.prototype.toString = function (printNode) {
29180             if (printNode === void 0) {
29181               printNode = function printNode(n) {
29182                 return String(n.key);
29183               };
29184             }
29185
29186             var out = [];
29187             printRow(this._root, '', true, function (v) {
29188               return out.push(v);
29189             }, printNode);
29190             return out.join('');
29191           };
29192
29193           Tree.prototype.update = function (key, newKey, newData) {
29194             var comparator = this._comparator;
29195
29196             var _a = split(key, this._root, comparator),
29197                 left = _a.left,
29198                 right = _a.right;
29199
29200             if (comparator(key, newKey) < 0) {
29201               right = insert(newKey, newData, right, comparator);
29202             } else {
29203               left = insert(newKey, newData, left, comparator);
29204             }
29205
29206             this._root = merge$3(left, right, comparator);
29207           };
29208
29209           Tree.prototype.split = function (key) {
29210             return split(key, this._root, this._comparator);
29211           };
29212
29213           return Tree;
29214         }();
29215
29216         function loadRecursive(keys, values, start, end) {
29217           var size = end - start;
29218
29219           if (size > 0) {
29220             var middle = start + Math.floor(size / 2);
29221             var key = keys[middle];
29222             var data = values[middle];
29223             var node = new Node(key, data);
29224             node.left = loadRecursive(keys, values, start, middle);
29225             node.right = loadRecursive(keys, values, middle + 1, end);
29226             return node;
29227           }
29228
29229           return null;
29230         }
29231
29232         function createList(keys, values) {
29233           var head = new Node(null, null);
29234           var p = head;
29235
29236           for (var i = 0; i < keys.length; i++) {
29237             p = p.next = new Node(keys[i], values[i]);
29238           }
29239
29240           p.next = null;
29241           return head.next;
29242         }
29243
29244         function toList(root) {
29245           var current = root;
29246           var Q = [];
29247           var done = false;
29248           var head = new Node(null, null);
29249           var p = head;
29250
29251           while (!done) {
29252             if (current) {
29253               Q.push(current);
29254               current = current.left;
29255             } else {
29256               if (Q.length > 0) {
29257                 current = p = p.next = Q.pop();
29258                 current = current.right;
29259               } else done = true;
29260             }
29261           }
29262
29263           p.next = null; // that'll work even if the tree was empty
29264
29265           return head.next;
29266         }
29267
29268         function sortedListToBST(list, start, end) {
29269           var size = end - start;
29270
29271           if (size > 0) {
29272             var middle = start + Math.floor(size / 2);
29273             var left = sortedListToBST(list, start, middle);
29274             var root = list.head;
29275             root.left = left;
29276             list.head = list.head.next;
29277             root.right = sortedListToBST(list, middle + 1, end);
29278             return root;
29279           }
29280
29281           return null;
29282         }
29283
29284         function mergeLists(l1, l2, compare) {
29285           var head = new Node(null, null); // dummy
29286
29287           var p = head;
29288           var p1 = l1;
29289           var p2 = l2;
29290
29291           while (p1 !== null && p2 !== null) {
29292             if (compare(p1.key, p2.key) < 0) {
29293               p.next = p1;
29294               p1 = p1.next;
29295             } else {
29296               p.next = p2;
29297               p2 = p2.next;
29298             }
29299
29300             p = p.next;
29301           }
29302
29303           if (p1 !== null) {
29304             p.next = p1;
29305           } else if (p2 !== null) {
29306             p.next = p2;
29307           }
29308
29309           return head.next;
29310         }
29311
29312         function sort(keys, values, left, right, compare) {
29313           if (left >= right) return;
29314           var pivot = keys[left + right >> 1];
29315           var i = left - 1;
29316           var j = right + 1;
29317
29318           while (true) {
29319             do {
29320               i++;
29321             } while (compare(keys[i], pivot) < 0);
29322
29323             do {
29324               j--;
29325             } while (compare(keys[j], pivot) > 0);
29326
29327             if (i >= j) break;
29328             var tmp = keys[i];
29329             keys[i] = keys[j];
29330             keys[j] = tmp;
29331             tmp = values[i];
29332             values[i] = values[j];
29333             values[j] = tmp;
29334           }
29335
29336           sort(keys, values, left, j, compare);
29337           sort(keys, values, j + 1, right, compare);
29338         }
29339
29340         function _classCallCheck(instance, Constructor) {
29341           if (!(instance instanceof Constructor)) {
29342             throw new TypeError("Cannot call a class as a function");
29343           }
29344         }
29345
29346         function _defineProperties(target, props) {
29347           for (var i = 0; i < props.length; i++) {
29348             var descriptor = props[i];
29349             descriptor.enumerable = descriptor.enumerable || false;
29350             descriptor.configurable = true;
29351             if ("value" in descriptor) descriptor.writable = true;
29352             Object.defineProperty(target, descriptor.key, descriptor);
29353           }
29354         }
29355
29356         function _createClass(Constructor, protoProps, staticProps) {
29357           if (protoProps) _defineProperties(Constructor.prototype, protoProps);
29358           if (staticProps) _defineProperties(Constructor, staticProps);
29359           return Constructor;
29360         }
29361         /**
29362          * A bounding box has the format:
29363          *
29364          *  { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
29365          *
29366          */
29367
29368
29369         var isInBbox = function isInBbox(bbox, point) {
29370           return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
29371         };
29372         /* Returns either null, or a bbox (aka an ordered pair of points)
29373          * If there is only one point of overlap, a bbox with identical points
29374          * will be returned */
29375
29376
29377         var getBboxOverlap = function getBboxOverlap(b1, b2) {
29378           // check if the bboxes overlap at all
29379           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
29380
29381           var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
29382           var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
29383
29384           var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
29385           var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
29386
29387           return {
29388             ll: {
29389               x: lowerX,
29390               y: lowerY
29391             },
29392             ur: {
29393               x: upperX,
29394               y: upperY
29395             }
29396           };
29397         };
29398         /* Javascript doesn't do integer math. Everything is
29399          * floating point with percision Number.EPSILON.
29400          *
29401          * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
29402          */
29403
29404
29405         var epsilon = Number.EPSILON; // IE Polyfill
29406
29407         if (epsilon === undefined) epsilon = Math.pow(2, -52);
29408         var EPSILON_SQ = epsilon * epsilon;
29409         /* FLP comparator */
29410
29411         var cmp = function cmp(a, b) {
29412           // check if they're both 0
29413           if (-epsilon < a && a < epsilon) {
29414             if (-epsilon < b && b < epsilon) {
29415               return 0;
29416             }
29417           } // check if they're flp equal
29418
29419
29420           var ab = a - b;
29421
29422           if (ab * ab < EPSILON_SQ * a * b) {
29423             return 0;
29424           } // normal comparison
29425
29426
29427           return a < b ? -1 : 1;
29428         };
29429         /**
29430          * This class rounds incoming values sufficiently so that
29431          * floating points problems are, for the most part, avoided.
29432          *
29433          * Incoming points are have their x & y values tested against
29434          * all previously seen x & y values. If either is 'too close'
29435          * to a previously seen value, it's value is 'snapped' to the
29436          * previously seen value.
29437          *
29438          * All points should be rounded by this class before being
29439          * stored in any data structures in the rest of this algorithm.
29440          */
29441
29442
29443         var PtRounder = /*#__PURE__*/function () {
29444           function PtRounder() {
29445             _classCallCheck(this, PtRounder);
29446
29447             this.reset();
29448           }
29449
29450           _createClass(PtRounder, [{
29451             key: "reset",
29452             value: function reset() {
29453               this.xRounder = new CoordRounder();
29454               this.yRounder = new CoordRounder();
29455             }
29456           }, {
29457             key: "round",
29458             value: function round(x, y) {
29459               return {
29460                 x: this.xRounder.round(x),
29461                 y: this.yRounder.round(y)
29462               };
29463             }
29464           }]);
29465
29466           return PtRounder;
29467         }();
29468
29469         var CoordRounder = /*#__PURE__*/function () {
29470           function CoordRounder() {
29471             _classCallCheck(this, CoordRounder);
29472
29473             this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
29474
29475             this.round(0);
29476           } // Note: this can rounds input values backwards or forwards.
29477           //       You might ask, why not restrict this to just rounding
29478           //       forwards? Wouldn't that allow left endpoints to always
29479           //       remain left endpoints during splitting (never change to
29480           //       right). No - it wouldn't, because we snap intersections
29481           //       to endpoints (to establish independence from the segment
29482           //       angle for t-intersections).
29483
29484
29485           _createClass(CoordRounder, [{
29486             key: "round",
29487             value: function round(coord) {
29488               var node = this.tree.add(coord);
29489               var prevNode = this.tree.prev(node);
29490
29491               if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
29492                 this.tree.remove(coord);
29493                 return prevNode.key;
29494               }
29495
29496               var nextNode = this.tree.next(node);
29497
29498               if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
29499                 this.tree.remove(coord);
29500                 return nextNode.key;
29501               }
29502
29503               return coord;
29504             }
29505           }]);
29506
29507           return CoordRounder;
29508         }(); // singleton available by import
29509
29510
29511         var rounder = new PtRounder();
29512         /* Cross Product of two vectors with first point at origin */
29513
29514         var crossProduct = function crossProduct(a, b) {
29515           return a.x * b.y - a.y * b.x;
29516         };
29517         /* Dot Product of two vectors with first point at origin */
29518
29519
29520         var dotProduct = function dotProduct(a, b) {
29521           return a.x * b.x + a.y * b.y;
29522         };
29523         /* Comparator for two vectors with same starting point */
29524
29525
29526         var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
29527           var v1 = {
29528             x: endPt1.x - basePt.x,
29529             y: endPt1.y - basePt.y
29530           };
29531           var v2 = {
29532             x: endPt2.x - basePt.x,
29533             y: endPt2.y - basePt.y
29534           };
29535           var kross = crossProduct(v1, v2);
29536           return cmp(kross, 0);
29537         };
29538
29539         var length = function length(v) {
29540           return Math.sqrt(dotProduct(v, v));
29541         };
29542         /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
29543
29544
29545         var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
29546           var vBase = {
29547             x: pBase.x - pShared.x,
29548             y: pBase.y - pShared.y
29549           };
29550           var vAngle = {
29551             x: pAngle.x - pShared.x,
29552             y: pAngle.y - pShared.y
29553           };
29554           return crossProduct(vAngle, vBase) / length(vAngle) / length(vBase);
29555         };
29556         /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
29557
29558
29559         var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
29560           var vBase = {
29561             x: pBase.x - pShared.x,
29562             y: pBase.y - pShared.y
29563           };
29564           var vAngle = {
29565             x: pAngle.x - pShared.x,
29566             y: pAngle.y - pShared.y
29567           };
29568           return dotProduct(vAngle, vBase) / length(vAngle) / length(vBase);
29569         };
29570         /* Get the x coordinate where the given line (defined by a point and vector)
29571          * crosses the horizontal line with the given y coordiante.
29572          * In the case of parrallel lines (including overlapping ones) returns null. */
29573
29574
29575         var horizontalIntersection = function horizontalIntersection(pt, v, y) {
29576           if (v.y === 0) return null;
29577           return {
29578             x: pt.x + v.x / v.y * (y - pt.y),
29579             y: y
29580           };
29581         };
29582         /* Get the y coordinate where the given line (defined by a point and vector)
29583          * crosses the vertical line with the given x coordiante.
29584          * In the case of parrallel lines (including overlapping ones) returns null. */
29585
29586
29587         var verticalIntersection = function verticalIntersection(pt, v, x) {
29588           if (v.x === 0) return null;
29589           return {
29590             x: x,
29591             y: pt.y + v.y / v.x * (x - pt.x)
29592           };
29593         };
29594         /* Get the intersection of two lines, each defined by a base point and a vector.
29595          * In the case of parrallel lines (including overlapping ones) returns null. */
29596
29597
29598         var intersection = function intersection(pt1, v1, pt2, v2) {
29599           // take some shortcuts for vertical and horizontal lines
29600           // this also ensures we don't calculate an intersection and then discover
29601           // it's actually outside the bounding box of the line
29602           if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
29603           if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
29604           if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
29605           if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
29606           // This algorithm is based on Schneider and Eberly.
29607           // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
29608
29609           var kross = crossProduct(v1, v2);
29610           if (kross == 0) return null;
29611           var ve = {
29612             x: pt2.x - pt1.x,
29613             y: pt2.y - pt1.y
29614           };
29615           var d1 = crossProduct(ve, v1) / kross;
29616           var d2 = crossProduct(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
29617
29618           var x1 = pt1.x + d2 * v1.x,
29619               x2 = pt2.x + d1 * v2.x;
29620           var y1 = pt1.y + d2 * v1.y,
29621               y2 = pt2.y + d1 * v2.y;
29622           var x = (x1 + x2) / 2;
29623           var y = (y1 + y2) / 2;
29624           return {
29625             x: x,
29626             y: y
29627           };
29628         };
29629
29630         var SweepEvent = /*#__PURE__*/function () {
29631           _createClass(SweepEvent, null, [{
29632             key: "compare",
29633             // for ordering sweep events in the sweep event queue
29634             value: function compare(a, b) {
29635               // favor event with a point that the sweep line hits first
29636               var ptCmp = SweepEvent.comparePoints(a.point, b.point);
29637               if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
29638
29639               if (a.point !== b.point) a.link(b); // favor right events over left
29640
29641               if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
29642               // ordering of this case is the same as for their segments
29643
29644               return Segment.compare(a.segment, b.segment);
29645             } // for ordering points in sweep line order
29646
29647           }, {
29648             key: "comparePoints",
29649             value: function comparePoints(aPt, bPt) {
29650               if (aPt.x < bPt.x) return -1;
29651               if (aPt.x > bPt.x) return 1;
29652               if (aPt.y < bPt.y) return -1;
29653               if (aPt.y > bPt.y) return 1;
29654               return 0;
29655             } // Warning: 'point' input will be modified and re-used (for performance)
29656
29657           }]);
29658
29659           function SweepEvent(point, isLeft) {
29660             _classCallCheck(this, SweepEvent);
29661
29662             if (point.events === undefined) point.events = [this];else point.events.push(this);
29663             this.point = point;
29664             this.isLeft = isLeft; // this.segment, this.otherSE set by factory
29665           }
29666
29667           _createClass(SweepEvent, [{
29668             key: "link",
29669             value: function link(other) {
29670               if (other.point === this.point) {
29671                 throw new Error('Tried to link already linked events');
29672               }
29673
29674               var otherEvents = other.point.events;
29675
29676               for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
29677                 var evt = otherEvents[i];
29678                 this.point.events.push(evt);
29679                 evt.point = this.point;
29680               }
29681
29682               this.checkForConsuming();
29683             }
29684             /* Do a pass over our linked events and check to see if any pair
29685              * of segments match, and should be consumed. */
29686
29687           }, {
29688             key: "checkForConsuming",
29689             value: function checkForConsuming() {
29690               // FIXME: The loops in this method run O(n^2) => no good.
29691               //        Maintain little ordered sweep event trees?
29692               //        Can we maintaining an ordering that avoids the need
29693               //        for the re-sorting with getLeftmostComparator in geom-out?
29694               // Compare each pair of events to see if other events also match
29695               var numEvents = this.point.events.length;
29696
29697               for (var i = 0; i < numEvents; i++) {
29698                 var evt1 = this.point.events[i];
29699                 if (evt1.segment.consumedBy !== undefined) continue;
29700
29701                 for (var j = i + 1; j < numEvents; j++) {
29702                   var evt2 = this.point.events[j];
29703                   if (evt2.consumedBy !== undefined) continue;
29704                   if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
29705                   evt1.segment.consume(evt2.segment);
29706                 }
29707               }
29708             }
29709           }, {
29710             key: "getAvailableLinkedEvents",
29711             value: function getAvailableLinkedEvents() {
29712               // point.events is always of length 2 or greater
29713               var events = [];
29714
29715               for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
29716                 var evt = this.point.events[i];
29717
29718                 if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
29719                   events.push(evt);
29720                 }
29721               }
29722
29723               return events;
29724             }
29725             /**
29726              * Returns a comparator function for sorting linked events that will
29727              * favor the event that will give us the smallest left-side angle.
29728              * All ring construction starts as low as possible heading to the right,
29729              * so by always turning left as sharp as possible we'll get polygons
29730              * without uncessary loops & holes.
29731              *
29732              * The comparator function has a compute cache such that it avoids
29733              * re-computing already-computed values.
29734              */
29735
29736           }, {
29737             key: "getLeftmostComparator",
29738             value: function getLeftmostComparator(baseEvent) {
29739               var _this = this;
29740
29741               var cache = new Map();
29742
29743               var fillCache = function fillCache(linkedEvent) {
29744                 var nextEvent = linkedEvent.otherSE;
29745                 cache.set(linkedEvent, {
29746                   sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
29747                   cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
29748                 });
29749               };
29750
29751               return function (a, b) {
29752                 if (!cache.has(a)) fillCache(a);
29753                 if (!cache.has(b)) fillCache(b);
29754
29755                 var _cache$get = cache.get(a),
29756                     asine = _cache$get.sine,
29757                     acosine = _cache$get.cosine;
29758
29759                 var _cache$get2 = cache.get(b),
29760                     bsine = _cache$get2.sine,
29761                     bcosine = _cache$get2.cosine; // both on or above x-axis
29762
29763
29764                 if (asine >= 0 && bsine >= 0) {
29765                   if (acosine < bcosine) return 1;
29766                   if (acosine > bcosine) return -1;
29767                   return 0;
29768                 } // both below x-axis
29769
29770
29771                 if (asine < 0 && bsine < 0) {
29772                   if (acosine < bcosine) return -1;
29773                   if (acosine > bcosine) return 1;
29774                   return 0;
29775                 } // one above x-axis, one below
29776
29777
29778                 if (bsine < asine) return -1;
29779                 if (bsine > asine) return 1;
29780                 return 0;
29781               };
29782             }
29783           }]);
29784
29785           return SweepEvent;
29786         }(); // segments and sweep events when all else is identical
29787
29788
29789         var segmentId = 0;
29790
29791         var Segment = /*#__PURE__*/function () {
29792           _createClass(Segment, null, [{
29793             key: "compare",
29794
29795             /* This compare() function is for ordering segments in the sweep
29796              * line tree, and does so according to the following criteria:
29797              *
29798              * Consider the vertical line that lies an infinestimal step to the
29799              * right of the right-more of the two left endpoints of the input
29800              * segments. Imagine slowly moving a point up from negative infinity
29801              * in the increasing y direction. Which of the two segments will that
29802              * point intersect first? That segment comes 'before' the other one.
29803              *
29804              * If neither segment would be intersected by such a line, (if one
29805              * or more of the segments are vertical) then the line to be considered
29806              * is directly on the right-more of the two left inputs.
29807              */
29808             value: function compare(a, b) {
29809               var alx = a.leftSE.point.x;
29810               var blx = b.leftSE.point.x;
29811               var arx = a.rightSE.point.x;
29812               var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
29813
29814               if (brx < alx) return 1;
29815               if (arx < blx) return -1;
29816               var aly = a.leftSE.point.y;
29817               var bly = b.leftSE.point.y;
29818               var ary = a.rightSE.point.y;
29819               var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
29820
29821               if (alx < blx) {
29822                 // are the two segments in the same horizontal plane?
29823                 if (bly < aly && bly < ary) return 1;
29824                 if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
29825
29826                 var aCmpBLeft = a.comparePoint(b.leftSE.point);
29827                 if (aCmpBLeft < 0) return 1;
29828                 if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
29829
29830                 var bCmpARight = b.comparePoint(a.rightSE.point);
29831                 if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
29832                 // left endpoint to be first (arbitrary?)
29833
29834                 return -1;
29835               } // is left endpoint of segment A the right-more?
29836
29837
29838               if (alx > blx) {
29839                 if (aly < bly && aly < bry) return -1;
29840                 if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
29841
29842                 var bCmpALeft = b.comparePoint(a.leftSE.point);
29843                 if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
29844
29845                 var aCmpBRight = a.comparePoint(b.rightSE.point);
29846                 if (aCmpBRight < 0) return 1;
29847                 if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
29848                 // left endpoint to be first (arbitrary?)
29849
29850                 return 1;
29851               } // if we get here, the two left endpoints are in the same
29852               // vertical plane, ie alx === blx
29853               // consider the lower left-endpoint to come first
29854
29855
29856               if (aly < bly) return -1;
29857               if (aly > bly) return 1; // left endpoints are identical
29858               // check for colinearity by using the left-more right endpoint
29859               // is the A right endpoint more left-more?
29860
29861               if (arx < brx) {
29862                 var _bCmpARight = b.comparePoint(a.rightSE.point);
29863
29864                 if (_bCmpARight !== 0) return _bCmpARight;
29865               } // is the B right endpoint more left-more?
29866
29867
29868               if (arx > brx) {
29869                 var _aCmpBRight = a.comparePoint(b.rightSE.point);
29870
29871                 if (_aCmpBRight < 0) return 1;
29872                 if (_aCmpBRight > 0) return -1;
29873               }
29874
29875               if (arx !== brx) {
29876                 // are these two [almost] vertical segments with opposite orientation?
29877                 // if so, the one with the lower right endpoint comes first
29878                 var ay = ary - aly;
29879                 var ax = arx - alx;
29880                 var by = bry - bly;
29881                 var bx = brx - blx;
29882                 if (ay > ax && by < bx) return 1;
29883                 if (ay < ax && by > bx) return -1;
29884               } // we have colinear segments with matching orientation
29885               // consider the one with more left-more right endpoint to be first
29886
29887
29888               if (arx > brx) return 1;
29889               if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
29890               // vertical plane, ie arx === brx
29891               // consider the lower right-endpoint to come first
29892
29893               if (ary < bry) return -1;
29894               if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
29895               // fall back on creation order as consistent tie-breaker
29896
29897               if (a.id < b.id) return -1;
29898               if (a.id > b.id) return 1; // identical segment, ie a === b
29899
29900               return 0;
29901             }
29902             /* Warning: a reference to ringWindings input will be stored,
29903              *  and possibly will be later modified */
29904
29905           }]);
29906
29907           function Segment(leftSE, rightSE, rings, windings) {
29908             _classCallCheck(this, Segment);
29909
29910             this.id = ++segmentId;
29911             this.leftSE = leftSE;
29912             leftSE.segment = this;
29913             leftSE.otherSE = rightSE;
29914             this.rightSE = rightSE;
29915             rightSE.segment = this;
29916             rightSE.otherSE = leftSE;
29917             this.rings = rings;
29918             this.windings = windings; // left unset for performance, set later in algorithm
29919             // this.ringOut, this.consumedBy, this.prev
29920           }
29921
29922           _createClass(Segment, [{
29923             key: "replaceRightSE",
29924
29925             /* When a segment is split, the rightSE is replaced with a new sweep event */
29926             value: function replaceRightSE(newRightSE) {
29927               this.rightSE = newRightSE;
29928               this.rightSE.segment = this;
29929               this.rightSE.otherSE = this.leftSE;
29930               this.leftSE.otherSE = this.rightSE;
29931             }
29932           }, {
29933             key: "bbox",
29934             value: function bbox() {
29935               var y1 = this.leftSE.point.y;
29936               var y2 = this.rightSE.point.y;
29937               return {
29938                 ll: {
29939                   x: this.leftSE.point.x,
29940                   y: y1 < y2 ? y1 : y2
29941                 },
29942                 ur: {
29943                   x: this.rightSE.point.x,
29944                   y: y1 > y2 ? y1 : y2
29945                 }
29946               };
29947             }
29948             /* A vector from the left point to the right */
29949
29950           }, {
29951             key: "vector",
29952             value: function vector() {
29953               return {
29954                 x: this.rightSE.point.x - this.leftSE.point.x,
29955                 y: this.rightSE.point.y - this.leftSE.point.y
29956               };
29957             }
29958           }, {
29959             key: "isAnEndpoint",
29960             value: function isAnEndpoint(pt) {
29961               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;
29962             }
29963             /* Compare this segment with a point.
29964              *
29965              * A point P is considered to be colinear to a segment if there
29966              * exists a distance D such that if we travel along the segment
29967              * from one * endpoint towards the other a distance D, we find
29968              * ourselves at point P.
29969              *
29970              * Return value indicates:
29971              *
29972              *   1: point lies above the segment (to the left of vertical)
29973              *   0: point is colinear to segment
29974              *  -1: point lies below the segment (to the right of vertical)
29975              */
29976
29977           }, {
29978             key: "comparePoint",
29979             value: function comparePoint(point) {
29980               if (this.isAnEndpoint(point)) return 0;
29981               var lPt = this.leftSE.point;
29982               var rPt = this.rightSE.point;
29983               var v = this.vector(); // Exactly vertical segments.
29984
29985               if (lPt.x === rPt.x) {
29986                 if (point.x === lPt.x) return 0;
29987                 return point.x < lPt.x ? 1 : -1;
29988               } // Nearly vertical segments with an intersection.
29989               // Check to see where a point on the line with matching Y coordinate is.
29990
29991
29992               var yDist = (point.y - lPt.y) / v.y;
29993               var xFromYDist = lPt.x + yDist * v.x;
29994               if (point.x === xFromYDist) return 0; // General case.
29995               // Check to see where a point on the line with matching X coordinate is.
29996
29997               var xDist = (point.x - lPt.x) / v.x;
29998               var yFromXDist = lPt.y + xDist * v.y;
29999               if (point.y === yFromXDist) return 0;
30000               return point.y < yFromXDist ? -1 : 1;
30001             }
30002             /**
30003              * Given another segment, returns the first non-trivial intersection
30004              * between the two segments (in terms of sweep line ordering), if it exists.
30005              *
30006              * A 'non-trivial' intersection is one that will cause one or both of the
30007              * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
30008              *
30009              *   * endpoint of segA with endpoint of segB --> trivial
30010              *   * endpoint of segA with point along segB --> non-trivial
30011              *   * endpoint of segB with point along segA --> non-trivial
30012              *   * point along segA with point along segB --> non-trivial
30013              *
30014              * If no non-trivial intersection exists, return null
30015              * Else, return null.
30016              */
30017
30018           }, {
30019             key: "getIntersection",
30020             value: function getIntersection(other) {
30021               // If bboxes don't overlap, there can't be any intersections
30022               var tBbox = this.bbox();
30023               var oBbox = other.bbox();
30024               var bboxOverlap = getBboxOverlap(tBbox, oBbox);
30025               if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
30026               // This will 'snap' intersections to endpoints if possible, and will
30027               // handle cases of colinearity.
30028
30029               var tlp = this.leftSE.point;
30030               var trp = this.rightSE.point;
30031               var olp = other.leftSE.point;
30032               var orp = other.rightSE.point; // does each endpoint touch the other segment?
30033               // note that we restrict the 'touching' definition to only allow segments
30034               // to touch endpoints that lie forward from where we are in the sweep line pass
30035
30036               var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
30037               var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
30038               var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
30039               var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
30040
30041               if (touchesThisLSE && touchesOtherLSE) {
30042                 // these two cases are for colinear segments with matching left
30043                 // endpoints, and one segment being longer than the other
30044                 if (touchesThisRSE && !touchesOtherRSE) return trp;
30045                 if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
30046                 // or just on their left endpoint (one trivial intersection
30047
30048                 return null;
30049               } // does this left endpoint matches (other doesn't)
30050
30051
30052               if (touchesThisLSE) {
30053                 // check for segments that just intersect on opposing endpoints
30054                 if (touchesOtherRSE) {
30055                   if (tlp.x === orp.x && tlp.y === orp.y) return null;
30056                 } // t-intersection on left endpoint
30057
30058
30059                 return tlp;
30060               } // does other left endpoint matches (this doesn't)
30061
30062
30063               if (touchesOtherLSE) {
30064                 // check for segments that just intersect on opposing endpoints
30065                 if (touchesThisRSE) {
30066                   if (trp.x === olp.x && trp.y === olp.y) return null;
30067                 } // t-intersection on left endpoint
30068
30069
30070                 return olp;
30071               } // trivial intersection on right endpoints
30072
30073
30074               if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
30075
30076               if (touchesThisRSE) return trp;
30077               if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
30078               // infinite lines laid over the segments
30079
30080               var pt = intersection(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
30081               // they would have an endpoint intersection and that case was already handled above
30082
30083               if (pt === null) return null; // is the intersection found between the lines not on the segments?
30084
30085               if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
30086
30087               return rounder.round(pt.x, pt.y);
30088             }
30089             /**
30090              * Split the given segment into multiple segments on the given points.
30091              *  * Each existing segment will retain its leftSE and a new rightSE will be
30092              *    generated for it.
30093              *  * A new segment will be generated which will adopt the original segment's
30094              *    rightSE, and a new leftSE will be generated for it.
30095              *  * If there are more than two points given to split on, new segments
30096              *    in the middle will be generated with new leftSE and rightSE's.
30097              *  * An array of the newly generated SweepEvents will be returned.
30098              *
30099              * Warning: input array of points is modified
30100              */
30101
30102           }, {
30103             key: "split",
30104             value: function split(point) {
30105               var newEvents = [];
30106               var alreadyLinked = point.events !== undefined;
30107               var newLeftSE = new SweepEvent(point, true);
30108               var newRightSE = new SweepEvent(point, false);
30109               var oldRightSE = this.rightSE;
30110               this.replaceRightSE(newRightSE);
30111               newEvents.push(newRightSE);
30112               newEvents.push(newLeftSE);
30113               var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
30114               // sometimes one of the resulting new segments is vertical, in which
30115               // case its left and right events may need to be swapped
30116
30117               if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
30118                 newSeg.swapEvents();
30119               }
30120
30121               if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
30122                 this.swapEvents();
30123               } // in the point we just used to create new sweep events with was already
30124               // linked to other events, we need to check if either of the affected
30125               // segments should be consumed
30126
30127
30128               if (alreadyLinked) {
30129                 newLeftSE.checkForConsuming();
30130                 newRightSE.checkForConsuming();
30131               }
30132
30133               return newEvents;
30134             }
30135             /* Swap which event is left and right */
30136
30137           }, {
30138             key: "swapEvents",
30139             value: function swapEvents() {
30140               var tmpEvt = this.rightSE;
30141               this.rightSE = this.leftSE;
30142               this.leftSE = tmpEvt;
30143               this.leftSE.isLeft = true;
30144               this.rightSE.isLeft = false;
30145
30146               for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
30147                 this.windings[i] *= -1;
30148               }
30149             }
30150             /* Consume another segment. We take their rings under our wing
30151              * and mark them as consumed. Use for perfectly overlapping segments */
30152
30153           }, {
30154             key: "consume",
30155             value: function consume(other) {
30156               var consumer = this;
30157               var consumee = other;
30158
30159               while (consumer.consumedBy) {
30160                 consumer = consumer.consumedBy;
30161               }
30162
30163               while (consumee.consumedBy) {
30164                 consumee = consumee.consumedBy;
30165               }
30166
30167               var cmp = Segment.compare(consumer, consumee);
30168               if (cmp === 0) return; // already consumed
30169               // the winner of the consumption is the earlier segment
30170               // according to sweep line ordering
30171
30172               if (cmp > 0) {
30173                 var tmp = consumer;
30174                 consumer = consumee;
30175                 consumee = tmp;
30176               } // make sure a segment doesn't consume it's prev
30177
30178
30179               if (consumer.prev === consumee) {
30180                 var _tmp = consumer;
30181                 consumer = consumee;
30182                 consumee = _tmp;
30183               }
30184
30185               for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
30186                 var ring = consumee.rings[i];
30187                 var winding = consumee.windings[i];
30188                 var index = consumer.rings.indexOf(ring);
30189
30190                 if (index === -1) {
30191                   consumer.rings.push(ring);
30192                   consumer.windings.push(winding);
30193                 } else consumer.windings[index] += winding;
30194               }
30195
30196               consumee.rings = null;
30197               consumee.windings = null;
30198               consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
30199
30200               consumee.leftSE.consumedBy = consumer.leftSE;
30201               consumee.rightSE.consumedBy = consumer.rightSE;
30202             }
30203             /* The first segment previous segment chain that is in the result */
30204
30205           }, {
30206             key: "prevInResult",
30207             value: function prevInResult() {
30208               if (this._prevInResult !== undefined) return this._prevInResult;
30209               if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
30210               return this._prevInResult;
30211             }
30212           }, {
30213             key: "beforeState",
30214             value: function beforeState() {
30215               if (this._beforeState !== undefined) return this._beforeState;
30216               if (!this.prev) this._beforeState = {
30217                 rings: [],
30218                 windings: [],
30219                 multiPolys: []
30220               };else {
30221                 var seg = this.prev.consumedBy || this.prev;
30222                 this._beforeState = seg.afterState();
30223               }
30224               return this._beforeState;
30225             }
30226           }, {
30227             key: "afterState",
30228             value: function afterState() {
30229               if (this._afterState !== undefined) return this._afterState;
30230               var beforeState = this.beforeState();
30231               this._afterState = {
30232                 rings: beforeState.rings.slice(0),
30233                 windings: beforeState.windings.slice(0),
30234                 multiPolys: []
30235               };
30236               var ringsAfter = this._afterState.rings;
30237               var windingsAfter = this._afterState.windings;
30238               var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
30239
30240               for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
30241                 var ring = this.rings[i];
30242                 var winding = this.windings[i];
30243                 var index = ringsAfter.indexOf(ring);
30244
30245                 if (index === -1) {
30246                   ringsAfter.push(ring);
30247                   windingsAfter.push(winding);
30248                 } else windingsAfter[index] += winding;
30249               } // calcualte polysAfter
30250
30251
30252               var polysAfter = [];
30253               var polysExclude = [];
30254
30255               for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
30256                 if (windingsAfter[_i] === 0) continue; // non-zero rule
30257
30258                 var _ring = ringsAfter[_i];
30259                 var poly = _ring.poly;
30260                 if (polysExclude.indexOf(poly) !== -1) continue;
30261                 if (_ring.isExterior) polysAfter.push(poly);else {
30262                   if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
30263
30264                   var _index = polysAfter.indexOf(_ring.poly);
30265
30266                   if (_index !== -1) polysAfter.splice(_index, 1);
30267                 }
30268               } // calculate multiPolysAfter
30269
30270
30271               for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
30272                 var mp = polysAfter[_i2].multiPoly;
30273                 if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
30274               }
30275
30276               return this._afterState;
30277             }
30278             /* Is this segment part of the final result? */
30279
30280           }, {
30281             key: "isInResult",
30282             value: function isInResult() {
30283               // if we've been consumed, we're not in the result
30284               if (this.consumedBy) return false;
30285               if (this._isInResult !== undefined) return this._isInResult;
30286               var mpsBefore = this.beforeState().multiPolys;
30287               var mpsAfter = this.afterState().multiPolys;
30288
30289               switch (operation.type) {
30290                 case 'union':
30291                   {
30292                     // UNION - included iff:
30293                     //  * On one side of us there is 0 poly interiors AND
30294                     //  * On the other side there is 1 or more.
30295                     var noBefores = mpsBefore.length === 0;
30296                     var noAfters = mpsAfter.length === 0;
30297                     this._isInResult = noBefores !== noAfters;
30298                     break;
30299                   }
30300
30301                 case 'intersection':
30302                   {
30303                     // INTERSECTION - included iff:
30304                     //  * on one side of us all multipolys are rep. with poly interiors AND
30305                     //  * on the other side of us, not all multipolys are repsented
30306                     //    with poly interiors
30307                     var least;
30308                     var most;
30309
30310                     if (mpsBefore.length < mpsAfter.length) {
30311                       least = mpsBefore.length;
30312                       most = mpsAfter.length;
30313                     } else {
30314                       least = mpsAfter.length;
30315                       most = mpsBefore.length;
30316                     }
30317
30318                     this._isInResult = most === operation.numMultiPolys && least < most;
30319                     break;
30320                   }
30321
30322                 case 'xor':
30323                   {
30324                     // XOR - included iff:
30325                     //  * the difference between the number of multipolys represented
30326                     //    with poly interiors on our two sides is an odd number
30327                     var diff = Math.abs(mpsBefore.length - mpsAfter.length);
30328                     this._isInResult = diff % 2 === 1;
30329                     break;
30330                   }
30331
30332                 case 'difference':
30333                   {
30334                     // DIFFERENCE included iff:
30335                     //  * on exactly one side, we have just the subject
30336                     var isJustSubject = function isJustSubject(mps) {
30337                       return mps.length === 1 && mps[0].isSubject;
30338                     };
30339
30340                     this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
30341                     break;
30342                   }
30343
30344                 default:
30345                   throw new Error("Unrecognized operation type found ".concat(operation.type));
30346               }
30347
30348               return this._isInResult;
30349             }
30350           }], [{
30351             key: "fromRing",
30352             value: function fromRing(pt1, pt2, ring) {
30353               var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
30354
30355               var cmpPts = SweepEvent.comparePoints(pt1, pt2);
30356
30357               if (cmpPts < 0) {
30358                 leftPt = pt1;
30359                 rightPt = pt2;
30360                 winding = 1;
30361               } else if (cmpPts > 0) {
30362                 leftPt = pt2;
30363                 rightPt = pt1;
30364                 winding = -1;
30365               } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
30366
30367               var leftSE = new SweepEvent(leftPt, true);
30368               var rightSE = new SweepEvent(rightPt, false);
30369               return new Segment(leftSE, rightSE, [ring], [winding]);
30370             }
30371           }]);
30372
30373           return Segment;
30374         }();
30375
30376         var RingIn = /*#__PURE__*/function () {
30377           function RingIn(geomRing, poly, isExterior) {
30378             _classCallCheck(this, RingIn);
30379
30380             if (!Array.isArray(geomRing) || geomRing.length === 0) {
30381               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30382             }
30383
30384             this.poly = poly;
30385             this.isExterior = isExterior;
30386             this.segments = [];
30387
30388             if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
30389               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30390             }
30391
30392             var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
30393             this.bbox = {
30394               ll: {
30395                 x: firstPoint.x,
30396                 y: firstPoint.y
30397               },
30398               ur: {
30399                 x: firstPoint.x,
30400                 y: firstPoint.y
30401               }
30402             };
30403             var prevPoint = firstPoint;
30404
30405             for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
30406               if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
30407                 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30408               }
30409
30410               var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
30411
30412               if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
30413               this.segments.push(Segment.fromRing(prevPoint, point, this));
30414               if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
30415               if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
30416               if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
30417               if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
30418               prevPoint = point;
30419             } // add segment from last to first if last is not the same as first
30420
30421
30422             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
30423               this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
30424             }
30425           }
30426
30427           _createClass(RingIn, [{
30428             key: "getSweepEvents",
30429             value: function getSweepEvents() {
30430               var sweepEvents = [];
30431
30432               for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
30433                 var segment = this.segments[i];
30434                 sweepEvents.push(segment.leftSE);
30435                 sweepEvents.push(segment.rightSE);
30436               }
30437
30438               return sweepEvents;
30439             }
30440           }]);
30441
30442           return RingIn;
30443         }();
30444
30445         var PolyIn = /*#__PURE__*/function () {
30446           function PolyIn(geomPoly, multiPoly) {
30447             _classCallCheck(this, PolyIn);
30448
30449             if (!Array.isArray(geomPoly)) {
30450               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30451             }
30452
30453             this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
30454
30455             this.bbox = {
30456               ll: {
30457                 x: this.exteriorRing.bbox.ll.x,
30458                 y: this.exteriorRing.bbox.ll.y
30459               },
30460               ur: {
30461                 x: this.exteriorRing.bbox.ur.x,
30462                 y: this.exteriorRing.bbox.ur.y
30463               }
30464             };
30465             this.interiorRings = [];
30466
30467             for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
30468               var ring = new RingIn(geomPoly[i], this, false);
30469               if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
30470               if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
30471               if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
30472               if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
30473               this.interiorRings.push(ring);
30474             }
30475
30476             this.multiPoly = multiPoly;
30477           }
30478
30479           _createClass(PolyIn, [{
30480             key: "getSweepEvents",
30481             value: function getSweepEvents() {
30482               var sweepEvents = this.exteriorRing.getSweepEvents();
30483
30484               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
30485                 var ringSweepEvents = this.interiorRings[i].getSweepEvents();
30486
30487                 for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
30488                   sweepEvents.push(ringSweepEvents[j]);
30489                 }
30490               }
30491
30492               return sweepEvents;
30493             }
30494           }]);
30495
30496           return PolyIn;
30497         }();
30498
30499         var MultiPolyIn = /*#__PURE__*/function () {
30500           function MultiPolyIn(geom, isSubject) {
30501             _classCallCheck(this, MultiPolyIn);
30502
30503             if (!Array.isArray(geom)) {
30504               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30505             }
30506
30507             try {
30508               // if the input looks like a polygon, convert it to a multipolygon
30509               if (typeof geom[0][0][0] === 'number') geom = [geom];
30510             } catch (ex) {// The input is either malformed or has empty arrays.
30511               // In either case, it will be handled later on.
30512             }
30513
30514             this.polys = [];
30515             this.bbox = {
30516               ll: {
30517                 x: Number.POSITIVE_INFINITY,
30518                 y: Number.POSITIVE_INFINITY
30519               },
30520               ur: {
30521                 x: Number.NEGATIVE_INFINITY,
30522                 y: Number.NEGATIVE_INFINITY
30523               }
30524             };
30525
30526             for (var i = 0, iMax = geom.length; i < iMax; i++) {
30527               var poly = new PolyIn(geom[i], this);
30528               if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
30529               if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
30530               if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
30531               if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
30532               this.polys.push(poly);
30533             }
30534
30535             this.isSubject = isSubject;
30536           }
30537
30538           _createClass(MultiPolyIn, [{
30539             key: "getSweepEvents",
30540             value: function getSweepEvents() {
30541               var sweepEvents = [];
30542
30543               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
30544                 var polySweepEvents = this.polys[i].getSweepEvents();
30545
30546                 for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
30547                   sweepEvents.push(polySweepEvents[j]);
30548                 }
30549               }
30550
30551               return sweepEvents;
30552             }
30553           }]);
30554
30555           return MultiPolyIn;
30556         }();
30557
30558         var RingOut = /*#__PURE__*/function () {
30559           _createClass(RingOut, null, [{
30560             key: "factory",
30561
30562             /* Given the segments from the sweep line pass, compute & return a series
30563              * of closed rings from all the segments marked to be part of the result */
30564             value: function factory(allSegments) {
30565               var ringsOut = [];
30566
30567               for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
30568                 var segment = allSegments[i];
30569                 if (!segment.isInResult() || segment.ringOut) continue;
30570                 var prevEvent = null;
30571                 var event = segment.leftSE;
30572                 var nextEvent = segment.rightSE;
30573                 var events = [event];
30574                 var startingPoint = event.point;
30575                 var intersectionLEs = [];
30576                 /* Walk the chain of linked events to form a closed ring */
30577
30578                 while (true) {
30579                   prevEvent = event;
30580                   event = nextEvent;
30581                   events.push(event);
30582                   /* Is the ring complete? */
30583
30584                   if (event.point === startingPoint) break;
30585
30586                   while (true) {
30587                     var availableLEs = event.getAvailableLinkedEvents();
30588                     /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
30589                      * part of the algorithm malfunctioned... please file a bug report. */
30590
30591                     if (availableLEs.length === 0) {
30592                       var firstPt = events[0].point;
30593                       var lastPt = events[events.length - 1].point;
30594                       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, "]."));
30595                     }
30596                     /* Only one way to go, so cotinue on the path */
30597
30598
30599                     if (availableLEs.length === 1) {
30600                       nextEvent = availableLEs[0].otherSE;
30601                       break;
30602                     }
30603                     /* We must have an intersection. Check for a completed loop */
30604
30605
30606                     var indexLE = null;
30607
30608                     for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
30609                       if (intersectionLEs[j].point === event.point) {
30610                         indexLE = j;
30611                         break;
30612                       }
30613                     }
30614                     /* Found a completed loop. Cut that off and make a ring */
30615
30616
30617                     if (indexLE !== null) {
30618                       var intersectionLE = intersectionLEs.splice(indexLE)[0];
30619                       var ringEvents = events.splice(intersectionLE.index);
30620                       ringEvents.unshift(ringEvents[0].otherSE);
30621                       ringsOut.push(new RingOut(ringEvents.reverse()));
30622                       continue;
30623                     }
30624                     /* register the intersection */
30625
30626
30627                     intersectionLEs.push({
30628                       index: events.length,
30629                       point: event.point
30630                     });
30631                     /* Choose the left-most option to continue the walk */
30632
30633                     var comparator = event.getLeftmostComparator(prevEvent);
30634                     nextEvent = availableLEs.sort(comparator)[0].otherSE;
30635                     break;
30636                   }
30637                 }
30638
30639                 ringsOut.push(new RingOut(events));
30640               }
30641
30642               return ringsOut;
30643             }
30644           }]);
30645
30646           function RingOut(events) {
30647             _classCallCheck(this, RingOut);
30648
30649             this.events = events;
30650
30651             for (var i = 0, iMax = events.length; i < iMax; i++) {
30652               events[i].segment.ringOut = this;
30653             }
30654
30655             this.poly = null;
30656           }
30657
30658           _createClass(RingOut, [{
30659             key: "getGeom",
30660             value: function getGeom() {
30661               // Remove superfluous points (ie extra points along a straight line),
30662               var prevPt = this.events[0].point;
30663               var points = [prevPt];
30664
30665               for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
30666                 var _pt = this.events[i].point;
30667                 var _nextPt = this.events[i + 1].point;
30668                 if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
30669                 points.push(_pt);
30670                 prevPt = _pt;
30671               } // ring was all (within rounding error of angle calc) colinear points
30672
30673
30674               if (points.length === 1) return null; // check if the starting point is necessary
30675
30676               var pt = points[0];
30677               var nextPt = points[1];
30678               if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
30679               points.push(points[0]);
30680               var step = this.isExteriorRing() ? 1 : -1;
30681               var iStart = this.isExteriorRing() ? 0 : points.length - 1;
30682               var iEnd = this.isExteriorRing() ? points.length : -1;
30683               var orderedPoints = [];
30684
30685               for (var _i = iStart; _i != iEnd; _i += step) {
30686                 orderedPoints.push([points[_i].x, points[_i].y]);
30687               }
30688
30689               return orderedPoints;
30690             }
30691           }, {
30692             key: "isExteriorRing",
30693             value: function isExteriorRing() {
30694               if (this._isExteriorRing === undefined) {
30695                 var enclosing = this.enclosingRing();
30696                 this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
30697               }
30698
30699               return this._isExteriorRing;
30700             }
30701           }, {
30702             key: "enclosingRing",
30703             value: function enclosingRing() {
30704               if (this._enclosingRing === undefined) {
30705                 this._enclosingRing = this._calcEnclosingRing();
30706               }
30707
30708               return this._enclosingRing;
30709             }
30710             /* Returns the ring that encloses this one, if any */
30711
30712           }, {
30713             key: "_calcEnclosingRing",
30714             value: function _calcEnclosingRing() {
30715               // start with the ealier sweep line event so that the prevSeg
30716               // chain doesn't lead us inside of a loop of ours
30717               var leftMostEvt = this.events[0];
30718
30719               for (var i = 1, iMax = this.events.length; i < iMax; i++) {
30720                 var evt = this.events[i];
30721                 if (SweepEvent.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
30722               }
30723
30724               var prevSeg = leftMostEvt.segment.prevInResult();
30725               var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
30726
30727               while (true) {
30728                 // no segment found, thus no ring can enclose us
30729                 if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
30730                 // segment must loop back around and enclose us
30731
30732                 if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
30733                 // segment must either loop around us or the ring of the prev prev
30734                 // seg, which would make us and the ring of the prev peers
30735
30736                 if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
30737                   if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
30738                     return prevSeg.ringOut;
30739                   } else return prevSeg.ringOut.enclosingRing();
30740                 } // two segments are from the same ring, so this was a penisula
30741                 // of that ring. iterate downward, keep searching
30742
30743
30744                 prevSeg = prevPrevSeg.prevInResult();
30745                 prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
30746               }
30747             }
30748           }]);
30749
30750           return RingOut;
30751         }();
30752
30753         var PolyOut = /*#__PURE__*/function () {
30754           function PolyOut(exteriorRing) {
30755             _classCallCheck(this, PolyOut);
30756
30757             this.exteriorRing = exteriorRing;
30758             exteriorRing.poly = this;
30759             this.interiorRings = [];
30760           }
30761
30762           _createClass(PolyOut, [{
30763             key: "addInterior",
30764             value: function addInterior(ring) {
30765               this.interiorRings.push(ring);
30766               ring.poly = this;
30767             }
30768           }, {
30769             key: "getGeom",
30770             value: function getGeom() {
30771               var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
30772
30773               if (geom[0] === null) return null;
30774
30775               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
30776                 var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
30777
30778                 if (ringGeom === null) continue;
30779                 geom.push(ringGeom);
30780               }
30781
30782               return geom;
30783             }
30784           }]);
30785
30786           return PolyOut;
30787         }();
30788
30789         var MultiPolyOut = /*#__PURE__*/function () {
30790           function MultiPolyOut(rings) {
30791             _classCallCheck(this, MultiPolyOut);
30792
30793             this.rings = rings;
30794             this.polys = this._composePolys(rings);
30795           }
30796
30797           _createClass(MultiPolyOut, [{
30798             key: "getGeom",
30799             value: function getGeom() {
30800               var geom = [];
30801
30802               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
30803                 var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
30804
30805                 if (polyGeom === null) continue;
30806                 geom.push(polyGeom);
30807               }
30808
30809               return geom;
30810             }
30811           }, {
30812             key: "_composePolys",
30813             value: function _composePolys(rings) {
30814               var polys = [];
30815
30816               for (var i = 0, iMax = rings.length; i < iMax; i++) {
30817                 var ring = rings[i];
30818                 if (ring.poly) continue;
30819                 if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
30820                   var enclosingRing = ring.enclosingRing();
30821                   if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
30822                   enclosingRing.poly.addInterior(ring);
30823                 }
30824               }
30825
30826               return polys;
30827             }
30828           }]);
30829
30830           return MultiPolyOut;
30831         }();
30832         /**
30833          * NOTE:  We must be careful not to change any segments while
30834          *        they are in the SplayTree. AFAIK, there's no way to tell
30835          *        the tree to rebalance itself - thus before splitting
30836          *        a segment that's in the tree, we remove it from the tree,
30837          *        do the split, then re-insert it. (Even though splitting a
30838          *        segment *shouldn't* change its correct position in the
30839          *        sweep line tree, the reality is because of rounding errors,
30840          *        it sometimes does.)
30841          */
30842
30843
30844         var SweepLine = /*#__PURE__*/function () {
30845           function SweepLine(queue) {
30846             var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
30847
30848             _classCallCheck(this, SweepLine);
30849
30850             this.queue = queue;
30851             this.tree = new Tree(comparator);
30852             this.segments = [];
30853           }
30854
30855           _createClass(SweepLine, [{
30856             key: "process",
30857             value: function process(event) {
30858               var segment = event.segment;
30859               var newEvents = []; // if we've already been consumed by another segment,
30860               // clean up our body parts and get out
30861
30862               if (event.consumedBy) {
30863                 if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
30864                 return newEvents;
30865               }
30866
30867               var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
30868               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.');
30869               var prevNode = node;
30870               var nextNode = node;
30871               var prevSeg = undefined;
30872               var nextSeg = undefined; // skip consumed segments still in tree
30873
30874               while (prevSeg === undefined) {
30875                 prevNode = this.tree.prev(prevNode);
30876                 if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
30877               } // skip consumed segments still in tree
30878
30879
30880               while (nextSeg === undefined) {
30881                 nextNode = this.tree.next(nextNode);
30882                 if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
30883               }
30884
30885               if (event.isLeft) {
30886                 // Check for intersections against the previous segment in the sweep line
30887                 var prevMySplitter = null;
30888
30889                 if (prevSeg) {
30890                   var prevInter = prevSeg.getIntersection(segment);
30891
30892                   if (prevInter !== null) {
30893                     if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
30894
30895                     if (!prevSeg.isAnEndpoint(prevInter)) {
30896                       var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
30897
30898                       for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
30899                         newEvents.push(newEventsFromSplit[i]);
30900                       }
30901                     }
30902                   }
30903                 } // Check for intersections against the next segment in the sweep line
30904
30905
30906                 var nextMySplitter = null;
30907
30908                 if (nextSeg) {
30909                   var nextInter = nextSeg.getIntersection(segment);
30910
30911                   if (nextInter !== null) {
30912                     if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
30913
30914                     if (!nextSeg.isAnEndpoint(nextInter)) {
30915                       var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
30916
30917                       for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
30918                         newEvents.push(_newEventsFromSplit[_i]);
30919                       }
30920                     }
30921                   }
30922                 } // For simplicity, even if we find more than one intersection we only
30923                 // spilt on the 'earliest' (sweep-line style) of the intersections.
30924                 // The other intersection will be handled in a future process().
30925
30926
30927                 if (prevMySplitter !== null || nextMySplitter !== null) {
30928                   var mySplitter = null;
30929                   if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
30930                     var cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
30931                     mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
30932                   } // Rounding errors can cause changes in ordering,
30933                   // so remove afected segments and right sweep events before splitting
30934
30935                   this.queue.remove(segment.rightSE);
30936                   newEvents.push(segment.rightSE);
30937
30938                   var _newEventsFromSplit2 = segment.split(mySplitter);
30939
30940                   for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
30941                     newEvents.push(_newEventsFromSplit2[_i2]);
30942                   }
30943                 }
30944
30945                 if (newEvents.length > 0) {
30946                   // We found some intersections, so re-do the current event to
30947                   // make sure sweep line ordering is totally consistent for later
30948                   // use with the segment 'prev' pointers
30949                   this.tree.remove(segment);
30950                   newEvents.push(event);
30951                 } else {
30952                   // done with left event
30953                   this.segments.push(segment);
30954                   segment.prev = prevSeg;
30955                 }
30956               } else {
30957                 // event.isRight
30958                 // since we're about to be removed from the sweep line, check for
30959                 // intersections between our previous and next segments
30960                 if (prevSeg && nextSeg) {
30961                   var inter = prevSeg.getIntersection(nextSeg);
30962
30963                   if (inter !== null) {
30964                     if (!prevSeg.isAnEndpoint(inter)) {
30965                       var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
30966
30967                       for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
30968                         newEvents.push(_newEventsFromSplit3[_i3]);
30969                       }
30970                     }
30971
30972                     if (!nextSeg.isAnEndpoint(inter)) {
30973                       var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
30974
30975                       for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
30976                         newEvents.push(_newEventsFromSplit4[_i4]);
30977                       }
30978                     }
30979                   }
30980                 }
30981
30982                 this.tree.remove(segment);
30983               }
30984
30985               return newEvents;
30986             }
30987             /* Safely split a segment that is currently in the datastructures
30988              * IE - a segment other than the one that is currently being processed. */
30989
30990           }, {
30991             key: "_splitSafely",
30992             value: function _splitSafely(seg, pt) {
30993               // Rounding errors can cause changes in ordering,
30994               // so remove afected segments and right sweep events before splitting
30995               // removeNode() doesn't work, so have re-find the seg
30996               // https://github.com/w8r/splay-tree/pull/5
30997               this.tree.remove(seg);
30998               var rightSE = seg.rightSE;
30999               this.queue.remove(rightSE);
31000               var newEvents = seg.split(pt);
31001               newEvents.push(rightSE); // splitting can trigger consumption
31002
31003               if (seg.consumedBy === undefined) this.tree.insert(seg);
31004               return newEvents;
31005             }
31006           }]);
31007
31008           return SweepLine;
31009         }();
31010
31011         var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
31012         var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
31013
31014         var Operation = /*#__PURE__*/function () {
31015           function Operation() {
31016             _classCallCheck(this, Operation);
31017           }
31018
31019           _createClass(Operation, [{
31020             key: "run",
31021             value: function run(type, geom, moreGeoms) {
31022               operation.type = type;
31023               rounder.reset();
31024               /* Convert inputs to MultiPoly objects */
31025
31026               var multipolys = [new MultiPolyIn(geom, true)];
31027
31028               for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
31029                 multipolys.push(new MultiPolyIn(moreGeoms[i], false));
31030               }
31031
31032               operation.numMultiPolys = multipolys.length;
31033               /* BBox optimization for difference operation
31034                * If the bbox of a multipolygon that's part of the clipping doesn't
31035                * intersect the bbox of the subject at all, we can just drop that
31036                * multiploygon. */
31037
31038               if (operation.type === 'difference') {
31039                 // in place removal
31040                 var subject = multipolys[0];
31041                 var _i = 1;
31042
31043                 while (_i < multipolys.length) {
31044                   if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
31045                 }
31046               }
31047               /* BBox optimization for intersection operation
31048                * If we can find any pair of multipolygons whose bbox does not overlap,
31049                * then the result will be empty. */
31050
31051
31052               if (operation.type === 'intersection') {
31053                 // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
31054                 //       it could be optimized to O(n * ln(n))
31055                 for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
31056                   var mpA = multipolys[_i2];
31057
31058                   for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
31059                     if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
31060                   }
31061                 }
31062               }
31063               /* Put segment endpoints in a priority queue */
31064
31065
31066               var queue = new Tree(SweepEvent.compare);
31067
31068               for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
31069                 var sweepEvents = multipolys[_i3].getSweepEvents();
31070
31071                 for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
31072                   queue.insert(sweepEvents[_j]);
31073
31074                   if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
31075                     // prevents an infinite loop, an otherwise common manifestation of bugs
31076                     throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
31077                   }
31078                 }
31079               }
31080               /* Pass the sweep line over those endpoints */
31081
31082
31083               var sweepLine = new SweepLine(queue);
31084               var prevQueueSize = queue.size;
31085               var node = queue.pop();
31086
31087               while (node) {
31088                 var evt = node.key;
31089
31090                 if (queue.size === prevQueueSize) {
31091                   // prevents an infinite loop, an otherwise common manifestation of bugs
31092                   var seg = evt.segment;
31093                   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.');
31094                 }
31095
31096                 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
31097                   // prevents an infinite loop, an otherwise common manifestation of bugs
31098                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
31099                 }
31100
31101                 if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
31102                   // prevents an infinite loop, an otherwise common manifestation of bugs
31103                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
31104                 }
31105
31106                 var newEvents = sweepLine.process(evt);
31107
31108                 for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
31109                   var _evt = newEvents[_i4];
31110                   if (_evt.consumedBy === undefined) queue.insert(_evt);
31111                 }
31112
31113                 prevQueueSize = queue.size;
31114                 node = queue.pop();
31115               } // free some memory we don't need anymore
31116
31117
31118               rounder.reset();
31119               /* Collect and compile segments we're keeping into a multipolygon */
31120
31121               var ringsOut = RingOut.factory(sweepLine.segments);
31122               var result = new MultiPolyOut(ringsOut);
31123               return result.getGeom();
31124             }
31125           }]);
31126
31127           return Operation;
31128         }(); // singleton available by import
31129
31130
31131         var operation = new Operation();
31132
31133         var union = function union(geom) {
31134           for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
31135             moreGeoms[_key - 1] = arguments[_key];
31136           }
31137
31138           return operation.run('union', geom, moreGeoms);
31139         };
31140
31141         var intersection$1 = function intersection(geom) {
31142           for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
31143             moreGeoms[_key2 - 1] = arguments[_key2];
31144           }
31145
31146           return operation.run('intersection', geom, moreGeoms);
31147         };
31148
31149         var xor = function xor(geom) {
31150           for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
31151             moreGeoms[_key3 - 1] = arguments[_key3];
31152           }
31153
31154           return operation.run('xor', geom, moreGeoms);
31155         };
31156
31157         var difference = function difference(subjectGeom) {
31158           for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
31159             clippingGeoms[_key4 - 1] = arguments[_key4];
31160           }
31161
31162           return operation.run('difference', subjectGeom, clippingGeoms);
31163         };
31164
31165         var index = {
31166           union: union,
31167           intersection: intersection$1,
31168           xor: xor,
31169           difference: difference
31170         };
31171
31172         var geojsonPrecision = {exports: {}};
31173
31174         (function () {
31175           function parse(t, coordinatePrecision, extrasPrecision) {
31176             function point(p) {
31177               return p.map(function (e, index) {
31178                 if (index < 2) {
31179                   return 1 * e.toFixed(coordinatePrecision);
31180                 } else {
31181                   return 1 * e.toFixed(extrasPrecision);
31182                 }
31183               });
31184             }
31185
31186             function multi(l) {
31187               return l.map(point);
31188             }
31189
31190             function poly(p) {
31191               return p.map(multi);
31192             }
31193
31194             function multiPoly(m) {
31195               return m.map(poly);
31196             }
31197
31198             function geometry(obj) {
31199               if (!obj) {
31200                 return {};
31201               }
31202
31203               switch (obj.type) {
31204                 case "Point":
31205                   obj.coordinates = point(obj.coordinates);
31206                   return obj;
31207
31208                 case "LineString":
31209                 case "MultiPoint":
31210                   obj.coordinates = multi(obj.coordinates);
31211                   return obj;
31212
31213                 case "Polygon":
31214                 case "MultiLineString":
31215                   obj.coordinates = poly(obj.coordinates);
31216                   return obj;
31217
31218                 case "MultiPolygon":
31219                   obj.coordinates = multiPoly(obj.coordinates);
31220                   return obj;
31221
31222                 case "GeometryCollection":
31223                   obj.geometries = obj.geometries.map(geometry);
31224                   return obj;
31225
31226                 default:
31227                   return {};
31228               }
31229             }
31230
31231             function feature(obj) {
31232               obj.geometry = geometry(obj.geometry);
31233               return obj;
31234             }
31235
31236             function featureCollection(f) {
31237               f.features = f.features.map(feature);
31238               return f;
31239             }
31240
31241             function geometryCollection(g) {
31242               g.geometries = g.geometries.map(geometry);
31243               return g;
31244             }
31245
31246             if (!t) {
31247               return t;
31248             }
31249
31250             switch (t.type) {
31251               case "Feature":
31252                 return feature(t);
31253
31254               case "GeometryCollection":
31255                 return geometryCollection(t);
31256
31257               case "FeatureCollection":
31258                 return featureCollection(t);
31259
31260               case "Point":
31261               case "LineString":
31262               case "Polygon":
31263               case "MultiPoint":
31264               case "MultiPolygon":
31265               case "MultiLineString":
31266                 return geometry(t);
31267
31268               default:
31269                 return t;
31270             }
31271           }
31272
31273           geojsonPrecision.exports = parse;
31274           geojsonPrecision.exports.parse = parse;
31275         })();
31276
31277         var precision = geojsonPrecision.exports;
31278
31279         var $$d = _export;
31280         var fails$5 = fails$N;
31281         var toObject = toObject$i;
31282         var toPrimitive = toPrimitive$7;
31283
31284         var FORCED$3 = fails$5(function () {
31285           return new Date(NaN).toJSON() !== null
31286             || Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) !== 1;
31287         });
31288
31289         // `Date.prototype.toJSON` method
31290         // https://tc39.es/ecma262/#sec-date.prototype.tojson
31291         $$d({ target: 'Date', proto: true, forced: FORCED$3 }, {
31292           // eslint-disable-next-line no-unused-vars -- required for `.length`
31293           toJSON: function toJSON(key) {
31294             var O = toObject(this);
31295             var pv = toPrimitive(O);
31296             return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString();
31297           }
31298         });
31299
31300         var $$c = _export;
31301
31302         // `URL.prototype.toJSON` method
31303         // https://url.spec.whatwg.org/#dom-url-tojson
31304         $$c({ target: 'URL', proto: true, enumerable: true }, {
31305           toJSON: function toJSON() {
31306             return URL.prototype.toString.call(this);
31307           }
31308         });
31309
31310         function isObject$3(obj) {
31311           return _typeof(obj) === 'object' && obj !== null;
31312         }
31313
31314         function forEach(obj, cb) {
31315           if (Array.isArray(obj)) {
31316             obj.forEach(cb);
31317           } else if (isObject$3(obj)) {
31318             Object.keys(obj).forEach(function (key) {
31319               var val = obj[key];
31320               cb(val, key);
31321             });
31322           }
31323         }
31324
31325         function getTreeDepth(obj) {
31326           var depth = 0;
31327
31328           if (Array.isArray(obj) || isObject$3(obj)) {
31329             forEach(obj, function (val) {
31330               if (Array.isArray(val) || isObject$3(val)) {
31331                 var tmpDepth = getTreeDepth(val);
31332
31333                 if (tmpDepth > depth) {
31334                   depth = tmpDepth;
31335                 }
31336               }
31337             });
31338             return depth + 1;
31339           }
31340
31341           return depth;
31342         }
31343
31344         function stringify(obj, options) {
31345           options = options || {};
31346           var indent = JSON.stringify([1], null, get(options, 'indent', 2)).slice(2, -3);
31347           var addMargin = get(options, 'margins', false);
31348           var addArrayMargin = get(options, 'arrayMargins', false);
31349           var addObjectMargin = get(options, 'objectMargins', false);
31350           var maxLength = indent === '' ? Infinity : get(options, 'maxLength', 80);
31351           var maxNesting = get(options, 'maxNesting', Infinity);
31352           return function _stringify(obj, currentIndent, reserved) {
31353             if (obj && typeof obj.toJSON === 'function') {
31354               obj = obj.toJSON();
31355             }
31356
31357             var string = JSON.stringify(obj);
31358
31359             if (string === undefined) {
31360               return string;
31361             }
31362
31363             var length = maxLength - currentIndent.length - reserved;
31364             var treeDepth = getTreeDepth(obj);
31365
31366             if (treeDepth <= maxNesting && string.length <= length) {
31367               var prettified = prettify(string, {
31368                 addMargin: addMargin,
31369                 addArrayMargin: addArrayMargin,
31370                 addObjectMargin: addObjectMargin
31371               });
31372
31373               if (prettified.length <= length) {
31374                 return prettified;
31375               }
31376             }
31377
31378             if (isObject$3(obj)) {
31379               var nextIndent = currentIndent + indent;
31380               var items = [];
31381               var delimiters;
31382
31383               var comma = function comma(array, index) {
31384                 return index === array.length - 1 ? 0 : 1;
31385               };
31386
31387               if (Array.isArray(obj)) {
31388                 for (var index = 0; index < obj.length; index++) {
31389                   items.push(_stringify(obj[index], nextIndent, comma(obj, index)) || 'null');
31390                 }
31391
31392                 delimiters = '[]';
31393               } else {
31394                 Object.keys(obj).forEach(function (key, index, array) {
31395                   var keyPart = JSON.stringify(key) + ': ';
31396
31397                   var value = _stringify(obj[key], nextIndent, keyPart.length + comma(array, index));
31398
31399                   if (value !== undefined) {
31400                     items.push(keyPart + value);
31401                   }
31402                 });
31403                 delimiters = '{}';
31404               }
31405
31406               if (items.length > 0) {
31407                 return [delimiters[0], indent + items.join(',\n' + nextIndent), delimiters[1]].join('\n' + currentIndent);
31408               }
31409             }
31410
31411             return string;
31412           }(obj, '', 0);
31413         } // Note: This regex matches even invalid JSON strings, but since we’re
31414         // working on the output of `JSON.stringify` we know that only valid strings
31415         // are present (unless the user supplied a weird `options.indent` but in
31416         // that case we don’t care since the output would be invalid anyway).
31417
31418
31419         var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
31420
31421         function prettify(string, options) {
31422           options = options || {};
31423           var tokens = {
31424             '{': '{',
31425             '}': '}',
31426             '[': '[',
31427             ']': ']',
31428             ',': ', ',
31429             ':': ': '
31430           };
31431
31432           if (options.addMargin || options.addObjectMargin) {
31433             tokens['{'] = '{ ';
31434             tokens['}'] = ' }';
31435           }
31436
31437           if (options.addMargin || options.addArrayMargin) {
31438             tokens['['] = '[ ';
31439             tokens[']'] = ' ]';
31440           }
31441
31442           return string.replace(stringOrChar, function (match, string) {
31443             return string ? match : tokens[match];
31444           });
31445         }
31446
31447         function get(options, name, defaultValue) {
31448           return name in options ? options[name] : defaultValue;
31449         }
31450
31451         var jsonStringifyPrettyCompact = stringify;
31452
31453         var _default = /*#__PURE__*/function () {
31454           // constructor
31455           //
31456           // `fc`  Optional FeatureCollection of known features
31457           //
31458           // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
31459           // Each feature must have a filename-like `id`, for example: `something.geojson`
31460           //
31461           // {
31462           //   "type": "FeatureCollection"
31463           //   "features": [
31464           //     {
31465           //       "type": "Feature",
31466           //       "id": "philly_metro.geojson",
31467           //       "properties": { … },
31468           //       "geometry": { … }
31469           //     }
31470           //   ]
31471           // }
31472           function _default(fc) {
31473             var _this = this;
31474
31475             _classCallCheck$1(this, _default);
31476
31477             // The _cache retains resolved features, so if you ask for the same thing multiple times
31478             // we don't repeat the expensive resolving/clipping operations.
31479             //
31480             // Each feature has a stable identifier that is used as the cache key.
31481             // The identifiers look like:
31482             // - for point locations, the stringified point:          e.g. '[8.67039,49.41882]'
31483             // - for geojson locations, the geojson id:               e.g. 'de-hamburg.geojson'
31484             // - for countrycoder locations, feature.id property:     e.g. 'Q2'  (countrycoder uses Wikidata identifiers)
31485             // - for aggregated locationSets, +[include]-[exclude]:   e.g '+[Q2]-[Q18,Q27611]'
31486             this._cache = {}; // When strict mode = true, throw on invalid locations or locationSets.
31487             // When strict mode = false, return `null` for invalid locations or locationSets.
31488
31489             this._strict = true; // process input FeatureCollection
31490
31491             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
31492               fc.features.forEach(function (feature) {
31493                 feature.properties = feature.properties || {};
31494                 var props = feature.properties; // Get `id` from either `id` or `properties`
31495
31496                 var id = feature.id || props.id;
31497                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // Ensure `id` exists and is lowercase
31498
31499                 id = id.toLowerCase();
31500                 feature.id = id;
31501                 props.id = id; // Ensure `area` property exists
31502
31503                 if (!props.area) {
31504                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
31505
31506                   props.area = Number(area.toFixed(2));
31507                 }
31508
31509                 _this._cache[id] = feature;
31510               });
31511             } // Replace CountryCoder world geometry to be a polygon covering the world.
31512
31513
31514             var world = _cloneDeep(feature$1('Q2'));
31515
31516             world.geometry = {
31517               type: 'Polygon',
31518               coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
31519             };
31520             world.id = 'Q2';
31521             world.properties.id = 'Q2';
31522             world.properties.area = geojsonArea.geometry(world.geometry) / 1e6; // m² to km²
31523
31524             this._cache.Q2 = world;
31525           } // validateLocation
31526           // `location`  The location to validate
31527           //
31528           // Pass a `location` value to validate
31529           //
31530           // Returns a result like:
31531           //   {
31532           //     type:     'point', 'geojson', or 'countrycoder'
31533           //     location:  the queried location
31534           //     id:        the stable identifier for the feature
31535           //   }
31536           // or `null` if the location is invalid
31537           //
31538
31539
31540           _createClass$1(_default, [{
31541             key: "validateLocation",
31542             value: function validateLocation(location) {
31543               if (Array.isArray(location) && (location.length === 2 || location.length === 3)) {
31544                 // [lon, lat] or [lon, lat, radius] point?
31545                 var lon = location[0];
31546                 var lat = location[1];
31547                 var radius = location[2];
31548
31549                 if (Number.isFinite(lon) && lon >= -180 && lon <= 180 && Number.isFinite(lat) && lat >= -90 && lat <= 90 && (location.length === 2 || Number.isFinite(radius) && radius > 0)) {
31550                   var id = '[' + location.toString() + ']';
31551                   return {
31552                     type: 'point',
31553                     location: location,
31554                     id: id
31555                   };
31556                 }
31557               } else if (typeof location === 'string' && /^\S+\.geojson$/i.test(location)) {
31558                 // a .geojson filename?
31559                 var _id = location.toLowerCase();
31560
31561                 if (this._cache[_id]) {
31562                   return {
31563                     type: 'geojson',
31564                     location: location,
31565                     id: _id
31566                   };
31567                 }
31568               } else if (typeof location === 'string' || typeof location === 'number') {
31569                 // a country-coder value?
31570                 var feature = feature$1(location);
31571
31572                 if (feature) {
31573                   // Use wikidata QID as the identifier, since that seems to be the one
31574                   // property that everything in CountryCoder is guaranteed to have.
31575                   var _id2 = feature.properties.wikidata;
31576                   return {
31577                     type: 'countrycoder',
31578                     location: location,
31579                     id: _id2
31580                   };
31581                 }
31582               }
31583
31584               if (this._strict) {
31585                 throw new Error("validateLocation:  Invalid location: \"".concat(location, "\"."));
31586               } else {
31587                 return null;
31588               }
31589             } // resolveLocation
31590             // `location`  The location to resolve
31591             //
31592             // Pass a `location` value to resolve
31593             //
31594             // Returns a result like:
31595             //   {
31596             //     type:      'point', 'geojson', or 'countrycoder'
31597             //     location:  the queried location
31598             //     id:        a stable identifier for the feature
31599             //     feature:   the resolved GeoJSON feature
31600             //   }
31601             //  or `null` if the location is invalid
31602             //
31603
31604           }, {
31605             key: "resolveLocation",
31606             value: function resolveLocation(location) {
31607               var valid = this.validateLocation(location);
31608               if (!valid) return null;
31609               var id = valid.id; // Return a result from cache if we can
31610
31611               if (this._cache[id]) {
31612                 return Object.assign(valid, {
31613                   feature: this._cache[id]
31614                 });
31615               } // A [lon,lat] coordinate pair?
31616
31617
31618               if (valid.type === 'point') {
31619                 var lon = location[0];
31620                 var lat = location[1];
31621                 var radius = location[2] || 25; // km
31622
31623                 var EDGES = 10;
31624                 var PRECISION = 3;
31625                 var area = Math.PI * radius * radius;
31626                 var feature = this._cache[id] = precision({
31627                   type: 'Feature',
31628                   id: id,
31629                   properties: {
31630                     id: id,
31631                     area: Number(area.toFixed(2))
31632                   },
31633                   geometry: circleToPolygon([lon, lat], radius * 1000, EDGES) // km to m
31634
31635                 }, PRECISION);
31636                 return Object.assign(valid, {
31637                   feature: feature
31638                 }); // A .geojson filename?
31639               } else if (valid.type === 'geojson') ; else if (valid.type === 'countrycoder') {
31640                 var _feature = _cloneDeep(feature$1(id));
31641
31642                 var props = _feature.properties; // -> This block of code is weird and requires some explanation. <-
31643                 // CountryCoder includes higher level features which are made up of members.
31644                 // These features don't have their own geometry, but CountryCoder provides an
31645                 //   `aggregateFeature` method to combine these members into a MultiPolygon.
31646                 // In the past, Turf/JSTS/martinez could not handle the aggregated features,
31647                 //   so we'd iteratively union them all together.  (this was slow)
31648                 // But now mfogel/polygon-clipping handles these MultiPolygons like a boss.
31649                 // This approach also has the benefit of removing all the internal boaders and
31650                 //   simplifying the regional polygons a lot.
31651
31652                 if (Array.isArray(props.members)) {
31653                   var aggregate = aggregateFeature(id);
31654                   aggregate.geometry.coordinates = _clip([aggregate], 'UNION').geometry.coordinates;
31655                   _feature.geometry = aggregate.geometry;
31656                 } // Ensure `area` property exists
31657
31658
31659                 if (!props.area) {
31660                   var _area = geojsonArea.geometry(_feature.geometry) / 1e6; // m² to km²
31661
31662
31663                   props.area = Number(_area.toFixed(2));
31664                 } // Ensure `id` property exists
31665
31666
31667                 _feature.id = id;
31668                 props.id = id;
31669                 this._cache[id] = _feature;
31670                 return Object.assign(valid, {
31671                   feature: _feature
31672                 });
31673               }
31674
31675               if (this._strict) {
31676                 throw new Error("resolveLocation:  Couldn't resolve location \"".concat(location, "\"."));
31677               } else {
31678                 return null;
31679               }
31680             } // validateLocationSet
31681             // `locationSet`  the locationSet to validate
31682             //
31683             // Pass a locationSet Object to validate like:
31684             //   {
31685             //     include: [ Array of locations ],
31686             //     exclude: [ Array of locations ]
31687             //   }
31688             //
31689             // Returns a result like:
31690             //   {
31691             //     type:         'locationset'
31692             //     locationSet:  the queried locationSet
31693             //     id:           the stable identifier for the feature
31694             //   }
31695             // or `null` if the locationSet is invalid
31696             //
31697
31698           }, {
31699             key: "validateLocationSet",
31700             value: function validateLocationSet(locationSet) {
31701               locationSet = locationSet || {};
31702               var validator = this.validateLocation.bind(this);
31703               var include = (locationSet.include || []).map(validator).filter(Boolean);
31704               var exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
31705
31706               if (!include.length) {
31707                 if (this._strict) {
31708                   throw new Error("validateLocationSet:  LocationSet includes nothing.");
31709                 } else {
31710                   // non-strict mode, replace an empty locationSet with one that includes "the world"
31711                   locationSet.include = ['Q2'];
31712                   include = [{
31713                     type: 'countrycoder',
31714                     location: 'Q2',
31715                     id: 'Q2'
31716                   }];
31717                 }
31718               } // Generate stable identifier
31719
31720
31721               include.sort(_sortLocations);
31722               var id = '+[' + include.map(function (d) {
31723                 return d.id;
31724               }).join(',') + ']';
31725
31726               if (exclude.length) {
31727                 exclude.sort(_sortLocations);
31728                 id += '-[' + exclude.map(function (d) {
31729                   return d.id;
31730                 }).join(',') + ']';
31731               }
31732
31733               return {
31734                 type: 'locationset',
31735                 locationSet: locationSet,
31736                 id: id
31737               };
31738             } // resolveLocationSet
31739             // `locationSet`  the locationSet to resolve
31740             //
31741             // Pass a locationSet Object to validate like:
31742             //   {
31743             //     include: [ Array of locations ],
31744             //     exclude: [ Array of locations ]
31745             //   }
31746             //
31747             // Returns a result like:
31748             //   {
31749             //     type:         'locationset'
31750             //     locationSet:  the queried locationSet
31751             //     id:           the stable identifier for the feature
31752             //     feature:      the resolved GeoJSON feature
31753             //   }
31754             // or `null` if the locationSet is invalid
31755             //
31756
31757           }, {
31758             key: "resolveLocationSet",
31759             value: function resolveLocationSet(locationSet) {
31760               locationSet = locationSet || {};
31761               var valid = this.validateLocationSet(locationSet);
31762               if (!valid) return null;
31763               var id = valid.id; // Return a result from cache if we can
31764
31765               if (this._cache[id]) {
31766                 return Object.assign(valid, {
31767                   feature: this._cache[id]
31768                 });
31769               }
31770
31771               var resolver = this.resolveLocation.bind(this);
31772               var includes = (locationSet.include || []).map(resolver).filter(Boolean);
31773               var excludes = (locationSet.exclude || []).map(resolver).filter(Boolean); // Return quickly if it's a single included location..
31774
31775               if (includes.length === 1 && excludes.length === 0) {
31776                 return Object.assign(valid, {
31777                   feature: includes[0].feature
31778                 });
31779               } // Calculate unions
31780
31781
31782               var includeGeoJSON = _clip(includes.map(function (d) {
31783                 return d.feature;
31784               }), 'UNION');
31785
31786               var excludeGeoJSON = _clip(excludes.map(function (d) {
31787                 return d.feature;
31788               }), 'UNION'); // Calculate difference, update `area` and return result
31789
31790
31791               var resultGeoJSON = excludeGeoJSON ? _clip([includeGeoJSON, excludeGeoJSON], 'DIFFERENCE') : includeGeoJSON;
31792               var area = geojsonArea.geometry(resultGeoJSON.geometry) / 1e6; // m² to km²
31793
31794               resultGeoJSON.id = id;
31795               resultGeoJSON.properties = {
31796                 id: id,
31797                 area: Number(area.toFixed(2))
31798               };
31799               this._cache[id] = resultGeoJSON;
31800               return Object.assign(valid, {
31801                 feature: resultGeoJSON
31802               });
31803             } // strict
31804             //
31805
31806           }, {
31807             key: "strict",
31808             value: function strict(val) {
31809               if (val === undefined) {
31810                 // get
31811                 return this._strict;
31812               } else {
31813                 // set
31814                 this._strict = val;
31815                 return this;
31816               }
31817             } // cache
31818             // convenience method to access the internal cache
31819
31820           }, {
31821             key: "cache",
31822             value: function cache() {
31823               return this._cache;
31824             } // stringify
31825             // convenience method to prettyStringify the given object
31826
31827           }, {
31828             key: "stringify",
31829             value: function stringify(obj, options) {
31830               return jsonStringifyPrettyCompact(obj, options);
31831             }
31832           }]);
31833
31834           return _default;
31835         }(); // Wrap the mfogel/polygon-clipping library and return a GeoJSON feature.
31836
31837         function _clip(features, which) {
31838           if (!Array.isArray(features) || !features.length) return null;
31839           var fn = {
31840             UNION: index.union,
31841             DIFFERENCE: index.difference
31842           }[which];
31843           var args = features.map(function (feature) {
31844             return feature.geometry.coordinates;
31845           });
31846           var coords = fn.apply(null, args);
31847           return {
31848             type: 'Feature',
31849             properties: {},
31850             geometry: {
31851               type: whichType(coords),
31852               coordinates: coords
31853             }
31854           }; // is this a Polygon or a MultiPolygon?
31855
31856           function whichType(coords) {
31857             var a = Array.isArray(coords);
31858             var b = a && Array.isArray(coords[0]);
31859             var c = b && Array.isArray(coords[0][0]);
31860             var d = c && Array.isArray(coords[0][0][0]);
31861             return d ? 'MultiPolygon' : 'Polygon';
31862           }
31863         }
31864
31865         function _cloneDeep(obj) {
31866           return JSON.parse(JSON.stringify(obj));
31867         } // Sorting the location lists is ok because they end up unioned together.
31868         // This sorting makes it possible to generate a deterministic id.
31869
31870
31871         function _sortLocations(a, b) {
31872           var rank = {
31873             countrycoder: 1,
31874             geojson: 2,
31875             point: 3
31876           };
31877           var aRank = rank[a.type];
31878           var bRank = rank[b.type];
31879           return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
31880         }
31881
31882         var $$b = _export;
31883
31884         // `Number.MAX_SAFE_INTEGER` constant
31885         // https://tc39.es/ecma262/#sec-number.max_safe_integer
31886         $$b({ target: 'Number', stat: true }, {
31887           MAX_SAFE_INTEGER: 0x1FFFFFFFFFFFFF
31888         });
31889
31890         var aesJs = {exports: {}};
31891
31892         (function (module, exports) {
31893           (function (root) {
31894
31895             function checkInt(value) {
31896               return parseInt(value) === value;
31897             }
31898
31899             function checkInts(arrayish) {
31900               if (!checkInt(arrayish.length)) {
31901                 return false;
31902               }
31903
31904               for (var i = 0; i < arrayish.length; i++) {
31905                 if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
31906                   return false;
31907                 }
31908               }
31909
31910               return true;
31911             }
31912
31913             function coerceArray(arg, copy) {
31914               // ArrayBuffer view
31915               if (arg.buffer && arg.name === 'Uint8Array') {
31916                 if (copy) {
31917                   if (arg.slice) {
31918                     arg = arg.slice();
31919                   } else {
31920                     arg = Array.prototype.slice.call(arg);
31921                   }
31922                 }
31923
31924                 return arg;
31925               } // It's an array; check it is a valid representation of a byte
31926
31927
31928               if (Array.isArray(arg)) {
31929                 if (!checkInts(arg)) {
31930                   throw new Error('Array contains invalid value: ' + arg);
31931                 }
31932
31933                 return new Uint8Array(arg);
31934               } // Something else, but behaves like an array (maybe a Buffer? Arguments?)
31935
31936
31937               if (checkInt(arg.length) && checkInts(arg)) {
31938                 return new Uint8Array(arg);
31939               }
31940
31941               throw new Error('unsupported array-like object');
31942             }
31943
31944             function createArray(length) {
31945               return new Uint8Array(length);
31946             }
31947
31948             function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
31949               if (sourceStart != null || sourceEnd != null) {
31950                 if (sourceArray.slice) {
31951                   sourceArray = sourceArray.slice(sourceStart, sourceEnd);
31952                 } else {
31953                   sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
31954                 }
31955               }
31956
31957               targetArray.set(sourceArray, targetStart);
31958             }
31959
31960             var convertUtf8 = function () {
31961               function toBytes(text) {
31962                 var result = [],
31963                     i = 0;
31964                 text = encodeURI(text);
31965
31966                 while (i < text.length) {
31967                   var c = text.charCodeAt(i++); // if it is a % sign, encode the following 2 bytes as a hex value
31968
31969                   if (c === 37) {
31970                     result.push(parseInt(text.substr(i, 2), 16));
31971                     i += 2; // otherwise, just the actual byte
31972                   } else {
31973                     result.push(c);
31974                   }
31975                 }
31976
31977                 return coerceArray(result);
31978               }
31979
31980               function fromBytes(bytes) {
31981                 var result = [],
31982                     i = 0;
31983
31984                 while (i < bytes.length) {
31985                   var c = bytes[i];
31986
31987                   if (c < 128) {
31988                     result.push(String.fromCharCode(c));
31989                     i++;
31990                   } else if (c > 191 && c < 224) {
31991                     result.push(String.fromCharCode((c & 0x1f) << 6 | bytes[i + 1] & 0x3f));
31992                     i += 2;
31993                   } else {
31994                     result.push(String.fromCharCode((c & 0x0f) << 12 | (bytes[i + 1] & 0x3f) << 6 | bytes[i + 2] & 0x3f));
31995                     i += 3;
31996                   }
31997                 }
31998
31999                 return result.join('');
32000               }
32001
32002               return {
32003                 toBytes: toBytes,
32004                 fromBytes: fromBytes
32005               };
32006             }();
32007
32008             var convertHex = function () {
32009               function toBytes(text) {
32010                 var result = [];
32011
32012                 for (var i = 0; i < text.length; i += 2) {
32013                   result.push(parseInt(text.substr(i, 2), 16));
32014                 }
32015
32016                 return result;
32017               } // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
32018
32019
32020               var Hex = '0123456789abcdef';
32021
32022               function fromBytes(bytes) {
32023                 var result = [];
32024
32025                 for (var i = 0; i < bytes.length; i++) {
32026                   var v = bytes[i];
32027                   result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
32028                 }
32029
32030                 return result.join('');
32031               }
32032
32033               return {
32034                 toBytes: toBytes,
32035                 fromBytes: fromBytes
32036               };
32037             }(); // Number of rounds by keysize
32038
32039
32040             var numberOfRounds = {
32041               16: 10,
32042               24: 12,
32043               32: 14
32044             }; // Round constant words
32045
32046             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)
32047
32048             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];
32049             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
32050
32051             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];
32052             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];
32053             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];
32054             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
32055
32056             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];
32057             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];
32058             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];
32059             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
32060
32061             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];
32062             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];
32063             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];
32064             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];
32065
32066             function convertToInt32(bytes) {
32067               var result = [];
32068
32069               for (var i = 0; i < bytes.length; i += 4) {
32070                 result.push(bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]);
32071               }
32072
32073               return result;
32074             }
32075
32076             var AES = function AES(key) {
32077               if (!(this instanceof AES)) {
32078                 throw Error('AES must be instanitated with `new`');
32079               }
32080
32081               Object.defineProperty(this, 'key', {
32082                 value: coerceArray(key, true)
32083               });
32084
32085               this._prepare();
32086             };
32087
32088             AES.prototype._prepare = function () {
32089               var rounds = numberOfRounds[this.key.length];
32090
32091               if (rounds == null) {
32092                 throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
32093               } // encryption round keys
32094
32095
32096               this._Ke = []; // decryption round keys
32097
32098               this._Kd = [];
32099
32100               for (var i = 0; i <= rounds; i++) {
32101                 this._Ke.push([0, 0, 0, 0]);
32102
32103                 this._Kd.push([0, 0, 0, 0]);
32104               }
32105
32106               var roundKeyCount = (rounds + 1) * 4;
32107               var KC = this.key.length / 4; // convert the key into ints
32108
32109               var tk = convertToInt32(this.key); // copy values into round key arrays
32110
32111               var index;
32112
32113               for (var i = 0; i < KC; i++) {
32114                 index = i >> 2;
32115                 this._Ke[index][i % 4] = tk[i];
32116                 this._Kd[rounds - index][i % 4] = tk[i];
32117               } // key expansion (fips-197 section 5.2)
32118
32119
32120               var rconpointer = 0;
32121               var t = KC,
32122                   tt;
32123
32124               while (t < roundKeyCount) {
32125                 tt = tk[KC - 1];
32126                 tk[0] ^= S[tt >> 16 & 0xFF] << 24 ^ S[tt >> 8 & 0xFF] << 16 ^ S[tt & 0xFF] << 8 ^ S[tt >> 24 & 0xFF] ^ rcon[rconpointer] << 24;
32127                 rconpointer += 1; // key expansion (for non-256 bit)
32128
32129                 if (KC != 8) {
32130                   for (var i = 1; i < KC; i++) {
32131                     tk[i] ^= tk[i - 1];
32132                   } // key expansion for 256-bit keys is "slightly different" (fips-197)
32133
32134                 } else {
32135                   for (var i = 1; i < KC / 2; i++) {
32136                     tk[i] ^= tk[i - 1];
32137                   }
32138
32139                   tt = tk[KC / 2 - 1];
32140                   tk[KC / 2] ^= S[tt & 0xFF] ^ S[tt >> 8 & 0xFF] << 8 ^ S[tt >> 16 & 0xFF] << 16 ^ S[tt >> 24 & 0xFF] << 24;
32141
32142                   for (var i = KC / 2 + 1; i < KC; i++) {
32143                     tk[i] ^= tk[i - 1];
32144                   }
32145                 } // copy values into round key arrays
32146
32147
32148                 var i = 0,
32149                     r,
32150                     c;
32151
32152                 while (i < KC && t < roundKeyCount) {
32153                   r = t >> 2;
32154                   c = t % 4;
32155                   this._Ke[r][c] = tk[i];
32156                   this._Kd[rounds - r][c] = tk[i++];
32157                   t++;
32158                 }
32159               } // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
32160
32161
32162               for (var r = 1; r < rounds; r++) {
32163                 for (var c = 0; c < 4; c++) {
32164                   tt = this._Kd[r][c];
32165                   this._Kd[r][c] = U1[tt >> 24 & 0xFF] ^ U2[tt >> 16 & 0xFF] ^ U3[tt >> 8 & 0xFF] ^ U4[tt & 0xFF];
32166                 }
32167               }
32168             };
32169
32170             AES.prototype.encrypt = function (plaintext) {
32171               if (plaintext.length != 16) {
32172                 throw new Error('invalid plaintext size (must be 16 bytes)');
32173               }
32174
32175               var rounds = this._Ke.length - 1;
32176               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
32177
32178               var t = convertToInt32(plaintext);
32179
32180               for (var i = 0; i < 4; i++) {
32181                 t[i] ^= this._Ke[0][i];
32182               } // apply round transforms
32183
32184
32185               for (var r = 1; r < rounds; r++) {
32186                 for (var i = 0; i < 4; i++) {
32187                   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];
32188                 }
32189
32190                 t = a.slice();
32191               } // the last round is special
32192
32193
32194               var result = createArray(16),
32195                   tt;
32196
32197               for (var i = 0; i < 4; i++) {
32198                 tt = this._Ke[rounds][i];
32199                 result[4 * i] = (S[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
32200                 result[4 * i + 1] = (S[t[(i + 1) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
32201                 result[4 * i + 2] = (S[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
32202                 result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
32203               }
32204
32205               return result;
32206             };
32207
32208             AES.prototype.decrypt = function (ciphertext) {
32209               if (ciphertext.length != 16) {
32210                 throw new Error('invalid ciphertext size (must be 16 bytes)');
32211               }
32212
32213               var rounds = this._Kd.length - 1;
32214               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
32215
32216               var t = convertToInt32(ciphertext);
32217
32218               for (var i = 0; i < 4; i++) {
32219                 t[i] ^= this._Kd[0][i];
32220               } // apply round transforms
32221
32222
32223               for (var r = 1; r < rounds; r++) {
32224                 for (var i = 0; i < 4; i++) {
32225                   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];
32226                 }
32227
32228                 t = a.slice();
32229               } // the last round is special
32230
32231
32232               var result = createArray(16),
32233                   tt;
32234
32235               for (var i = 0; i < 4; i++) {
32236                 tt = this._Kd[rounds][i];
32237                 result[4 * i] = (Si[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
32238                 result[4 * i + 1] = (Si[t[(i + 3) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
32239                 result[4 * i + 2] = (Si[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
32240                 result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
32241               }
32242
32243               return result;
32244             };
32245             /**
32246              *  Mode Of Operation - Electonic Codebook (ECB)
32247              */
32248
32249
32250             var ModeOfOperationECB = function ModeOfOperationECB(key) {
32251               if (!(this instanceof ModeOfOperationECB)) {
32252                 throw Error('AES must be instanitated with `new`');
32253               }
32254
32255               this.description = "Electronic Code Block";
32256               this.name = "ecb";
32257               this._aes = new AES(key);
32258             };
32259
32260             ModeOfOperationECB.prototype.encrypt = function (plaintext) {
32261               plaintext = coerceArray(plaintext);
32262
32263               if (plaintext.length % 16 !== 0) {
32264                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
32265               }
32266
32267               var ciphertext = createArray(plaintext.length);
32268               var block = createArray(16);
32269
32270               for (var i = 0; i < plaintext.length; i += 16) {
32271                 copyArray(plaintext, block, 0, i, i + 16);
32272                 block = this._aes.encrypt(block);
32273                 copyArray(block, ciphertext, i);
32274               }
32275
32276               return ciphertext;
32277             };
32278
32279             ModeOfOperationECB.prototype.decrypt = function (ciphertext) {
32280               ciphertext = coerceArray(ciphertext);
32281
32282               if (ciphertext.length % 16 !== 0) {
32283                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
32284               }
32285
32286               var plaintext = createArray(ciphertext.length);
32287               var block = createArray(16);
32288
32289               for (var i = 0; i < ciphertext.length; i += 16) {
32290                 copyArray(ciphertext, block, 0, i, i + 16);
32291                 block = this._aes.decrypt(block);
32292                 copyArray(block, plaintext, i);
32293               }
32294
32295               return plaintext;
32296             };
32297             /**
32298              *  Mode Of Operation - Cipher Block Chaining (CBC)
32299              */
32300
32301
32302             var ModeOfOperationCBC = function ModeOfOperationCBC(key, iv) {
32303               if (!(this instanceof ModeOfOperationCBC)) {
32304                 throw Error('AES must be instanitated with `new`');
32305               }
32306
32307               this.description = "Cipher Block Chaining";
32308               this.name = "cbc";
32309
32310               if (!iv) {
32311                 iv = createArray(16);
32312               } else if (iv.length != 16) {
32313                 throw new Error('invalid initialation vector size (must be 16 bytes)');
32314               }
32315
32316               this._lastCipherblock = coerceArray(iv, true);
32317               this._aes = new AES(key);
32318             };
32319
32320             ModeOfOperationCBC.prototype.encrypt = function (plaintext) {
32321               plaintext = coerceArray(plaintext);
32322
32323               if (plaintext.length % 16 !== 0) {
32324                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
32325               }
32326
32327               var ciphertext = createArray(plaintext.length);
32328               var block = createArray(16);
32329
32330               for (var i = 0; i < plaintext.length; i += 16) {
32331                 copyArray(plaintext, block, 0, i, i + 16);
32332
32333                 for (var j = 0; j < 16; j++) {
32334                   block[j] ^= this._lastCipherblock[j];
32335                 }
32336
32337                 this._lastCipherblock = this._aes.encrypt(block);
32338                 copyArray(this._lastCipherblock, ciphertext, i);
32339               }
32340
32341               return ciphertext;
32342             };
32343
32344             ModeOfOperationCBC.prototype.decrypt = function (ciphertext) {
32345               ciphertext = coerceArray(ciphertext);
32346
32347               if (ciphertext.length % 16 !== 0) {
32348                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
32349               }
32350
32351               var plaintext = createArray(ciphertext.length);
32352               var block = createArray(16);
32353
32354               for (var i = 0; i < ciphertext.length; i += 16) {
32355                 copyArray(ciphertext, block, 0, i, i + 16);
32356                 block = this._aes.decrypt(block);
32357
32358                 for (var j = 0; j < 16; j++) {
32359                   plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
32360                 }
32361
32362                 copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
32363               }
32364
32365               return plaintext;
32366             };
32367             /**
32368              *  Mode Of Operation - Cipher Feedback (CFB)
32369              */
32370
32371
32372             var ModeOfOperationCFB = function ModeOfOperationCFB(key, iv, segmentSize) {
32373               if (!(this instanceof ModeOfOperationCFB)) {
32374                 throw Error('AES must be instanitated with `new`');
32375               }
32376
32377               this.description = "Cipher Feedback";
32378               this.name = "cfb";
32379
32380               if (!iv) {
32381                 iv = createArray(16);
32382               } else if (iv.length != 16) {
32383                 throw new Error('invalid initialation vector size (must be 16 size)');
32384               }
32385
32386               if (!segmentSize) {
32387                 segmentSize = 1;
32388               }
32389
32390               this.segmentSize = segmentSize;
32391               this._shiftRegister = coerceArray(iv, true);
32392               this._aes = new AES(key);
32393             };
32394
32395             ModeOfOperationCFB.prototype.encrypt = function (plaintext) {
32396               if (plaintext.length % this.segmentSize != 0) {
32397                 throw new Error('invalid plaintext size (must be segmentSize bytes)');
32398               }
32399
32400               var encrypted = coerceArray(plaintext, true);
32401               var xorSegment;
32402
32403               for (var i = 0; i < encrypted.length; i += this.segmentSize) {
32404                 xorSegment = this._aes.encrypt(this._shiftRegister);
32405
32406                 for (var j = 0; j < this.segmentSize; j++) {
32407                   encrypted[i + j] ^= xorSegment[j];
32408                 } // Shift the register
32409
32410
32411                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
32412                 copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
32413               }
32414
32415               return encrypted;
32416             };
32417
32418             ModeOfOperationCFB.prototype.decrypt = function (ciphertext) {
32419               if (ciphertext.length % this.segmentSize != 0) {
32420                 throw new Error('invalid ciphertext size (must be segmentSize bytes)');
32421               }
32422
32423               var plaintext = coerceArray(ciphertext, true);
32424               var xorSegment;
32425
32426               for (var i = 0; i < plaintext.length; i += this.segmentSize) {
32427                 xorSegment = this._aes.encrypt(this._shiftRegister);
32428
32429                 for (var j = 0; j < this.segmentSize; j++) {
32430                   plaintext[i + j] ^= xorSegment[j];
32431                 } // Shift the register
32432
32433
32434                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
32435                 copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
32436               }
32437
32438               return plaintext;
32439             };
32440             /**
32441              *  Mode Of Operation - Output Feedback (OFB)
32442              */
32443
32444
32445             var ModeOfOperationOFB = function ModeOfOperationOFB(key, iv) {
32446               if (!(this instanceof ModeOfOperationOFB)) {
32447                 throw Error('AES must be instanitated with `new`');
32448               }
32449
32450               this.description = "Output Feedback";
32451               this.name = "ofb";
32452
32453               if (!iv) {
32454                 iv = createArray(16);
32455               } else if (iv.length != 16) {
32456                 throw new Error('invalid initialation vector size (must be 16 bytes)');
32457               }
32458
32459               this._lastPrecipher = coerceArray(iv, true);
32460               this._lastPrecipherIndex = 16;
32461               this._aes = new AES(key);
32462             };
32463
32464             ModeOfOperationOFB.prototype.encrypt = function (plaintext) {
32465               var encrypted = coerceArray(plaintext, true);
32466
32467               for (var i = 0; i < encrypted.length; i++) {
32468                 if (this._lastPrecipherIndex === 16) {
32469                   this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
32470                   this._lastPrecipherIndex = 0;
32471                 }
32472
32473                 encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
32474               }
32475
32476               return encrypted;
32477             }; // Decryption is symetric
32478
32479
32480             ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
32481             /**
32482              *  Counter object for CTR common mode of operation
32483              */
32484
32485             var Counter = function Counter(initialValue) {
32486               if (!(this instanceof Counter)) {
32487                 throw Error('Counter must be instanitated with `new`');
32488               } // We allow 0, but anything false-ish uses the default 1
32489
32490
32491               if (initialValue !== 0 && !initialValue) {
32492                 initialValue = 1;
32493               }
32494
32495               if (typeof initialValue === 'number') {
32496                 this._counter = createArray(16);
32497                 this.setValue(initialValue);
32498               } else {
32499                 this.setBytes(initialValue);
32500               }
32501             };
32502
32503             Counter.prototype.setValue = function (value) {
32504               if (typeof value !== 'number' || parseInt(value) != value) {
32505                 throw new Error('invalid counter value (must be an integer)');
32506               } // We cannot safely handle numbers beyond the safe range for integers
32507
32508
32509               if (value > Number.MAX_SAFE_INTEGER) {
32510                 throw new Error('integer value out of safe range');
32511               }
32512
32513               for (var index = 15; index >= 0; --index) {
32514                 this._counter[index] = value % 256;
32515                 value = parseInt(value / 256);
32516               }
32517             };
32518
32519             Counter.prototype.setBytes = function (bytes) {
32520               bytes = coerceArray(bytes, true);
32521
32522               if (bytes.length != 16) {
32523                 throw new Error('invalid counter bytes size (must be 16 bytes)');
32524               }
32525
32526               this._counter = bytes;
32527             };
32528
32529             Counter.prototype.increment = function () {
32530               for (var i = 15; i >= 0; i--) {
32531                 if (this._counter[i] === 255) {
32532                   this._counter[i] = 0;
32533                 } else {
32534                   this._counter[i]++;
32535                   break;
32536                 }
32537               }
32538             };
32539             /**
32540              *  Mode Of Operation - Counter (CTR)
32541              */
32542
32543
32544             var ModeOfOperationCTR = function ModeOfOperationCTR(key, counter) {
32545               if (!(this instanceof ModeOfOperationCTR)) {
32546                 throw Error('AES must be instanitated with `new`');
32547               }
32548
32549               this.description = "Counter";
32550               this.name = "ctr";
32551
32552               if (!(counter instanceof Counter)) {
32553                 counter = new Counter(counter);
32554               }
32555
32556               this._counter = counter;
32557               this._remainingCounter = null;
32558               this._remainingCounterIndex = 16;
32559               this._aes = new AES(key);
32560             };
32561
32562             ModeOfOperationCTR.prototype.encrypt = function (plaintext) {
32563               var encrypted = coerceArray(plaintext, true);
32564
32565               for (var i = 0; i < encrypted.length; i++) {
32566                 if (this._remainingCounterIndex === 16) {
32567                   this._remainingCounter = this._aes.encrypt(this._counter._counter);
32568                   this._remainingCounterIndex = 0;
32569
32570                   this._counter.increment();
32571                 }
32572
32573                 encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
32574               }
32575
32576               return encrypted;
32577             }; // Decryption is symetric
32578
32579
32580             ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt; ///////////////////////
32581             // Padding
32582             // See:https://tools.ietf.org/html/rfc2315
32583
32584             function pkcs7pad(data) {
32585               data = coerceArray(data, true);
32586               var padder = 16 - data.length % 16;
32587               var result = createArray(data.length + padder);
32588               copyArray(data, result);
32589
32590               for (var i = data.length; i < result.length; i++) {
32591                 result[i] = padder;
32592               }
32593
32594               return result;
32595             }
32596
32597             function pkcs7strip(data) {
32598               data = coerceArray(data, true);
32599
32600               if (data.length < 16) {
32601                 throw new Error('PKCS#7 invalid length');
32602               }
32603
32604               var padder = data[data.length - 1];
32605
32606               if (padder > 16) {
32607                 throw new Error('PKCS#7 padding byte out of range');
32608               }
32609
32610               var length = data.length - padder;
32611
32612               for (var i = 0; i < padder; i++) {
32613                 if (data[length + i] !== padder) {
32614                   throw new Error('PKCS#7 invalid padding byte');
32615                 }
32616               }
32617
32618               var result = createArray(length);
32619               copyArray(data, result, 0, 0, length);
32620               return result;
32621             } ///////////////////////
32622             // Exporting
32623             // The block cipher
32624
32625
32626             var aesjs = {
32627               AES: AES,
32628               Counter: Counter,
32629               ModeOfOperation: {
32630                 ecb: ModeOfOperationECB,
32631                 cbc: ModeOfOperationCBC,
32632                 cfb: ModeOfOperationCFB,
32633                 ofb: ModeOfOperationOFB,
32634                 ctr: ModeOfOperationCTR
32635               },
32636               utils: {
32637                 hex: convertHex,
32638                 utf8: convertUtf8
32639               },
32640               padding: {
32641                 pkcs7: {
32642                   pad: pkcs7pad,
32643                   strip: pkcs7strip
32644                 }
32645               },
32646               _arrayTest: {
32647                 coerceArray: coerceArray,
32648                 createArray: createArray,
32649                 copyArray: copyArray
32650               }
32651             }; // node.js
32652
32653             {
32654               module.exports = aesjs; // RequireJS/AMD
32655               // http://www.requirejs.org/docs/api.html
32656               // https://github.com/amdjs/amdjs-api/wiki/AMD
32657             }
32658           })();
32659         })(aesJs);
32660
32661         var aesjs = aesJs.exports;
32662
32663         // We can use keys that are 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes).
32664         // To generate a random key:  window.crypto.getRandomValues(new Uint8Array(16));
32665         // This default signing key is built into iD and can be used to mask/unmask sensitive values.
32666
32667         var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
32668         function utilAesEncrypt(text, key) {
32669           key = key || DEFAULT_128;
32670           var textBytes = aesjs.utils.utf8.toBytes(text);
32671           var aesCtr = new aesjs.ModeOfOperation.ctr(key);
32672           var encryptedBytes = aesCtr.encrypt(textBytes);
32673           var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
32674           return encryptedHex;
32675         }
32676         function utilAesDecrypt(encryptedHex, key) {
32677           key = key || DEFAULT_128;
32678           var encryptedBytes = aesjs.utils.hex.toBytes(encryptedHex);
32679           var aesCtr = new aesjs.ModeOfOperation.ctr(key);
32680           var decryptedBytes = aesCtr.decrypt(encryptedBytes);
32681           var text = aesjs.utils.utf8.fromBytes(decryptedBytes);
32682           return text;
32683         }
32684
32685         function utilCleanTags(tags) {
32686           var out = {};
32687
32688           for (var k in tags) {
32689             if (!k) continue;
32690             var v = tags[k];
32691
32692             if (v !== undefined) {
32693               out[k] = cleanValue(k, v);
32694             }
32695           }
32696
32697           return out;
32698
32699           function cleanValue(k, v) {
32700             function keepSpaces(k) {
32701               return /_hours|_times|:conditional$/.test(k);
32702             }
32703
32704             function skip(k) {
32705               return /^(description|note|fixme)$/.test(k);
32706             }
32707
32708             if (skip(k)) return v;
32709             var cleaned = v.split(';').map(function (s) {
32710               return s.trim();
32711             }).join(keepSpaces(k) ? '; ' : ';'); // The code below is not intended to validate websites and emails.
32712             // It is only intended to prevent obvious copy-paste errors. (#2323)
32713             // clean website- and email-like tags
32714
32715             if (k.indexOf('website') !== -1 || k.indexOf('email') !== -1 || cleaned.indexOf('http') === 0) {
32716               cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
32717             }
32718
32719             return cleaned;
32720           }
32721         }
32722
32723         var _detected;
32724
32725         function utilDetect(refresh) {
32726           if (_detected && !refresh) return _detected;
32727           _detected = {};
32728           var ua = navigator.userAgent;
32729           var m = null;
32730           /* Browser */
32731
32732           m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
32733
32734           if (m !== null) {
32735             _detected.browser = m[1];
32736             _detected.version = m[2];
32737           }
32738
32739           if (!_detected.browser) {
32740             m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
32741
32742             if (m !== null) {
32743               _detected.browser = 'msie';
32744               _detected.version = m[1];
32745             }
32746           }
32747
32748           if (!_detected.browser) {
32749             m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
32750
32751             if (m !== null) {
32752               _detected.browser = 'Opera';
32753               _detected.version = m[2];
32754             }
32755           }
32756
32757           if (!_detected.browser) {
32758             m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
32759
32760             if (m !== null) {
32761               _detected.browser = m[1];
32762               _detected.version = m[2];
32763               m = ua.match(/version\/([\.\d]+)/i);
32764               if (m !== null) _detected.version = m[1];
32765             }
32766           }
32767
32768           if (!_detected.browser) {
32769             _detected.browser = navigator.appName;
32770             _detected.version = navigator.appVersion;
32771           } // keep major.minor version only..
32772
32773
32774           _detected.version = _detected.version.split(/\W/).slice(0, 2).join('.'); // detect other browser capabilities
32775           // Legacy Opera has incomplete svg style support. See #715
32776
32777           _detected.opera = _detected.browser.toLowerCase() === 'opera' && parseFloat(_detected.version) < 15;
32778
32779           if (_detected.browser.toLowerCase() === 'msie') {
32780             _detected.ie = true;
32781             _detected.browser = 'Internet Explorer';
32782             _detected.support = parseFloat(_detected.version) >= 11;
32783           } else {
32784             _detected.ie = false;
32785             _detected.support = true;
32786           }
32787
32788           _detected.filedrop = window.FileReader && 'ondrop' in window;
32789           _detected.download = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
32790           _detected.cssfilters = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
32791           /* Platform */
32792
32793           if (/Win/.test(ua)) {
32794             _detected.os = 'win';
32795             _detected.platform = 'Windows';
32796           } else if (/Mac/.test(ua)) {
32797             _detected.os = 'mac';
32798             _detected.platform = 'Macintosh';
32799           } else if (/X11/.test(ua) || /Linux/.test(ua)) {
32800             _detected.os = 'linux';
32801             _detected.platform = 'Linux';
32802           } else {
32803             _detected.os = 'win';
32804             _detected.platform = 'Unknown';
32805           }
32806
32807           _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
32808           // so assume any "mac" with multitouch is actually iOS
32809           navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
32810           /* Locale */
32811           // An array of locales requested by the browser in priority order.
32812
32813           _detected.browserLocales = Array.from(new Set( // remove duplicates
32814           [navigator.language].concat(navigator.languages || []).concat([// old property for backwards compatibility
32815           navigator.userLanguage]) // remove any undefined values
32816           .filter(Boolean)));
32817           /* Host */
32818
32819           var loc = window.top.location;
32820           var origin = loc.origin;
32821
32822           if (!origin) {
32823             // for unpatched IE11
32824             origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port : '');
32825           }
32826
32827           _detected.host = origin + loc.pathname;
32828           return _detected;
32829         }
32830
32831         // Like selection.property('value', ...), but avoids no-op value sets,
32832         // which can result in layout/repaint thrashing in some situations.
32833         function utilGetSetValue(selection, value) {
32834           function d3_selection_value(value) {
32835             function valueNull() {
32836               delete this.value;
32837             }
32838
32839             function valueConstant() {
32840               if (this.value !== value) {
32841                 this.value = value;
32842               }
32843             }
32844
32845             function valueFunction() {
32846               var x = value.apply(this, arguments);
32847
32848               if (x === null || x === undefined) {
32849                 delete this.value;
32850               } else if (this.value !== x) {
32851                 this.value = x;
32852               }
32853             }
32854
32855             return value === null || value === undefined ? valueNull : typeof value === 'function' ? valueFunction : valueConstant;
32856           }
32857
32858           if (arguments.length === 1) {
32859             return selection.property('value');
32860           }
32861
32862           return selection.each(d3_selection_value(value));
32863         }
32864
32865         function utilKeybinding(namespace) {
32866           var _keybindings = {};
32867
32868           function testBindings(d3_event, isCapturing) {
32869             var didMatch = false;
32870             var bindings = Object.keys(_keybindings).map(function (id) {
32871               return _keybindings[id];
32872             });
32873             var i, binding; // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
32874             // so we don't strictly match on the shift key, but we prioritize
32875             // shifted keybindings first, and fallback to unshifted only if no match.
32876             // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
32877             // priority match shifted keybindings first
32878
32879             for (i = 0; i < bindings.length; i++) {
32880               binding = bindings[i];
32881               if (!binding.event.modifiers.shiftKey) continue; // no shift
32882
32883               if (!!binding.capture !== isCapturing) continue;
32884
32885               if (matches(d3_event, binding, true)) {
32886                 binding.callback(d3_event);
32887                 didMatch = true; // match a max of one binding per event
32888
32889                 break;
32890               }
32891             }
32892
32893             if (didMatch) return; // then unshifted keybindings
32894
32895             for (i = 0; i < bindings.length; i++) {
32896               binding = bindings[i];
32897               if (binding.event.modifiers.shiftKey) continue; // shift
32898
32899               if (!!binding.capture !== isCapturing) continue;
32900
32901               if (matches(d3_event, binding, false)) {
32902                 binding.callback(d3_event);
32903                 break;
32904               }
32905             }
32906
32907             function matches(d3_event, binding, testShift) {
32908               var event = d3_event;
32909               var isMatch = false;
32910               var tryKeyCode = true; // Prefer a match on `KeyboardEvent.key`
32911
32912               if (event.key !== undefined) {
32913                 tryKeyCode = event.key.charCodeAt(0) > 255; // outside ISO-Latin-1
32914
32915                 isMatch = true;
32916
32917                 if (binding.event.key === undefined) {
32918                   isMatch = false;
32919                 } else if (Array.isArray(binding.event.key)) {
32920                   if (binding.event.key.map(function (s) {
32921                     return s.toLowerCase();
32922                   }).indexOf(event.key.toLowerCase()) === -1) {
32923                     isMatch = false;
32924                   }
32925                 } else {
32926                   if (event.key.toLowerCase() !== binding.event.key.toLowerCase()) {
32927                     isMatch = false;
32928                   }
32929                 }
32930               } // Fallback match on `KeyboardEvent.keyCode`, can happen if:
32931               // - browser doesn't support `KeyboardEvent.key`
32932               // - `KeyboardEvent.key` is outside ISO-Latin-1 range (cyrillic?)
32933
32934
32935               if (!isMatch && tryKeyCode) {
32936                 isMatch = event.keyCode === binding.event.keyCode;
32937               }
32938
32939               if (!isMatch) return false; // test modifier keys
32940
32941               if (!(event.ctrlKey && event.altKey)) {
32942                 // if both are set, assume AltGr and skip it - #4096
32943                 if (event.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
32944                 if (event.altKey !== binding.event.modifiers.altKey) return false;
32945               }
32946
32947               if (event.metaKey !== binding.event.modifiers.metaKey) return false;
32948               if (testShift && event.shiftKey !== binding.event.modifiers.shiftKey) return false;
32949               return true;
32950             }
32951           }
32952
32953           function capture(d3_event) {
32954             testBindings(d3_event, true);
32955           }
32956
32957           function bubble(d3_event) {
32958             var tagName = select(d3_event.target).node().tagName;
32959
32960             if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
32961               return;
32962             }
32963
32964             testBindings(d3_event, false);
32965           }
32966
32967           function keybinding(selection) {
32968             selection = selection || select(document);
32969             selection.on('keydown.capture.' + namespace, capture, true);
32970             selection.on('keydown.bubble.' + namespace, bubble, false);
32971             return keybinding;
32972           } // was: keybinding.off()
32973
32974
32975           keybinding.unbind = function (selection) {
32976             _keybindings = [];
32977             selection = selection || select(document);
32978             selection.on('keydown.capture.' + namespace, null);
32979             selection.on('keydown.bubble.' + namespace, null);
32980             return keybinding;
32981           };
32982
32983           keybinding.clear = function () {
32984             _keybindings = {};
32985             return keybinding;
32986           }; // Remove one or more keycode bindings.
32987
32988
32989           keybinding.off = function (codes, capture) {
32990             var arr = utilArrayUniq([].concat(codes));
32991
32992             for (var i = 0; i < arr.length; i++) {
32993               var id = arr[i] + (capture ? '-capture' : '-bubble');
32994               delete _keybindings[id];
32995             }
32996
32997             return keybinding;
32998           }; // Add one or more keycode bindings.
32999
33000
33001           keybinding.on = function (codes, callback, capture) {
33002             if (typeof callback !== 'function') {
33003               return keybinding.off(codes, capture);
33004             }
33005
33006             var arr = utilArrayUniq([].concat(codes));
33007
33008             for (var i = 0; i < arr.length; i++) {
33009               var id = arr[i] + (capture ? '-capture' : '-bubble');
33010               var binding = {
33011                 id: id,
33012                 capture: capture,
33013                 callback: callback,
33014                 event: {
33015                   key: undefined,
33016                   // preferred
33017                   keyCode: 0,
33018                   // fallback
33019                   modifiers: {
33020                     shiftKey: false,
33021                     ctrlKey: false,
33022                     altKey: false,
33023                     metaKey: false
33024                   }
33025                 }
33026               };
33027
33028               if (_keybindings[id]) {
33029                 console.warn('warning: duplicate keybinding for "' + id + '"'); // eslint-disable-line no-console
33030               }
33031
33032               _keybindings[id] = binding;
33033               var matches = arr[i].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
33034
33035               for (var j = 0; j < matches.length; j++) {
33036                 // Normalise matching errors
33037                 if (matches[j] === '++') matches[j] = '+';
33038
33039                 if (matches[j] in utilKeybinding.modifierCodes) {
33040                   var prop = utilKeybinding.modifierProperties[utilKeybinding.modifierCodes[matches[j]]];
33041                   binding.event.modifiers[prop] = true;
33042                 } else {
33043                   binding.event.key = utilKeybinding.keys[matches[j]] || matches[j];
33044
33045                   if (matches[j] in utilKeybinding.keyCodes) {
33046                     binding.event.keyCode = utilKeybinding.keyCodes[matches[j]];
33047                   }
33048                 }
33049               }
33050             }
33051
33052             return keybinding;
33053           };
33054
33055           return keybinding;
33056         }
33057         /*
33058          * See https://github.com/keithamus/jwerty
33059          */
33060
33061         utilKeybinding.modifierCodes = {
33062           // Shift key, ⇧
33063           '⇧': 16,
33064           shift: 16,
33065           // CTRL key, on Mac: ⌃
33066           '⌃': 17,
33067           ctrl: 17,
33068           // ALT key, on Mac: ⌥ (Alt)
33069           '⌥': 18,
33070           alt: 18,
33071           option: 18,
33072           // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
33073           '⌘': 91,
33074           meta: 91,
33075           cmd: 91,
33076           'super': 91,
33077           win: 91
33078         };
33079         utilKeybinding.modifierProperties = {
33080           16: 'shiftKey',
33081           17: 'ctrlKey',
33082           18: 'altKey',
33083           91: 'metaKey'
33084         };
33085         utilKeybinding.plusKeys = ['plus', 'ffplus', '=', 'ffequals', '≠', '±'];
33086         utilKeybinding.minusKeys = ['_', '-', 'ffminus', 'dash', '–', '—'];
33087         utilKeybinding.keys = {
33088           // Backspace key, on Mac: ⌫ (Backspace)
33089           '⌫': 'Backspace',
33090           backspace: 'Backspace',
33091           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
33092           '⇥': 'Tab',
33093           '⇆': 'Tab',
33094           tab: 'Tab',
33095           // Return key, ↩
33096           '↩': 'Enter',
33097           '↵': 'Enter',
33098           '⏎': 'Enter',
33099           'return': 'Enter',
33100           enter: 'Enter',
33101           '⌅': 'Enter',
33102           // Pause/Break key
33103           'pause': 'Pause',
33104           'pause-break': 'Pause',
33105           // Caps Lock key, ⇪
33106           '⇪': 'CapsLock',
33107           caps: 'CapsLock',
33108           'caps-lock': 'CapsLock',
33109           // Escape key, on Mac: ⎋, on Windows: Esc
33110           '⎋': ['Escape', 'Esc'],
33111           escape: ['Escape', 'Esc'],
33112           esc: ['Escape', 'Esc'],
33113           // Space key
33114           space: [' ', 'Spacebar'],
33115           // Page-Up key, or pgup, on Mac: ↖
33116           '↖': 'PageUp',
33117           pgup: 'PageUp',
33118           'page-up': 'PageUp',
33119           // Page-Down key, or pgdown, on Mac: ↘
33120           '↘': 'PageDown',
33121           pgdown: 'PageDown',
33122           'page-down': 'PageDown',
33123           // END key, on Mac: ⇟
33124           '⇟': 'End',
33125           end: 'End',
33126           // HOME key, on Mac: ⇞
33127           '⇞': 'Home',
33128           home: 'Home',
33129           // Insert key, or ins
33130           ins: 'Insert',
33131           insert: 'Insert',
33132           // Delete key, on Mac: ⌦ (Delete)
33133           '⌦': ['Delete', 'Del'],
33134           del: ['Delete', 'Del'],
33135           'delete': ['Delete', 'Del'],
33136           // Left Arrow Key, or ←
33137           '←': ['ArrowLeft', 'Left'],
33138           left: ['ArrowLeft', 'Left'],
33139           'arrow-left': ['ArrowLeft', 'Left'],
33140           // Up Arrow Key, or ↑
33141           '↑': ['ArrowUp', 'Up'],
33142           up: ['ArrowUp', 'Up'],
33143           'arrow-up': ['ArrowUp', 'Up'],
33144           // Right Arrow Key, or →
33145           '→': ['ArrowRight', 'Right'],
33146           right: ['ArrowRight', 'Right'],
33147           'arrow-right': ['ArrowRight', 'Right'],
33148           // Up Arrow Key, or ↓
33149           '↓': ['ArrowDown', 'Down'],
33150           down: ['ArrowDown', 'Down'],
33151           'arrow-down': ['ArrowDown', 'Down'],
33152           // odities, stuff for backward compatibility (browsers and code):
33153           // Num-Multiply, or *
33154           '*': ['*', 'Multiply'],
33155           star: ['*', 'Multiply'],
33156           asterisk: ['*', 'Multiply'],
33157           multiply: ['*', 'Multiply'],
33158           // Num-Plus or +
33159           '+': ['+', 'Add'],
33160           'plus': ['+', 'Add'],
33161           // Num-Subtract, or -
33162           '-': ['-', 'Subtract'],
33163           subtract: ['-', 'Subtract'],
33164           'dash': ['-', 'Subtract'],
33165           // Semicolon
33166           semicolon: ';',
33167           // = or equals
33168           equals: '=',
33169           // Comma, or ,
33170           comma: ',',
33171           // Period, or ., or full-stop
33172           period: '.',
33173           'full-stop': '.',
33174           // Slash, or /, or forward-slash
33175           slash: '/',
33176           'forward-slash': '/',
33177           // Tick, or `, or back-quote
33178           tick: '`',
33179           'back-quote': '`',
33180           // Open bracket, or [
33181           'open-bracket': '[',
33182           // Back slash, or \
33183           'back-slash': '\\',
33184           // Close backet, or ]
33185           'close-bracket': ']',
33186           // Apostrophe, or Quote, or '
33187           quote: '\'',
33188           apostrophe: '\'',
33189           // NUMPAD 0-9
33190           'num-0': '0',
33191           'num-1': '1',
33192           'num-2': '2',
33193           'num-3': '3',
33194           'num-4': '4',
33195           'num-5': '5',
33196           'num-6': '6',
33197           'num-7': '7',
33198           'num-8': '8',
33199           'num-9': '9',
33200           // F1-F25
33201           f1: 'F1',
33202           f2: 'F2',
33203           f3: 'F3',
33204           f4: 'F4',
33205           f5: 'F5',
33206           f6: 'F6',
33207           f7: 'F7',
33208           f8: 'F8',
33209           f9: 'F9',
33210           f10: 'F10',
33211           f11: 'F11',
33212           f12: 'F12',
33213           f13: 'F13',
33214           f14: 'F14',
33215           f15: 'F15',
33216           f16: 'F16',
33217           f17: 'F17',
33218           f18: 'F18',
33219           f19: 'F19',
33220           f20: 'F20',
33221           f21: 'F21',
33222           f22: 'F22',
33223           f23: 'F23',
33224           f24: 'F24',
33225           f25: 'F25'
33226         };
33227         utilKeybinding.keyCodes = {
33228           // Backspace key, on Mac: ⌫ (Backspace)
33229           '⌫': 8,
33230           backspace: 8,
33231           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
33232           '⇥': 9,
33233           '⇆': 9,
33234           tab: 9,
33235           // Return key, ↩
33236           '↩': 13,
33237           '↵': 13,
33238           '⏎': 13,
33239           'return': 13,
33240           enter: 13,
33241           '⌅': 13,
33242           // Pause/Break key
33243           'pause': 19,
33244           'pause-break': 19,
33245           // Caps Lock key, ⇪
33246           '⇪': 20,
33247           caps: 20,
33248           'caps-lock': 20,
33249           // Escape key, on Mac: ⎋, on Windows: Esc
33250           '⎋': 27,
33251           escape: 27,
33252           esc: 27,
33253           // Space key
33254           space: 32,
33255           // Page-Up key, or pgup, on Mac: ↖
33256           '↖': 33,
33257           pgup: 33,
33258           'page-up': 33,
33259           // Page-Down key, or pgdown, on Mac: ↘
33260           '↘': 34,
33261           pgdown: 34,
33262           'page-down': 34,
33263           // END key, on Mac: ⇟
33264           '⇟': 35,
33265           end: 35,
33266           // HOME key, on Mac: ⇞
33267           '⇞': 36,
33268           home: 36,
33269           // Insert key, or ins
33270           ins: 45,
33271           insert: 45,
33272           // Delete key, on Mac: ⌦ (Delete)
33273           '⌦': 46,
33274           del: 46,
33275           'delete': 46,
33276           // Left Arrow Key, or ←
33277           '←': 37,
33278           left: 37,
33279           'arrow-left': 37,
33280           // Up Arrow Key, or ↑
33281           '↑': 38,
33282           up: 38,
33283           'arrow-up': 38,
33284           // Right Arrow Key, or →
33285           '→': 39,
33286           right: 39,
33287           'arrow-right': 39,
33288           // Up Arrow Key, or ↓
33289           '↓': 40,
33290           down: 40,
33291           'arrow-down': 40,
33292           // odities, printing characters that come out wrong:
33293           // Firefox Equals
33294           'ffequals': 61,
33295           // Num-Multiply, or *
33296           '*': 106,
33297           star: 106,
33298           asterisk: 106,
33299           multiply: 106,
33300           // Num-Plus or +
33301           '+': 107,
33302           'plus': 107,
33303           // Num-Subtract, or -
33304           '-': 109,
33305           subtract: 109,
33306           // Vertical Bar / Pipe
33307           '|': 124,
33308           // Firefox Plus
33309           'ffplus': 171,
33310           // Firefox Minus
33311           'ffminus': 173,
33312           // Semicolon
33313           ';': 186,
33314           semicolon: 186,
33315           // = or equals
33316           '=': 187,
33317           'equals': 187,
33318           // Comma, or ,
33319           ',': 188,
33320           comma: 188,
33321           // Dash / Underscore key
33322           'dash': 189,
33323           // Period, or ., or full-stop
33324           '.': 190,
33325           period: 190,
33326           'full-stop': 190,
33327           // Slash, or /, or forward-slash
33328           '/': 191,
33329           slash: 191,
33330           'forward-slash': 191,
33331           // Tick, or `, or back-quote
33332           '`': 192,
33333           tick: 192,
33334           'back-quote': 192,
33335           // Open bracket, or [
33336           '[': 219,
33337           'open-bracket': 219,
33338           // Back slash, or \
33339           '\\': 220,
33340           'back-slash': 220,
33341           // Close backet, or ]
33342           ']': 221,
33343           'close-bracket': 221,
33344           // Apostrophe, or Quote, or '
33345           '\'': 222,
33346           quote: 222,
33347           apostrophe: 222
33348         }; // NUMPAD 0-9
33349
33350         var i = 95,
33351             n = 0;
33352
33353         while (++i < 106) {
33354           utilKeybinding.keyCodes['num-' + n] = i;
33355           ++n;
33356         } // 0-9
33357
33358
33359         i = 47;
33360         n = 0;
33361
33362         while (++i < 58) {
33363           utilKeybinding.keyCodes[n] = i;
33364           ++n;
33365         } // F1-F25
33366
33367
33368         i = 111;
33369         n = 1;
33370
33371         while (++i < 136) {
33372           utilKeybinding.keyCodes['f' + n] = i;
33373           ++n;
33374         } // a-z
33375
33376
33377         i = 64;
33378
33379         while (++i < 91) {
33380           utilKeybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
33381         }
33382
33383         function utilObjectOmit(obj, omitKeys) {
33384           return Object.keys(obj).reduce(function (result, key) {
33385             if (omitKeys.indexOf(key) === -1) {
33386               result[key] = obj[key]; // keep
33387             }
33388
33389             return result;
33390           }, {});
33391         }
33392
33393         // Copies a variable number of methods from source to target.
33394         function utilRebind(target, source) {
33395           var i = 1,
33396               n = arguments.length,
33397               method;
33398
33399           while (++i < n) {
33400             target[method = arguments[i]] = d3_rebind(target, source, source[method]);
33401           }
33402
33403           return target;
33404         } // Method is assumed to be a standard D3 getter-setter:
33405         // If passed with no arguments, gets the value.
33406         // If passed with arguments, sets the value and returns the target.
33407
33408         function d3_rebind(target, source, method) {
33409           return function () {
33410             var value = method.apply(source, arguments);
33411             return value === source ? target : value;
33412           };
33413         }
33414
33415         // A per-domain session mutex backed by a cookie and dead man's
33416         // switch. If the session crashes, the mutex will auto-release
33417         // after 5 seconds.
33418         // This accepts a string and returns an object that complies with utilSessionMutexType
33419         function utilSessionMutex(name) {
33420           var mutex = {};
33421           var intervalID;
33422
33423           function renew() {
33424             var expires = new Date();
33425             expires.setSeconds(expires.getSeconds() + 5);
33426             document.cookie = name + '=1; expires=' + expires.toUTCString() + '; sameSite=strict';
33427           }
33428
33429           mutex.lock = function () {
33430             if (intervalID) return true;
33431             var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
33432             if (cookie) return false;
33433             renew();
33434             intervalID = window.setInterval(renew, 4000);
33435             return true;
33436           };
33437
33438           mutex.unlock = function () {
33439             if (!intervalID) return;
33440             document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict';
33441             clearInterval(intervalID);
33442             intervalID = null;
33443           };
33444
33445           mutex.locked = function () {
33446             return !!intervalID;
33447           };
33448
33449           return mutex;
33450         }
33451
33452         function utilTiler() {
33453           var _size = [256, 256];
33454           var _scale = 256;
33455           var _tileSize = 256;
33456           var _zoomExtent = [0, 20];
33457           var _translate = [_size[0] / 2, _size[1] / 2];
33458           var _margin = 0;
33459           var _skipNullIsland = false;
33460
33461           function clamp(num, min, max) {
33462             return Math.max(min, Math.min(num, max));
33463           }
33464
33465           function nearNullIsland(tile) {
33466             var x = tile[0];
33467             var y = tile[1];
33468             var z = tile[2];
33469
33470             if (z >= 7) {
33471               var center = Math.pow(2, z - 1);
33472               var width = Math.pow(2, z - 6);
33473               var min = center - width / 2;
33474               var max = center + width / 2 - 1;
33475               return x >= min && x <= max && y >= min && y <= max;
33476             }
33477
33478             return false;
33479           }
33480
33481           function tiler() {
33482             var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
33483             var z0 = clamp(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
33484             var tileMin = 0;
33485             var tileMax = Math.pow(2, z0) - 1;
33486             var log2ts = Math.log(_tileSize) * Math.LOG2E;
33487             var k = Math.pow(2, z - z0 + log2ts);
33488             var origin = [(_translate[0] - _scale / 2) / k, (_translate[1] - _scale / 2) / k];
33489             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));
33490             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));
33491             var tiles = [];
33492
33493             for (var i = 0; i < rows.length; i++) {
33494               var y = rows[i];
33495
33496               for (var j = 0; j < cols.length; j++) {
33497                 var x = cols[j];
33498
33499                 if (i >= _margin && i <= rows.length - _margin && j >= _margin && j <= cols.length - _margin) {
33500                   tiles.unshift([x, y, z0]); // tiles in view at beginning
33501                 } else {
33502                   tiles.push([x, y, z0]); // tiles in margin at the end
33503                 }
33504               }
33505             }
33506
33507             tiles.translate = origin;
33508             tiles.scale = k;
33509             return tiles;
33510           }
33511           /**
33512            * getTiles() returns an array of tiles that cover the map view
33513            */
33514
33515
33516           tiler.getTiles = function (projection) {
33517             var origin = [projection.scale() * Math.PI - projection.translate()[0], projection.scale() * Math.PI - projection.translate()[1]];
33518             this.size(projection.clipExtent()[1]).scale(projection.scale() * 2 * Math.PI).translate(projection.translate());
33519             var tiles = tiler();
33520             var ts = tiles.scale;
33521             return tiles.map(function (tile) {
33522               if (_skipNullIsland && nearNullIsland(tile)) {
33523                 return false;
33524               }
33525
33526               var x = tile[0] * ts - origin[0];
33527               var y = tile[1] * ts - origin[1];
33528               return {
33529                 id: tile.toString(),
33530                 xyz: tile,
33531                 extent: geoExtent(projection.invert([x, y + ts]), projection.invert([x + ts, y]))
33532               };
33533             }).filter(Boolean);
33534           };
33535           /**
33536            * getGeoJSON() returns a FeatureCollection for debugging tiles
33537            */
33538
33539
33540           tiler.getGeoJSON = function (projection) {
33541             var features = tiler.getTiles(projection).map(function (tile) {
33542               return {
33543                 type: 'Feature',
33544                 properties: {
33545                   id: tile.id,
33546                   name: tile.id
33547                 },
33548                 geometry: {
33549                   type: 'Polygon',
33550                   coordinates: [tile.extent.polygon()]
33551                 }
33552               };
33553             });
33554             return {
33555               type: 'FeatureCollection',
33556               features: features
33557             };
33558           };
33559
33560           tiler.tileSize = function (val) {
33561             if (!arguments.length) return _tileSize;
33562             _tileSize = val;
33563             return tiler;
33564           };
33565
33566           tiler.zoomExtent = function (val) {
33567             if (!arguments.length) return _zoomExtent;
33568             _zoomExtent = val;
33569             return tiler;
33570           };
33571
33572           tiler.size = function (val) {
33573             if (!arguments.length) return _size;
33574             _size = val;
33575             return tiler;
33576           };
33577
33578           tiler.scale = function (val) {
33579             if (!arguments.length) return _scale;
33580             _scale = val;
33581             return tiler;
33582           };
33583
33584           tiler.translate = function (val) {
33585             if (!arguments.length) return _translate;
33586             _translate = val;
33587             return tiler;
33588           }; // number to extend the rows/columns beyond those covering the viewport
33589
33590
33591           tiler.margin = function (val) {
33592             if (!arguments.length) return _margin;
33593             _margin = +val;
33594             return tiler;
33595           };
33596
33597           tiler.skipNullIsland = function (val) {
33598             if (!arguments.length) return _skipNullIsland;
33599             _skipNullIsland = val;
33600             return tiler;
33601           };
33602
33603           return tiler;
33604         }
33605
33606         function utilTriggerEvent(target, type) {
33607           target.each(function () {
33608             var evt = document.createEvent('HTMLEvents');
33609             evt.initEvent(type, true, true);
33610             this.dispatchEvent(evt);
33611           });
33612         }
33613
33614         var _mainLocations = coreLocations(); // singleton
33615         // `coreLocations` maintains an internal index of all the boundaries/geofences used by iD.
33616         // It's used by presets, community index, background imagery, to know where in the world these things are valid.
33617         // These geofences should be defined by `locationSet` objects:
33618         //
33619         // let locationSet = {
33620         //   include: [ Array of locations ],
33621         //   exclude: [ Array of locations ]
33622         // };
33623         //
33624         // For more info see the location-conflation and country-coder projects, see:
33625         // https://github.com/ideditor/location-conflation
33626         // https://github.com/ideditor/country-coder
33627         //
33628
33629         function coreLocations() {
33630           var _this = {};
33631           var _resolvedFeatures = {}; // cache of *resolved* locationSet features
33632
33633           var _loco = new _default(); // instance of a location-conflation resolver
33634
33635
33636           var _wp; // instance of a which-polygon index
33637           // pre-resolve the worldwide locationSet
33638
33639
33640           var world = {
33641             locationSet: {
33642               include: ['Q2']
33643             }
33644           };
33645           resolveLocationSet(world);
33646           rebuildIndex();
33647           var _queue = [];
33648
33649           var _deferred = new Set();
33650
33651           var _inProcess; // Returns a Promise to process the queue
33652
33653
33654           function processQueue() {
33655             if (!_queue.length) return Promise.resolve(); // console.log(`queue length ${_queue.length}`);
33656
33657             var chunk = _queue.pop();
33658
33659             return new Promise(function (resolvePromise) {
33660               var handle = window.requestIdleCallback(function () {
33661                 _deferred["delete"](handle); // const t0 = performance.now();
33662
33663
33664                 chunk.forEach(resolveLocationSet); // const t1 = performance.now();
33665                 // console.log('chunk processed in ' + (t1 - t0) + ' ms');
33666
33667                 resolvePromise();
33668               });
33669
33670               _deferred.add(handle);
33671             }).then(function () {
33672               return processQueue();
33673             });
33674           } // Pass an Object with a `locationSet` property,
33675           // Performs the locationSet resolution, caches the result, and sets a `locationSetID` property on the object.
33676
33677
33678           function resolveLocationSet(obj) {
33679             if (obj.locationSetID) return; // work was done already
33680
33681             try {
33682               var locationSet = obj.locationSet;
33683
33684               if (!locationSet) {
33685                 throw new Error('object missing locationSet property');
33686               }
33687
33688               if (!locationSet.include) {
33689                 // missing `include`, default to worldwide include
33690                 locationSet.include = ['Q2']; // https://github.com/openstreetmap/iD/pull/8305#discussion_r662344647
33691               }
33692
33693               var resolved = _loco.resolveLocationSet(locationSet);
33694
33695               var locationSetID = resolved.id;
33696               obj.locationSetID = locationSetID;
33697
33698               if (!resolved.feature.geometry.coordinates.length || !resolved.feature.properties.area) {
33699                 throw new Error("locationSet ".concat(locationSetID, " resolves to an empty feature."));
33700               }
33701
33702               if (!_resolvedFeatures[locationSetID]) {
33703                 // First time seeing this locationSet feature
33704                 var feature = JSON.parse(JSON.stringify(resolved.feature)); // deep clone
33705
33706                 feature.id = locationSetID; // Important: always use the locationSet `id` (`+[Q30]`), not the feature `id` (`Q30`)
33707
33708                 feature.properties.id = locationSetID;
33709                 _resolvedFeatures[locationSetID] = feature; // insert into cache
33710               }
33711             } catch (err) {
33712               obj.locationSet = {
33713                 include: ['Q2']
33714               }; // default worldwide
33715
33716               obj.locationSetID = '+[Q2]';
33717             }
33718           } // Rebuilds the whichPolygon index with whatever features have been resolved.
33719
33720
33721           function rebuildIndex() {
33722             _wp = whichPolygon_1({
33723               features: Object.values(_resolvedFeatures)
33724             });
33725           } //
33726           // `mergeCustomGeoJSON`
33727           //  Accepts an FeatureCollection-like object containing custom locations
33728           //  Each feature must have a filename-like `id`, for example: `something.geojson`
33729           //
33730           //  {
33731           //    "type": "FeatureCollection"
33732           //    "features": [
33733           //      {
33734           //        "type": "Feature",
33735           //        "id": "philly_metro.geojson",
33736           //        "properties": { … },
33737           //        "geometry": { … }
33738           //      }
33739           //    ]
33740           //  }
33741           //
33742
33743
33744           _this.mergeCustomGeoJSON = function (fc) {
33745             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
33746               fc.features.forEach(function (feature) {
33747                 feature.properties = feature.properties || {};
33748                 var props = feature.properties; // Get `id` from either `id` or `properties`
33749
33750                 var id = feature.id || props.id;
33751                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // Ensure `id` exists and is lowercase
33752
33753                 id = id.toLowerCase();
33754                 feature.id = id;
33755                 props.id = id; // Ensure `area` property exists
33756
33757                 if (!props.area) {
33758                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
33759
33760                   props.area = Number(area.toFixed(2));
33761                 }
33762
33763                 _loco._cache[id] = feature;
33764               });
33765             }
33766           }; //
33767           // `mergeLocationSets`
33768           //  Accepts an Array of Objects containing `locationSet` properties.
33769           //  The locationSets will be resolved and indexed in the background.
33770           //  [
33771           //   { id: 'preset1', locationSet: {…} },
33772           //   { id: 'preset2', locationSet: {…} },
33773           //   { id: 'preset3', locationSet: {…} },
33774           //   …
33775           //  ]
33776           //  After resolving and indexing, the Objects will be decorated with a
33777           //  `locationSetID` property.
33778           //  [
33779           //   { id: 'preset1', locationSet: {…}, locationSetID: '+[Q2]' },
33780           //   { id: 'preset2', locationSet: {…}, locationSetID: '+[Q30]' },
33781           //   { id: 'preset3', locationSet: {…}, locationSetID: '+[Q2]' },
33782           //   …
33783           //  ]
33784           //
33785           //  Returns a Promise fulfilled when the resolving/indexing has been completed
33786           //  This will take some seconds but happen in the background during browser idle time.
33787           //
33788
33789
33790           _this.mergeLocationSets = function (objects) {
33791             if (!Array.isArray(objects)) return Promise.reject('nothing to do'); // Resolve all locationSets -> geojson, processing data in chunks
33792             //
33793             // Because this will happen during idle callbacks, we want to choose a chunk size
33794             // that won't make the browser stutter too badly.  LocationSets that are a simple
33795             // country coder include will resolve instantly, but ones that involve complex
33796             // include/exclude operations will take some milliseconds longer.
33797             //
33798             // Some discussion and performance results on these tickets:
33799             // https://github.com/ideditor/location-conflation/issues/26
33800             // https://github.com/osmlab/name-suggestion-index/issues/4784#issuecomment-742003434
33801
33802             _queue = _queue.concat(utilArrayChunk(objects, 200));
33803
33804             if (!_inProcess) {
33805               _inProcess = processQueue().then(function () {
33806                 rebuildIndex();
33807                 _inProcess = null;
33808                 return objects;
33809               });
33810             }
33811
33812             return _inProcess;
33813           }; //
33814           // `locationSetID`
33815           // Returns a locationSetID for a given locationSet (fallback to `+[Q2]`, world)
33816           // (The locationset doesn't necessarily need to be resolved to compute its `id`)
33817           //
33818           // Arguments
33819           //   `locationSet`: A locationSet, e.g. `{ include: ['us'] }`
33820           // Returns
33821           //   The locationSetID, e.g. `+[Q30]`
33822           //
33823
33824
33825           _this.locationSetID = function (locationSet) {
33826             var locationSetID;
33827
33828             try {
33829               locationSetID = _loco.validateLocationSet(locationSet).id;
33830             } catch (err) {
33831               locationSetID = '+[Q2]'; // the world
33832             }
33833
33834             return locationSetID;
33835           }; //
33836           // `feature`
33837           // Returns the resolved GeoJSON feature for a given locationSetID (fallback to 'world')
33838           //
33839           // Arguments
33840           //   `locationSetID`: id of the form like `+[Q30]`  (United States)
33841           // Returns
33842           //   A GeoJSON feature:
33843           //   {
33844           //     type: 'Feature',
33845           //     id: '+[Q30]',
33846           //     properties: { id: '+[Q30]', area: 21817019.17, … },
33847           //     geometry: { … }
33848           //   }
33849
33850
33851           _this.feature = function (locationSetID) {
33852             return _resolvedFeatures[locationSetID] || _resolvedFeatures['+[Q2]'];
33853           }; //
33854           // `locationsAt`
33855           // Find all the resolved locationSets valid at the given location.
33856           // Results include the area (in km²) to facilitate sorting.
33857           //
33858           // Arguments
33859           //   `loc`: the [lon,lat] location to query, e.g. `[-74.4813, 40.7967]`
33860           // Returns
33861           //   Object of locationSetIDs to areas (in km²)
33862           //   {
33863           //     "+[Q2]": 511207893.3958111,
33864           //     "+[Q30]": 21817019.17,
33865           //     "+[new_jersey.geojson]": 22390.77,
33866           //     …
33867           //   }
33868           //
33869
33870
33871           _this.locationsAt = function (loc) {
33872             var result = {};
33873             (_wp(loc, true) || []).forEach(function (prop) {
33874               return result[prop.id] = prop.area;
33875             });
33876             return result;
33877           }; //
33878           // `query`
33879           // Execute a query directly against which-polygon
33880           // https://github.com/mapbox/which-polygon
33881           //
33882           // Arguments
33883           //   `loc`: the [lon,lat] location to query,
33884           //   `multi`: `true` to return all results, `false` to return first result
33885           // Returns
33886           //   Array of GeoJSON *properties* for the locationSet features that exist at `loc`
33887           //
33888
33889
33890           _this.query = function (loc, multi) {
33891             return _wp(loc, multi);
33892           }; // Direct access to the location-conflation resolver
33893
33894
33895           _this.loco = function () {
33896             return _loco;
33897           }; // Direct access to the which-polygon index
33898
33899
33900           _this.wp = function () {
33901             return _wp;
33902           };
33903
33904           return _this;
33905         }
33906
33907         var $$a = _export;
33908         var $findIndex = arrayIteration.findIndex;
33909         var addToUnscopables = addToUnscopables$5;
33910
33911         var FIND_INDEX = 'findIndex';
33912         var SKIPS_HOLES = true;
33913
33914         // Shouldn't skip holes
33915         if (FIND_INDEX in []) Array(1)[FIND_INDEX](function () { SKIPS_HOLES = false; });
33916
33917         // `Array.prototype.findIndex` method
33918         // https://tc39.es/ecma262/#sec-array.prototype.findindex
33919         $$a({ target: 'Array', proto: true, forced: SKIPS_HOLES }, {
33920           findIndex: function findIndex(callbackfn /* , that = undefined */) {
33921             return $findIndex(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
33922           }
33923         });
33924
33925         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
33926         addToUnscopables(FIND_INDEX);
33927
33928         var isRegExp = isRegexp;
33929
33930         var notARegexp = function (it) {
33931           if (isRegExp(it)) {
33932             throw TypeError("The method doesn't accept regular expressions");
33933           } return it;
33934         };
33935
33936         var wellKnownSymbol = wellKnownSymbol$s;
33937
33938         var MATCH = wellKnownSymbol('match');
33939
33940         var correctIsRegexpLogic = function (METHOD_NAME) {
33941           var regexp = /./;
33942           try {
33943             '/./'[METHOD_NAME](regexp);
33944           } catch (error1) {
33945             try {
33946               regexp[MATCH] = false;
33947               return '/./'[METHOD_NAME](regexp);
33948             } catch (error2) { /* empty */ }
33949           } return false;
33950         };
33951
33952         var $$9 = _export;
33953         var notARegExp$2 = notARegexp;
33954         var requireObjectCoercible$3 = requireObjectCoercible$e;
33955         var correctIsRegExpLogic$2 = correctIsRegexpLogic;
33956
33957         // `String.prototype.includes` method
33958         // https://tc39.es/ecma262/#sec-string.prototype.includes
33959         $$9({ target: 'String', proto: true, forced: !correctIsRegExpLogic$2('includes') }, {
33960           includes: function includes(searchString /* , position = 0 */) {
33961             return !!~String(requireObjectCoercible$3(this))
33962               .indexOf(notARegExp$2(searchString), arguments.length > 1 ? arguments[1] : undefined);
33963           }
33964         });
33965
33966         var _mainLocalizer = coreLocalizer(); // singleton
33967
33968
33969         var _t = _mainLocalizer.t;
33970         // coreLocalizer manages language and locale parameters including translated strings
33971         //
33972
33973         function coreLocalizer() {
33974           var localizer = {};
33975           var _dataLanguages = {}; // `_dataLocales` is an object containing all _supported_ locale codes -> language info.
33976           // * `rtl` - right-to-left or left-to-right text direction
33977           // * `pct` - the percent of strings translated; 1 = 100%, full coverage
33978           //
33979           // {
33980           // en: { rtl: false, pct: {…} },
33981           // de: { rtl: false, pct: {…} },
33982           // …
33983           // }
33984
33985           var _dataLocales = {}; // `localeStrings` is an object containing all _loaded_ locale codes -> string data.
33986           // {
33987           // en: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
33988           // de: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
33989           // …
33990           // }
33991
33992           var _localeStrings = {}; // the current locale
33993
33994           var _localeCode = 'en-US'; // `_localeCodes` must contain `_localeCode` first, optionally followed by fallbacks
33995
33996           var _localeCodes = ['en-US', 'en'];
33997           var _languageCode = 'en';
33998           var _textDirection = 'ltr';
33999           var _usesMetric = false;
34000           var _languageNames = {};
34001           var _scriptNames = {}; // getters for the current locale parameters
34002
34003           localizer.localeCode = function () {
34004             return _localeCode;
34005           };
34006
34007           localizer.localeCodes = function () {
34008             return _localeCodes;
34009           };
34010
34011           localizer.languageCode = function () {
34012             return _languageCode;
34013           };
34014
34015           localizer.textDirection = function () {
34016             return _textDirection;
34017           };
34018
34019           localizer.usesMetric = function () {
34020             return _usesMetric;
34021           };
34022
34023           localizer.languageNames = function () {
34024             return _languageNames;
34025           };
34026
34027           localizer.scriptNames = function () {
34028             return _scriptNames;
34029           }; // The client app may want to manually set the locale, regardless of the
34030           // settings provided by the browser
34031
34032
34033           var _preferredLocaleCodes = [];
34034
34035           localizer.preferredLocaleCodes = function (codes) {
34036             if (!arguments.length) return _preferredLocaleCodes;
34037
34038             if (typeof codes === 'string') {
34039               // be generous and accept delimited strings as input
34040               _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
34041             } else {
34042               _preferredLocaleCodes = codes;
34043             }
34044
34045             return localizer;
34046           };
34047
34048           var _loadPromise;
34049
34050           localizer.ensureLoaded = function () {
34051             if (_loadPromise) return _loadPromise;
34052             var filesToFetch = ['languages', // load the list of languages
34053             'locales' // load the list of supported locales
34054             ];
34055             var localeDirs = {
34056               general: 'locales',
34057               tagging: 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/translations'
34058             };
34059             var fileMap = _mainFileFetcher.fileMap();
34060
34061             for (var scopeId in localeDirs) {
34062               var key = "locales_index_".concat(scopeId);
34063
34064               if (!fileMap[key]) {
34065                 fileMap[key] = localeDirs[scopeId] + '/index.min.json';
34066               }
34067
34068               filesToFetch.push(key);
34069             }
34070
34071             return _loadPromise = Promise.all(filesToFetch.map(function (key) {
34072               return _mainFileFetcher.get(key);
34073             })).then(function (results) {
34074               _dataLanguages = results[0];
34075               _dataLocales = results[1];
34076               var indexes = results.slice(2);
34077
34078               var requestedLocales = (_preferredLocaleCodes || []).concat(utilDetect().browserLocales) // List of locales preferred by the browser in priority order.
34079               .concat(['en']); // fallback to English since it's the only guaranteed complete language
34080
34081
34082               _localeCodes = localesToUseFrom(requestedLocales);
34083               _localeCode = _localeCodes[0]; // Run iD in the highest-priority locale; the rest are fallbacks
34084
34085               var loadStringsPromises = [];
34086               indexes.forEach(function (index, i) {
34087                 // Will always return the index for `en` if nothing else
34088                 var fullCoverageIndex = _localeCodes.findIndex(function (locale) {
34089                   return index[locale] && index[locale].pct === 1;
34090                 }); // We only need to load locales up until we find one with full coverage
34091
34092
34093                 _localeCodes.slice(0, fullCoverageIndex + 1).forEach(function (code) {
34094                   var scopeId = Object.keys(localeDirs)[i];
34095                   var directory = Object.values(localeDirs)[i];
34096                   if (index[code]) loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
34097                 });
34098               });
34099               return Promise.all(loadStringsPromises);
34100             }).then(function () {
34101               updateForCurrentLocale();
34102             })["catch"](function (err) {
34103               return console.error(err);
34104             }); // eslint-disable-line
34105           }; // Returns the locales from `requestedLocales` supported by iD that we should use
34106
34107
34108           function localesToUseFrom(requestedLocales) {
34109             var supportedLocales = _dataLocales;
34110             var toUse = [];
34111
34112             for (var i in requestedLocales) {
34113               var locale = requestedLocales[i];
34114               if (supportedLocales[locale]) toUse.push(locale);
34115
34116               if (locale.includes('-')) {
34117                 // Full locale ('es-ES'), add fallback to the base ('es')
34118                 var langPart = locale.split('-')[0];
34119                 if (supportedLocales[langPart]) toUse.push(langPart);
34120               }
34121             } // remove duplicates
34122
34123
34124             return utilArrayUniq(toUse);
34125           }
34126
34127           function updateForCurrentLocale() {
34128             if (!_localeCode) return;
34129             _languageCode = _localeCode.split('-')[0];
34130             var currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
34131             var hash = utilStringQs(window.location.hash);
34132
34133             if (hash.rtl === 'true') {
34134               _textDirection = 'rtl';
34135             } else if (hash.rtl === 'false') {
34136               _textDirection = 'ltr';
34137             } else {
34138               _textDirection = currentData && currentData.rtl ? 'rtl' : 'ltr';
34139             }
34140
34141             var locale = _localeCode;
34142             if (locale.toLowerCase() === 'en-us') locale = 'en';
34143             _languageNames = _localeStrings.general[locale].languageNames;
34144             _scriptNames = _localeStrings.general[locale].scriptNames;
34145             _usesMetric = _localeCode.slice(-3).toLowerCase() !== '-us';
34146           }
34147           /* Locales */
34148           // Returns a Promise to load the strings for the requested locale
34149
34150
34151           localizer.loadLocale = function (locale, scopeId, directory) {
34152             // US English is the default
34153             if (locale.toLowerCase() === 'en-us') locale = 'en';
34154
34155             if (_localeStrings[scopeId] && _localeStrings[scopeId][locale]) {
34156               // already loaded
34157               return Promise.resolve(locale);
34158             }
34159
34160             var fileMap = _mainFileFetcher.fileMap();
34161             var key = "locale_".concat(scopeId, "_").concat(locale);
34162
34163             if (!fileMap[key]) {
34164               fileMap[key] = "".concat(directory, "/").concat(locale, ".min.json");
34165             }
34166
34167             return _mainFileFetcher.get(key).then(function (d) {
34168               if (!_localeStrings[scopeId]) _localeStrings[scopeId] = {};
34169               _localeStrings[scopeId][locale] = d[locale];
34170               return locale;
34171             });
34172           };
34173
34174           localizer.pluralRule = function (number) {
34175             return pluralRule(number, _localeCode);
34176           }; // Returns the plural rule for the given `number` with the given `localeCode`.
34177           // One of: `zero`, `one`, `two`, `few`, `many`, `other`
34178
34179
34180           function pluralRule(number, localeCode) {
34181             // modern browsers have this functionality built-in
34182             var rules = 'Intl' in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
34183
34184             if (rules) {
34185               return rules.select(number);
34186             } // fallback to basic one/other, as in English
34187
34188
34189             if (number === 1) return 'one';
34190             return 'other';
34191           }
34192           /**
34193           * Try to find that string in `locale` or the current `_localeCode` matching
34194           * the given `stringId`. If no string can be found in the requested locale,
34195           * we'll recurse down all the `_localeCodes` until one is found.
34196           *
34197           * @param  {string}   stringId      string identifier
34198           * @param  {object?}  replacements  token replacements and default string
34199           * @param  {string?}  locale        locale to use (defaults to currentLocale)
34200           * @return {string?}  localized string
34201           */
34202
34203
34204           localizer.tInfo = function (origStringId, replacements, locale) {
34205             var stringId = origStringId.trim();
34206             var scopeId = 'general';
34207
34208             if (stringId[0] === '_') {
34209               var split = stringId.split('.');
34210               scopeId = split[0].slice(1);
34211               stringId = split.slice(1).join('.');
34212             }
34213
34214             locale = locale || _localeCode;
34215             var path = stringId.split('.').map(function (s) {
34216               return s.replace(/<TX_DOT>/g, '.');
34217             }).reverse();
34218             var stringsKey = locale; // US English is the default
34219
34220             if (stringsKey.toLowerCase() === 'en-us') stringsKey = 'en';
34221             var result = _localeStrings && _localeStrings[scopeId] && _localeStrings[scopeId][stringsKey];
34222
34223             while (result !== undefined && path.length) {
34224               result = result[path.pop()];
34225             }
34226
34227             if (result !== undefined) {
34228               if (replacements) {
34229                 if (_typeof(result) === 'object' && Object.keys(result).length) {
34230                   // If plural forms are provided, dig one level deeper based on the
34231                   // first numeric token replacement provided.
34232                   var number = Object.values(replacements).find(function (value) {
34233                     return typeof value === 'number';
34234                   });
34235
34236                   if (number !== undefined) {
34237                     var rule = pluralRule(number, locale);
34238
34239                     if (result[rule]) {
34240                       result = result[rule];
34241                     } else {
34242                       // We're pretty sure this should be a plural but no string
34243                       // could be found for the given rule. Just pick the first
34244                       // string and hope it makes sense.
34245                       result = Object.values(result)[0];
34246                     }
34247                   }
34248                 }
34249
34250                 if (typeof result === 'string') {
34251                   for (var key in replacements) {
34252                     var value = replacements[key];
34253
34254                     if (typeof value === 'number') {
34255                       if (value.toLocaleString) {
34256                         // format numbers for the locale
34257                         value = value.toLocaleString(locale, {
34258                           style: 'decimal',
34259                           useGrouping: true,
34260                           minimumFractionDigits: 0
34261                         });
34262                       } else {
34263                         value = value.toString();
34264                       }
34265                     }
34266
34267                     var token = "{".concat(key, "}");
34268                     var regex = new RegExp(token, 'g');
34269                     result = result.replace(regex, value);
34270                   }
34271                 }
34272               }
34273
34274               if (typeof result === 'string') {
34275                 // found a localized string!
34276                 return {
34277                   text: result,
34278                   locale: locale
34279                 };
34280               }
34281             } // no localized string found...
34282             // attempt to fallback to a lower-priority language
34283
34284
34285             var index = _localeCodes.indexOf(locale);
34286
34287             if (index >= 0 && index < _localeCodes.length - 1) {
34288               // eventually this will be 'en' or another locale with 100% coverage
34289               var fallback = _localeCodes[index + 1];
34290               return localizer.tInfo(origStringId, replacements, fallback);
34291             }
34292
34293             if (replacements && 'default' in replacements) {
34294               // Fallback to a default value if one is specified in `replacements`
34295               return {
34296                 text: replacements["default"],
34297                 locale: null
34298               };
34299             }
34300
34301             var missing = "Missing ".concat(locale, " translation: ").concat(origStringId);
34302             if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
34303
34304             return {
34305               text: missing,
34306               locale: 'en'
34307             };
34308           };
34309
34310           localizer.hasTextForStringId = function (stringId) {
34311             return !!localizer.tInfo(stringId, {
34312               "default": 'nothing found'
34313             }).locale;
34314           }; // Returns only the localized text, discarding the locale info
34315
34316
34317           localizer.t = function (stringId, replacements, locale) {
34318             return localizer.tInfo(stringId, replacements, locale).text;
34319           }; // Returns the localized text wrapped in an HTML element encoding the locale info
34320
34321
34322           localizer.t.html = function (stringId, replacements, locale) {
34323             var info = localizer.tInfo(stringId, replacements, locale); // text may be empty or undefined if `replacements.default` is
34324
34325             return info.text ? localizer.htmlForLocalizedText(info.text, info.locale) : '';
34326           };
34327
34328           localizer.htmlForLocalizedText = function (text, localeCode) {
34329             return "<span class=\"localized-text\" lang=\"".concat(localeCode || 'unknown', "\">").concat(text, "</span>");
34330           };
34331
34332           localizer.languageName = function (code, options) {
34333             if (_languageNames[code]) {
34334               // name in locale language
34335               // e.g. "German"
34336               return _languageNames[code];
34337             } // sometimes we only want the local name
34338
34339
34340             if (options && options.localOnly) return null;
34341             var langInfo = _dataLanguages[code];
34342
34343             if (langInfo) {
34344               if (langInfo.nativeName) {
34345                 // name in native language
34346                 // e.g. "Deutsch (de)"
34347                 return localizer.t('translate.language_and_code', {
34348                   language: langInfo.nativeName,
34349                   code: code
34350                 });
34351               } else if (langInfo.base && langInfo.script) {
34352                 var base = langInfo.base; // the code of the language this is based on
34353
34354                 if (_languageNames[base]) {
34355                   // base language name in locale language
34356                   var scriptCode = langInfo.script;
34357                   var script = _scriptNames[scriptCode] || scriptCode; // e.g. "Serbian (Cyrillic)"
34358
34359                   return localizer.t('translate.language_and_code', {
34360                     language: _languageNames[base],
34361                     code: script
34362                   });
34363                 } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
34364                   // e.g. "српски (sr-Cyrl)"
34365                   return localizer.t('translate.language_and_code', {
34366                     language: _dataLanguages[base].nativeName,
34367                     code: code
34368                   });
34369                 }
34370               }
34371             }
34372
34373             return code; // if not found, use the code
34374           };
34375
34376           return localizer;
34377         }
34378
34379         // `presetCollection` is a wrapper around an `Array` of presets `collection`,
34380         // and decorated with some extra methods for searching and matching geometry
34381         //
34382
34383         function presetCollection(collection) {
34384           var MAXRESULTS = 50;
34385           var _this = {};
34386           var _memo = {};
34387           _this.collection = collection;
34388
34389           _this.item = function (id) {
34390             if (_memo[id]) return _memo[id];
34391
34392             var found = _this.collection.find(function (d) {
34393               return d.id === id;
34394             });
34395
34396             if (found) _memo[id] = found;
34397             return found;
34398           };
34399
34400           _this.index = function (id) {
34401             return _this.collection.findIndex(function (d) {
34402               return d.id === id;
34403             });
34404           };
34405
34406           _this.matchGeometry = function (geometry) {
34407             return presetCollection(_this.collection.filter(function (d) {
34408               return d.matchGeometry(geometry);
34409             }));
34410           };
34411
34412           _this.matchAllGeometry = function (geometries) {
34413             return presetCollection(_this.collection.filter(function (d) {
34414               return d && d.matchAllGeometry(geometries);
34415             }));
34416           };
34417
34418           _this.matchAnyGeometry = function (geometries) {
34419             return presetCollection(_this.collection.filter(function (d) {
34420               return geometries.some(function (geom) {
34421                 return d.matchGeometry(geom);
34422               });
34423             }));
34424           };
34425
34426           _this.fallback = function (geometry) {
34427             var id = geometry;
34428             if (id === 'vertex') id = 'point';
34429             return _this.item(id);
34430           };
34431
34432           _this.search = function (value, geometry, loc) {
34433             if (!value) return _this; // don't remove diacritical characters since we're assuming the user is being intentional
34434
34435             value = value.toLowerCase().trim(); // match at name beginning or just after a space (e.g. "office" -> match "Law Office")
34436
34437             function leading(a) {
34438               var index = a.indexOf(value);
34439               return index === 0 || a[index - 1] === ' ';
34440             } // match at name beginning only
34441
34442
34443             function leadingStrict(a) {
34444               var index = a.indexOf(value);
34445               return index === 0;
34446             }
34447
34448             function sortPresets(nameProp) {
34449               return function sortNames(a, b) {
34450                 var aCompare = a[nameProp]();
34451                 var bCompare = b[nameProp](); // priority if search string matches preset name exactly - #4325
34452
34453                 if (value === aCompare) return -1;
34454                 if (value === bCompare) return 1; // priority for higher matchScore
34455
34456                 var i = b.originalScore - a.originalScore;
34457                 if (i !== 0) return i; // priority if search string appears earlier in preset name
34458
34459                 i = aCompare.indexOf(value) - bCompare.indexOf(value);
34460                 if (i !== 0) return i; // priority for shorter preset names
34461
34462                 return aCompare.length - bCompare.length;
34463               };
34464             }
34465
34466             var pool = _this.collection;
34467
34468             if (Array.isArray(loc)) {
34469               var validLocations = _mainLocations.locationsAt(loc);
34470               pool = pool.filter(function (a) {
34471                 return !a.locationSetID || validLocations[a.locationSetID];
34472               });
34473             }
34474
34475             var searchable = pool.filter(function (a) {
34476               return a.searchable !== false && a.suggestion !== true;
34477             });
34478             var suggestions = pool.filter(function (a) {
34479               return a.suggestion === true;
34480             }); // matches value to preset.name
34481
34482             var leadingNames = searchable.filter(function (a) {
34483               return leading(a.searchName());
34484             }).sort(sortPresets('searchName')); // matches value to preset suggestion name
34485
34486             var leadingSuggestions = suggestions.filter(function (a) {
34487               return leadingStrict(a.searchName());
34488             }).sort(sortPresets('searchName'));
34489             var leadingNamesStripped = searchable.filter(function (a) {
34490               return leading(a.searchNameStripped());
34491             }).sort(sortPresets('searchNameStripped'));
34492             var leadingSuggestionsStripped = suggestions.filter(function (a) {
34493               return leadingStrict(a.searchNameStripped());
34494             }).sort(sortPresets('searchNameStripped')); // matches value to preset.terms values
34495
34496             var leadingTerms = searchable.filter(function (a) {
34497               return (a.terms() || []).some(leading);
34498             });
34499             var leadingSuggestionTerms = suggestions.filter(function (a) {
34500               return (a.terms() || []).some(leading);
34501             }); // matches value to preset.tags values
34502
34503             var leadingTagValues = searchable.filter(function (a) {
34504               return Object.values(a.tags || {}).filter(function (val) {
34505                 return val !== '*';
34506               }).some(leading);
34507             }); // finds close matches to value in preset.name
34508
34509             var similarName = searchable.map(function (a) {
34510               return {
34511                 preset: a,
34512                 dist: utilEditDistance(value, a.searchName())
34513               };
34514             }).filter(function (a) {
34515               return a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 3;
34516             }).sort(function (a, b) {
34517               return a.dist - b.dist;
34518             }).map(function (a) {
34519               return a.preset;
34520             }); // finds close matches to value to preset suggestion name
34521
34522             var similarSuggestions = suggestions.map(function (a) {
34523               return {
34524                 preset: a,
34525                 dist: utilEditDistance(value, a.searchName())
34526               };
34527             }).filter(function (a) {
34528               return a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 1;
34529             }).sort(function (a, b) {
34530               return a.dist - b.dist;
34531             }).map(function (a) {
34532               return a.preset;
34533             }); // finds close matches to value in preset.terms
34534
34535             var similarTerms = searchable.filter(function (a) {
34536               return (a.terms() || []).some(function (b) {
34537                 return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
34538               });
34539             });
34540             var results = leadingNames.concat(leadingSuggestions, leadingNamesStripped, leadingSuggestionsStripped, leadingTerms, leadingSuggestionTerms, leadingTagValues, similarName, similarSuggestions, similarTerms).slice(0, MAXRESULTS - 1);
34541
34542             if (geometry) {
34543               if (typeof geometry === 'string') {
34544                 results.push(_this.fallback(geometry));
34545               } else {
34546                 geometry.forEach(function (geom) {
34547                   return results.push(_this.fallback(geom));
34548                 });
34549               }
34550             }
34551
34552             return presetCollection(utilArrayUniq(results));
34553           };
34554
34555           return _this;
34556         }
34557
34558         // `presetCategory` builds a `presetCollection` of member presets,
34559         // decorated with some extra methods for searching and matching geometry
34560         //
34561
34562         function presetCategory(categoryID, category, allPresets) {
34563           var _this = Object.assign({}, category); // shallow copy
34564
34565
34566           var _searchName; // cache
34567
34568
34569           var _searchNameStripped; // cache
34570
34571
34572           _this.id = categoryID;
34573           _this.members = presetCollection((category.members || []).map(function (presetID) {
34574             return allPresets[presetID];
34575           }).filter(Boolean));
34576           _this.geometry = _this.members.collection.reduce(function (acc, preset) {
34577             for (var i in preset.geometry) {
34578               var geometry = preset.geometry[i];
34579
34580               if (acc.indexOf(geometry) === -1) {
34581                 acc.push(geometry);
34582               }
34583             }
34584
34585             return acc;
34586           }, []);
34587
34588           _this.matchGeometry = function (geom) {
34589             return _this.geometry.indexOf(geom) >= 0;
34590           };
34591
34592           _this.matchAllGeometry = function (geometries) {
34593             return _this.members.collection.some(function (preset) {
34594               return preset.matchAllGeometry(geometries);
34595             });
34596           };
34597
34598           _this.matchScore = function () {
34599             return -1;
34600           };
34601
34602           _this.name = function () {
34603             return _t("_tagging.presets.categories.".concat(categoryID, ".name"), {
34604               'default': categoryID
34605             });
34606           };
34607
34608           _this.nameLabel = function () {
34609             return _t.html("_tagging.presets.categories.".concat(categoryID, ".name"), {
34610               'default': categoryID
34611             });
34612           };
34613
34614           _this.terms = function () {
34615             return [];
34616           };
34617
34618           _this.searchName = function () {
34619             if (!_searchName) {
34620               _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
34621             }
34622
34623             return _searchName;
34624           };
34625
34626           _this.searchNameStripped = function () {
34627             if (!_searchNameStripped) {
34628               _searchNameStripped = _this.searchName(); // split combined diacritical characters into their parts
34629
34630               if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize('NFD'); // remove diacritics
34631
34632               _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, '');
34633             }
34634
34635             return _searchNameStripped;
34636           };
34637
34638           return _this;
34639         }
34640
34641         // `presetField` decorates a given `field` Object
34642         // with some extra methods for searching and matching geometry
34643         //
34644
34645         function presetField(fieldID, field) {
34646           var _this = Object.assign({}, field); // shallow copy
34647
34648
34649           _this.id = fieldID; // for use in classes, element ids, css selectors
34650
34651           _this.safeid = utilSafeClassName(fieldID);
34652
34653           _this.matchGeometry = function (geom) {
34654             return !_this.geometry || _this.geometry.indexOf(geom) !== -1;
34655           };
34656
34657           _this.matchAllGeometry = function (geometries) {
34658             return !_this.geometry || geometries.every(function (geom) {
34659               return _this.geometry.indexOf(geom) !== -1;
34660             });
34661           };
34662
34663           _this.t = function (scope, options) {
34664             return _t("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options);
34665           };
34666
34667           _this.t.html = function (scope, options) {
34668             return _t.html("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options);
34669           };
34670
34671           _this.hasTextForStringId = function (scope) {
34672             return _mainLocalizer.hasTextForStringId("_tagging.presets.fields.".concat(fieldID, ".").concat(scope));
34673           };
34674
34675           _this.title = function () {
34676             return _this.overrideLabel || _this.t('label', {
34677               'default': fieldID
34678             });
34679           };
34680
34681           _this.label = function () {
34682             return _this.overrideLabel || _this.t.html('label', {
34683               'default': fieldID
34684             });
34685           };
34686
34687           var _placeholder = _this.placeholder;
34688
34689           _this.placeholder = function () {
34690             return _this.t('placeholder', {
34691               'default': _placeholder
34692             });
34693           };
34694
34695           _this.originalTerms = (_this.terms || []).join();
34696
34697           _this.terms = function () {
34698             return _this.t('terms', {
34699               'default': _this.originalTerms
34700             }).toLowerCase().trim().split(/\s*,+\s*/);
34701           };
34702
34703           _this.increment = _this.type === 'number' ? _this.increment || 1 : undefined;
34704           return _this;
34705         }
34706
34707         var $$8 = _export;
34708         var lastIndexOf = arrayLastIndexOf;
34709
34710         // `Array.prototype.lastIndexOf` method
34711         // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
34712         // eslint-disable-next-line es/no-array-prototype-lastindexof -- required for testing
34713         $$8({ target: 'Array', proto: true, forced: lastIndexOf !== [].lastIndexOf }, {
34714           lastIndexOf: lastIndexOf
34715         });
34716
34717         // `presetPreset` decorates a given `preset` Object
34718         // with some extra methods for searching and matching geometry
34719         //
34720
34721         function presetPreset(presetID, preset, addable, allFields, allPresets) {
34722           allFields = allFields || {};
34723           allPresets = allPresets || {};
34724
34725           var _this = Object.assign({}, preset); // shallow copy
34726
34727
34728           var _addable = addable || false;
34729
34730           var _resolvedFields; // cache
34731
34732
34733           var _resolvedMoreFields; // cache
34734
34735
34736           var _searchName; // cache
34737
34738
34739           var _searchNameStripped; // cache
34740
34741
34742           _this.id = presetID;
34743           _this.safeid = utilSafeClassName(presetID); // for use in css classes, selectors, element ids
34744
34745           _this.originalTerms = (_this.terms || []).join();
34746           _this.originalName = _this.name || '';
34747           _this.originalScore = _this.matchScore || 1;
34748           _this.originalReference = _this.reference || {};
34749           _this.originalFields = _this.fields || [];
34750           _this.originalMoreFields = _this.moreFields || [];
34751
34752           _this.fields = function () {
34753             return _resolvedFields || (_resolvedFields = resolve('fields'));
34754           };
34755
34756           _this.moreFields = function () {
34757             return _resolvedMoreFields || (_resolvedMoreFields = resolve('moreFields'));
34758           };
34759
34760           _this.resetFields = function () {
34761             return _resolvedFields = _resolvedMoreFields = null;
34762           };
34763
34764           _this.tags = _this.tags || {};
34765           _this.addTags = _this.addTags || _this.tags;
34766           _this.removeTags = _this.removeTags || _this.addTags;
34767           _this.geometry = _this.geometry || [];
34768
34769           _this.matchGeometry = function (geom) {
34770             return _this.geometry.indexOf(geom) >= 0;
34771           };
34772
34773           _this.matchAllGeometry = function (geoms) {
34774             return geoms.every(_this.matchGeometry);
34775           };
34776
34777           _this.matchScore = function (entityTags) {
34778             var tags = _this.tags;
34779             var seen = {};
34780             var score = 0; // match on tags
34781
34782             for (var k in tags) {
34783               seen[k] = true;
34784
34785               if (entityTags[k] === tags[k]) {
34786                 score += _this.originalScore;
34787               } else if (tags[k] === '*' && k in entityTags) {
34788                 score += _this.originalScore / 2;
34789               } else {
34790                 return -1;
34791               }
34792             } // boost score for additional matches in addTags - #6802
34793
34794
34795             var addTags = _this.addTags;
34796
34797             for (var _k in addTags) {
34798               if (!seen[_k] && entityTags[_k] === addTags[_k]) {
34799                 score += _this.originalScore;
34800               }
34801             }
34802
34803             return score;
34804           };
34805
34806           _this.t = function (scope, options) {
34807             var textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
34808             return _t(textID, options);
34809           };
34810
34811           _this.t.html = function (scope, options) {
34812             var textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
34813             return _t.html(textID, options);
34814           };
34815
34816           _this.name = function () {
34817             return _this.t('name', {
34818               'default': _this.originalName
34819             });
34820           };
34821
34822           _this.nameLabel = function () {
34823             return _this.t.html('name', {
34824               'default': _this.originalName
34825             });
34826           };
34827
34828           _this.subtitle = function () {
34829             if (_this.suggestion) {
34830               var path = presetID.split('/');
34831               path.pop(); // remove brand name
34832
34833               return _t('_tagging.presets.presets.' + path.join('/') + '.name');
34834             }
34835
34836             return null;
34837           };
34838
34839           _this.subtitleLabel = function () {
34840             if (_this.suggestion) {
34841               var path = presetID.split('/');
34842               path.pop(); // remove brand name
34843
34844               return _t.html('_tagging.presets.presets.' + path.join('/') + '.name');
34845             }
34846
34847             return null;
34848           };
34849
34850           _this.terms = function () {
34851             return _this.t('terms', {
34852               'default': _this.originalTerms
34853             }).toLowerCase().trim().split(/\s*,+\s*/);
34854           };
34855
34856           _this.searchName = function () {
34857             if (!_searchName) {
34858               _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
34859             }
34860
34861             return _searchName;
34862           };
34863
34864           _this.searchNameStripped = function () {
34865             if (!_searchNameStripped) {
34866               _searchNameStripped = _this.searchName(); // split combined diacritical characters into their parts
34867
34868               if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize('NFD'); // remove diacritics
34869
34870               _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, '');
34871             }
34872
34873             return _searchNameStripped;
34874           };
34875
34876           _this.isFallback = function () {
34877             var tagCount = Object.keys(_this.tags).length;
34878             return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty('area');
34879           };
34880
34881           _this.addable = function (val) {
34882             if (!arguments.length) return _addable;
34883             _addable = val;
34884             return _this;
34885           };
34886
34887           _this.reference = function () {
34888             // Lookup documentation on Wikidata...
34889             var qid = _this.tags.wikidata || _this.tags['flag:wikidata'] || _this.tags['brand:wikidata'] || _this.tags['network:wikidata'] || _this.tags['operator:wikidata'];
34890
34891             if (qid) {
34892               return {
34893                 qid: qid
34894               };
34895             } // Lookup documentation on OSM Wikibase...
34896
34897
34898             var key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
34899             var value = _this.originalReference.value || _this.tags[key];
34900
34901             if (value === '*') {
34902               return {
34903                 key: key
34904               };
34905             } else {
34906               return {
34907                 key: key,
34908                 value: value
34909               };
34910             }
34911           };
34912
34913           _this.unsetTags = function (tags, geometry, ignoringKeys, skipFieldDefaults) {
34914             // allow manually keeping some tags
34915             var removeTags = ignoringKeys ? utilObjectOmit(_this.removeTags, ignoringKeys) : _this.removeTags;
34916             tags = utilObjectOmit(tags, Object.keys(removeTags));
34917
34918             if (geometry && !skipFieldDefaults) {
34919               _this.fields().forEach(function (field) {
34920                 if (field.matchGeometry(geometry) && field.key && field["default"] === tags[field.key]) {
34921                   delete tags[field.key];
34922                 }
34923               });
34924             }
34925
34926             delete tags.area;
34927             return tags;
34928           };
34929
34930           _this.setTags = function (tags, geometry, skipFieldDefaults) {
34931             var addTags = _this.addTags;
34932             tags = Object.assign({}, tags); // shallow copy
34933
34934             for (var k in addTags) {
34935               if (addTags[k] === '*') {
34936                 // if this tag is ancillary, don't override an existing value since any value is okay
34937                 if (_this.tags[k] || !tags[k] || tags[k] === 'no') {
34938                   tags[k] = 'yes';
34939                 }
34940               } else {
34941                 tags[k] = addTags[k];
34942               }
34943             } // Add area=yes if necessary.
34944             // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
34945             // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
34946             // 2. chosen preset doesn't have a key in osmAreaKeys (`railway=station`)
34947
34948
34949             if (!addTags.hasOwnProperty('area')) {
34950               delete tags.area;
34951
34952               if (geometry === 'area') {
34953                 var needsAreaTag = true;
34954
34955                 if (_this.geometry.indexOf('line') === -1) {
34956                   for (var _k2 in addTags) {
34957                     if (_k2 in osmAreaKeys) {
34958                       needsAreaTag = false;
34959                       break;
34960                     }
34961                   }
34962                 }
34963
34964                 if (needsAreaTag) {
34965                   tags.area = 'yes';
34966                 }
34967               }
34968             }
34969
34970             if (geometry && !skipFieldDefaults) {
34971               _this.fields().forEach(function (field) {
34972                 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field["default"]) {
34973                   tags[field.key] = field["default"];
34974                 }
34975               });
34976             }
34977
34978             return tags;
34979           }; // For a preset without fields, use the fields of the parent preset.
34980           // Replace {preset} placeholders with the fields of the specified presets.
34981
34982
34983           function resolve(which) {
34984             var fieldIDs = which === 'fields' ? _this.originalFields : _this.originalMoreFields;
34985             var resolved = [];
34986             fieldIDs.forEach(function (fieldID) {
34987               var match = fieldID.match(/\{(.*)\}/);
34988
34989               if (match !== null) {
34990                 // a presetID wrapped in braces {}
34991                 resolved = resolved.concat(inheritFields(match[1], which));
34992               } else if (allFields[fieldID]) {
34993                 // a normal fieldID
34994                 resolved.push(allFields[fieldID]);
34995               } else {
34996                 console.log("Cannot resolve \"".concat(fieldID, "\" found in ").concat(_this.id, ".").concat(which)); // eslint-disable-line no-console
34997               }
34998             }); // no fields resolved, so use the parent's if possible
34999
35000             if (!resolved.length) {
35001               var endIndex = _this.id.lastIndexOf('/');
35002
35003               var parentID = endIndex && _this.id.substring(0, endIndex);
35004
35005               if (parentID) {
35006                 resolved = inheritFields(parentID, which);
35007               }
35008             }
35009
35010             return utilArrayUniq(resolved); // returns an array of fields to inherit from the given presetID, if found
35011
35012             function inheritFields(presetID, which) {
35013               var parent = allPresets[presetID];
35014               if (!parent) return [];
35015
35016               if (which === 'fields') {
35017                 return parent.fields().filter(shouldInherit);
35018               } else if (which === 'moreFields') {
35019                 return parent.moreFields();
35020               } else {
35021                 return [];
35022               }
35023             } // Skip `fields` for the keys which define the preset.
35024             // These are usually `typeCombo` fields like `shop=*`
35025
35026
35027             function shouldInherit(f) {
35028               if (f.key && _this.tags[f.key] !== undefined && // inherit anyway if multiple values are allowed or just a checkbox
35029               f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'manyCombo' && f.type !== 'check') return false;
35030               return true;
35031             }
35032           }
35033
35034           return _this;
35035         }
35036
35037         var _mainPresetIndex = presetIndex(); // singleton
35038         // `presetIndex` wraps a `presetCollection`
35039         // with methods for loading new data and returning defaults
35040         //
35041
35042         function presetIndex() {
35043           var dispatch = dispatch$8('favoritePreset', 'recentsChange');
35044           var MAXRECENTS = 30; // seed the preset lists with geometry fallbacks
35045
35046           var POINT = presetPreset('point', {
35047             name: 'Point',
35048             tags: {},
35049             geometry: ['point', 'vertex'],
35050             matchScore: 0.1
35051           });
35052           var LINE = presetPreset('line', {
35053             name: 'Line',
35054             tags: {},
35055             geometry: ['line'],
35056             matchScore: 0.1
35057           });
35058           var AREA = presetPreset('area', {
35059             name: 'Area',
35060             tags: {
35061               area: 'yes'
35062             },
35063             geometry: ['area'],
35064             matchScore: 0.1
35065           });
35066           var RELATION = presetPreset('relation', {
35067             name: 'Relation',
35068             tags: {},
35069             geometry: ['relation'],
35070             matchScore: 0.1
35071           });
35072
35073           var _this = presetCollection([POINT, LINE, AREA, RELATION]);
35074
35075           var _presets = {
35076             point: POINT,
35077             line: LINE,
35078             area: AREA,
35079             relation: RELATION
35080           };
35081           var _defaults = {
35082             point: presetCollection([POINT]),
35083             vertex: presetCollection([POINT]),
35084             line: presetCollection([LINE]),
35085             area: presetCollection([AREA]),
35086             relation: presetCollection([RELATION])
35087           };
35088           var _fields = {};
35089           var _categories = {};
35090           var _universal = [];
35091           var _addablePresetIDs = null; // Set of preset IDs that the user can add
35092
35093           var _recents;
35094
35095           var _favorites; // Index of presets by (geometry, tag key).
35096
35097
35098           var _geometryIndex = {
35099             point: {},
35100             vertex: {},
35101             line: {},
35102             area: {},
35103             relation: {}
35104           };
35105
35106           var _loadPromise;
35107
35108           _this.ensureLoaded = function () {
35109             if (_loadPromise) return _loadPromise;
35110             return _loadPromise = Promise.all([_mainFileFetcher.get('preset_categories'), _mainFileFetcher.get('preset_defaults'), _mainFileFetcher.get('preset_presets'), _mainFileFetcher.get('preset_fields')]).then(function (vals) {
35111               _this.merge({
35112                 categories: vals[0],
35113                 defaults: vals[1],
35114                 presets: vals[2],
35115                 fields: vals[3]
35116               });
35117
35118               osmSetAreaKeys(_this.areaKeys());
35119               osmSetPointTags(_this.pointTags());
35120               osmSetVertexTags(_this.vertexTags());
35121             });
35122           }; // `merge` accepts an object containing new preset data (all properties optional):
35123           // {
35124           //   fields: {},
35125           //   presets: {},
35126           //   categories: {},
35127           //   defaults: {},
35128           //   featureCollection: {}
35129           //}
35130
35131
35132           _this.merge = function (d) {
35133             var newLocationSets = []; // Merge Fields
35134
35135             if (d.fields) {
35136               Object.keys(d.fields).forEach(function (fieldID) {
35137                 var f = d.fields[fieldID];
35138
35139                 if (f) {
35140                   // add or replace
35141                   f = presetField(fieldID, f);
35142                   if (f.locationSet) newLocationSets.push(f);
35143                   _fields[fieldID] = f;
35144                 } else {
35145                   // remove
35146                   delete _fields[fieldID];
35147                 }
35148               });
35149             } // Merge Presets
35150
35151
35152             if (d.presets) {
35153               Object.keys(d.presets).forEach(function (presetID) {
35154                 var p = d.presets[presetID];
35155
35156                 if (p) {
35157                   // add or replace
35158                   var isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
35159
35160                   p = presetPreset(presetID, p, isAddable, _fields, _presets);
35161                   if (p.locationSet) newLocationSets.push(p);
35162                   _presets[presetID] = p;
35163                 } else {
35164                   // remove (but not if it's a fallback)
35165                   var existing = _presets[presetID];
35166
35167                   if (existing && !existing.isFallback()) {
35168                     delete _presets[presetID];
35169                   }
35170                 }
35171               });
35172             } // Merge Categories
35173
35174
35175             if (d.categories) {
35176               Object.keys(d.categories).forEach(function (categoryID) {
35177                 var c = d.categories[categoryID];
35178
35179                 if (c) {
35180                   // add or replace
35181                   c = presetCategory(categoryID, c, _presets);
35182                   if (c.locationSet) newLocationSets.push(c);
35183                   _categories[categoryID] = c;
35184                 } else {
35185                   // remove
35186                   delete _categories[categoryID];
35187                 }
35188               });
35189             } // Rebuild _this.collection after changing presets and categories
35190
35191
35192             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Defaults
35193
35194             if (d.defaults) {
35195               Object.keys(d.defaults).forEach(function (geometry) {
35196                 var def = d.defaults[geometry];
35197
35198                 if (Array.isArray(def)) {
35199                   // add or replace
35200                   _defaults[geometry] = presetCollection(def.map(function (id) {
35201                     return _presets[id] || _categories[id];
35202                   }).filter(Boolean));
35203                 } else {
35204                   // remove
35205                   delete _defaults[geometry];
35206                 }
35207               });
35208             } // Rebuild universal fields array
35209
35210
35211             _universal = Object.values(_fields).filter(function (field) {
35212               return field.universal;
35213             }); // Reset all the preset fields - they'll need to be resolved again
35214
35215             Object.values(_presets).forEach(function (preset) {
35216               return preset.resetFields();
35217             }); // Rebuild geometry index
35218
35219             _geometryIndex = {
35220               point: {},
35221               vertex: {},
35222               line: {},
35223               area: {},
35224               relation: {}
35225             };
35226
35227             _this.collection.forEach(function (preset) {
35228               (preset.geometry || []).forEach(function (geometry) {
35229                 var g = _geometryIndex[geometry];
35230
35231                 for (var key in preset.tags) {
35232                   g[key] = g[key] || {};
35233                   var value = preset.tags[key];
35234                   (g[key][value] = g[key][value] || []).push(preset);
35235                 }
35236               });
35237             }); // Merge Custom Features
35238
35239
35240             if (d.featureCollection && Array.isArray(d.featureCollection.features)) {
35241               _mainLocations.mergeCustomGeoJSON(d.featureCollection);
35242             } // Resolve all locationSet features.
35243
35244
35245             if (newLocationSets.length) {
35246               _mainLocations.mergeLocationSets(newLocationSets);
35247             }
35248
35249             return _this;
35250           };
35251
35252           _this.match = function (entity, resolver) {
35253             return resolver["transient"](entity, 'presetMatch', function () {
35254               var geometry = entity.geometry(resolver); // Treat entities on addr:interpolation lines as points, not vertices - #3241
35255
35256               if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
35257                 geometry = 'point';
35258               }
35259
35260               var entityExtent = entity.extent(resolver);
35261               return _this.matchTags(entity.tags, geometry, entityExtent.center());
35262             });
35263           };
35264
35265           _this.matchTags = function (tags, geometry, loc) {
35266             var keyIndex = _geometryIndex[geometry];
35267             var bestScore = -1;
35268             var bestMatch;
35269             var matchCandidates = [];
35270
35271             for (var k in tags) {
35272               var indexMatches = [];
35273               var valueIndex = keyIndex[k];
35274               if (!valueIndex) continue;
35275               var keyValueMatches = valueIndex[tags[k]];
35276               if (keyValueMatches) indexMatches.push.apply(indexMatches, _toConsumableArray(keyValueMatches));
35277               var keyStarMatches = valueIndex['*'];
35278               if (keyStarMatches) indexMatches.push.apply(indexMatches, _toConsumableArray(keyStarMatches));
35279               if (indexMatches.length === 0) continue;
35280
35281               for (var i = 0; i < indexMatches.length; i++) {
35282                 var candidate = indexMatches[i];
35283                 var score = candidate.matchScore(tags);
35284
35285                 if (score === -1) {
35286                   continue;
35287                 }
35288
35289                 matchCandidates.push({
35290                   score: score,
35291                   candidate: candidate
35292                 });
35293
35294                 if (score > bestScore) {
35295                   bestScore = score;
35296                   bestMatch = candidate;
35297                 }
35298               }
35299             }
35300
35301             if (bestMatch && bestMatch.locationSetID && bestMatch.locationSetID !== '+[Q2]' && Array.isArray(loc)) {
35302               var validLocations = _mainLocations.locationsAt(loc);
35303
35304               if (!validLocations[bestMatch.locationSetID]) {
35305                 matchCandidates.sort(function (a, b) {
35306                   return a.score < b.score ? 1 : -1;
35307                 });
35308
35309                 for (var _i = 0; _i < matchCandidates.length; _i++) {
35310                   var candidateScore = matchCandidates[_i];
35311
35312                   if (!candidateScore.candidate.locationSetID || validLocations[candidateScore.candidate.locationSetID]) {
35313                     bestMatch = candidateScore.candidate;
35314                     bestScore = candidateScore.score;
35315                     break;
35316                   }
35317                 }
35318               }
35319             } // If any part of an address is present, allow fallback to "Address" preset - #4353
35320
35321
35322             if (!bestMatch || bestMatch.isFallback()) {
35323               for (var _k in tags) {
35324                 if (/^addr:/.test(_k) && keyIndex['addr:*'] && keyIndex['addr:*']['*']) {
35325                   bestMatch = keyIndex['addr:*']['*'][0];
35326                   break;
35327                 }
35328               }
35329             }
35330
35331             return bestMatch || _this.fallback(geometry);
35332           };
35333
35334           _this.allowsVertex = function (entity, resolver) {
35335             if (entity.type !== 'node') return false;
35336             if (Object.keys(entity.tags).length === 0) return true;
35337             return resolver["transient"](entity, 'vertexMatch', function () {
35338               // address lines allow vertices to act as standalone points
35339               if (entity.isOnAddressLine(resolver)) return true;
35340               var geometries = osmNodeGeometriesForTags(entity.tags);
35341               if (geometries.vertex) return true;
35342               if (geometries.point) return false; // allow vertices for unspecified points
35343
35344               return true;
35345             });
35346           }; // Because of the open nature of tagging, iD will never have a complete
35347           // list of tags used in OSM, so we want it to have logic like "assume
35348           // that a closed way with an amenity tag is an area, unless the amenity
35349           // is one of these specific types". This function computes a structure
35350           // that allows testing of such conditions, based on the presets designated
35351           // as as supporting (or not supporting) the area geometry.
35352           //
35353           // The returned object L is a keeplist/discardlist of tags. A closed way
35354           // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
35355           // (see `Way#isArea()`). In other words, the keys of L form the keeplist,
35356           // and the subkeys form the discardlist.
35357
35358
35359           _this.areaKeys = function () {
35360             // The ignore list is for keys that imply lines. (We always add `area=yes` for exceptions)
35361             var ignore = ['barrier', 'highway', 'footway', 'railway', 'junction', 'type'];
35362             var areaKeys = {}; // ignore name-suggestion-index and deprecated presets
35363
35364             var presets = _this.collection.filter(function (p) {
35365               return !p.suggestion && !p.replacement;
35366             }); // keeplist
35367
35368
35369             presets.forEach(function (p) {
35370               var keys = p.tags && Object.keys(p.tags);
35371               var key = keys && keys.length && keys[0]; // pick the first tag
35372
35373               if (!key) return;
35374               if (ignore.indexOf(key) !== -1) return;
35375
35376               if (p.geometry.indexOf('area') !== -1) {
35377                 // probably an area..
35378                 areaKeys[key] = areaKeys[key] || {};
35379               }
35380             }); // discardlist
35381
35382             presets.forEach(function (p) {
35383               var key;
35384
35385               for (key in p.addTags) {
35386                 // examine all addTags to get a better sense of what can be tagged on lines - #6800
35387                 var value = p.addTags[key];
35388
35389                 if (key in areaKeys && // probably an area...
35390                 p.geometry.indexOf('line') !== -1 && // but sometimes a line
35391                 value !== '*') {
35392                   areaKeys[key][value] = true;
35393                 }
35394               }
35395             });
35396             return areaKeys;
35397           };
35398
35399           _this.pointTags = function () {
35400             return _this.collection.reduce(function (pointTags, d) {
35401               // ignore name-suggestion-index, deprecated, and generic presets
35402               if (d.suggestion || d.replacement || d.searchable === false) return pointTags; // only care about the primary tag
35403
35404               var keys = d.tags && Object.keys(d.tags);
35405               var key = keys && keys.length && keys[0]; // pick the first tag
35406
35407               if (!key) return pointTags; // if this can be a point
35408
35409               if (d.geometry.indexOf('point') !== -1) {
35410                 pointTags[key] = pointTags[key] || {};
35411                 pointTags[key][d.tags[key]] = true;
35412               }
35413
35414               return pointTags;
35415             }, {});
35416           };
35417
35418           _this.vertexTags = function () {
35419             return _this.collection.reduce(function (vertexTags, d) {
35420               // ignore name-suggestion-index, deprecated, and generic presets
35421               if (d.suggestion || d.replacement || d.searchable === false) return vertexTags; // only care about the primary tag
35422
35423               var keys = d.tags && Object.keys(d.tags);
35424               var key = keys && keys.length && keys[0]; // pick the first tag
35425
35426               if (!key) return vertexTags; // if this can be a vertex
35427
35428               if (d.geometry.indexOf('vertex') !== -1) {
35429                 vertexTags[key] = vertexTags[key] || {};
35430                 vertexTags[key][d.tags[key]] = true;
35431               }
35432
35433               return vertexTags;
35434             }, {});
35435           };
35436
35437           _this.field = function (id) {
35438             return _fields[id];
35439           };
35440
35441           _this.universal = function () {
35442             return _universal;
35443           };
35444
35445           _this.defaults = function (geometry, n, startWithRecents, loc) {
35446             var recents = [];
35447
35448             if (startWithRecents) {
35449               recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
35450             }
35451
35452             var defaults;
35453
35454             if (_addablePresetIDs) {
35455               defaults = Array.from(_addablePresetIDs).map(function (id) {
35456                 var preset = _this.item(id);
35457
35458                 if (preset && preset.matchGeometry(geometry)) return preset;
35459                 return null;
35460               }).filter(Boolean);
35461             } else {
35462               defaults = _defaults[geometry].collection.concat(_this.fallback(geometry));
35463             }
35464
35465             var result = presetCollection(utilArrayUniq(recents.concat(defaults)).slice(0, n - 1));
35466
35467             if (Array.isArray(loc)) {
35468               var validLocations = _mainLocations.locationsAt(loc);
35469               result.collection = result.collection.filter(function (a) {
35470                 return !a.locationSetID || validLocations[a.locationSetID];
35471               });
35472             }
35473
35474             return result;
35475           }; // pass a Set of addable preset ids
35476
35477
35478           _this.addablePresetIDs = function (val) {
35479             if (!arguments.length) return _addablePresetIDs; // accept and convert arrays
35480
35481             if (Array.isArray(val)) val = new Set(val);
35482             _addablePresetIDs = val;
35483
35484             if (_addablePresetIDs) {
35485               // reset all presets
35486               _this.collection.forEach(function (p) {
35487                 // categories aren't addable
35488                 if (p.addable) p.addable(_addablePresetIDs.has(p.id));
35489               });
35490             } else {
35491               _this.collection.forEach(function (p) {
35492                 if (p.addable) p.addable(true);
35493               });
35494             }
35495
35496             return _this;
35497           };
35498
35499           _this.recent = function () {
35500             return presetCollection(utilArrayUniq(_this.getRecents().map(function (d) {
35501               return d.preset;
35502             })));
35503           };
35504
35505           function RibbonItem(preset, source) {
35506             var item = {};
35507             item.preset = preset;
35508             item.source = source;
35509
35510             item.isFavorite = function () {
35511               return item.source === 'favorite';
35512             };
35513
35514             item.isRecent = function () {
35515               return item.source === 'recent';
35516             };
35517
35518             item.matches = function (preset) {
35519               return item.preset.id === preset.id;
35520             };
35521
35522             item.minified = function () {
35523               return {
35524                 pID: item.preset.id
35525               };
35526             };
35527
35528             return item;
35529           }
35530
35531           function ribbonItemForMinified(d, source) {
35532             if (d && d.pID) {
35533               var preset = _this.item(d.pID);
35534
35535               if (!preset) return null;
35536               return RibbonItem(preset, source);
35537             }
35538
35539             return null;
35540           }
35541
35542           _this.getGenericRibbonItems = function () {
35543             return ['point', 'line', 'area'].map(function (id) {
35544               return RibbonItem(_this.item(id), 'generic');
35545             });
35546           };
35547
35548           _this.getAddable = function () {
35549             if (!_addablePresetIDs) return [];
35550             return _addablePresetIDs.map(function (id) {
35551               var preset = _this.item(id);
35552
35553               if (preset) return RibbonItem(preset, 'addable');
35554               return null;
35555             }).filter(Boolean);
35556           };
35557
35558           function setRecents(items) {
35559             _recents = items;
35560             var minifiedItems = items.map(function (d) {
35561               return d.minified();
35562             });
35563             corePreferences('preset_recents', JSON.stringify(minifiedItems));
35564             dispatch.call('recentsChange');
35565           }
35566
35567           _this.getRecents = function () {
35568             if (!_recents) {
35569               // fetch from local storage
35570               _recents = (JSON.parse(corePreferences('preset_recents')) || []).reduce(function (acc, d) {
35571                 var item = ribbonItemForMinified(d, 'recent');
35572                 if (item && item.preset.addable()) acc.push(item);
35573                 return acc;
35574               }, []);
35575             }
35576
35577             return _recents;
35578           };
35579
35580           _this.addRecent = function (preset, besidePreset, after) {
35581             var recents = _this.getRecents();
35582
35583             var beforeItem = _this.recentMatching(besidePreset);
35584
35585             var toIndex = recents.indexOf(beforeItem);
35586             if (after) toIndex += 1;
35587             var newItem = RibbonItem(preset, 'recent');
35588             recents.splice(toIndex, 0, newItem);
35589             setRecents(recents);
35590           };
35591
35592           _this.removeRecent = function (preset) {
35593             var item = _this.recentMatching(preset);
35594
35595             if (item) {
35596               var items = _this.getRecents();
35597
35598               items.splice(items.indexOf(item), 1);
35599               setRecents(items);
35600             }
35601           };
35602
35603           _this.recentMatching = function (preset) {
35604             var items = _this.getRecents();
35605
35606             for (var i in items) {
35607               if (items[i].matches(preset)) {
35608                 return items[i];
35609               }
35610             }
35611
35612             return null;
35613           };
35614
35615           _this.moveItem = function (items, fromIndex, toIndex) {
35616             if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) return null;
35617             items.splice(toIndex, 0, items.splice(fromIndex, 1)[0]);
35618             return items;
35619           };
35620
35621           _this.moveRecent = function (item, beforeItem) {
35622             var recents = _this.getRecents();
35623
35624             var fromIndex = recents.indexOf(item);
35625             var toIndex = recents.indexOf(beforeItem);
35626
35627             var items = _this.moveItem(recents, fromIndex, toIndex);
35628
35629             if (items) setRecents(items);
35630           };
35631
35632           _this.setMostRecent = function (preset) {
35633             if (preset.searchable === false) return;
35634
35635             var items = _this.getRecents();
35636
35637             var item = _this.recentMatching(preset);
35638
35639             if (item) {
35640               items.splice(items.indexOf(item), 1);
35641             } else {
35642               item = RibbonItem(preset, 'recent');
35643             } // remove the last recent (first in, first out)
35644
35645
35646             while (items.length >= MAXRECENTS) {
35647               items.pop();
35648             } // prepend array
35649
35650
35651             items.unshift(item);
35652             setRecents(items);
35653           };
35654
35655           function setFavorites(items) {
35656             _favorites = items;
35657             var minifiedItems = items.map(function (d) {
35658               return d.minified();
35659             });
35660             corePreferences('preset_favorites', JSON.stringify(minifiedItems)); // call update
35661
35662             dispatch.call('favoritePreset');
35663           }
35664
35665           _this.addFavorite = function (preset, besidePreset, after) {
35666             var favorites = _this.getFavorites();
35667
35668             var beforeItem = _this.favoriteMatching(besidePreset);
35669
35670             var toIndex = favorites.indexOf(beforeItem);
35671             if (after) toIndex += 1;
35672             var newItem = RibbonItem(preset, 'favorite');
35673             favorites.splice(toIndex, 0, newItem);
35674             setFavorites(favorites);
35675           };
35676
35677           _this.toggleFavorite = function (preset) {
35678             var favs = _this.getFavorites();
35679
35680             var favorite = _this.favoriteMatching(preset);
35681
35682             if (favorite) {
35683               favs.splice(favs.indexOf(favorite), 1);
35684             } else {
35685               // only allow 10 favorites
35686               if (favs.length === 10) {
35687                 // remove the last favorite (last in, first out)
35688                 favs.pop();
35689               } // append array
35690
35691
35692               favs.push(RibbonItem(preset, 'favorite'));
35693             }
35694
35695             setFavorites(favs);
35696           };
35697
35698           _this.removeFavorite = function (preset) {
35699             var item = _this.favoriteMatching(preset);
35700
35701             if (item) {
35702               var items = _this.getFavorites();
35703
35704               items.splice(items.indexOf(item), 1);
35705               setFavorites(items);
35706             }
35707           };
35708
35709           _this.getFavorites = function () {
35710             if (!_favorites) {
35711               // fetch from local storage
35712               var rawFavorites = JSON.parse(corePreferences('preset_favorites'));
35713
35714               if (!rawFavorites) {
35715                 rawFavorites = [];
35716                 corePreferences('preset_favorites', JSON.stringify(rawFavorites));
35717               }
35718
35719               _favorites = rawFavorites.reduce(function (output, d) {
35720                 var item = ribbonItemForMinified(d, 'favorite');
35721                 if (item && item.preset.addable()) output.push(item);
35722                 return output;
35723               }, []);
35724             }
35725
35726             return _favorites;
35727           };
35728
35729           _this.favoriteMatching = function (preset) {
35730             var favs = _this.getFavorites();
35731
35732             for (var index in favs) {
35733               if (favs[index].matches(preset)) {
35734                 return favs[index];
35735               }
35736             }
35737
35738             return null;
35739           };
35740
35741           return utilRebind(_this, dispatch, 'on');
35742         }
35743
35744         function utilTagText(entity) {
35745           var obj = entity && entity.tags || {};
35746           return Object.keys(obj).map(function (k) {
35747             return k + '=' + obj[k];
35748           }).join(', ');
35749         }
35750         function utilTotalExtent(array, graph) {
35751           var extent = geoExtent();
35752           var val, entity;
35753
35754           for (var i = 0; i < array.length; i++) {
35755             val = array[i];
35756             entity = typeof val === 'string' ? graph.hasEntity(val) : val;
35757
35758             if (entity) {
35759               extent._extend(entity.extent(graph));
35760             }
35761           }
35762
35763           return extent;
35764         }
35765         function utilTagDiff(oldTags, newTags) {
35766           var tagDiff = [];
35767           var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
35768           keys.forEach(function (k) {
35769             var oldVal = oldTags[k];
35770             var newVal = newTags[k];
35771
35772             if ((oldVal || oldVal === '') && (newVal === undefined || newVal !== oldVal)) {
35773               tagDiff.push({
35774                 type: '-',
35775                 key: k,
35776                 oldVal: oldVal,
35777                 newVal: newVal,
35778                 display: '- ' + k + '=' + oldVal
35779               });
35780             }
35781
35782             if ((newVal || newVal === '') && (oldVal === undefined || newVal !== oldVal)) {
35783               tagDiff.push({
35784                 type: '+',
35785                 key: k,
35786                 oldVal: oldVal,
35787                 newVal: newVal,
35788                 display: '+ ' + k + '=' + newVal
35789               });
35790             }
35791           });
35792           return tagDiff;
35793         }
35794         function utilEntitySelector(ids) {
35795           return ids.length ? '.' + ids.join(',.') : 'nothing';
35796         } // returns an selector to select entity ids for:
35797         //  - entityIDs passed in
35798         //  - shallow descendant entityIDs for any of those entities that are relations
35799
35800         function utilEntityOrMemberSelector(ids, graph) {
35801           var seen = new Set(ids);
35802           ids.forEach(collectShallowDescendants);
35803           return utilEntitySelector(Array.from(seen));
35804
35805           function collectShallowDescendants(id) {
35806             var entity = graph.hasEntity(id);
35807             if (!entity || entity.type !== 'relation') return;
35808             entity.members.map(function (member) {
35809               return member.id;
35810             }).forEach(function (id) {
35811               seen.add(id);
35812             });
35813           }
35814         } // returns an selector to select entity ids for:
35815         //  - entityIDs passed in
35816         //  - deep descendant entityIDs for any of those entities that are relations
35817
35818         function utilEntityOrDeepMemberSelector(ids, graph) {
35819           return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
35820         } // returns an selector to select entity ids for:
35821         //  - entityIDs passed in
35822         //  - deep descendant entityIDs for any of those entities that are relations
35823
35824         function utilEntityAndDeepMemberIDs(ids, graph) {
35825           var seen = new Set();
35826           ids.forEach(collectDeepDescendants);
35827           return Array.from(seen);
35828
35829           function collectDeepDescendants(id) {
35830             if (seen.has(id)) return;
35831             seen.add(id);
35832             var entity = graph.hasEntity(id);
35833             if (!entity || entity.type !== 'relation') return;
35834             entity.members.map(function (member) {
35835               return member.id;
35836             }).forEach(collectDeepDescendants); // recurse
35837           }
35838         } // returns an selector to select entity ids for:
35839         //  - deep descendant entityIDs for any of those entities that are relations
35840
35841         function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
35842           var idsSet = new Set(ids);
35843           var seen = new Set();
35844           var returners = new Set();
35845           ids.forEach(collectDeepDescendants);
35846           return utilEntitySelector(Array.from(returners));
35847
35848           function collectDeepDescendants(id) {
35849             if (seen.has(id)) return;
35850             seen.add(id);
35851
35852             if (!idsSet.has(id)) {
35853               returners.add(id);
35854             }
35855
35856             var entity = graph.hasEntity(id);
35857             if (!entity || entity.type !== 'relation') return;
35858             if (skipMultipolgonMembers && entity.isMultipolygon()) return;
35859             entity.members.map(function (member) {
35860               return member.id;
35861             }).forEach(collectDeepDescendants); // recurse
35862           }
35863         } // Adds or removes highlight styling for the specified entities
35864
35865         function utilHighlightEntities(ids, highlighted, context) {
35866           context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed('highlighted', highlighted);
35867         } // returns an Array that is the union of:
35868         //  - nodes for any nodeIDs passed in
35869         //  - child nodes of any wayIDs passed in
35870         //  - descendant member and child nodes of relationIDs passed in
35871
35872         function utilGetAllNodes(ids, graph) {
35873           var seen = new Set();
35874           var nodes = new Set();
35875           ids.forEach(collectNodes);
35876           return Array.from(nodes);
35877
35878           function collectNodes(id) {
35879             if (seen.has(id)) return;
35880             seen.add(id);
35881             var entity = graph.hasEntity(id);
35882             if (!entity) return;
35883
35884             if (entity.type === 'node') {
35885               nodes.add(entity);
35886             } else if (entity.type === 'way') {
35887               entity.nodes.forEach(collectNodes);
35888             } else {
35889               entity.members.map(function (member) {
35890                 return member.id;
35891               }).forEach(collectNodes); // recurse
35892             }
35893           }
35894         }
35895         function utilDisplayName(entity) {
35896           var localizedNameKey = 'name:' + _mainLocalizer.languageCode().toLowerCase();
35897           var name = entity.tags[localizedNameKey] || entity.tags.name || '';
35898           if (name) return name;
35899           var tags = {
35900             direction: entity.tags.direction,
35901             from: entity.tags.from,
35902             network: entity.tags.cycle_network || entity.tags.network,
35903             ref: entity.tags.ref,
35904             to: entity.tags.to,
35905             via: entity.tags.via
35906           };
35907           var keyComponents = [];
35908
35909           if (tags.network) {
35910             keyComponents.push('network');
35911           }
35912
35913           if (tags.ref) {
35914             keyComponents.push('ref');
35915           } // Routes may need more disambiguation based on direction or destination
35916
35917
35918           if (entity.tags.route) {
35919             if (tags.direction) {
35920               keyComponents.push('direction');
35921             } else if (tags.from && tags.to) {
35922               keyComponents.push('from');
35923               keyComponents.push('to');
35924
35925               if (tags.via) {
35926                 keyComponents.push('via');
35927               }
35928             }
35929           }
35930
35931           if (keyComponents.length) {
35932             name = _t('inspector.display_name.' + keyComponents.join('_'), tags);
35933           }
35934
35935           return name;
35936         }
35937         function utilDisplayNameForPath(entity) {
35938           var name = utilDisplayName(entity);
35939           var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
35940           var isNewChromium = Number(utilDetect().version.split('.')[0]) >= 96.0;
35941
35942           if (!isFirefox && !isNewChromium && name && rtlRegex.test(name)) {
35943             name = fixRTLTextForSvg(name);
35944           }
35945
35946           return name;
35947         }
35948         function utilDisplayType(id) {
35949           return {
35950             n: _t('inspector.node'),
35951             w: _t('inspector.way'),
35952             r: _t('inspector.relation')
35953           }[id.charAt(0)];
35954         } // `utilDisplayLabel`
35955         // Returns a string suitable for display
35956         // By default returns something like name/ref, fallback to preset type, fallback to OSM type
35957         //   "Main Street" or "Tertiary Road"
35958         // If `verbose=true`, include both preset name and feature name.
35959         //   "Tertiary Road Main Street"
35960         //
35961
35962         function utilDisplayLabel(entity, graphOrGeometry, verbose) {
35963           var result;
35964           var displayName = utilDisplayName(entity);
35965           var preset = typeof graphOrGeometry === 'string' ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
35966           var presetName = preset && (preset.suggestion ? preset.subtitle() : preset.name());
35967
35968           if (verbose) {
35969             result = [presetName, displayName].filter(Boolean).join(' ');
35970           } else {
35971             result = displayName || presetName;
35972           } // Fallback to the OSM type (node/way/relation)
35973
35974
35975           return result || utilDisplayType(entity.id);
35976         }
35977         function utilEntityRoot(entityType) {
35978           return {
35979             node: 'n',
35980             way: 'w',
35981             relation: 'r'
35982           }[entityType];
35983         } // Returns a single object containing the tags of all the given entities.
35984         // Example:
35985         // {
35986         //   highway: 'service',
35987         //   service: 'parking_aisle'
35988         // }
35989         //           +
35990         // {
35991         //   highway: 'service',
35992         //   service: 'driveway',
35993         //   width: '3'
35994         // }
35995         //           =
35996         // {
35997         //   highway: 'service',
35998         //   service: [ 'driveway', 'parking_aisle' ],
35999         //   width: [ '3', undefined ]
36000         // }
36001
36002         function utilCombinedTags(entityIDs, graph) {
36003           var tags = {};
36004           var tagCounts = {};
36005           var allKeys = new Set();
36006           var entities = entityIDs.map(function (entityID) {
36007             return graph.hasEntity(entityID);
36008           }).filter(Boolean); // gather the aggregate keys
36009
36010           entities.forEach(function (entity) {
36011             var keys = Object.keys(entity.tags).filter(Boolean);
36012             keys.forEach(function (key) {
36013               allKeys.add(key);
36014             });
36015           });
36016           entities.forEach(function (entity) {
36017             allKeys.forEach(function (key) {
36018               var value = entity.tags[key]; // purposely allow `undefined`
36019
36020               if (!tags.hasOwnProperty(key)) {
36021                 // first value, set as raw
36022                 tags[key] = value;
36023               } else {
36024                 if (!Array.isArray(tags[key])) {
36025                   if (tags[key] !== value) {
36026                     // first alternate value, replace single value with array
36027                     tags[key] = [tags[key], value];
36028                   }
36029                 } else {
36030                   // type is array
36031                   if (tags[key].indexOf(value) === -1) {
36032                     // subsequent alternate value, add to array
36033                     tags[key].push(value);
36034                   }
36035                 }
36036               }
36037
36038               var tagHash = key + '=' + value;
36039               if (!tagCounts[tagHash]) tagCounts[tagHash] = 0;
36040               tagCounts[tagHash] += 1;
36041             });
36042           });
36043
36044           for (var key in tags) {
36045             if (!Array.isArray(tags[key])) continue; // sort values by frequency then alphabetically
36046
36047             tags[key] = tags[key].sort(function (val1, val2) {
36048               var key = key; // capture
36049
36050               var count2 = tagCounts[key + '=' + val2];
36051               var count1 = tagCounts[key + '=' + val1];
36052
36053               if (count2 !== count1) {
36054                 return count2 - count1;
36055               }
36056
36057               if (val2 && val1) {
36058                 return val1.localeCompare(val2);
36059               }
36060
36061               return val1 ? 1 : -1;
36062             });
36063           }
36064
36065           return tags;
36066         }
36067         function utilStringQs(str) {
36068           var i = 0; // advance past any leading '?' or '#' characters
36069
36070           while (i < str.length && (str[i] === '?' || str[i] === '#')) {
36071             i++;
36072           }
36073
36074           str = str.slice(i);
36075           return str.split('&').reduce(function (obj, pair) {
36076             var parts = pair.split('=');
36077
36078             if (parts.length === 2) {
36079               obj[parts[0]] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
36080             }
36081
36082             return obj;
36083           }, {});
36084         }
36085         function utilQsString(obj, noencode) {
36086           // encode everything except special characters used in certain hash parameters:
36087           // "/" in map states, ":", ",", {" and "}" in background
36088           function softEncode(s) {
36089             return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
36090           }
36091
36092           return Object.keys(obj).sort().map(function (key) {
36093             return encodeURIComponent(key) + '=' + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
36094           }).join('&');
36095         }
36096         function utilPrefixDOMProperty(property) {
36097           var prefixes = ['webkit', 'ms', 'moz', 'o'];
36098           var i = -1;
36099           var n = prefixes.length;
36100           var s = document.body;
36101           if (property in s) return property;
36102           property = property.substr(0, 1).toUpperCase() + property.substr(1);
36103
36104           while (++i < n) {
36105             if (prefixes[i] + property in s) {
36106               return prefixes[i] + property;
36107             }
36108           }
36109
36110           return false;
36111         }
36112         function utilPrefixCSSProperty(property) {
36113           var prefixes = ['webkit', 'ms', 'Moz', 'O'];
36114           var i = -1;
36115           var n = prefixes.length;
36116           var s = document.body.style;
36117
36118           if (property.toLowerCase() in s) {
36119             return property.toLowerCase();
36120           }
36121
36122           while (++i < n) {
36123             if (prefixes[i] + property in s) {
36124               return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
36125             }
36126           }
36127
36128           return false;
36129         }
36130         var transformProperty;
36131         function utilSetTransform(el, x, y, scale) {
36132           var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform');
36133           var translate = utilDetect().opera ? 'translate(' + x + 'px,' + y + 'px)' : 'translate3d(' + x + 'px,' + y + 'px,0)';
36134           return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
36135         } // Calculates Levenshtein distance between two strings
36136         // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
36137         // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
36138
36139         function utilEditDistance(a, b) {
36140           a = remove$6(a.toLowerCase());
36141           b = remove$6(b.toLowerCase());
36142           if (a.length === 0) return b.length;
36143           if (b.length === 0) return a.length;
36144           var matrix = [];
36145           var i, j;
36146
36147           for (i = 0; i <= b.length; i++) {
36148             matrix[i] = [i];
36149           }
36150
36151           for (j = 0; j <= a.length; j++) {
36152             matrix[0][j] = j;
36153           }
36154
36155           for (i = 1; i <= b.length; i++) {
36156             for (j = 1; j <= a.length; j++) {
36157               if (b.charAt(i - 1) === a.charAt(j - 1)) {
36158                 matrix[i][j] = matrix[i - 1][j - 1];
36159               } else {
36160                 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
36161                 Math.min(matrix[i][j - 1] + 1, // insertion
36162                 matrix[i - 1][j] + 1)); // deletion
36163               }
36164             }
36165           }
36166
36167           return matrix[b.length][a.length];
36168         } // a d3.mouse-alike which
36169         // 1. Only works on HTML elements, not SVG
36170         // 2. Does not cause style recalculation
36171
36172         function utilFastMouse(container) {
36173           var rect = container.getBoundingClientRect();
36174           var rectLeft = rect.left;
36175           var rectTop = rect.top;
36176           var clientLeft = +container.clientLeft;
36177           var clientTop = +container.clientTop;
36178           return function (e) {
36179             return [e.clientX - rectLeft - clientLeft, e.clientY - rectTop - clientTop];
36180           };
36181         }
36182         function utilAsyncMap(inputs, func, callback) {
36183           var remaining = inputs.length;
36184           var results = [];
36185           var errors = [];
36186           inputs.forEach(function (d, i) {
36187             func(d, function done(err, data) {
36188               errors[i] = err;
36189               results[i] = data;
36190               remaining--;
36191               if (!remaining) callback(errors, results);
36192             });
36193           });
36194         } // wraps an index to an interval [0..length-1]
36195
36196         function utilWrap(index, length) {
36197           if (index < 0) {
36198             index += Math.ceil(-index / length) * length;
36199           }
36200
36201           return index % length;
36202         }
36203         /**
36204          * a replacement for functor
36205          *
36206          * @param {*} value any value
36207          * @returns {Function} a function that returns that value or the value if it's a function
36208          */
36209
36210         function utilFunctor(value) {
36211           if (typeof value === 'function') return value;
36212           return function () {
36213             return value;
36214           };
36215         }
36216         function utilNoAuto(selection) {
36217           var isText = selection.size() && selection.node().tagName.toLowerCase() === 'textarea';
36218           return selection // assign 'new-password' even for non-password fields to prevent browsers (Chrome) ignoring 'off'
36219           .attr('autocomplete', 'new-password').attr('autocorrect', 'off').attr('autocapitalize', 'off').attr('spellcheck', isText ? 'true' : 'false');
36220         } // https://stackoverflow.com/questions/194846/is-there-any-kind-of-hash-code-function-in-javascript
36221         // https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
36222
36223         function utilHashcode(str) {
36224           var hash = 0;
36225
36226           if (str.length === 0) {
36227             return hash;
36228           }
36229
36230           for (var i = 0; i < str.length; i++) {
36231             var _char = str.charCodeAt(i);
36232
36233             hash = (hash << 5) - hash + _char;
36234             hash = hash & hash; // Convert to 32bit integer
36235           }
36236
36237           return hash;
36238         } // Returns version of `str` with all runs of special characters replaced by `_`;
36239         // suitable for HTML ids, classes, selectors, etc.
36240
36241         function utilSafeClassName(str) {
36242           return str.toLowerCase().replace(/[^a-z0-9]+/g, '_');
36243         } // Returns string based on `val` that is highly unlikely to collide with an id
36244         // used previously or that's present elsewhere in the document. Useful for preventing
36245         // browser-provided autofills or when embedding iD on pages with unknown elements.
36246
36247         function utilUniqueDomId(val) {
36248           return 'ideditor-' + utilSafeClassName(val.toString()) + '-' + new Date().getTime().toString();
36249         } // Returns the length of `str` in unicode characters. This can be less than
36250         // `String.length()` since a single unicode character can be composed of multiple
36251         // JavaScript UTF-16 code units.
36252
36253         function utilUnicodeCharsCount(str) {
36254           // Native ES2015 implementations of `Array.from` split strings into unicode characters
36255           return Array.from(str).length;
36256         } // Returns a new string representing `str` cut from its start to `limit` length
36257         // in unicode characters. Note that this runs the risk of splitting graphemes.
36258
36259         function utilUnicodeCharsTruncated(str, limit) {
36260           return Array.from(str).slice(0, limit).join('');
36261         }
36262
36263         function osmEntity(attrs) {
36264           // For prototypal inheritance.
36265           if (this instanceof osmEntity) return; // Create the appropriate subtype.
36266
36267           if (attrs && attrs.type) {
36268             return osmEntity[attrs.type].apply(this, arguments);
36269           } else if (attrs && attrs.id) {
36270             return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
36271           } // Initialize a generic Entity (used only in tests).
36272
36273
36274           return new osmEntity().initialize(arguments);
36275         }
36276
36277         osmEntity.id = function (type) {
36278           return osmEntity.id.fromOSM(type, osmEntity.id.next[type]--);
36279         };
36280
36281         osmEntity.id.next = {
36282           changeset: -1,
36283           node: -1,
36284           way: -1,
36285           relation: -1
36286         };
36287
36288         osmEntity.id.fromOSM = function (type, id) {
36289           return type[0] + id;
36290         };
36291
36292         osmEntity.id.toOSM = function (id) {
36293           return id.slice(1);
36294         };
36295
36296         osmEntity.id.type = function (id) {
36297           return {
36298             'c': 'changeset',
36299             'n': 'node',
36300             'w': 'way',
36301             'r': 'relation'
36302           }[id[0]];
36303         }; // A function suitable for use as the second argument to d3.selection#data().
36304
36305
36306         osmEntity.key = function (entity) {
36307           return entity.id + 'v' + (entity.v || 0);
36308         };
36309
36310         var _deprecatedTagValuesByKey;
36311
36312         osmEntity.deprecatedTagValuesByKey = function (dataDeprecated) {
36313           if (!_deprecatedTagValuesByKey) {
36314             _deprecatedTagValuesByKey = {};
36315             dataDeprecated.forEach(function (d) {
36316               var oldKeys = Object.keys(d.old);
36317
36318               if (oldKeys.length === 1) {
36319                 var oldKey = oldKeys[0];
36320                 var oldValue = d.old[oldKey];
36321
36322                 if (oldValue !== '*') {
36323                   if (!_deprecatedTagValuesByKey[oldKey]) {
36324                     _deprecatedTagValuesByKey[oldKey] = [oldValue];
36325                   } else {
36326                     _deprecatedTagValuesByKey[oldKey].push(oldValue);
36327                   }
36328                 }
36329               }
36330             });
36331           }
36332
36333           return _deprecatedTagValuesByKey;
36334         };
36335
36336         osmEntity.prototype = {
36337           tags: {},
36338           initialize: function initialize(sources) {
36339             for (var i = 0; i < sources.length; ++i) {
36340               var source = sources[i];
36341
36342               for (var prop in source) {
36343                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
36344                   if (source[prop] === undefined) {
36345                     delete this[prop];
36346                   } else {
36347                     this[prop] = source[prop];
36348                   }
36349                 }
36350               }
36351             }
36352
36353             if (!this.id && this.type) {
36354               this.id = osmEntity.id(this.type);
36355             }
36356
36357             if (!this.hasOwnProperty('visible')) {
36358               this.visible = true;
36359             }
36360
36361             if (debug) {
36362               Object.freeze(this);
36363               Object.freeze(this.tags);
36364               if (this.loc) Object.freeze(this.loc);
36365               if (this.nodes) Object.freeze(this.nodes);
36366               if (this.members) Object.freeze(this.members);
36367             }
36368
36369             return this;
36370           },
36371           copy: function copy(resolver, copies) {
36372             if (copies[this.id]) return copies[this.id];
36373             var copy = osmEntity(this, {
36374               id: undefined,
36375               user: undefined,
36376               version: undefined
36377             });
36378             copies[this.id] = copy;
36379             return copy;
36380           },
36381           osmId: function osmId() {
36382             return osmEntity.id.toOSM(this.id);
36383           },
36384           isNew: function isNew() {
36385             return this.osmId() < 0;
36386           },
36387           update: function update(attrs) {
36388             return osmEntity(this, attrs, {
36389               v: 1 + (this.v || 0)
36390             });
36391           },
36392           mergeTags: function mergeTags(tags) {
36393             var merged = Object.assign({}, this.tags); // shallow copy
36394
36395             var changed = false;
36396
36397             for (var k in tags) {
36398               var t1 = merged[k];
36399               var t2 = tags[k];
36400
36401               if (!t1) {
36402                 changed = true;
36403                 merged[k] = t2;
36404               } else if (t1 !== t2) {
36405                 changed = true;
36406                 merged[k] = utilUnicodeCharsTruncated(utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(';'), 255 // avoid exceeding character limit; see also services/osm.js -> maxCharsForTagValue()
36407                 );
36408               }
36409             }
36410
36411             return changed ? this.update({
36412               tags: merged
36413             }) : this;
36414           },
36415           intersects: function intersects(extent, resolver) {
36416             return this.extent(resolver).intersects(extent);
36417           },
36418           hasNonGeometryTags: function hasNonGeometryTags() {
36419             return Object.keys(this.tags).some(function (k) {
36420               return k !== 'area';
36421             });
36422           },
36423           hasParentRelations: function hasParentRelations(resolver) {
36424             return resolver.parentRelations(this).length > 0;
36425           },
36426           hasInterestingTags: function hasInterestingTags() {
36427             return Object.keys(this.tags).some(osmIsInterestingTag);
36428           },
36429           isHighwayIntersection: function isHighwayIntersection() {
36430             return false;
36431           },
36432           isDegenerate: function isDegenerate() {
36433             return true;
36434           },
36435           deprecatedTags: function deprecatedTags(dataDeprecated) {
36436             var tags = this.tags; // if there are no tags, none can be deprecated
36437
36438             if (Object.keys(tags).length === 0) return [];
36439             var deprecated = [];
36440             dataDeprecated.forEach(function (d) {
36441               var oldKeys = Object.keys(d.old);
36442
36443               if (d.replace) {
36444                 var hasExistingValues = Object.keys(d.replace).some(function (replaceKey) {
36445                   if (!tags[replaceKey] || d.old[replaceKey]) return false;
36446                   var replaceValue = d.replace[replaceKey];
36447                   if (replaceValue === '*') return false;
36448                   if (replaceValue === tags[replaceKey]) return false;
36449                   return true;
36450                 }); // don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
36451
36452                 if (hasExistingValues) return;
36453               }
36454
36455               var matchesDeprecatedTags = oldKeys.every(function (oldKey) {
36456                 if (!tags[oldKey]) return false;
36457                 if (d.old[oldKey] === '*') return true;
36458                 if (d.old[oldKey] === tags[oldKey]) return true;
36459                 var vals = tags[oldKey].split(';').filter(Boolean);
36460
36461                 if (vals.length === 0) {
36462                   return false;
36463                 } else if (vals.length > 1) {
36464                   return vals.indexOf(d.old[oldKey]) !== -1;
36465                 } else {
36466                   if (tags[oldKey] === d.old[oldKey]) {
36467                     if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
36468                       var replaceKeys = Object.keys(d.replace);
36469                       return !replaceKeys.every(function (replaceKey) {
36470                         return tags[replaceKey] === d.replace[replaceKey];
36471                       });
36472                     } else {
36473                       return true;
36474                     }
36475                   }
36476                 }
36477
36478                 return false;
36479               });
36480
36481               if (matchesDeprecatedTags) {
36482                 deprecated.push(d);
36483               }
36484             });
36485             return deprecated;
36486           }
36487         };
36488
36489         function osmLanes(entity) {
36490           if (entity.type !== 'way') return null;
36491           if (!entity.tags.highway) return null;
36492           var tags = entity.tags;
36493           var isOneWay = entity.isOneWay();
36494           var laneCount = getLaneCount(tags, isOneWay);
36495           var maxspeed = parseMaxspeed(tags);
36496           var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
36497           var forward = laneDirections.forward;
36498           var backward = laneDirections.backward;
36499           var bothways = laneDirections.bothways; // parse the piped string 'x|y|z' format
36500
36501           var turnLanes = {};
36502           turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
36503           turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
36504           turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
36505           var maxspeedLanes = {};
36506           maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
36507           maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
36508           maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
36509           var psvLanes = {};
36510           psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
36511           psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
36512           psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
36513           var busLanes = {};
36514           busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
36515           busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
36516           busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
36517           var taxiLanes = {};
36518           taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
36519           taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
36520           taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
36521           var hovLanes = {};
36522           hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
36523           hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
36524           hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
36525           var hgvLanes = {};
36526           hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
36527           hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
36528           hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
36529           var bicyclewayLanes = {};
36530           bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
36531           bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
36532           bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
36533           var lanesObj = {
36534             forward: [],
36535             backward: [],
36536             unspecified: []
36537           }; // map forward/backward/unspecified of each lane type to lanesObj
36538
36539           mapToLanesObj(lanesObj, turnLanes, 'turnLane');
36540           mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
36541           mapToLanesObj(lanesObj, psvLanes, 'psv');
36542           mapToLanesObj(lanesObj, busLanes, 'bus');
36543           mapToLanesObj(lanesObj, taxiLanes, 'taxi');
36544           mapToLanesObj(lanesObj, hovLanes, 'hov');
36545           mapToLanesObj(lanesObj, hgvLanes, 'hgv');
36546           mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
36547           return {
36548             metadata: {
36549               count: laneCount,
36550               oneway: isOneWay,
36551               forward: forward,
36552               backward: backward,
36553               bothways: bothways,
36554               turnLanes: turnLanes,
36555               maxspeed: maxspeed,
36556               maxspeedLanes: maxspeedLanes,
36557               psvLanes: psvLanes,
36558               busLanes: busLanes,
36559               taxiLanes: taxiLanes,
36560               hovLanes: hovLanes,
36561               hgvLanes: hgvLanes,
36562               bicyclewayLanes: bicyclewayLanes
36563             },
36564             lanes: lanesObj
36565           };
36566         }
36567
36568         function getLaneCount(tags, isOneWay) {
36569           var count;
36570
36571           if (tags.lanes) {
36572             count = parseInt(tags.lanes, 10);
36573
36574             if (count > 0) {
36575               return count;
36576             }
36577           }
36578
36579           switch (tags.highway) {
36580             case 'trunk':
36581             case 'motorway':
36582               count = isOneWay ? 2 : 4;
36583               break;
36584
36585             default:
36586               count = isOneWay ? 1 : 2;
36587               break;
36588           }
36589
36590           return count;
36591         }
36592
36593         function parseMaxspeed(tags) {
36594           var maxspeed = tags.maxspeed;
36595           if (!maxspeed) return;
36596           var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
36597           if (!maxspeedRegex.test(maxspeed)) return;
36598           return parseInt(maxspeed, 10);
36599         }
36600
36601         function parseLaneDirections(tags, isOneWay, laneCount) {
36602           var forward = parseInt(tags['lanes:forward'], 10);
36603           var backward = parseInt(tags['lanes:backward'], 10);
36604           var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
36605
36606           if (parseInt(tags.oneway, 10) === -1) {
36607             forward = 0;
36608             bothways = 0;
36609             backward = laneCount;
36610           } else if (isOneWay) {
36611             forward = laneCount;
36612             bothways = 0;
36613             backward = 0;
36614           } else if (isNaN(forward) && isNaN(backward)) {
36615             backward = Math.floor((laneCount - bothways) / 2);
36616             forward = laneCount - bothways - backward;
36617           } else if (isNaN(forward)) {
36618             if (backward > laneCount - bothways) {
36619               backward = laneCount - bothways;
36620             }
36621
36622             forward = laneCount - bothways - backward;
36623           } else if (isNaN(backward)) {
36624             if (forward > laneCount - bothways) {
36625               forward = laneCount - bothways;
36626             }
36627
36628             backward = laneCount - bothways - forward;
36629           }
36630
36631           return {
36632             forward: forward,
36633             backward: backward,
36634             bothways: bothways
36635           };
36636         }
36637
36638         function parseTurnLanes(tag) {
36639           if (!tag) return;
36640           var validValues = ['left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right', 'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'];
36641           return tag.split('|').map(function (s) {
36642             if (s === '') s = 'none';
36643             return s.split(';').map(function (d) {
36644               return validValues.indexOf(d) === -1 ? 'unknown' : d;
36645             });
36646           });
36647         }
36648
36649         function parseMaxspeedLanes(tag, maxspeed) {
36650           if (!tag) return;
36651           return tag.split('|').map(function (s) {
36652             if (s === 'none') return s;
36653             var m = parseInt(s, 10);
36654             if (s === '' || m === maxspeed) return null;
36655             return isNaN(m) ? 'unknown' : m;
36656           });
36657         }
36658
36659         function parseMiscLanes(tag) {
36660           if (!tag) return;
36661           var validValues = ['yes', 'no', 'designated'];
36662           return tag.split('|').map(function (s) {
36663             if (s === '') s = 'no';
36664             return validValues.indexOf(s) === -1 ? 'unknown' : s;
36665           });
36666         }
36667
36668         function parseBicycleWay(tag) {
36669           if (!tag) return;
36670           var validValues = ['yes', 'no', 'designated', 'lane'];
36671           return tag.split('|').map(function (s) {
36672             if (s === '') s = 'no';
36673             return validValues.indexOf(s) === -1 ? 'unknown' : s;
36674           });
36675         }
36676
36677         function mapToLanesObj(lanesObj, data, key) {
36678           if (data.forward) {
36679             data.forward.forEach(function (l, i) {
36680               if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
36681               lanesObj.forward[i][key] = l;
36682             });
36683           }
36684
36685           if (data.backward) {
36686             data.backward.forEach(function (l, i) {
36687               if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
36688               lanesObj.backward[i][key] = l;
36689             });
36690           }
36691
36692           if (data.unspecified) {
36693             data.unspecified.forEach(function (l, i) {
36694               if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
36695               lanesObj.unspecified[i][key] = l;
36696             });
36697           }
36698         }
36699
36700         function osmWay() {
36701           if (!(this instanceof osmWay)) {
36702             return new osmWay().initialize(arguments);
36703           } else if (arguments.length) {
36704             this.initialize(arguments);
36705           }
36706         }
36707         osmEntity.way = osmWay;
36708         osmWay.prototype = Object.create(osmEntity.prototype);
36709         Object.assign(osmWay.prototype, {
36710           type: 'way',
36711           nodes: [],
36712           copy: function copy(resolver, copies) {
36713             if (copies[this.id]) return copies[this.id];
36714             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
36715             var nodes = this.nodes.map(function (id) {
36716               return resolver.entity(id).copy(resolver, copies).id;
36717             });
36718             copy = copy.update({
36719               nodes: nodes
36720             });
36721             copies[this.id] = copy;
36722             return copy;
36723           },
36724           extent: function extent(resolver) {
36725             return resolver["transient"](this, 'extent', function () {
36726               var extent = geoExtent();
36727
36728               for (var i = 0; i < this.nodes.length; i++) {
36729                 var node = resolver.hasEntity(this.nodes[i]);
36730
36731                 if (node) {
36732                   extent._extend(node.extent());
36733                 }
36734               }
36735
36736               return extent;
36737             });
36738           },
36739           first: function first() {
36740             return this.nodes[0];
36741           },
36742           last: function last() {
36743             return this.nodes[this.nodes.length - 1];
36744           },
36745           contains: function contains(node) {
36746             return this.nodes.indexOf(node) >= 0;
36747           },
36748           affix: function affix(node) {
36749             if (this.nodes[0] === node) return 'prefix';
36750             if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
36751           },
36752           layer: function layer() {
36753             // explicit layer tag, clamp between -10, 10..
36754             if (isFinite(this.tags.layer)) {
36755               return Math.max(-10, Math.min(+this.tags.layer, 10));
36756             } // implied layer tag..
36757
36758
36759             if (this.tags.covered === 'yes') return -1;
36760             if (this.tags.location === 'overground') return 1;
36761             if (this.tags.location === 'underground') return -1;
36762             if (this.tags.location === 'underwater') return -10;
36763             if (this.tags.power === 'line') return 10;
36764             if (this.tags.power === 'minor_line') return 10;
36765             if (this.tags.aerialway) return 10;
36766             if (this.tags.bridge) return 1;
36767             if (this.tags.cutting) return -1;
36768             if (this.tags.tunnel) return -1;
36769             if (this.tags.waterway) return -1;
36770             if (this.tags.man_made === 'pipeline') return -10;
36771             if (this.tags.boundary) return -10;
36772             return 0;
36773           },
36774           // the approximate width of the line based on its tags except its `width` tag
36775           impliedLineWidthMeters: function impliedLineWidthMeters() {
36776             var averageWidths = {
36777               highway: {
36778                 // width is for single lane
36779                 motorway: 5,
36780                 motorway_link: 5,
36781                 trunk: 4.5,
36782                 trunk_link: 4.5,
36783                 primary: 4,
36784                 secondary: 4,
36785                 tertiary: 4,
36786                 primary_link: 4,
36787                 secondary_link: 4,
36788                 tertiary_link: 4,
36789                 unclassified: 4,
36790                 road: 4,
36791                 living_street: 4,
36792                 bus_guideway: 4,
36793                 pedestrian: 4,
36794                 residential: 3.5,
36795                 service: 3.5,
36796                 track: 3,
36797                 cycleway: 2.5,
36798                 bridleway: 2,
36799                 corridor: 2,
36800                 steps: 2,
36801                 path: 1.5,
36802                 footway: 1.5
36803               },
36804               railway: {
36805                 // width includes ties and rail bed, not just track gauge
36806                 rail: 2.5,
36807                 light_rail: 2.5,
36808                 tram: 2.5,
36809                 subway: 2.5,
36810                 monorail: 2.5,
36811                 funicular: 2.5,
36812                 disused: 2.5,
36813                 preserved: 2.5,
36814                 miniature: 1.5,
36815                 narrow_gauge: 1.5
36816               },
36817               waterway: {
36818                 river: 50,
36819                 canal: 25,
36820                 stream: 5,
36821                 tidal_channel: 5,
36822                 fish_pass: 2.5,
36823                 drain: 2.5,
36824                 ditch: 1.5
36825               }
36826             };
36827
36828             for (var key in averageWidths) {
36829               if (this.tags[key] && averageWidths[key][this.tags[key]]) {
36830                 var width = averageWidths[key][this.tags[key]];
36831
36832                 if (key === 'highway') {
36833                   var laneCount = this.tags.lanes && parseInt(this.tags.lanes, 10);
36834                   if (!laneCount) laneCount = this.isOneWay() ? 1 : 2;
36835                   return width * laneCount;
36836                 }
36837
36838                 return width;
36839               }
36840             }
36841
36842             return null;
36843           },
36844           isOneWay: function isOneWay() {
36845             // explicit oneway tag..
36846             var values = {
36847               'yes': true,
36848               '1': true,
36849               '-1': true,
36850               'reversible': true,
36851               'alternating': true,
36852               'no': false,
36853               '0': false
36854             };
36855
36856             if (values[this.tags.oneway] !== undefined) {
36857               return values[this.tags.oneway];
36858             } // implied oneway tag..
36859
36860
36861             for (var key in this.tags) {
36862               if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) {
36863                 return true;
36864               }
36865             }
36866
36867             return false;
36868           },
36869           // Some identifier for tag that implies that this way is "sided",
36870           // i.e. the right side is the 'inside' (e.g. the right side of a
36871           // natural=cliff is lower).
36872           sidednessIdentifier: function sidednessIdentifier() {
36873             for (var key in this.tags) {
36874               var value = this.tags[key];
36875
36876               if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
36877                 if (osmRightSideIsInsideTags[key][value] === true) {
36878                   return key;
36879                 } else {
36880                   // if the map's value is something other than a
36881                   // literal true, we should use it so we can
36882                   // special case some keys (e.g. natural=coastline
36883                   // is handled differently to other naturals).
36884                   return osmRightSideIsInsideTags[key][value];
36885                 }
36886               }
36887             }
36888
36889             return null;
36890           },
36891           isSided: function isSided() {
36892             if (this.tags.two_sided === 'yes') {
36893               return false;
36894             }
36895
36896             return this.sidednessIdentifier() !== null;
36897           },
36898           lanes: function lanes() {
36899             return osmLanes(this);
36900           },
36901           isClosed: function isClosed() {
36902             return this.nodes.length > 1 && this.first() === this.last();
36903           },
36904           isConvex: function isConvex(resolver) {
36905             if (!this.isClosed() || this.isDegenerate()) return null;
36906             var nodes = utilArrayUniq(resolver.childNodes(this));
36907             var coords = nodes.map(function (n) {
36908               return n.loc;
36909             });
36910             var curr = 0;
36911             var prev = 0;
36912
36913             for (var i = 0; i < coords.length; i++) {
36914               var o = coords[(i + 1) % coords.length];
36915               var a = coords[i];
36916               var b = coords[(i + 2) % coords.length];
36917               var res = geoVecCross(a, b, o);
36918               curr = res > 0 ? 1 : res < 0 ? -1 : 0;
36919
36920               if (curr === 0) {
36921                 continue;
36922               } else if (prev && curr !== prev) {
36923                 return false;
36924               }
36925
36926               prev = curr;
36927             }
36928
36929             return true;
36930           },
36931           // returns an object with the tag that implies this is an area, if any
36932           tagSuggestingArea: function tagSuggestingArea() {
36933             return osmTagSuggestingArea(this.tags);
36934           },
36935           isArea: function isArea() {
36936             if (this.tags.area === 'yes') return true;
36937             if (!this.isClosed() || this.tags.area === 'no') return false;
36938             return this.tagSuggestingArea() !== null;
36939           },
36940           isDegenerate: function isDegenerate() {
36941             return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
36942           },
36943           areAdjacent: function areAdjacent(n1, n2) {
36944             for (var i = 0; i < this.nodes.length; i++) {
36945               if (this.nodes[i] === n1) {
36946                 if (this.nodes[i - 1] === n2) return true;
36947                 if (this.nodes[i + 1] === n2) return true;
36948               }
36949             }
36950
36951             return false;
36952           },
36953           geometry: function geometry(graph) {
36954             return graph["transient"](this, 'geometry', function () {
36955               return this.isArea() ? 'area' : 'line';
36956             });
36957           },
36958           // returns an array of objects representing the segments between the nodes in this way
36959           segments: function segments(graph) {
36960             function segmentExtent(graph) {
36961               var n1 = graph.hasEntity(this.nodes[0]);
36962               var n2 = graph.hasEntity(this.nodes[1]);
36963               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])]]);
36964             }
36965
36966             return graph["transient"](this, 'segments', function () {
36967               var segments = [];
36968
36969               for (var i = 0; i < this.nodes.length - 1; i++) {
36970                 segments.push({
36971                   id: this.id + '-' + i,
36972                   wayId: this.id,
36973                   index: i,
36974                   nodes: [this.nodes[i], this.nodes[i + 1]],
36975                   extent: segmentExtent
36976                 });
36977               }
36978
36979               return segments;
36980             });
36981           },
36982           // If this way is not closed, append the beginning node to the end of the nodelist to close it.
36983           close: function close() {
36984             if (this.isClosed() || !this.nodes.length) return this;
36985             var nodes = this.nodes.slice();
36986             nodes = nodes.filter(noRepeatNodes);
36987             nodes.push(nodes[0]);
36988             return this.update({
36989               nodes: nodes
36990             });
36991           },
36992           // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
36993           unclose: function unclose() {
36994             if (!this.isClosed()) return this;
36995             var nodes = this.nodes.slice();
36996             var connector = this.first();
36997             var i = nodes.length - 1; // remove trailing connectors..
36998
36999             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
37000               nodes.splice(i, 1);
37001               i = nodes.length - 1;
37002             }
37003
37004             nodes = nodes.filter(noRepeatNodes);
37005             return this.update({
37006               nodes: nodes
37007             });
37008           },
37009           // Adds a node (id) in front of the node which is currently at position index.
37010           // If index is undefined, the node will be added to the end of the way for linear ways,
37011           //   or just before the final connecting node for circular ways.
37012           // Consecutive duplicates are eliminated including existing ones.
37013           // Circularity is always preserved when adding a node.
37014           addNode: function addNode(id, index) {
37015             var nodes = this.nodes.slice();
37016             var isClosed = this.isClosed();
37017             var max = isClosed ? nodes.length - 1 : nodes.length;
37018
37019             if (index === undefined) {
37020               index = max;
37021             }
37022
37023             if (index < 0 || index > max) {
37024               throw new RangeError('index ' + index + ' out of range 0..' + max);
37025             } // If this is a closed way, remove all connector nodes except the first one
37026             // (there may be duplicates) and adjust index if necessary..
37027
37028
37029             if (isClosed) {
37030               var connector = this.first(); // leading connectors..
37031
37032               var i = 1;
37033
37034               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
37035                 nodes.splice(i, 1);
37036                 if (index > i) index--;
37037               } // trailing connectors..
37038
37039
37040               i = nodes.length - 1;
37041
37042               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
37043                 nodes.splice(i, 1);
37044                 if (index > i) index--;
37045                 i = nodes.length - 1;
37046               }
37047             }
37048
37049             nodes.splice(index, 0, id);
37050             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37051
37052             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37053               nodes.push(nodes[0]);
37054             }
37055
37056             return this.update({
37057               nodes: nodes
37058             });
37059           },
37060           // Replaces the node which is currently at position index with the given node (id).
37061           // Consecutive duplicates are eliminated including existing ones.
37062           // Circularity is preserved when updating a node.
37063           updateNode: function updateNode(id, index) {
37064             var nodes = this.nodes.slice();
37065             var isClosed = this.isClosed();
37066             var max = nodes.length - 1;
37067
37068             if (index === undefined || index < 0 || index > max) {
37069               throw new RangeError('index ' + index + ' out of range 0..' + max);
37070             } // If this is a closed way, remove all connector nodes except the first one
37071             // (there may be duplicates) and adjust index if necessary..
37072
37073
37074             if (isClosed) {
37075               var connector = this.first(); // leading connectors..
37076
37077               var i = 1;
37078
37079               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
37080                 nodes.splice(i, 1);
37081                 if (index > i) index--;
37082               } // trailing connectors..
37083
37084
37085               i = nodes.length - 1;
37086
37087               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
37088                 nodes.splice(i, 1);
37089                 if (index === i) index = 0; // update leading connector instead
37090
37091                 i = nodes.length - 1;
37092               }
37093             }
37094
37095             nodes.splice(index, 1, id);
37096             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37097
37098             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37099               nodes.push(nodes[0]);
37100             }
37101
37102             return this.update({
37103               nodes: nodes
37104             });
37105           },
37106           // Replaces each occurrence of node id needle with replacement.
37107           // Consecutive duplicates are eliminated including existing ones.
37108           // Circularity is preserved.
37109           replaceNode: function replaceNode(needleID, replacementID) {
37110             var nodes = this.nodes.slice();
37111             var isClosed = this.isClosed();
37112
37113             for (var i = 0; i < nodes.length; i++) {
37114               if (nodes[i] === needleID) {
37115                 nodes[i] = replacementID;
37116               }
37117             }
37118
37119             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37120
37121             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37122               nodes.push(nodes[0]);
37123             }
37124
37125             return this.update({
37126               nodes: nodes
37127             });
37128           },
37129           // Removes each occurrence of node id.
37130           // Consecutive duplicates are eliminated including existing ones.
37131           // Circularity is preserved.
37132           removeNode: function removeNode(id) {
37133             var nodes = this.nodes.slice();
37134             var isClosed = this.isClosed();
37135             nodes = nodes.filter(function (node) {
37136               return node !== id;
37137             }).filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37138
37139             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37140               nodes.push(nodes[0]);
37141             }
37142
37143             return this.update({
37144               nodes: nodes
37145             });
37146           },
37147           asJXON: function asJXON(changeset_id) {
37148             var r = {
37149               way: {
37150                 '@id': this.osmId(),
37151                 '@version': this.version || 0,
37152                 nd: this.nodes.map(function (id) {
37153                   return {
37154                     keyAttributes: {
37155                       ref: osmEntity.id.toOSM(id)
37156                     }
37157                   };
37158                 }, this),
37159                 tag: Object.keys(this.tags).map(function (k) {
37160                   return {
37161                     keyAttributes: {
37162                       k: k,
37163                       v: this.tags[k]
37164                     }
37165                   };
37166                 }, this)
37167               }
37168             };
37169
37170             if (changeset_id) {
37171               r.way['@changeset'] = changeset_id;
37172             }
37173
37174             return r;
37175           },
37176           asGeoJSON: function asGeoJSON(resolver) {
37177             return resolver["transient"](this, 'GeoJSON', function () {
37178               var coordinates = resolver.childNodes(this).map(function (n) {
37179                 return n.loc;
37180               });
37181
37182               if (this.isArea() && this.isClosed()) {
37183                 return {
37184                   type: 'Polygon',
37185                   coordinates: [coordinates]
37186                 };
37187               } else {
37188                 return {
37189                   type: 'LineString',
37190                   coordinates: coordinates
37191                 };
37192               }
37193             });
37194           },
37195           area: function area(resolver) {
37196             return resolver["transient"](this, 'area', function () {
37197               var nodes = resolver.childNodes(this);
37198               var json = {
37199                 type: 'Polygon',
37200                 coordinates: [nodes.map(function (n) {
37201                   return n.loc;
37202                 })]
37203               };
37204
37205               if (!this.isClosed() && nodes.length) {
37206                 json.coordinates[0].push(nodes[0].loc);
37207               }
37208
37209               var area = d3_geoArea(json); // Heuristic for detecting counterclockwise winding order. Assumes
37210               // that OpenStreetMap polygons are not hemisphere-spanning.
37211
37212               if (area > 2 * Math.PI) {
37213                 json.coordinates[0] = json.coordinates[0].reverse();
37214                 area = d3_geoArea(json);
37215               }
37216
37217               return isNaN(area) ? 0 : area;
37218             });
37219           }
37220         }); // Filter function to eliminate consecutive duplicates.
37221
37222         function noRepeatNodes(node, i, arr) {
37223           return i === 0 || node !== arr[i - 1];
37224         }
37225
37226         //
37227         // 1. Relation tagged with `type=multipolygon` and no interesting tags.
37228         // 2. One and only one member with the `outer` role. Must be a way with interesting tags.
37229         // 3. No members without a role.
37230         //
37231         // Old multipolygons are no longer recommended but are still rendered as areas by iD.
37232
37233         function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
37234           if (entity.type !== 'relation' || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
37235             return false;
37236           }
37237
37238           var outerMember;
37239
37240           for (var memberIndex in entity.members) {
37241             var member = entity.members[memberIndex];
37242
37243             if (!member.role || member.role === 'outer') {
37244               if (outerMember) return false;
37245               if (member.type !== 'way') return false;
37246               if (!graph.hasEntity(member.id)) return false;
37247               outerMember = graph.entity(member.id);
37248
37249               if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
37250                 return false;
37251               }
37252             }
37253           }
37254
37255           return outerMember;
37256         } // For fixing up rendering of multipolygons with tags on the outer member.
37257         // https://github.com/openstreetmap/iD/issues/613
37258
37259         function osmIsOldMultipolygonOuterMember(entity, graph) {
37260           if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) {
37261             return false;
37262           }
37263
37264           var parents = graph.parentRelations(entity);
37265           if (parents.length !== 1) return false;
37266           var parent = parents[0];
37267
37268           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
37269             return false;
37270           }
37271
37272           var members = parent.members,
37273               member;
37274
37275           for (var i = 0; i < members.length; i++) {
37276             member = members[i];
37277
37278             if (member.id === entity.id && member.role && member.role !== 'outer') {
37279               // Not outer member
37280               return false;
37281             }
37282
37283             if (member.id !== entity.id && (!member.role || member.role === 'outer')) {
37284               // Not a simple multipolygon
37285               return false;
37286             }
37287           }
37288
37289           return parent;
37290         }
37291         function osmOldMultipolygonOuterMember(entity, graph) {
37292           if (entity.type !== 'way') return false;
37293           var parents = graph.parentRelations(entity);
37294           if (parents.length !== 1) return false;
37295           var parent = parents[0];
37296
37297           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
37298             return false;
37299           }
37300
37301           var members = parent.members,
37302               member,
37303               outerMember;
37304
37305           for (var i = 0; i < members.length; i++) {
37306             member = members[i];
37307
37308             if (!member.role || member.role === 'outer') {
37309               if (outerMember) return false; // Not a simple multipolygon
37310
37311               outerMember = member;
37312             }
37313           }
37314
37315           if (!outerMember) return false;
37316           var outerEntity = graph.hasEntity(outerMember.id);
37317
37318           if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) {
37319             return false;
37320           }
37321
37322           return outerEntity;
37323         } // Join `toJoin` array into sequences of connecting ways.
37324         // Segments which share identical start/end nodes will, as much as possible,
37325         // be connected with each other.
37326         //
37327         // The return value is a nested array. Each constituent array contains elements
37328         // of `toJoin` which have been determined to connect.
37329         //
37330         // Each consitituent array also has a `nodes` property whose value is an
37331         // ordered array of member nodes, with appropriate order reversal and
37332         // start/end coordinate de-duplication.
37333         //
37334         // Members of `toJoin` must have, at minimum, `type` and `id` properties.
37335         // Thus either an array of `osmWay`s or a relation member array may be used.
37336         //
37337         // If an member is an `osmWay`, its tags and childnodes may be reversed via
37338         // `actionReverse` in the output.
37339         //
37340         // The returned sequences array also has an `actions` array property, containing
37341         // any reversal actions that should be applied to the graph, should the calling
37342         // code attempt to actually join the given ways.
37343         //
37344         // Incomplete members (those for which `graph.hasEntity(element.id)` returns
37345         // false) and non-way members are ignored.
37346         //
37347
37348         function osmJoinWays(toJoin, graph) {
37349           function resolve(member) {
37350             return graph.childNodes(graph.entity(member.id));
37351           }
37352
37353           function reverse(item) {
37354             var action = actionReverse(item.id, {
37355               reverseOneway: true
37356             });
37357             sequences.actions.push(action);
37358             return item instanceof osmWay ? action(graph).entity(item.id) : item;
37359           } // make a copy containing only the items to join
37360
37361
37362           toJoin = toJoin.filter(function (member) {
37363             return member.type === 'way' && graph.hasEntity(member.id);
37364           }); // Are the things we are joining relation members or `osmWays`?
37365           // If `osmWays`, skip the "prefer a forward path" code below (see #4872)
37366
37367           var i;
37368           var joinAsMembers = true;
37369
37370           for (i = 0; i < toJoin.length; i++) {
37371             if (toJoin[i] instanceof osmWay) {
37372               joinAsMembers = false;
37373               break;
37374             }
37375           }
37376
37377           var sequences = [];
37378           sequences.actions = [];
37379
37380           while (toJoin.length) {
37381             // start a new sequence
37382             var item = toJoin.shift();
37383             var currWays = [item];
37384             var currNodes = resolve(item).slice(); // add to it
37385
37386             while (toJoin.length) {
37387               var start = currNodes[0];
37388               var end = currNodes[currNodes.length - 1];
37389               var fn = null;
37390               var nodes = null; // Find the next way/member to join.
37391
37392               for (i = 0; i < toJoin.length; i++) {
37393                 item = toJoin[i];
37394                 nodes = resolve(item); // (for member ordering only, not way ordering - see #4872)
37395                 // Strongly prefer to generate a forward path that preserves the order
37396                 // of the members array. For multipolygons and most relations, member
37397                 // order does not matter - but for routes, it does. (see #4589)
37398                 // If we started this sequence backwards (i.e. next member way attaches to
37399                 // the start node and not the end node), reverse the initial way before continuing.
37400
37401                 if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start || nodes[0] === start)) {
37402                   currWays[0] = reverse(currWays[0]);
37403                   currNodes.reverse();
37404                   start = currNodes[0];
37405                   end = currNodes[currNodes.length - 1];
37406                 }
37407
37408                 if (nodes[0] === end) {
37409                   fn = currNodes.push; // join to end
37410
37411                   nodes = nodes.slice(1);
37412                   break;
37413                 } else if (nodes[nodes.length - 1] === end) {
37414                   fn = currNodes.push; // join to end
37415
37416                   nodes = nodes.slice(0, -1).reverse();
37417                   item = reverse(item);
37418                   break;
37419                 } else if (nodes[nodes.length - 1] === start) {
37420                   fn = currNodes.unshift; // join to beginning
37421
37422                   nodes = nodes.slice(0, -1);
37423                   break;
37424                 } else if (nodes[0] === start) {
37425                   fn = currNodes.unshift; // join to beginning
37426
37427                   nodes = nodes.slice(1).reverse();
37428                   item = reverse(item);
37429                   break;
37430                 } else {
37431                   fn = nodes = null;
37432                 }
37433               }
37434
37435               if (!nodes) {
37436                 // couldn't find a joinable way/member
37437                 break;
37438               }
37439
37440               fn.apply(currWays, [item]);
37441               fn.apply(currNodes, nodes);
37442               toJoin.splice(i, 1);
37443             }
37444
37445             currWays.nodes = currNodes;
37446             sequences.push(currWays);
37447           }
37448
37449           return sequences;
37450         }
37451
37452         function actionAddMember(relationId, member, memberIndex, insertPair) {
37453           return function action(graph) {
37454             var relation = graph.entity(relationId); // There are some special rules for Public Transport v2 routes.
37455
37456             var isPTv2 = /stop|platform/.test(member.role);
37457
37458             if ((isNaN(memberIndex) || insertPair) && member.type === 'way' && !isPTv2) {
37459               // Try to perform sensible inserts based on how the ways join together
37460               graph = addWayMember(relation, graph);
37461             } else {
37462               // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
37463               // Stops and Platforms for PTv2 should be ordered first.
37464               // hack: We do not currently have the ability to place them in the exactly correct order.
37465               if (isPTv2 && isNaN(memberIndex)) {
37466                 memberIndex = 0;
37467               }
37468
37469               graph = graph.replace(relation.addMember(member, memberIndex));
37470             }
37471
37472             return graph;
37473           }; // Add a way member into the relation "wherever it makes sense".
37474           // In this situation we were not supplied a memberIndex.
37475
37476           function addWayMember(relation, graph) {
37477             var groups, tempWay, item, i, j, k; // remove PTv2 stops and platforms before doing anything.
37478
37479             var PTv2members = [];
37480             var members = [];
37481
37482             for (i = 0; i < relation.members.length; i++) {
37483               var m = relation.members[i];
37484
37485               if (/stop|platform/.test(m.role)) {
37486                 PTv2members.push(m);
37487               } else {
37488                 members.push(m);
37489               }
37490             }
37491
37492             relation = relation.update({
37493               members: members
37494             });
37495
37496             if (insertPair) {
37497               // We're adding a member that must stay paired with an existing member.
37498               // (This feature is used by `actionSplit`)
37499               //
37500               // This is tricky because the members may exist multiple times in the
37501               // member list, and with different A-B/B-A ordering and different roles.
37502               // (e.g. a bus route that loops out and back - #4589).
37503               //
37504               // Replace the existing member with a temporary way,
37505               // so that `osmJoinWays` can treat the pair like a single way.
37506               tempWay = osmWay({
37507                 id: 'wTemp',
37508                 nodes: insertPair.nodes
37509               });
37510               graph = graph.replace(tempWay);
37511               var tempMember = {
37512                 id: tempWay.id,
37513                 type: 'way',
37514                 role: member.role
37515               };
37516               var tempRelation = relation.replaceMember({
37517                 id: insertPair.originalID
37518               }, tempMember, true);
37519               groups = utilArrayGroupBy(tempRelation.members, 'type');
37520               groups.way = groups.way || [];
37521             } else {
37522               // Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
37523               groups = utilArrayGroupBy(relation.members, 'type');
37524               groups.way = groups.way || [];
37525               groups.way.push(member);
37526             }
37527
37528             members = withIndex(groups.way);
37529             var joined = osmJoinWays(members, graph); // `joined` might not contain all of the way members,
37530             // But will contain only the completed (downloaded) members
37531
37532             for (i = 0; i < joined.length; i++) {
37533               var segment = joined[i];
37534               var nodes = segment.nodes.slice();
37535               var startIndex = segment[0].index; // j = array index in `members` where this segment starts
37536
37537               for (j = 0; j < members.length; j++) {
37538                 if (members[j].index === startIndex) {
37539                   break;
37540                 }
37541               } // k = each member in segment
37542
37543
37544               for (k = 0; k < segment.length; k++) {
37545                 item = segment[k];
37546                 var way = graph.entity(item.id); // If this is a paired item, generate members in correct order and role
37547
37548                 if (tempWay && item.id === tempWay.id) {
37549                   if (nodes[0].id === insertPair.nodes[0]) {
37550                     item.pair = [{
37551                       id: insertPair.originalID,
37552                       type: 'way',
37553                       role: item.role
37554                     }, {
37555                       id: insertPair.insertedID,
37556                       type: 'way',
37557                       role: item.role
37558                     }];
37559                   } else {
37560                     item.pair = [{
37561                       id: insertPair.insertedID,
37562                       type: 'way',
37563                       role: item.role
37564                     }, {
37565                       id: insertPair.originalID,
37566                       type: 'way',
37567                       role: item.role
37568                     }];
37569                   }
37570                 } // reorder `members` if necessary
37571
37572
37573                 if (k > 0) {
37574                   if (j + k >= members.length || item.index !== members[j + k].index) {
37575                     moveMember(members, item.index, j + k);
37576                   }
37577                 }
37578
37579                 nodes.splice(0, way.nodes.length - 1);
37580               }
37581             }
37582
37583             if (tempWay) {
37584               graph = graph.remove(tempWay);
37585             } // Final pass: skip dead items, split pairs, remove index properties
37586
37587
37588             var wayMembers = [];
37589
37590             for (i = 0; i < members.length; i++) {
37591               item = members[i];
37592               if (item.index === -1) continue;
37593
37594               if (item.pair) {
37595                 wayMembers.push(item.pair[0]);
37596                 wayMembers.push(item.pair[1]);
37597               } else {
37598                 wayMembers.push(utilObjectOmit(item, ['index']));
37599               }
37600             } // Put stops and platforms first, then nodes, ways, relations
37601             // This is recommended for Public Transport v2 routes:
37602             // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
37603
37604
37605             var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
37606             return graph.replace(relation.update({
37607               members: newMembers
37608             })); // `moveMember()` changes the `members` array in place by splicing
37609             // the item with `.index = findIndex` to where it belongs,
37610             // and marking the old position as "dead" with `.index = -1`
37611             //
37612             // j=5, k=0                jk
37613             // segment                 5 4 7 6
37614             // members       0 1 2 3 4 5 6 7 8 9        keep 5 in j+k
37615             //
37616             // j=5, k=1                j k
37617             // segment                 5 4 7 6
37618             // members       0 1 2 3 4 5 6 7 8 9        move 4 to j+k
37619             // members       0 1 2 3 x 5 4 6 7 8 9      moved
37620             //
37621             // j=5, k=2                j   k
37622             // segment                 5 4 7 6
37623             // members       0 1 2 3 x 5 4 6 7 8 9      move 7 to j+k
37624             // members       0 1 2 3 x 5 4 7 6 x 8 9    moved
37625             //
37626             // j=5, k=3                j     k
37627             // segment                 5 4 7 6
37628             // members       0 1 2 3 x 5 4 7 6 x 8 9    keep 6 in j+k
37629             //
37630
37631             function moveMember(arr, findIndex, toIndex) {
37632               var i;
37633
37634               for (i = 0; i < arr.length; i++) {
37635                 if (arr[i].index === findIndex) {
37636                   break;
37637                 }
37638               }
37639
37640               var item = Object.assign({}, arr[i]); // shallow copy
37641
37642               arr[i].index = -1; // mark as dead
37643
37644               item.index = toIndex;
37645               arr.splice(toIndex, 0, item);
37646             } // This is the same as `Relation.indexedMembers`,
37647             // Except we don't want to index all the members, only the ways
37648
37649
37650             function withIndex(arr) {
37651               var result = new Array(arr.length);
37652
37653               for (var i = 0; i < arr.length; i++) {
37654                 result[i] = Object.assign({}, arr[i]); // shallow copy
37655
37656                 result[i].index = i;
37657               }
37658
37659               return result;
37660             }
37661           }
37662         }
37663
37664         function actionAddMidpoint(midpoint, node) {
37665           return function (graph) {
37666             graph = graph.replace(node.move(midpoint.loc));
37667             var parents = utilArrayIntersection(graph.parentWays(graph.entity(midpoint.edge[0])), graph.parentWays(graph.entity(midpoint.edge[1])));
37668             parents.forEach(function (way) {
37669               for (var i = 0; i < way.nodes.length - 1; i++) {
37670                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
37671                   graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1)); // Add only one midpoint on doubled-back segments,
37672                   // turning them into self-intersections.
37673
37674                   return;
37675                 }
37676               }
37677             });
37678             return graph;
37679           };
37680         }
37681
37682         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
37683         function actionAddVertex(wayId, nodeId, index) {
37684           return function (graph) {
37685             return graph.replace(graph.entity(wayId).addNode(nodeId, index));
37686           };
37687         }
37688
37689         function actionChangeMember(relationId, member, memberIndex) {
37690           return function (graph) {
37691             return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
37692           };
37693         }
37694
37695         function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
37696           return function action(graph) {
37697             var entity = graph.entity(entityID);
37698             var geometry = entity.geometry(graph);
37699             var tags = entity.tags; // preserve tags that the new preset might care about, if any
37700
37701             if (oldPreset) tags = oldPreset.unsetTags(tags, geometry, newPreset && newPreset.addTags ? Object.keys(newPreset.addTags) : null);
37702             if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
37703             return graph.replace(entity.update({
37704               tags: tags
37705             }));
37706           };
37707         }
37708
37709         function actionChangeTags(entityId, tags) {
37710           return function (graph) {
37711             var entity = graph.entity(entityId);
37712             return graph.replace(entity.update({
37713               tags: tags
37714             }));
37715           };
37716         }
37717
37718         function osmNode() {
37719           if (!(this instanceof osmNode)) {
37720             return new osmNode().initialize(arguments);
37721           } else if (arguments.length) {
37722             this.initialize(arguments);
37723           }
37724         }
37725         osmEntity.node = osmNode;
37726         osmNode.prototype = Object.create(osmEntity.prototype);
37727         Object.assign(osmNode.prototype, {
37728           type: 'node',
37729           loc: [9999, 9999],
37730           extent: function extent() {
37731             return new geoExtent(this.loc);
37732           },
37733           geometry: function geometry(graph) {
37734             return graph["transient"](this, 'geometry', function () {
37735               return graph.isPoi(this) ? 'point' : 'vertex';
37736             });
37737           },
37738           move: function move(loc) {
37739             return this.update({
37740               loc: loc
37741             });
37742           },
37743           isDegenerate: function isDegenerate() {
37744             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);
37745           },
37746           // Inspect tags and geometry to determine which direction(s) this node/vertex points
37747           directions: function directions(resolver, projection) {
37748             var val;
37749             var i; // which tag to use?
37750
37751             if (this.isHighwayIntersection(resolver) && (this.tags.stop || '').toLowerCase() === 'all') {
37752               // all-way stop tag on a highway intersection
37753               val = 'all';
37754             } else {
37755               // generic direction tag
37756               val = (this.tags.direction || '').toLowerCase(); // better suffix-style direction tag
37757
37758               var re = /:direction$/i;
37759               var keys = Object.keys(this.tags);
37760
37761               for (i = 0; i < keys.length; i++) {
37762                 if (re.test(keys[i])) {
37763                   val = this.tags[keys[i]].toLowerCase();
37764                   break;
37765                 }
37766               }
37767             }
37768
37769             if (val === '') return [];
37770             var cardinal = {
37771               north: 0,
37772               n: 0,
37773               northnortheast: 22,
37774               nne: 22,
37775               northeast: 45,
37776               ne: 45,
37777               eastnortheast: 67,
37778               ene: 67,
37779               east: 90,
37780               e: 90,
37781               eastsoutheast: 112,
37782               ese: 112,
37783               southeast: 135,
37784               se: 135,
37785               southsoutheast: 157,
37786               sse: 157,
37787               south: 180,
37788               s: 180,
37789               southsouthwest: 202,
37790               ssw: 202,
37791               southwest: 225,
37792               sw: 225,
37793               westsouthwest: 247,
37794               wsw: 247,
37795               west: 270,
37796               w: 270,
37797               westnorthwest: 292,
37798               wnw: 292,
37799               northwest: 315,
37800               nw: 315,
37801               northnorthwest: 337,
37802               nnw: 337
37803             };
37804             var values = val.split(';');
37805             var results = [];
37806             values.forEach(function (v) {
37807               // swap cardinal for numeric directions
37808               if (cardinal[v] !== undefined) {
37809                 v = cardinal[v];
37810               } // numeric direction - just add to results
37811
37812
37813               if (v !== '' && !isNaN(+v)) {
37814                 results.push(+v);
37815                 return;
37816               } // string direction - inspect parent ways
37817
37818
37819               var lookBackward = this.tags['traffic_sign:backward'] || v === 'backward' || v === 'both' || v === 'all';
37820               var lookForward = this.tags['traffic_sign:forward'] || v === 'forward' || v === 'both' || v === 'all';
37821               if (!lookForward && !lookBackward) return;
37822               var nodeIds = {};
37823               resolver.parentWays(this).forEach(function (parent) {
37824                 var nodes = parent.nodes;
37825
37826                 for (i = 0; i < nodes.length; i++) {
37827                   if (nodes[i] === this.id) {
37828                     // match current entity
37829                     if (lookForward && i > 0) {
37830                       nodeIds[nodes[i - 1]] = true; // look back to prev node
37831                     }
37832
37833                     if (lookBackward && i < nodes.length - 1) {
37834                       nodeIds[nodes[i + 1]] = true; // look ahead to next node
37835                     }
37836                   }
37837                 }
37838               }, this);
37839               Object.keys(nodeIds).forEach(function (nodeId) {
37840                 // +90 because geoAngle returns angle from X axis, not Y (north)
37841                 results.push(geoAngle(this, resolver.entity(nodeId), projection) * (180 / Math.PI) + 90);
37842               }, this);
37843             }, this);
37844             return utilArrayUniq(results);
37845           },
37846           isCrossing: function isCrossing() {
37847             return this.tags.highway === 'crossing' || this.tags.railway && this.tags.railway.indexOf('crossing') !== -1;
37848           },
37849           isEndpoint: function isEndpoint(resolver) {
37850             return resolver["transient"](this, 'isEndpoint', function () {
37851               var id = this.id;
37852               return resolver.parentWays(this).filter(function (parent) {
37853                 return !parent.isClosed() && !!parent.affix(id);
37854               }).length > 0;
37855             });
37856           },
37857           isConnected: function isConnected(resolver) {
37858             return resolver["transient"](this, 'isConnected', function () {
37859               var parents = resolver.parentWays(this);
37860
37861               if (parents.length > 1) {
37862                 // vertex is connected to multiple parent ways
37863                 for (var i in parents) {
37864                   if (parents[i].geometry(resolver) === 'line' && parents[i].hasInterestingTags()) return true;
37865                 }
37866               } else if (parents.length === 1) {
37867                 var way = parents[0];
37868                 var nodes = way.nodes.slice();
37869
37870                 if (way.isClosed()) {
37871                   nodes.pop();
37872                 } // ignore connecting node if closed
37873                 // return true if vertex appears multiple times (way is self intersecting)
37874
37875
37876                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
37877               }
37878
37879               return false;
37880             });
37881           },
37882           parentIntersectionWays: function parentIntersectionWays(resolver) {
37883             return resolver["transient"](this, 'parentIntersectionWays', function () {
37884               return resolver.parentWays(this).filter(function (parent) {
37885                 return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === 'line';
37886               });
37887             });
37888           },
37889           isIntersection: function isIntersection(resolver) {
37890             return this.parentIntersectionWays(resolver).length > 1;
37891           },
37892           isHighwayIntersection: function isHighwayIntersection(resolver) {
37893             return resolver["transient"](this, 'isHighwayIntersection', function () {
37894               return resolver.parentWays(this).filter(function (parent) {
37895                 return parent.tags.highway && parent.geometry(resolver) === 'line';
37896               }).length > 1;
37897             });
37898           },
37899           isOnAddressLine: function isOnAddressLine(resolver) {
37900             return resolver["transient"](this, 'isOnAddressLine', function () {
37901               return resolver.parentWays(this).filter(function (parent) {
37902                 return parent.tags.hasOwnProperty('addr:interpolation') && parent.geometry(resolver) === 'line';
37903               }).length > 0;
37904             });
37905           },
37906           asJXON: function asJXON(changeset_id) {
37907             var r = {
37908               node: {
37909                 '@id': this.osmId(),
37910                 '@lon': this.loc[0],
37911                 '@lat': this.loc[1],
37912                 '@version': this.version || 0,
37913                 tag: Object.keys(this.tags).map(function (k) {
37914                   return {
37915                     keyAttributes: {
37916                       k: k,
37917                       v: this.tags[k]
37918                     }
37919                   };
37920                 }, this)
37921               }
37922             };
37923             if (changeset_id) r.node['@changeset'] = changeset_id;
37924             return r;
37925           },
37926           asGeoJSON: function asGeoJSON() {
37927             return {
37928               type: 'Point',
37929               coordinates: this.loc
37930             };
37931           }
37932         });
37933
37934         function actionCircularize(wayId, projection, maxAngle) {
37935           maxAngle = (maxAngle || 20) * Math.PI / 180;
37936
37937           var action = function action(graph, t) {
37938             if (t === null || !isFinite(t)) t = 1;
37939             t = Math.min(Math.max(+t, 0), 1);
37940             var way = graph.entity(wayId);
37941             var origNodes = {};
37942             graph.childNodes(way).forEach(function (node) {
37943               if (!origNodes[node.id]) origNodes[node.id] = node;
37944             });
37945
37946             if (!way.isConvex(graph)) {
37947               graph = action.makeConvex(graph);
37948             }
37949
37950             var nodes = utilArrayUniq(graph.childNodes(way));
37951             var keyNodes = nodes.filter(function (n) {
37952               return graph.parentWays(n).length !== 1;
37953             });
37954             var points = nodes.map(function (n) {
37955               return projection(n.loc);
37956             });
37957             var keyPoints = keyNodes.map(function (n) {
37958               return projection(n.loc);
37959             });
37960             var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points);
37961             var radius = d3_median(points, function (p) {
37962               return geoVecLength(centroid, p);
37963             });
37964             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
37965             var ids, i, j, k; // we need at least two key nodes for the algorithm to work
37966
37967             if (!keyNodes.length) {
37968               keyNodes = [nodes[0]];
37969               keyPoints = [points[0]];
37970             }
37971
37972             if (keyNodes.length === 1) {
37973               var index = nodes.indexOf(keyNodes[0]);
37974               var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
37975               keyNodes.push(nodes[oppositeIndex]);
37976               keyPoints.push(points[oppositeIndex]);
37977             } // key points and nodes are those connected to the ways,
37978             // they are projected onto the circle, in between nodes are moved
37979             // to constant intervals between key nodes, extra in between nodes are
37980             // added if necessary.
37981
37982
37983             for (i = 0; i < keyPoints.length; i++) {
37984               var nextKeyNodeIndex = (i + 1) % keyNodes.length;
37985               var startNode = keyNodes[i];
37986               var endNode = keyNodes[nextKeyNodeIndex];
37987               var startNodeIndex = nodes.indexOf(startNode);
37988               var endNodeIndex = nodes.indexOf(endNode);
37989               var numberNewPoints = -1;
37990               var indexRange = endNodeIndex - startNodeIndex;
37991               var nearNodes = {};
37992               var inBetweenNodes = [];
37993               var startAngle, endAngle, totalAngle, eachAngle;
37994               var angle, loc, node, origNode;
37995
37996               if (indexRange < 0) {
37997                 indexRange += nodes.length;
37998               } // position this key node
37999
38000
38001               var distance = geoVecLength(centroid, keyPoints[i]) || 1e-4;
38002               keyPoints[i] = [centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
38003               loc = projection.invert(keyPoints[i]);
38004               node = keyNodes[i];
38005               origNode = origNodes[node.id];
38006               node = node.move(geoVecInterp(origNode.loc, loc, t));
38007               graph = graph.replace(node); // figure out the between delta angle we want to match to
38008
38009               startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
38010               endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
38011               totalAngle = endAngle - startAngle; // detects looping around -pi/pi
38012
38013               if (totalAngle * sign > 0) {
38014                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
38015               }
38016
38017               do {
38018                 numberNewPoints++;
38019                 eachAngle = totalAngle / (indexRange + numberNewPoints);
38020               } while (Math.abs(eachAngle) > maxAngle); // move existing nodes
38021
38022
38023               for (j = 1; j < indexRange; j++) {
38024                 angle = startAngle + j * eachAngle;
38025                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]);
38026                 node = nodes[(j + startNodeIndex) % nodes.length];
38027                 origNode = origNodes[node.id];
38028                 nearNodes[node.id] = angle;
38029                 node = node.move(geoVecInterp(origNode.loc, loc, t));
38030                 graph = graph.replace(node);
38031               } // add new in between nodes if necessary
38032
38033
38034               for (j = 0; j < numberNewPoints; j++) {
38035                 angle = startAngle + (indexRange + j) * eachAngle;
38036                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]); // choose a nearnode to use as the original
38037
38038                 var min = Infinity;
38039
38040                 for (var nodeId in nearNodes) {
38041                   var nearAngle = nearNodes[nodeId];
38042                   var dist = Math.abs(nearAngle - angle);
38043
38044                   if (dist < min) {
38045                     min = dist;
38046                     origNode = origNodes[nodeId];
38047                   }
38048                 }
38049
38050                 node = osmNode({
38051                   loc: geoVecInterp(origNode.loc, loc, t)
38052                 });
38053                 graph = graph.replace(node);
38054                 nodes.splice(endNodeIndex + j, 0, node);
38055                 inBetweenNodes.push(node.id);
38056               } // Check for other ways that share these keyNodes..
38057               // If keyNodes are adjacent in both ways,
38058               // we can add inBetweenNodes to that shared way too..
38059
38060
38061               if (indexRange === 1 && inBetweenNodes.length) {
38062                 var startIndex1 = way.nodes.lastIndexOf(startNode.id);
38063                 var endIndex1 = way.nodes.lastIndexOf(endNode.id);
38064                 var wayDirection1 = endIndex1 - startIndex1;
38065
38066                 if (wayDirection1 < -1) {
38067                   wayDirection1 = 1;
38068                 }
38069
38070                 var parentWays = graph.parentWays(keyNodes[i]);
38071
38072                 for (j = 0; j < parentWays.length; j++) {
38073                   var sharedWay = parentWays[j];
38074                   if (sharedWay === way) continue;
38075
38076                   if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
38077                     var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id);
38078                     var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id);
38079                     var wayDirection2 = endIndex2 - startIndex2;
38080                     var insertAt = endIndex2;
38081
38082                     if (wayDirection2 < -1) {
38083                       wayDirection2 = 1;
38084                     }
38085
38086                     if (wayDirection1 !== wayDirection2) {
38087                       inBetweenNodes.reverse();
38088                       insertAt = startIndex2;
38089                     }
38090
38091                     for (k = 0; k < inBetweenNodes.length; k++) {
38092                       sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
38093                     }
38094
38095                     graph = graph.replace(sharedWay);
38096                   }
38097                 }
38098               }
38099             } // update the way to have all the new nodes
38100
38101
38102             ids = nodes.map(function (n) {
38103               return n.id;
38104             });
38105             ids.push(ids[0]);
38106             way = way.update({
38107               nodes: ids
38108             });
38109             graph = graph.replace(way);
38110             return graph;
38111           };
38112
38113           action.makeConvex = function (graph) {
38114             var way = graph.entity(wayId);
38115             var nodes = utilArrayUniq(graph.childNodes(way));
38116             var points = nodes.map(function (n) {
38117               return projection(n.loc);
38118             });
38119             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
38120             var hull = d3_polygonHull(points);
38121             var i, j; // D3 convex hulls go counterclockwise..
38122
38123             if (sign === -1) {
38124               nodes.reverse();
38125               points.reverse();
38126             }
38127
38128             for (i = 0; i < hull.length - 1; i++) {
38129               var startIndex = points.indexOf(hull[i]);
38130               var endIndex = points.indexOf(hull[i + 1]);
38131               var indexRange = endIndex - startIndex;
38132
38133               if (indexRange < 0) {
38134                 indexRange += nodes.length;
38135               } // move interior nodes to the surface of the convex hull..
38136
38137
38138               for (j = 1; j < indexRange; j++) {
38139                 var point = geoVecInterp(hull[i], hull[i + 1], j / indexRange);
38140                 var node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
38141                 graph = graph.replace(node);
38142               }
38143             }
38144
38145             return graph;
38146           };
38147
38148           action.disabled = function (graph) {
38149             if (!graph.entity(wayId).isClosed()) {
38150               return 'not_closed';
38151             } //disable when already circular
38152
38153
38154             var way = graph.entity(wayId);
38155             var nodes = utilArrayUniq(graph.childNodes(way));
38156             var points = nodes.map(function (n) {
38157               return projection(n.loc);
38158             });
38159             var hull = d3_polygonHull(points);
38160             var epsilonAngle = Math.PI / 180;
38161
38162             if (hull.length !== points.length || hull.length < 3) {
38163               return false;
38164             }
38165
38166             var centroid = d3_polygonCentroid(points);
38167             var radius = geoVecLengthSquare(centroid, points[0]);
38168             var i, actualPoint; // compare distances between centroid and points
38169
38170             for (i = 0; i < hull.length; i++) {
38171               actualPoint = hull[i];
38172               var actualDist = geoVecLengthSquare(actualPoint, centroid);
38173               var diff = Math.abs(actualDist - radius); //compare distances with epsilon-error (5%)
38174
38175               if (diff > 0.05 * radius) {
38176                 return false;
38177               }
38178             } //check if central angles are smaller than maxAngle
38179
38180
38181             for (i = 0; i < hull.length; i++) {
38182               actualPoint = hull[i];
38183               var nextPoint = hull[(i + 1) % hull.length];
38184               var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
38185               var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
38186               var angle = endAngle - startAngle;
38187
38188               if (angle < 0) {
38189                 angle = -angle;
38190               }
38191
38192               if (angle > Math.PI) {
38193                 angle = 2 * Math.PI - angle;
38194               }
38195
38196               if (angle > maxAngle + epsilonAngle) {
38197                 return false;
38198               }
38199             }
38200
38201             return 'already_circular';
38202           };
38203
38204           action.transitionable = true;
38205           return action;
38206         }
38207
38208         function actionDeleteWay(wayID) {
38209           function canDeleteNode(node, graph) {
38210             // don't delete nodes still attached to ways or relations
38211             if (graph.parentWays(node).length || graph.parentRelations(node).length) return false;
38212             var geometries = osmNodeGeometriesForTags(node.tags); // don't delete if this node can be a standalone point
38213
38214             if (geometries.point) return false; // delete if this node only be a vertex
38215
38216             if (geometries.vertex) return true; // iD doesn't know if this should be a point or vertex,
38217             // so only delete if there are no interesting tags
38218
38219             return !node.hasInterestingTags();
38220           }
38221
38222           var action = function action(graph) {
38223             var way = graph.entity(wayID);
38224             graph.parentRelations(way).forEach(function (parent) {
38225               parent = parent.removeMembersWithID(wayID);
38226               graph = graph.replace(parent);
38227
38228               if (parent.isDegenerate()) {
38229                 graph = actionDeleteRelation(parent.id)(graph);
38230               }
38231             });
38232             new Set(way.nodes).forEach(function (nodeID) {
38233               graph = graph.replace(way.removeNode(nodeID));
38234               var node = graph.entity(nodeID);
38235
38236               if (canDeleteNode(node, graph)) {
38237                 graph = graph.remove(node);
38238               }
38239             });
38240             return graph.remove(way);
38241           };
38242
38243           return action;
38244         }
38245
38246         function actionDeleteMultiple(ids) {
38247           var actions = {
38248             way: actionDeleteWay,
38249             node: actionDeleteNode,
38250             relation: actionDeleteRelation
38251           };
38252
38253           var action = function action(graph) {
38254             ids.forEach(function (id) {
38255               if (graph.hasEntity(id)) {
38256                 // It may have been deleted already.
38257                 graph = actions[graph.entity(id).type](id)(graph);
38258               }
38259             });
38260             return graph;
38261           };
38262
38263           return action;
38264         }
38265
38266         function actionDeleteRelation(relationID, allowUntaggedMembers) {
38267           function canDeleteEntity(entity, graph) {
38268             return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && !entity.hasInterestingTags() && !allowUntaggedMembers;
38269           }
38270
38271           var action = function action(graph) {
38272             var relation = graph.entity(relationID);
38273             graph.parentRelations(relation).forEach(function (parent) {
38274               parent = parent.removeMembersWithID(relationID);
38275               graph = graph.replace(parent);
38276
38277               if (parent.isDegenerate()) {
38278                 graph = actionDeleteRelation(parent.id)(graph);
38279               }
38280             });
38281             var memberIDs = utilArrayUniq(relation.members.map(function (m) {
38282               return m.id;
38283             }));
38284             memberIDs.forEach(function (memberID) {
38285               graph = graph.replace(relation.removeMembersWithID(memberID));
38286               var entity = graph.entity(memberID);
38287
38288               if (canDeleteEntity(entity, graph)) {
38289                 graph = actionDeleteMultiple([memberID])(graph);
38290               }
38291             });
38292             return graph.remove(relation);
38293           };
38294
38295           return action;
38296         }
38297
38298         function actionDeleteNode(nodeId) {
38299           var action = function action(graph) {
38300             var node = graph.entity(nodeId);
38301             graph.parentWays(node).forEach(function (parent) {
38302               parent = parent.removeNode(nodeId);
38303               graph = graph.replace(parent);
38304
38305               if (parent.isDegenerate()) {
38306                 graph = actionDeleteWay(parent.id)(graph);
38307               }
38308             });
38309             graph.parentRelations(node).forEach(function (parent) {
38310               parent = parent.removeMembersWithID(nodeId);
38311               graph = graph.replace(parent);
38312
38313               if (parent.isDegenerate()) {
38314                 graph = actionDeleteRelation(parent.id)(graph);
38315               }
38316             });
38317             return graph.remove(node);
38318           };
38319
38320           return action;
38321         }
38322
38323         //
38324         // First choose a node to be the survivor, with preference given
38325         // to an existing (not new) node.
38326         //
38327         // Tags and relation memberships of of non-surviving nodes are merged
38328         // to the survivor.
38329         //
38330         // This is the inverse of `iD.actionDisconnect`.
38331         //
38332         // Reference:
38333         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
38334         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
38335         //
38336
38337         function actionConnect(nodeIDs) {
38338           var action = function action(graph) {
38339             var survivor;
38340             var node;
38341             var parents;
38342             var i, j; // Choose a survivor node, prefer an existing (not new) node - #4974
38343
38344             for (i = 0; i < nodeIDs.length; i++) {
38345               survivor = graph.entity(nodeIDs[i]);
38346               if (survivor.version) break; // found one
38347             } // Replace all non-surviving nodes with the survivor and merge tags.
38348
38349
38350             for (i = 0; i < nodeIDs.length; i++) {
38351               node = graph.entity(nodeIDs[i]);
38352               if (node.id === survivor.id) continue;
38353               parents = graph.parentWays(node);
38354
38355               for (j = 0; j < parents.length; j++) {
38356                 graph = graph.replace(parents[j].replaceNode(node.id, survivor.id));
38357               }
38358
38359               parents = graph.parentRelations(node);
38360
38361               for (j = 0; j < parents.length; j++) {
38362                 graph = graph.replace(parents[j].replaceMember(node, survivor));
38363               }
38364
38365               survivor = survivor.mergeTags(node.tags);
38366               graph = actionDeleteNode(node.id)(graph);
38367             }
38368
38369             graph = graph.replace(survivor); // find and delete any degenerate ways created by connecting adjacent vertices
38370
38371             parents = graph.parentWays(survivor);
38372
38373             for (i = 0; i < parents.length; i++) {
38374               if (parents[i].isDegenerate()) {
38375                 graph = actionDeleteWay(parents[i].id)(graph);
38376               }
38377             }
38378
38379             return graph;
38380           };
38381
38382           action.disabled = function (graph) {
38383             var seen = {};
38384             var restrictionIDs = [];
38385             var survivor;
38386             var node, way;
38387             var relations, relation, role;
38388             var i, j, k; // Choose a survivor node, prefer an existing (not new) node - #4974
38389
38390             for (i = 0; i < nodeIDs.length; i++) {
38391               survivor = graph.entity(nodeIDs[i]);
38392               if (survivor.version) break; // found one
38393             } // 1. disable if the nodes being connected have conflicting relation roles
38394
38395
38396             for (i = 0; i < nodeIDs.length; i++) {
38397               node = graph.entity(nodeIDs[i]);
38398               relations = graph.parentRelations(node);
38399
38400               for (j = 0; j < relations.length; j++) {
38401                 relation = relations[j];
38402                 role = relation.memberById(node.id).role || ''; // if this node is a via node in a restriction, remember for later
38403
38404                 if (relation.hasFromViaTo()) {
38405                   restrictionIDs.push(relation.id);
38406                 }
38407
38408                 if (seen[relation.id] !== undefined && seen[relation.id] !== role) {
38409                   return 'relation';
38410                 } else {
38411                   seen[relation.id] = role;
38412                 }
38413               }
38414             } // gather restrictions for parent ways
38415
38416
38417             for (i = 0; i < nodeIDs.length; i++) {
38418               node = graph.entity(nodeIDs[i]);
38419               var parents = graph.parentWays(node);
38420
38421               for (j = 0; j < parents.length; j++) {
38422                 var parent = parents[j];
38423                 relations = graph.parentRelations(parent);
38424
38425                 for (k = 0; k < relations.length; k++) {
38426                   relation = relations[k];
38427
38428                   if (relation.hasFromViaTo()) {
38429                     restrictionIDs.push(relation.id);
38430                   }
38431                 }
38432               }
38433             } // test restrictions
38434
38435
38436             restrictionIDs = utilArrayUniq(restrictionIDs);
38437
38438             for (i = 0; i < restrictionIDs.length; i++) {
38439               relation = graph.entity(restrictionIDs[i]);
38440               if (!relation.isComplete(graph)) continue;
38441               var memberWays = relation.members.filter(function (m) {
38442                 return m.type === 'way';
38443               }).map(function (m) {
38444                 return graph.entity(m.id);
38445               });
38446               memberWays = utilArrayUniq(memberWays);
38447               var f = relation.memberByRole('from');
38448               var t = relation.memberByRole('to');
38449               var isUturn = f.id === t.id; // 2a. disable if connection would damage a restriction
38450               // (a key node is a node at the junction of ways)
38451
38452               var nodes = {
38453                 from: [],
38454                 via: [],
38455                 to: [],
38456                 keyfrom: [],
38457                 keyto: []
38458               };
38459
38460               for (j = 0; j < relation.members.length; j++) {
38461                 collectNodes(relation.members[j], nodes);
38462               }
38463
38464               nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
38465               nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
38466               var filter = keyNodeFilter(nodes.keyfrom, nodes.keyto);
38467               nodes.from = nodes.from.filter(filter);
38468               nodes.via = nodes.via.filter(filter);
38469               nodes.to = nodes.to.filter(filter);
38470               var connectFrom = false;
38471               var connectVia = false;
38472               var connectTo = false;
38473               var connectKeyFrom = false;
38474               var connectKeyTo = false;
38475
38476               for (j = 0; j < nodeIDs.length; j++) {
38477                 var n = nodeIDs[j];
38478
38479                 if (nodes.from.indexOf(n) !== -1) {
38480                   connectFrom = true;
38481                 }
38482
38483                 if (nodes.via.indexOf(n) !== -1) {
38484                   connectVia = true;
38485                 }
38486
38487                 if (nodes.to.indexOf(n) !== -1) {
38488                   connectTo = true;
38489                 }
38490
38491                 if (nodes.keyfrom.indexOf(n) !== -1) {
38492                   connectKeyFrom = true;
38493                 }
38494
38495                 if (nodes.keyto.indexOf(n) !== -1) {
38496                   connectKeyTo = true;
38497                 }
38498               }
38499
38500               if (connectFrom && connectTo && !isUturn) {
38501                 return 'restriction';
38502               }
38503
38504               if (connectFrom && connectVia) {
38505                 return 'restriction';
38506               }
38507
38508               if (connectTo && connectVia) {
38509                 return 'restriction';
38510               } // connecting to a key node -
38511               // if both nodes are on a member way (i.e. part of the turn restriction),
38512               // the connecting node must be adjacent to the key node.
38513
38514
38515               if (connectKeyFrom || connectKeyTo) {
38516                 if (nodeIDs.length !== 2) {
38517                   return 'restriction';
38518                 }
38519
38520                 var n0 = null;
38521                 var n1 = null;
38522
38523                 for (j = 0; j < memberWays.length; j++) {
38524                   way = memberWays[j];
38525
38526                   if (way.contains(nodeIDs[0])) {
38527                     n0 = nodeIDs[0];
38528                   }
38529
38530                   if (way.contains(nodeIDs[1])) {
38531                     n1 = nodeIDs[1];
38532                   }
38533                 }
38534
38535                 if (n0 && n1) {
38536                   // both nodes are part of the restriction
38537                   var ok = false;
38538
38539                   for (j = 0; j < memberWays.length; j++) {
38540                     way = memberWays[j];
38541
38542                     if (way.areAdjacent(n0, n1)) {
38543                       ok = true;
38544                       break;
38545                     }
38546                   }
38547
38548                   if (!ok) {
38549                     return 'restriction';
38550                   }
38551                 }
38552               } // 2b. disable if nodes being connected will destroy a member way in a restriction
38553               // (to test, make a copy and try actually connecting the nodes)
38554
38555
38556               for (j = 0; j < memberWays.length; j++) {
38557                 way = memberWays[j].update({}); // make copy
38558
38559                 for (k = 0; k < nodeIDs.length; k++) {
38560                   if (nodeIDs[k] === survivor.id) continue;
38561
38562                   if (way.areAdjacent(nodeIDs[k], survivor.id)) {
38563                     way = way.removeNode(nodeIDs[k]);
38564                   } else {
38565                     way = way.replaceNode(nodeIDs[k], survivor.id);
38566                   }
38567                 }
38568
38569                 if (way.isDegenerate()) {
38570                   return 'restriction';
38571                 }
38572               }
38573             }
38574
38575             return false; // if a key node appears multiple times (indexOf !== lastIndexOf) it's a FROM-VIA or TO-VIA junction
38576
38577             function hasDuplicates(n, i, arr) {
38578               return arr.indexOf(n) !== arr.lastIndexOf(n);
38579             }
38580
38581             function keyNodeFilter(froms, tos) {
38582               return function (n) {
38583                 return froms.indexOf(n) === -1 && tos.indexOf(n) === -1;
38584               };
38585             }
38586
38587             function collectNodes(member, collection) {
38588               var entity = graph.hasEntity(member.id);
38589               if (!entity) return;
38590               var role = member.role || '';
38591
38592               if (!collection[role]) {
38593                 collection[role] = [];
38594               }
38595
38596               if (member.type === 'node') {
38597                 collection[role].push(member.id);
38598
38599                 if (role === 'via') {
38600                   collection.keyfrom.push(member.id);
38601                   collection.keyto.push(member.id);
38602                 }
38603               } else if (member.type === 'way') {
38604                 collection[role].push.apply(collection[role], entity.nodes);
38605
38606                 if (role === 'from' || role === 'via') {
38607                   collection.keyfrom.push(entity.first());
38608                   collection.keyfrom.push(entity.last());
38609                 }
38610
38611                 if (role === 'to' || role === 'via') {
38612                   collection.keyto.push(entity.first());
38613                   collection.keyto.push(entity.last());
38614                 }
38615               }
38616             }
38617           };
38618
38619           return action;
38620         }
38621
38622         function actionCopyEntities(ids, fromGraph) {
38623           var _copies = {};
38624
38625           var action = function action(graph) {
38626             ids.forEach(function (id) {
38627               fromGraph.entity(id).copy(fromGraph, _copies);
38628             });
38629
38630             for (var id in _copies) {
38631               graph = graph.replace(_copies[id]);
38632             }
38633
38634             return graph;
38635           };
38636
38637           action.copies = function () {
38638             return _copies;
38639           };
38640
38641           return action;
38642         }
38643
38644         function actionDeleteMember(relationId, memberIndex) {
38645           return function (graph) {
38646             var relation = graph.entity(relationId).removeMember(memberIndex);
38647             graph = graph.replace(relation);
38648
38649             if (relation.isDegenerate()) {
38650               graph = actionDeleteRelation(relation.id)(graph);
38651             }
38652
38653             return graph;
38654           };
38655         }
38656
38657         function actionDiscardTags(difference, discardTags) {
38658           discardTags = discardTags || {};
38659           return function (graph) {
38660             difference.modified().forEach(checkTags);
38661             difference.created().forEach(checkTags);
38662             return graph;
38663
38664             function checkTags(entity) {
38665               var keys = Object.keys(entity.tags);
38666               var didDiscard = false;
38667               var tags = {};
38668
38669               for (var i = 0; i < keys.length; i++) {
38670                 var k = keys[i];
38671
38672                 if (discardTags[k] || !entity.tags[k]) {
38673                   didDiscard = true;
38674                 } else {
38675                   tags[k] = entity.tags[k];
38676                 }
38677               }
38678
38679               if (didDiscard) {
38680                 graph = graph.replace(entity.update({
38681                   tags: tags
38682                 }));
38683               }
38684             }
38685           };
38686         }
38687
38688         //
38689         // Optionally, disconnect only the given ways.
38690         //
38691         // For testing convenience, accepts an ID to assign to the (first) new node.
38692         // Normally, this will be undefined and the way will automatically
38693         // be assigned a new ID.
38694         //
38695         // This is the inverse of `iD.actionConnect`.
38696         //
38697         // Reference:
38698         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
38699         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
38700         //
38701
38702         function actionDisconnect(nodeId, newNodeId) {
38703           var wayIds;
38704
38705           var action = function action(graph) {
38706             var node = graph.entity(nodeId);
38707             var connections = action.connections(graph);
38708             connections.forEach(function (connection) {
38709               var way = graph.entity(connection.wayID);
38710               var newNode = osmNode({
38711                 id: newNodeId,
38712                 loc: node.loc,
38713                 tags: node.tags
38714               });
38715               graph = graph.replace(newNode);
38716
38717               if (connection.index === 0 && way.isArea()) {
38718                 // replace shared node with shared node..
38719                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
38720               } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
38721                 // replace closing node with new new node..
38722                 graph = graph.replace(way.unclose().addNode(newNode.id));
38723               } else {
38724                 // replace shared node with multiple new nodes..
38725                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
38726               }
38727             });
38728             return graph;
38729           };
38730
38731           action.connections = function (graph) {
38732             var candidates = [];
38733             var keeping = false;
38734             var parentWays = graph.parentWays(graph.entity(nodeId));
38735             var way, waynode;
38736
38737             for (var i = 0; i < parentWays.length; i++) {
38738               way = parentWays[i];
38739
38740               if (wayIds && wayIds.indexOf(way.id) === -1) {
38741                 keeping = true;
38742                 continue;
38743               }
38744
38745               if (way.isArea() && way.nodes[0] === nodeId) {
38746                 candidates.push({
38747                   wayID: way.id,
38748                   index: 0
38749                 });
38750               } else {
38751                 for (var j = 0; j < way.nodes.length; j++) {
38752                   waynode = way.nodes[j];
38753
38754                   if (waynode === nodeId) {
38755                     if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j === way.nodes.length - 1) {
38756                       continue;
38757                     }
38758
38759                     candidates.push({
38760                       wayID: way.id,
38761                       index: j
38762                     });
38763                   }
38764                 }
38765               }
38766             }
38767
38768             return keeping ? candidates : candidates.slice(1);
38769           };
38770
38771           action.disabled = function (graph) {
38772             var connections = action.connections(graph);
38773             if (connections.length === 0) return 'not_connected';
38774             var parentWays = graph.parentWays(graph.entity(nodeId));
38775             var seenRelationIds = {};
38776             var sharedRelation;
38777             parentWays.forEach(function (way) {
38778               var relations = graph.parentRelations(way);
38779               relations.forEach(function (relation) {
38780                 if (relation.id in seenRelationIds) {
38781                   if (wayIds) {
38782                     if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
38783                       sharedRelation = relation;
38784                     }
38785                   } else {
38786                     sharedRelation = relation;
38787                   }
38788                 } else {
38789                   seenRelationIds[relation.id] = way.id;
38790                 }
38791               });
38792             });
38793             if (sharedRelation) return 'relation';
38794           };
38795
38796           action.limitWays = function (val) {
38797             if (!arguments.length) return wayIds;
38798             wayIds = val;
38799             return action;
38800           };
38801
38802           return action;
38803         }
38804
38805         function actionExtract(entityID, projection) {
38806           var extractedNodeID;
38807
38808           var action = function action(graph) {
38809             var entity = graph.entity(entityID);
38810
38811             if (entity.type === 'node') {
38812               return extractFromNode(entity, graph);
38813             }
38814
38815             return extractFromWayOrRelation(entity, graph);
38816           };
38817
38818           function extractFromNode(node, graph) {
38819             extractedNodeID = node.id; // Create a new node to replace the one we will detach
38820
38821             var replacement = osmNode({
38822               loc: node.loc
38823             });
38824             graph = graph.replace(replacement); // Process each way in turn, updating the graph as we go
38825
38826             graph = graph.parentWays(node).reduce(function (accGraph, parentWay) {
38827               return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
38828             }, graph); // Process any relations too
38829
38830             return graph.parentRelations(node).reduce(function (accGraph, parentRel) {
38831               return accGraph.replace(parentRel.replaceMember(node, replacement));
38832             }, graph);
38833           }
38834
38835           function extractFromWayOrRelation(entity, graph) {
38836             var fromGeometry = entity.geometry(graph);
38837             var keysToCopyAndRetain = ['source', 'wheelchair'];
38838             var keysToRetain = ['area'];
38839             var buildingKeysToRetain = ['architect', 'building', 'height', 'layer'];
38840             var extractedLoc = d3_geoPath(projection).centroid(entity.asGeoJSON(graph));
38841             extractedLoc = extractedLoc && projection.invert(extractedLoc);
38842
38843             if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
38844               extractedLoc = entity.extent(graph).center();
38845             }
38846
38847             var indoorAreaValues = {
38848               area: true,
38849               corridor: true,
38850               elevator: true,
38851               level: true,
38852               room: true
38853             };
38854             var isBuilding = entity.tags.building && entity.tags.building !== 'no' || entity.tags['building:part'] && entity.tags['building:part'] !== 'no';
38855             var isIndoorArea = fromGeometry === 'area' && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
38856             var entityTags = Object.assign({}, entity.tags); // shallow copy
38857
38858             var pointTags = {};
38859
38860             for (var key in entityTags) {
38861               if (entity.type === 'relation' && key === 'type') {
38862                 continue;
38863               }
38864
38865               if (keysToRetain.indexOf(key) !== -1) {
38866                 continue;
38867               }
38868
38869               if (isBuilding) {
38870                 // don't transfer building-related tags
38871                 if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
38872               } // leave `indoor` tag on the area
38873
38874
38875               if (isIndoorArea && key === 'indoor') {
38876                 continue;
38877               } // copy the tag from the entity to the point
38878
38879
38880               pointTags[key] = entityTags[key]; // leave addresses and some other tags so they're on both features
38881
38882               if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
38883                 continue;
38884               } else if (isIndoorArea && key === 'level') {
38885                 // leave `level` on both features
38886                 continue;
38887               } // remove the tag from the entity
38888
38889
38890               delete entityTags[key];
38891             }
38892
38893             if (!isBuilding && !isIndoorArea && fromGeometry === 'area') {
38894               // ensure that areas keep area geometry
38895               entityTags.area = 'yes';
38896             }
38897
38898             var replacement = osmNode({
38899               loc: extractedLoc,
38900               tags: pointTags
38901             });
38902             graph = graph.replace(replacement);
38903             extractedNodeID = replacement.id;
38904             return graph.replace(entity.update({
38905               tags: entityTags
38906             }));
38907           }
38908
38909           action.getExtractedNodeID = function () {
38910             return extractedNodeID;
38911           };
38912
38913           return action;
38914         }
38915
38916         //
38917         // This is the inverse of `iD.actionSplit`.
38918         //
38919         // Reference:
38920         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
38921         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
38922         //
38923
38924         function actionJoin(ids) {
38925           function groupEntitiesByGeometry(graph) {
38926             var entities = ids.map(function (id) {
38927               return graph.entity(id);
38928             });
38929             return Object.assign({
38930               line: []
38931             }, utilArrayGroupBy(entities, function (entity) {
38932               return entity.geometry(graph);
38933             }));
38934           }
38935
38936           var action = function action(graph) {
38937             var ways = ids.map(graph.entity, graph); // if any of the ways are sided (e.g. coastline, cliff, kerb)
38938             // sort them first so they establish the overall order - #6033
38939
38940             ways.sort(function (a, b) {
38941               var aSided = a.isSided();
38942               var bSided = b.isSided();
38943               return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
38944             }); // Prefer to keep an existing way.
38945             // if there are multiple existing ways, keep the oldest one
38946             // the oldest way is determined by the ID of the way
38947
38948             var survivorID = (ways.filter(function (way) {
38949               return !way.isNew();
38950             }).sort(function (a, b) {
38951               return +a.osmId() - +b.osmId();
38952             })[0] || ways[0]).id;
38953             var sequences = osmJoinWays(ways, graph);
38954             var joined = sequences[0]; // We might need to reverse some of these ways before joining them.  #4688
38955             // `joined.actions` property will contain any actions we need to apply.
38956
38957             graph = sequences.actions.reduce(function (g, action) {
38958               return action(g);
38959             }, graph);
38960             var survivor = graph.entity(survivorID);
38961             survivor = survivor.update({
38962               nodes: joined.nodes.map(function (n) {
38963                 return n.id;
38964               })
38965             });
38966             graph = graph.replace(survivor);
38967             joined.forEach(function (way) {
38968               if (way.id === survivorID) return;
38969               graph.parentRelations(way).forEach(function (parent) {
38970                 graph = graph.replace(parent.replaceMember(way, survivor));
38971               });
38972               survivor = survivor.mergeTags(way.tags);
38973               graph = graph.replace(survivor);
38974               graph = actionDeleteWay(way.id)(graph);
38975             }); // Finds if the join created a single-member multipolygon,
38976             // and if so turns it into a basic area instead
38977
38978             function checkForSimpleMultipolygon() {
38979               if (!survivor.isClosed()) return;
38980               var multipolygons = graph.parentMultipolygons(survivor).filter(function (multipolygon) {
38981                 // find multipolygons where the survivor is the only member
38982                 return multipolygon.members.length === 1;
38983               }); // skip if this is the single member of multiple multipolygons
38984
38985               if (multipolygons.length !== 1) return;
38986               var multipolygon = multipolygons[0];
38987
38988               for (var key in survivor.tags) {
38989                 if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
38990                 multipolygon.tags[key] !== survivor.tags[key]) return;
38991               }
38992
38993               survivor = survivor.mergeTags(multipolygon.tags);
38994               graph = graph.replace(survivor);
38995               graph = actionDeleteRelation(multipolygon.id, true
38996               /* allow untagged members */
38997               )(graph);
38998               var tags = Object.assign({}, survivor.tags);
38999
39000               if (survivor.geometry(graph) !== 'area') {
39001                 // ensure the feature persists as an area
39002                 tags.area = 'yes';
39003               }
39004
39005               delete tags.type; // remove type=multipolygon
39006
39007               survivor = survivor.update({
39008                 tags: tags
39009               });
39010               graph = graph.replace(survivor);
39011             }
39012
39013             checkForSimpleMultipolygon();
39014             return graph;
39015           }; // Returns the number of nodes the resultant way is expected to have
39016
39017
39018           action.resultingWayNodesLength = function (graph) {
39019             return ids.reduce(function (count, id) {
39020               return count + graph.entity(id).nodes.length;
39021             }, 0) - ids.length - 1;
39022           };
39023
39024           action.disabled = function (graph) {
39025             var geometries = groupEntitiesByGeometry(graph);
39026
39027             if (ids.length < 2 || ids.length !== geometries.line.length) {
39028               return 'not_eligible';
39029             }
39030
39031             var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
39032
39033             if (joined.length > 1) {
39034               return 'not_adjacent';
39035             }
39036
39037             var i; // All joined ways must belong to the same set of (non-restriction) relations.
39038             // Restriction relations have different logic, below, which allows some cases
39039             // this prohibits, and prohibits some cases this allows.
39040
39041             var sortedParentRelations = function sortedParentRelations(id) {
39042               return graph.parentRelations(graph.entity(id)).filter(function (rel) {
39043                 return !rel.isRestriction() && !rel.isConnectivity();
39044               }).sort(function (a, b) {
39045                 return a.id - b.id;
39046               });
39047             };
39048
39049             var relsA = sortedParentRelations(ids[0]);
39050
39051             for (i = 1; i < ids.length; i++) {
39052               var relsB = sortedParentRelations(ids[i]);
39053
39054               if (!utilArrayIdentical(relsA, relsB)) {
39055                 return 'conflicting_relations';
39056               }
39057             } // Loop through all combinations of path-pairs
39058             // to check potential intersections between all pairs
39059
39060
39061             for (i = 0; i < ids.length - 1; i++) {
39062               for (var j = i + 1; j < ids.length; j++) {
39063                 var path1 = graph.childNodes(graph.entity(ids[i])).map(function (e) {
39064                   return e.loc;
39065                 });
39066                 var path2 = graph.childNodes(graph.entity(ids[j])).map(function (e) {
39067                   return e.loc;
39068                 });
39069                 var intersections = geoPathIntersections(path1, path2); // Check if intersections are just nodes lying on top of
39070                 // each other/the line, as opposed to crossing it
39071
39072                 var common = utilArrayIntersection(joined[0].nodes.map(function (n) {
39073                   return n.loc.toString();
39074                 }), intersections.map(function (n) {
39075                   return n.toString();
39076                 }));
39077
39078                 if (common.length !== intersections.length) {
39079                   return 'paths_intersect';
39080                 }
39081               }
39082             }
39083
39084             var nodeIds = joined[0].nodes.map(function (n) {
39085               return n.id;
39086             }).slice(1, -1);
39087             var relation;
39088             var tags = {};
39089             var conflicting = false;
39090             joined[0].forEach(function (way) {
39091               var parents = graph.parentRelations(way);
39092               parents.forEach(function (parent) {
39093                 if ((parent.isRestriction() || parent.isConnectivity()) && parent.members.some(function (m) {
39094                   return nodeIds.indexOf(m.id) >= 0;
39095                 })) {
39096                   relation = parent;
39097                 }
39098               });
39099
39100               for (var k in way.tags) {
39101                 if (!(k in tags)) {
39102                   tags[k] = way.tags[k];
39103                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
39104                   conflicting = true;
39105                 }
39106               }
39107             });
39108
39109             if (relation) {
39110               return relation.isRestriction() ? 'restriction' : 'connectivity';
39111             }
39112
39113             if (conflicting) {
39114               return 'conflicting_tags';
39115             }
39116           };
39117
39118           return action;
39119         }
39120
39121         function actionMerge(ids) {
39122           function groupEntitiesByGeometry(graph) {
39123             var entities = ids.map(function (id) {
39124               return graph.entity(id);
39125             });
39126             return Object.assign({
39127               point: [],
39128               area: [],
39129               line: [],
39130               relation: []
39131             }, utilArrayGroupBy(entities, function (entity) {
39132               return entity.geometry(graph);
39133             }));
39134           }
39135
39136           var action = function action(graph) {
39137             var geometries = groupEntitiesByGeometry(graph);
39138             var target = geometries.area[0] || geometries.line[0];
39139             var points = geometries.point;
39140             points.forEach(function (point) {
39141               target = target.mergeTags(point.tags);
39142               graph = graph.replace(target);
39143               graph.parentRelations(point).forEach(function (parent) {
39144                 graph = graph.replace(parent.replaceMember(point, target));
39145               });
39146               var nodes = utilArrayUniq(graph.childNodes(target));
39147               var removeNode = point;
39148
39149               for (var i = 0; i < nodes.length; i++) {
39150                 var node = nodes[i];
39151
39152                 if (graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags()) {
39153                   continue;
39154                 } // Found an uninteresting child node on the target way.
39155                 // Move orig point into its place to preserve point's history. #3683
39156
39157
39158                 graph = graph.replace(point.update({
39159                   tags: {},
39160                   loc: node.loc
39161                 }));
39162                 target = target.replaceNode(node.id, point.id);
39163                 graph = graph.replace(target);
39164                 removeNode = node;
39165                 break;
39166               }
39167
39168               graph = graph.remove(removeNode);
39169             });
39170
39171             if (target.tags.area === 'yes') {
39172               var tags = Object.assign({}, target.tags); // shallow copy
39173
39174               delete tags.area;
39175
39176               if (osmTagSuggestingArea(tags)) {
39177                 // remove the `area` tag if area geometry is now implied - #3851
39178                 target = target.update({
39179                   tags: tags
39180                 });
39181                 graph = graph.replace(target);
39182               }
39183             }
39184
39185             return graph;
39186           };
39187
39188           action.disabled = function (graph) {
39189             var geometries = groupEntitiesByGeometry(graph);
39190
39191             if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
39192               return 'not_eligible';
39193             }
39194           };
39195
39196           return action;
39197         }
39198
39199         //
39200         // 1. move all the nodes to a common location
39201         // 2. `actionConnect` them
39202
39203         function actionMergeNodes(nodeIDs, loc) {
39204           // If there is a single "interesting" node, use that as the location.
39205           // Otherwise return the average location of all the nodes.
39206           function chooseLoc(graph) {
39207             if (!nodeIDs.length) return null;
39208             var sum = [0, 0];
39209             var interestingCount = 0;
39210             var interestingLoc;
39211
39212             for (var i = 0; i < nodeIDs.length; i++) {
39213               var node = graph.entity(nodeIDs[i]);
39214
39215               if (node.hasInterestingTags()) {
39216                 interestingLoc = ++interestingCount === 1 ? node.loc : null;
39217               }
39218
39219               sum = geoVecAdd(sum, node.loc);
39220             }
39221
39222             return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
39223           }
39224
39225           var action = function action(graph) {
39226             if (nodeIDs.length < 2) return graph;
39227             var toLoc = loc;
39228
39229             if (!toLoc) {
39230               toLoc = chooseLoc(graph);
39231             }
39232
39233             for (var i = 0; i < nodeIDs.length; i++) {
39234               var node = graph.entity(nodeIDs[i]);
39235
39236               if (node.loc !== toLoc) {
39237                 graph = graph.replace(node.move(toLoc));
39238               }
39239             }
39240
39241             return actionConnect(nodeIDs)(graph);
39242           };
39243
39244           action.disabled = function (graph) {
39245             if (nodeIDs.length < 2) return 'not_eligible';
39246
39247             for (var i = 0; i < nodeIDs.length; i++) {
39248               var entity = graph.entity(nodeIDs[i]);
39249               if (entity.type !== 'node') return 'not_eligible';
39250             }
39251
39252             return actionConnect(nodeIDs).disabled(graph);
39253           };
39254
39255           return action;
39256         }
39257
39258         function osmChangeset() {
39259           if (!(this instanceof osmChangeset)) {
39260             return new osmChangeset().initialize(arguments);
39261           } else if (arguments.length) {
39262             this.initialize(arguments);
39263           }
39264         }
39265         osmEntity.changeset = osmChangeset;
39266         osmChangeset.prototype = Object.create(osmEntity.prototype);
39267         Object.assign(osmChangeset.prototype, {
39268           type: 'changeset',
39269           extent: function extent() {
39270             return new geoExtent();
39271           },
39272           geometry: function geometry() {
39273             return 'changeset';
39274           },
39275           asJXON: function asJXON() {
39276             return {
39277               osm: {
39278                 changeset: {
39279                   tag: Object.keys(this.tags).map(function (k) {
39280                     return {
39281                       '@k': k,
39282                       '@v': this.tags[k]
39283                     };
39284                   }, this),
39285                   '@version': 0.6,
39286                   '@generator': 'iD'
39287                 }
39288               }
39289             };
39290           },
39291           // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
39292           // XML. Returns a string.
39293           osmChangeJXON: function osmChangeJXON(changes) {
39294             var changeset_id = this.id;
39295
39296             function nest(x, order) {
39297               var groups = {};
39298
39299               for (var i = 0; i < x.length; i++) {
39300                 var tagName = Object.keys(x[i])[0];
39301                 if (!groups[tagName]) groups[tagName] = [];
39302                 groups[tagName].push(x[i][tagName]);
39303               }
39304
39305               var ordered = {};
39306               order.forEach(function (o) {
39307                 if (groups[o]) ordered[o] = groups[o];
39308               });
39309               return ordered;
39310             } // sort relations in a changeset by dependencies
39311
39312
39313             function sort(changes) {
39314               // find a referenced relation in the current changeset
39315               function resolve(item) {
39316                 return relations.find(function (relation) {
39317                   return item.keyAttributes.type === 'relation' && item.keyAttributes.ref === relation['@id'];
39318                 });
39319               } // a new item is an item that has not been already processed
39320
39321
39322               function isNew(item) {
39323                 return !sorted[item['@id']] && !processing.find(function (proc) {
39324                   return proc['@id'] === item['@id'];
39325                 });
39326               }
39327
39328               var processing = [];
39329               var sorted = {};
39330               var relations = changes.relation;
39331               if (!relations) return changes;
39332
39333               for (var i = 0; i < relations.length; i++) {
39334                 var relation = relations[i]; // skip relation if already sorted
39335
39336                 if (!sorted[relation['@id']]) {
39337                   processing.push(relation);
39338                 }
39339
39340                 while (processing.length > 0) {
39341                   var next = processing[0],
39342                       deps = next.member.map(resolve).filter(Boolean).filter(isNew);
39343
39344                   if (deps.length === 0) {
39345                     sorted[next['@id']] = next;
39346                     processing.shift();
39347                   } else {
39348                     processing = deps.concat(processing);
39349                   }
39350                 }
39351               }
39352
39353               changes.relation = Object.values(sorted);
39354               return changes;
39355             }
39356
39357             function rep(entity) {
39358               return entity.asJXON(changeset_id);
39359             }
39360
39361             return {
39362               osmChange: {
39363                 '@version': 0.6,
39364                 '@generator': 'iD',
39365                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
39366                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
39367                 'delete': Object.assign(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {
39368                   '@if-unused': true
39369                 })
39370               }
39371             };
39372           },
39373           asGeoJSON: function asGeoJSON() {
39374             return {};
39375           }
39376         });
39377
39378         function osmNote() {
39379           if (!(this instanceof osmNote)) {
39380             return new osmNote().initialize(arguments);
39381           } else if (arguments.length) {
39382             this.initialize(arguments);
39383           }
39384         }
39385
39386         osmNote.id = function () {
39387           return osmNote.id.next--;
39388         };
39389
39390         osmNote.id.next = -1;
39391         Object.assign(osmNote.prototype, {
39392           type: 'note',
39393           initialize: function initialize(sources) {
39394             for (var i = 0; i < sources.length; ++i) {
39395               var source = sources[i];
39396
39397               for (var prop in source) {
39398                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
39399                   if (source[prop] === undefined) {
39400                     delete this[prop];
39401                   } else {
39402                     this[prop] = source[prop];
39403                   }
39404                 }
39405               }
39406             }
39407
39408             if (!this.id) {
39409               this.id = osmNote.id().toString();
39410             }
39411
39412             return this;
39413           },
39414           extent: function extent() {
39415             return new geoExtent(this.loc);
39416           },
39417           update: function update(attrs) {
39418             return osmNote(this, attrs); // {v: 1 + (this.v || 0)}
39419           },
39420           isNew: function isNew() {
39421             return this.id < 0;
39422           },
39423           move: function move(loc) {
39424             return this.update({
39425               loc: loc
39426             });
39427           }
39428         });
39429
39430         function osmRelation() {
39431           if (!(this instanceof osmRelation)) {
39432             return new osmRelation().initialize(arguments);
39433           } else if (arguments.length) {
39434             this.initialize(arguments);
39435           }
39436         }
39437         osmEntity.relation = osmRelation;
39438         osmRelation.prototype = Object.create(osmEntity.prototype);
39439
39440         osmRelation.creationOrder = function (a, b) {
39441           var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
39442           var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
39443           if (aId < 0 || bId < 0) return aId - bId;
39444           return bId - aId;
39445         };
39446
39447         Object.assign(osmRelation.prototype, {
39448           type: 'relation',
39449           members: [],
39450           copy: function copy(resolver, copies) {
39451             if (copies[this.id]) return copies[this.id];
39452             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
39453             var members = this.members.map(function (member) {
39454               return Object.assign({}, member, {
39455                 id: resolver.entity(member.id).copy(resolver, copies).id
39456               });
39457             });
39458             copy = copy.update({
39459               members: members
39460             });
39461             copies[this.id] = copy;
39462             return copy;
39463           },
39464           extent: function extent(resolver, memo) {
39465             return resolver["transient"](this, 'extent', function () {
39466               if (memo && memo[this.id]) return geoExtent();
39467               memo = memo || {};
39468               memo[this.id] = true;
39469               var extent = geoExtent();
39470
39471               for (var i = 0; i < this.members.length; i++) {
39472                 var member = resolver.hasEntity(this.members[i].id);
39473
39474                 if (member) {
39475                   extent._extend(member.extent(resolver, memo));
39476                 }
39477               }
39478
39479               return extent;
39480             });
39481           },
39482           geometry: function geometry(graph) {
39483             return graph["transient"](this, 'geometry', function () {
39484               return this.isMultipolygon() ? 'area' : 'relation';
39485             });
39486           },
39487           isDegenerate: function isDegenerate() {
39488             return this.members.length === 0;
39489           },
39490           // Return an array of members, each extended with an 'index' property whose value
39491           // is the member index.
39492           indexedMembers: function indexedMembers() {
39493             var result = new Array(this.members.length);
39494
39495             for (var i = 0; i < this.members.length; i++) {
39496               result[i] = Object.assign({}, this.members[i], {
39497                 index: i
39498               });
39499             }
39500
39501             return result;
39502           },
39503           // Return the first member with the given role. A copy of the member object
39504           // is returned, extended with an 'index' property whose value is the member index.
39505           memberByRole: function memberByRole(role) {
39506             for (var i = 0; i < this.members.length; i++) {
39507               if (this.members[i].role === role) {
39508                 return Object.assign({}, this.members[i], {
39509                   index: i
39510                 });
39511               }
39512             }
39513           },
39514           // Same as memberByRole, but returns all members with the given role
39515           membersByRole: function membersByRole(role) {
39516             var result = [];
39517
39518             for (var i = 0; i < this.members.length; i++) {
39519               if (this.members[i].role === role) {
39520                 result.push(Object.assign({}, this.members[i], {
39521                   index: i
39522                 }));
39523               }
39524             }
39525
39526             return result;
39527           },
39528           // Return the first member with the given id. A copy of the member object
39529           // is returned, extended with an 'index' property whose value is the member index.
39530           memberById: function memberById(id) {
39531             for (var i = 0; i < this.members.length; i++) {
39532               if (this.members[i].id === id) {
39533                 return Object.assign({}, this.members[i], {
39534                   index: i
39535                 });
39536               }
39537             }
39538           },
39539           // Return the first member with the given id and role. A copy of the member object
39540           // is returned, extended with an 'index' property whose value is the member index.
39541           memberByIdAndRole: function memberByIdAndRole(id, role) {
39542             for (var i = 0; i < this.members.length; i++) {
39543               if (this.members[i].id === id && this.members[i].role === role) {
39544                 return Object.assign({}, this.members[i], {
39545                   index: i
39546                 });
39547               }
39548             }
39549           },
39550           addMember: function addMember(member, index) {
39551             var members = this.members.slice();
39552             members.splice(index === undefined ? members.length : index, 0, member);
39553             return this.update({
39554               members: members
39555             });
39556           },
39557           updateMember: function updateMember(member, index) {
39558             var members = this.members.slice();
39559             members.splice(index, 1, Object.assign({}, members[index], member));
39560             return this.update({
39561               members: members
39562             });
39563           },
39564           removeMember: function removeMember(index) {
39565             var members = this.members.slice();
39566             members.splice(index, 1);
39567             return this.update({
39568               members: members
39569             });
39570           },
39571           removeMembersWithID: function removeMembersWithID(id) {
39572             var members = this.members.filter(function (m) {
39573               return m.id !== id;
39574             });
39575             return this.update({
39576               members: members
39577             });
39578           },
39579           moveMember: function moveMember(fromIndex, toIndex) {
39580             var members = this.members.slice();
39581             members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
39582             return this.update({
39583               members: members
39584             });
39585           },
39586           // Wherever a member appears with id `needle.id`, replace it with a member
39587           // with id `replacement.id`, type `replacement.type`, and the original role,
39588           // By default, adding a duplicate member (by id and role) is prevented.
39589           // Return an updated relation.
39590           replaceMember: function replaceMember(needle, replacement, keepDuplicates) {
39591             if (!this.memberById(needle.id)) return this;
39592             var members = [];
39593
39594             for (var i = 0; i < this.members.length; i++) {
39595               var member = this.members[i];
39596
39597               if (member.id !== needle.id) {
39598                 members.push(member);
39599               } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
39600                 members.push({
39601                   id: replacement.id,
39602                   type: replacement.type,
39603                   role: member.role
39604                 });
39605               }
39606             }
39607
39608             return this.update({
39609               members: members
39610             });
39611           },
39612           asJXON: function asJXON(changeset_id) {
39613             var r = {
39614               relation: {
39615                 '@id': this.osmId(),
39616                 '@version': this.version || 0,
39617                 member: this.members.map(function (member) {
39618                   return {
39619                     keyAttributes: {
39620                       type: member.type,
39621                       role: member.role,
39622                       ref: osmEntity.id.toOSM(member.id)
39623                     }
39624                   };
39625                 }, this),
39626                 tag: Object.keys(this.tags).map(function (k) {
39627                   return {
39628                     keyAttributes: {
39629                       k: k,
39630                       v: this.tags[k]
39631                     }
39632                   };
39633                 }, this)
39634               }
39635             };
39636
39637             if (changeset_id) {
39638               r.relation['@changeset'] = changeset_id;
39639             }
39640
39641             return r;
39642           },
39643           asGeoJSON: function asGeoJSON(resolver) {
39644             return resolver["transient"](this, 'GeoJSON', function () {
39645               if (this.isMultipolygon()) {
39646                 return {
39647                   type: 'MultiPolygon',
39648                   coordinates: this.multipolygon(resolver)
39649                 };
39650               } else {
39651                 return {
39652                   type: 'FeatureCollection',
39653                   properties: this.tags,
39654                   features: this.members.map(function (member) {
39655                     return Object.assign({
39656                       role: member.role
39657                     }, resolver.entity(member.id).asGeoJSON(resolver));
39658                   })
39659                 };
39660               }
39661             });
39662           },
39663           area: function area(resolver) {
39664             return resolver["transient"](this, 'area', function () {
39665               return d3_geoArea(this.asGeoJSON(resolver));
39666             });
39667           },
39668           isMultipolygon: function isMultipolygon() {
39669             return this.tags.type === 'multipolygon';
39670           },
39671           isComplete: function isComplete(resolver) {
39672             for (var i = 0; i < this.members.length; i++) {
39673               if (!resolver.hasEntity(this.members[i].id)) {
39674                 return false;
39675               }
39676             }
39677
39678             return true;
39679           },
39680           hasFromViaTo: function hasFromViaTo() {
39681             return this.members.some(function (m) {
39682               return m.role === 'from';
39683             }) && this.members.some(function (m) {
39684               return m.role === 'via';
39685             }) && this.members.some(function (m) {
39686               return m.role === 'to';
39687             });
39688           },
39689           isRestriction: function isRestriction() {
39690             return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
39691           },
39692           isValidRestriction: function isValidRestriction() {
39693             if (!this.isRestriction()) return false;
39694             var froms = this.members.filter(function (m) {
39695               return m.role === 'from';
39696             });
39697             var vias = this.members.filter(function (m) {
39698               return m.role === 'via';
39699             });
39700             var tos = this.members.filter(function (m) {
39701               return m.role === 'to';
39702             });
39703             if (froms.length !== 1 && this.tags.restriction !== 'no_entry') return false;
39704             if (froms.some(function (m) {
39705               return m.type !== 'way';
39706             })) return false;
39707             if (tos.length !== 1 && this.tags.restriction !== 'no_exit') return false;
39708             if (tos.some(function (m) {
39709               return m.type !== 'way';
39710             })) return false;
39711             if (vias.length === 0) return false;
39712             if (vias.length > 1 && vias.some(function (m) {
39713               return m.type !== 'way';
39714             })) return false;
39715             return true;
39716           },
39717           isConnectivity: function isConnectivity() {
39718             return !!(this.tags.type && this.tags.type.match(/^connectivity:?/));
39719           },
39720           // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
39721           // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
39722           //
39723           // This corresponds to the structure needed for rendering a multipolygon path using a
39724           // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
39725           //
39726           // In the case of invalid geometries, this function will still return a result which
39727           // includes the nodes of all way members, but some Nds may be unclosed and some inner
39728           // rings not matched with the intended outer ring.
39729           //
39730           multipolygon: function multipolygon(resolver) {
39731             var outers = this.members.filter(function (m) {
39732               return 'outer' === (m.role || 'outer');
39733             });
39734             var inners = this.members.filter(function (m) {
39735               return 'inner' === m.role;
39736             });
39737             outers = osmJoinWays(outers, resolver);
39738             inners = osmJoinWays(inners, resolver);
39739
39740             var sequenceToLineString = function sequenceToLineString(sequence) {
39741               if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
39742                 // close unclosed parts to ensure correct area rendering - #2945
39743                 sequence.nodes.push(sequence.nodes[0]);
39744               }
39745
39746               return sequence.nodes.map(function (node) {
39747                 return node.loc;
39748               });
39749             };
39750
39751             outers = outers.map(sequenceToLineString);
39752             inners = inners.map(sequenceToLineString);
39753             var result = outers.map(function (o) {
39754               // Heuristic for detecting counterclockwise winding order. Assumes
39755               // that OpenStreetMap polygons are not hemisphere-spanning.
39756               return [d3_geoArea({
39757                 type: 'Polygon',
39758                 coordinates: [o]
39759               }) > 2 * Math.PI ? o.reverse() : o];
39760             });
39761
39762             function findOuter(inner) {
39763               var o, outer;
39764
39765               for (o = 0; o < outers.length; o++) {
39766                 outer = outers[o];
39767
39768                 if (geoPolygonContainsPolygon(outer, inner)) {
39769                   return o;
39770                 }
39771               }
39772
39773               for (o = 0; o < outers.length; o++) {
39774                 outer = outers[o];
39775
39776                 if (geoPolygonIntersectsPolygon(outer, inner, false)) {
39777                   return o;
39778                 }
39779               }
39780             }
39781
39782             for (var i = 0; i < inners.length; i++) {
39783               var inner = inners[i];
39784
39785               if (d3_geoArea({
39786                 type: 'Polygon',
39787                 coordinates: [inner]
39788               }) < 2 * Math.PI) {
39789                 inner = inner.reverse();
39790               }
39791
39792               var o = findOuter(inners[i]);
39793
39794               if (o !== undefined) {
39795                 result[o].push(inners[i]);
39796               } else {
39797                 result.push([inners[i]]); // Invalid geometry
39798               }
39799             }
39800
39801             return result;
39802           }
39803         });
39804
39805         var QAItem = /*#__PURE__*/function () {
39806           function QAItem(loc, service, itemType, id, props) {
39807             _classCallCheck$1(this, QAItem);
39808
39809             // Store required properties
39810             this.loc = loc;
39811             this.service = service.title;
39812             this.itemType = itemType; // All issues must have an ID for selection, use generic if none specified
39813
39814             this.id = id ? id : "".concat(QAItem.id());
39815             this.update(props); // Some QA services have marker icons to differentiate issues
39816
39817             if (service && typeof service.getIcon === 'function') {
39818               this.icon = service.getIcon(itemType);
39819             }
39820           }
39821
39822           _createClass$1(QAItem, [{
39823             key: "update",
39824             value: function update(props) {
39825               var _this = this;
39826
39827               // You can't override this initial information
39828               var loc = this.loc,
39829                   service = this.service,
39830                   itemType = this.itemType,
39831                   id = this.id;
39832               Object.keys(props).forEach(function (prop) {
39833                 return _this[prop] = props[prop];
39834               });
39835               this.loc = loc;
39836               this.service = service;
39837               this.itemType = itemType;
39838               this.id = id;
39839               return this;
39840             } // Generic handling for newly created QAItems
39841
39842           }], [{
39843             key: "id",
39844             value: function id() {
39845               return this.nextId--;
39846             }
39847           }]);
39848
39849           return QAItem;
39850         }();
39851         QAItem.nextId = -1;
39852
39853         //
39854         // Optionally, split only the given ways, if multiple ways share
39855         // the given node.
39856         //
39857         // This is the inverse of `iD.actionJoin`.
39858         //
39859         // For testing convenience, accepts an ID to assign to the new way.
39860         // Normally, this will be undefined and the way will automatically
39861         // be assigned a new ID.
39862         //
39863         // Reference:
39864         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
39865         //
39866
39867         function actionSplit(nodeIds, newWayIds) {
39868           // accept single ID for backwards-compatiblity
39869           if (typeof nodeIds === 'string') nodeIds = [nodeIds];
39870
39871           var _wayIDs; // the strategy for picking which way will have a new version and which way is newly created
39872
39873
39874           var _keepHistoryOn = 'longest'; // 'longest', 'first'
39875           // The IDs of the ways actually created by running this action
39876
39877           var _createdWayIDs = [];
39878
39879           function dist(graph, nA, nB) {
39880             var locA = graph.entity(nA).loc;
39881             var locB = graph.entity(nB).loc;
39882             var epsilon = 1e-6;
39883             return locA && locB ? geoSphericalDistance(locA, locB) : epsilon;
39884           } // If the way is closed, we need to search for a partner node
39885           // to split the way at.
39886           //
39887           // The following looks for a node that is both far away from
39888           // the initial node in terms of way segment length and nearby
39889           // in terms of beeline-distance. This assures that areas get
39890           // split on the most "natural" points (independent of the number
39891           // of nodes).
39892           // For example: bone-shaped areas get split across their waist
39893           // line, circles across the diameter.
39894
39895
39896           function splitArea(nodes, idxA, graph) {
39897             var lengths = new Array(nodes.length);
39898             var length;
39899             var i;
39900             var best = 0;
39901             var idxB;
39902
39903             function wrap(index) {
39904               return utilWrap(index, nodes.length);
39905             } // calculate lengths
39906
39907
39908             length = 0;
39909
39910             for (i = wrap(idxA + 1); i !== idxA; i = wrap(i + 1)) {
39911               length += dist(graph, nodes[i], nodes[wrap(i - 1)]);
39912               lengths[i] = length;
39913             }
39914
39915             length = 0;
39916
39917             for (i = wrap(idxA - 1); i !== idxA; i = wrap(i - 1)) {
39918               length += dist(graph, nodes[i], nodes[wrap(i + 1)]);
39919
39920               if (length < lengths[i]) {
39921                 lengths[i] = length;
39922               }
39923             } // determine best opposite node to split
39924
39925
39926             for (i = 0; i < nodes.length; i++) {
39927               var cost = lengths[i] / dist(graph, nodes[idxA], nodes[i]);
39928
39929               if (cost > best) {
39930                 idxB = i;
39931                 best = cost;
39932               }
39933             }
39934
39935             return idxB;
39936           }
39937
39938           function totalLengthBetweenNodes(graph, nodes) {
39939             var totalLength = 0;
39940
39941             for (var i = 0; i < nodes.length - 1; i++) {
39942               totalLength += dist(graph, nodes[i], nodes[i + 1]);
39943             }
39944
39945             return totalLength;
39946           }
39947
39948           function split(graph, nodeId, wayA, newWayId) {
39949             var wayB = osmWay({
39950               id: newWayId,
39951               tags: wayA.tags
39952             }); // `wayB` is the NEW way
39953
39954             var origNodes = wayA.nodes.slice();
39955             var nodesA;
39956             var nodesB;
39957             var isArea = wayA.isArea();
39958             var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
39959
39960             if (wayA.isClosed()) {
39961               var nodes = wayA.nodes.slice(0, -1);
39962               var idxA = nodes.indexOf(nodeId);
39963               var idxB = splitArea(nodes, idxA, graph);
39964
39965               if (idxB < idxA) {
39966                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
39967                 nodesB = nodes.slice(idxB, idxA + 1);
39968               } else {
39969                 nodesA = nodes.slice(idxA, idxB + 1);
39970                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
39971               }
39972             } else {
39973               var idx = wayA.nodes.indexOf(nodeId, 1);
39974               nodesA = wayA.nodes.slice(0, idx + 1);
39975               nodesB = wayA.nodes.slice(idx);
39976             }
39977
39978             var lengthA = totalLengthBetweenNodes(graph, nodesA);
39979             var lengthB = totalLengthBetweenNodes(graph, nodesB);
39980
39981             if (_keepHistoryOn === 'longest' && lengthB > lengthA) {
39982               // keep the history on the longer way, regardless of the node count
39983               wayA = wayA.update({
39984                 nodes: nodesB
39985               });
39986               wayB = wayB.update({
39987                 nodes: nodesA
39988               });
39989               var temp = lengthA;
39990               lengthA = lengthB;
39991               lengthB = temp;
39992             } else {
39993               wayA = wayA.update({
39994                 nodes: nodesA
39995               });
39996               wayB = wayB.update({
39997                 nodes: nodesB
39998               });
39999             }
40000
40001             if (wayA.tags.step_count) {
40002               // divide up the the step count proportionally between the two ways
40003               var stepCount = parseFloat(wayA.tags.step_count);
40004
40005               if (stepCount && // ensure a number
40006               isFinite(stepCount) && // ensure positive
40007               stepCount > 0 && // ensure integer
40008               Math.round(stepCount) === stepCount) {
40009                 var tagsA = Object.assign({}, wayA.tags);
40010                 var tagsB = Object.assign({}, wayB.tags);
40011                 var ratioA = lengthA / (lengthA + lengthB);
40012                 var countA = Math.round(stepCount * ratioA);
40013                 tagsA.step_count = countA.toString();
40014                 tagsB.step_count = (stepCount - countA).toString();
40015                 wayA = wayA.update({
40016                   tags: tagsA
40017                 });
40018                 wayB = wayB.update({
40019                   tags: tagsB
40020                 });
40021               }
40022             }
40023
40024             graph = graph.replace(wayA);
40025             graph = graph.replace(wayB);
40026             graph.parentRelations(wayA).forEach(function (relation) {
40027               var member; // Turn restrictions - make sure:
40028               // 1. Splitting a FROM/TO way - only `wayA` OR `wayB` remains in relation
40029               //    (whichever one is connected to the VIA node/ways)
40030               // 2. Splitting a VIA way - `wayB` remains in relation as a VIA way
40031
40032               if (relation.hasFromViaTo()) {
40033                 var f = relation.memberByRole('from');
40034                 var v = relation.membersByRole('via');
40035                 var t = relation.memberByRole('to');
40036                 var i; // 1. split a FROM/TO
40037
40038                 if (f.id === wayA.id || t.id === wayA.id) {
40039                   var keepB = false;
40040
40041                   if (v.length === 1 && v[0].type === 'node') {
40042                     // check via node
40043                     keepB = wayB.contains(v[0].id);
40044                   } else {
40045                     // check via way(s)
40046                     for (i = 0; i < v.length; i++) {
40047                       if (v[i].type === 'way') {
40048                         var wayVia = graph.hasEntity(v[i].id);
40049
40050                         if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
40051                           keepB = true;
40052                           break;
40053                         }
40054                       }
40055                     }
40056                   }
40057
40058                   if (keepB) {
40059                     relation = relation.replaceMember(wayA, wayB);
40060                     graph = graph.replace(relation);
40061                   } // 2. split a VIA
40062
40063                 } else {
40064                   for (i = 0; i < v.length; i++) {
40065                     if (v[i].type === 'way' && v[i].id === wayA.id) {
40066                       member = {
40067                         id: wayB.id,
40068                         type: 'way',
40069                         role: 'via'
40070                       };
40071                       graph = actionAddMember(relation.id, member, v[i].index + 1)(graph);
40072                       break;
40073                     }
40074                   }
40075                 } // All other relations (Routes, Multipolygons, etc):
40076                 // 1. Both `wayA` and `wayB` remain in the relation
40077                 // 2. But must be inserted as a pair (see `actionAddMember` for details)
40078
40079               } else {
40080                 if (relation === isOuter) {
40081                   graph = graph.replace(relation.mergeTags(wayA.tags));
40082                   graph = graph.replace(wayA.update({
40083                     tags: {}
40084                   }));
40085                   graph = graph.replace(wayB.update({
40086                     tags: {}
40087                   }));
40088                 }
40089
40090                 member = {
40091                   id: wayB.id,
40092                   type: 'way',
40093                   role: relation.memberById(wayA.id).role
40094                 };
40095                 var insertPair = {
40096                   originalID: wayA.id,
40097                   insertedID: wayB.id,
40098                   nodes: origNodes
40099                 };
40100                 graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
40101               }
40102             });
40103
40104             if (!isOuter && isArea) {
40105               var multipolygon = osmRelation({
40106                 tags: Object.assign({}, wayA.tags, {
40107                   type: 'multipolygon'
40108                 }),
40109                 members: [{
40110                   id: wayA.id,
40111                   role: 'outer',
40112                   type: 'way'
40113                 }, {
40114                   id: wayB.id,
40115                   role: 'outer',
40116                   type: 'way'
40117                 }]
40118               });
40119               graph = graph.replace(multipolygon);
40120               graph = graph.replace(wayA.update({
40121                 tags: {}
40122               }));
40123               graph = graph.replace(wayB.update({
40124                 tags: {}
40125               }));
40126             }
40127
40128             _createdWayIDs.push(wayB.id);
40129
40130             return graph;
40131           }
40132
40133           var action = function action(graph) {
40134             _createdWayIDs = [];
40135             var newWayIndex = 0;
40136
40137             for (var i = 0; i < nodeIds.length; i++) {
40138               var nodeId = nodeIds[i];
40139               var candidates = action.waysForNode(nodeId, graph);
40140
40141               for (var j = 0; j < candidates.length; j++) {
40142                 graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
40143                 newWayIndex += 1;
40144               }
40145             }
40146
40147             return graph;
40148           };
40149
40150           action.getCreatedWayIDs = function () {
40151             return _createdWayIDs;
40152           };
40153
40154           action.waysForNode = function (nodeId, graph) {
40155             var node = graph.entity(nodeId);
40156             var splittableParents = graph.parentWays(node).filter(isSplittable);
40157
40158             if (!_wayIDs) {
40159               // If the ways to split aren't specified, only split the lines.
40160               // If there are no lines to split, split the areas.
40161               var hasLine = splittableParents.some(function (parent) {
40162                 return parent.geometry(graph) === 'line';
40163               });
40164
40165               if (hasLine) {
40166                 return splittableParents.filter(function (parent) {
40167                   return parent.geometry(graph) === 'line';
40168                 });
40169               }
40170             }
40171
40172             return splittableParents;
40173
40174             function isSplittable(parent) {
40175               // If the ways to split are specified, ignore everything else.
40176               if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false; // We can fake splitting closed ways at their endpoints...
40177
40178               if (parent.isClosed()) return true; // otherwise, we can't split nodes at their endpoints.
40179
40180               for (var i = 1; i < parent.nodes.length - 1; i++) {
40181                 if (parent.nodes[i] === nodeId) return true;
40182               }
40183
40184               return false;
40185             }
40186           };
40187
40188           action.ways = function (graph) {
40189             return utilArrayUniq([].concat.apply([], nodeIds.map(function (nodeId) {
40190               return action.waysForNode(nodeId, graph);
40191             })));
40192           };
40193
40194           action.disabled = function (graph) {
40195             for (var i = 0; i < nodeIds.length; i++) {
40196               var nodeId = nodeIds[i];
40197               var candidates = action.waysForNode(nodeId, graph);
40198
40199               if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
40200                 return 'not_eligible';
40201               }
40202             }
40203           };
40204
40205           action.limitWays = function (val) {
40206             if (!arguments.length) return _wayIDs;
40207             _wayIDs = val;
40208             return action;
40209           };
40210
40211           action.keepHistoryOn = function (val) {
40212             if (!arguments.length) return _keepHistoryOn;
40213             _keepHistoryOn = val;
40214             return action;
40215           };
40216
40217           return action;
40218         }
40219
40220         function coreGraph(other, mutable) {
40221           if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
40222
40223           if (other instanceof coreGraph) {
40224             var base = other.base();
40225             this.entities = Object.assign(Object.create(base.entities), other.entities);
40226             this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
40227             this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
40228           } else {
40229             this.entities = Object.create({});
40230             this._parentWays = Object.create({});
40231             this._parentRels = Object.create({});
40232             this.rebase(other || [], [this]);
40233           }
40234
40235           this.transients = {};
40236           this._childNodes = {};
40237           this.frozen = !mutable;
40238         }
40239         coreGraph.prototype = {
40240           hasEntity: function hasEntity(id) {
40241             return this.entities[id];
40242           },
40243           entity: function entity(id) {
40244             var entity = this.entities[id]; //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
40245
40246             if (!entity) {
40247               entity = this.entities.__proto__[id]; // eslint-disable-line no-proto
40248             }
40249
40250             if (!entity) {
40251               throw new Error('entity ' + id + ' not found');
40252             }
40253
40254             return entity;
40255           },
40256           geometry: function geometry(id) {
40257             return this.entity(id).geometry(this);
40258           },
40259           "transient": function transient(entity, key, fn) {
40260             var id = entity.id;
40261             var transients = this.transients[id] || (this.transients[id] = {});
40262
40263             if (transients[key] !== undefined) {
40264               return transients[key];
40265             }
40266
40267             transients[key] = fn.call(entity);
40268             return transients[key];
40269           },
40270           parentWays: function parentWays(entity) {
40271             var parents = this._parentWays[entity.id];
40272             var result = [];
40273
40274             if (parents) {
40275               parents.forEach(function (id) {
40276                 result.push(this.entity(id));
40277               }, this);
40278             }
40279
40280             return result;
40281           },
40282           isPoi: function isPoi(entity) {
40283             var parents = this._parentWays[entity.id];
40284             return !parents || parents.size === 0;
40285           },
40286           isShared: function isShared(entity) {
40287             var parents = this._parentWays[entity.id];
40288             return parents && parents.size > 1;
40289           },
40290           parentRelations: function parentRelations(entity) {
40291             var parents = this._parentRels[entity.id];
40292             var result = [];
40293
40294             if (parents) {
40295               parents.forEach(function (id) {
40296                 result.push(this.entity(id));
40297               }, this);
40298             }
40299
40300             return result;
40301           },
40302           parentMultipolygons: function parentMultipolygons(entity) {
40303             return this.parentRelations(entity).filter(function (relation) {
40304               return relation.isMultipolygon();
40305             });
40306           },
40307           childNodes: function childNodes(entity) {
40308             if (this._childNodes[entity.id]) return this._childNodes[entity.id];
40309             if (!entity.nodes) return [];
40310             var nodes = [];
40311
40312             for (var i = 0; i < entity.nodes.length; i++) {
40313               nodes[i] = this.entity(entity.nodes[i]);
40314             }
40315             this._childNodes[entity.id] = nodes;
40316             return this._childNodes[entity.id];
40317           },
40318           base: function base() {
40319             return {
40320               'entities': Object.getPrototypeOf(this.entities),
40321               'parentWays': Object.getPrototypeOf(this._parentWays),
40322               'parentRels': Object.getPrototypeOf(this._parentRels)
40323             };
40324           },
40325           // Unlike other graph methods, rebase mutates in place. This is because it
40326           // is used only during the history operation that merges newly downloaded
40327           // data into each state. To external consumers, it should appear as if the
40328           // graph always contained the newly downloaded data.
40329           rebase: function rebase(entities, stack, force) {
40330             var base = this.base();
40331             var i, j, k, id;
40332
40333             for (i = 0; i < entities.length; i++) {
40334               var entity = entities[i];
40335               if (!entity.visible || !force && base.entities[entity.id]) continue; // Merging data into the base graph
40336
40337               base.entities[entity.id] = entity;
40338
40339               this._updateCalculated(undefined, entity, base.parentWays, base.parentRels); // Restore provisionally-deleted nodes that are discovered to have an extant parent
40340
40341
40342               if (entity.type === 'way') {
40343                 for (j = 0; j < entity.nodes.length; j++) {
40344                   id = entity.nodes[j];
40345
40346                   for (k = 1; k < stack.length; k++) {
40347                     var ents = stack[k].entities;
40348
40349                     if (ents.hasOwnProperty(id) && ents[id] === undefined) {
40350                       delete ents[id];
40351                     }
40352                   }
40353                 }
40354               }
40355             }
40356
40357             for (i = 0; i < stack.length; i++) {
40358               stack[i]._updateRebased();
40359             }
40360           },
40361           _updateRebased: function _updateRebased() {
40362             var base = this.base();
40363             Object.keys(this._parentWays).forEach(function (child) {
40364               if (base.parentWays[child]) {
40365                 base.parentWays[child].forEach(function (id) {
40366                   if (!this.entities.hasOwnProperty(id)) {
40367                     this._parentWays[child].add(id);
40368                   }
40369                 }, this);
40370               }
40371             }, this);
40372             Object.keys(this._parentRels).forEach(function (child) {
40373               if (base.parentRels[child]) {
40374                 base.parentRels[child].forEach(function (id) {
40375                   if (!this.entities.hasOwnProperty(id)) {
40376                     this._parentRels[child].add(id);
40377                   }
40378                 }, this);
40379               }
40380             }, this);
40381             this.transients = {}; // this._childNodes is not updated, under the assumption that
40382             // ways are always downloaded with their child nodes.
40383           },
40384           // Updates calculated properties (parentWays, parentRels) for the specified change
40385           _updateCalculated: function _updateCalculated(oldentity, entity, parentWays, parentRels) {
40386             parentWays = parentWays || this._parentWays;
40387             parentRels = parentRels || this._parentRels;
40388             var type = entity && entity.type || oldentity && oldentity.type;
40389             var removed, added, i;
40390
40391             if (type === 'way') {
40392               // Update parentWays
40393               if (oldentity && entity) {
40394                 removed = utilArrayDifference(oldentity.nodes, entity.nodes);
40395                 added = utilArrayDifference(entity.nodes, oldentity.nodes);
40396               } else if (oldentity) {
40397                 removed = oldentity.nodes;
40398                 added = [];
40399               } else if (entity) {
40400                 removed = [];
40401                 added = entity.nodes;
40402               }
40403
40404               for (i = 0; i < removed.length; i++) {
40405                 // make a copy of prototype property, store as own property, and update..
40406                 parentWays[removed[i]] = new Set(parentWays[removed[i]]);
40407                 parentWays[removed[i]]["delete"](oldentity.id);
40408               }
40409
40410               for (i = 0; i < added.length; i++) {
40411                 // make a copy of prototype property, store as own property, and update..
40412                 parentWays[added[i]] = new Set(parentWays[added[i]]);
40413                 parentWays[added[i]].add(entity.id);
40414               }
40415             } else if (type === 'relation') {
40416               // Update parentRels
40417               // diff only on the IDs since the same entity can be a member multiple times with different roles
40418               var oldentityMemberIDs = oldentity ? oldentity.members.map(function (m) {
40419                 return m.id;
40420               }) : [];
40421               var entityMemberIDs = entity ? entity.members.map(function (m) {
40422                 return m.id;
40423               }) : [];
40424
40425               if (oldentity && entity) {
40426                 removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
40427                 added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
40428               } else if (oldentity) {
40429                 removed = oldentityMemberIDs;
40430                 added = [];
40431               } else if (entity) {
40432                 removed = [];
40433                 added = entityMemberIDs;
40434               }
40435
40436               for (i = 0; i < removed.length; i++) {
40437                 // make a copy of prototype property, store as own property, and update..
40438                 parentRels[removed[i]] = new Set(parentRels[removed[i]]);
40439                 parentRels[removed[i]]["delete"](oldentity.id);
40440               }
40441
40442               for (i = 0; i < added.length; i++) {
40443                 // make a copy of prototype property, store as own property, and update..
40444                 parentRels[added[i]] = new Set(parentRels[added[i]]);
40445                 parentRels[added[i]].add(entity.id);
40446               }
40447             }
40448           },
40449           replace: function replace(entity) {
40450             if (this.entities[entity.id] === entity) return this;
40451             return this.update(function () {
40452               this._updateCalculated(this.entities[entity.id], entity);
40453
40454               this.entities[entity.id] = entity;
40455             });
40456           },
40457           remove: function remove(entity) {
40458             return this.update(function () {
40459               this._updateCalculated(entity, undefined);
40460
40461               this.entities[entity.id] = undefined;
40462             });
40463           },
40464           revert: function revert(id) {
40465             var baseEntity = this.base().entities[id];
40466             var headEntity = this.entities[id];
40467             if (headEntity === baseEntity) return this;
40468             return this.update(function () {
40469               this._updateCalculated(headEntity, baseEntity);
40470
40471               delete this.entities[id];
40472             });
40473           },
40474           update: function update() {
40475             var graph = this.frozen ? coreGraph(this, true) : this;
40476
40477             for (var i = 0; i < arguments.length; i++) {
40478               arguments[i].call(graph, graph);
40479             }
40480
40481             if (this.frozen) graph.frozen = true;
40482             return graph;
40483           },
40484           // Obliterates any existing entities
40485           load: function load(entities) {
40486             var base = this.base();
40487             this.entities = Object.create(base.entities);
40488
40489             for (var i in entities) {
40490               this.entities[i] = entities[i];
40491
40492               this._updateCalculated(base.entities[i], this.entities[i]);
40493             }
40494
40495             return this;
40496           }
40497         };
40498
40499         function osmTurn(turn) {
40500           if (!(this instanceof osmTurn)) {
40501             return new osmTurn(turn);
40502           }
40503
40504           Object.assign(this, turn);
40505         }
40506         function osmIntersection(graph, startVertexId, maxDistance) {
40507           maxDistance = maxDistance || 30; // in meters
40508
40509           var vgraph = coreGraph(); // virtual graph
40510
40511           var i, j, k;
40512
40513           function memberOfRestriction(entity) {
40514             return graph.parentRelations(entity).some(function (r) {
40515               return r.isRestriction();
40516             });
40517           }
40518
40519           function isRoad(way) {
40520             if (way.isArea() || way.isDegenerate()) return false;
40521             var roads = {
40522               'motorway': true,
40523               'motorway_link': true,
40524               'trunk': true,
40525               'trunk_link': true,
40526               'primary': true,
40527               'primary_link': true,
40528               'secondary': true,
40529               'secondary_link': true,
40530               'tertiary': true,
40531               'tertiary_link': true,
40532               'residential': true,
40533               'unclassified': true,
40534               'living_street': true,
40535               'service': true,
40536               'road': true,
40537               'track': true
40538             };
40539             return roads[way.tags.highway];
40540           }
40541
40542           var startNode = graph.entity(startVertexId);
40543           var checkVertices = [startNode];
40544           var checkWays;
40545           var vertices = [];
40546           var vertexIds = [];
40547           var vertex;
40548           var ways = [];
40549           var wayIds = [];
40550           var way;
40551           var nodes = [];
40552           var node;
40553           var parents = [];
40554           var parent; // `actions` will store whatever actions must be performed to satisfy
40555           // preconditions for adding a turn restriction to this intersection.
40556           //  - Remove any existing degenerate turn restrictions (missing from/to, etc)
40557           //  - Reverse oneways so that they are drawn in the forward direction
40558           //  - Split ways on key vertices
40559
40560           var actions = []; // STEP 1:  walk the graph outwards from starting vertex to search
40561           //  for more key vertices and ways to include in the intersection..
40562
40563           while (checkVertices.length) {
40564             vertex = checkVertices.pop(); // check this vertex for parent ways that are roads
40565
40566             checkWays = graph.parentWays(vertex);
40567             var hasWays = false;
40568
40569             for (i = 0; i < checkWays.length; i++) {
40570               way = checkWays[i];
40571               if (!isRoad(way) && !memberOfRestriction(way)) continue;
40572               ways.push(way); // it's a road, or it's already in a turn restriction
40573
40574               hasWays = true; // check the way's children for more key vertices
40575
40576               nodes = utilArrayUniq(graph.childNodes(way));
40577
40578               for (j = 0; j < nodes.length; j++) {
40579                 node = nodes[j];
40580                 if (node === vertex) continue; // same thing
40581
40582                 if (vertices.indexOf(node) !== -1) continue; // seen it already
40583
40584                 if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start
40585                 // a key vertex will have parents that are also roads
40586
40587                 var hasParents = false;
40588                 parents = graph.parentWays(node);
40589
40590                 for (k = 0; k < parents.length; k++) {
40591                   parent = parents[k];
40592                   if (parent === way) continue; // same thing
40593
40594                   if (ways.indexOf(parent) !== -1) continue; // seen it already
40595
40596                   if (!isRoad(parent)) continue; // not a road
40597
40598                   hasParents = true;
40599                   break;
40600                 }
40601
40602                 if (hasParents) {
40603                   checkVertices.push(node);
40604                 }
40605               }
40606             }
40607
40608             if (hasWays) {
40609               vertices.push(vertex);
40610             }
40611           }
40612
40613           vertices = utilArrayUniq(vertices);
40614           ways = utilArrayUniq(ways); // STEP 2:  Build a virtual graph containing only the entities in the intersection..
40615           // Everything done after this step should act on the virtual graph
40616           // Any actions that must be performed later to the main graph go in `actions` array
40617
40618           ways.forEach(function (way) {
40619             graph.childNodes(way).forEach(function (node) {
40620               vgraph = vgraph.replace(node);
40621             });
40622             vgraph = vgraph.replace(way);
40623             graph.parentRelations(way).forEach(function (relation) {
40624               if (relation.isRestriction()) {
40625                 if (relation.isValidRestriction(graph)) {
40626                   vgraph = vgraph.replace(relation);
40627                 } else if (relation.isComplete(graph)) {
40628                   actions.push(actionDeleteRelation(relation.id));
40629                 }
40630               }
40631             });
40632           }); // STEP 3:  Force all oneways to be drawn in the forward direction
40633
40634           ways.forEach(function (w) {
40635             var way = vgraph.entity(w.id);
40636
40637             if (way.tags.oneway === '-1') {
40638               var action = actionReverse(way.id, {
40639                 reverseOneway: true
40640               });
40641               actions.push(action);
40642               vgraph = action(vgraph);
40643             }
40644           }); // STEP 4:  Split ways on key vertices
40645
40646           var origCount = osmEntity.id.next.way;
40647           vertices.forEach(function (v) {
40648             // This is an odd way to do it, but we need to find all the ways that
40649             // will be split here, then split them one at a time to ensure that these
40650             // actions can be replayed on the main graph exactly in the same order.
40651             // (It is unintuitive, but the order of ways returned from graph.parentWays()
40652             // is arbitrary, depending on how the main graph and vgraph were built)
40653             var splitAll = actionSplit([v.id]).keepHistoryOn('first');
40654
40655             if (!splitAll.disabled(vgraph)) {
40656               splitAll.ways(vgraph).forEach(function (way) {
40657                 var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
40658                 actions.push(splitOne);
40659                 vgraph = splitOne(vgraph);
40660               });
40661             }
40662           }); // In here is where we should also split the intersection at nearby junction.
40663           //   for https://github.com/mapbox/iD-internal/issues/31
40664           // nearbyVertices.forEach(function(v) {
40665           // });
40666           // Reasons why we reset the way id count here:
40667           //  1. Continuity with way ids created by the splits so that we can replay
40668           //     these actions later if the user decides to create a turn restriction
40669           //  2. Avoids churning way ids just by hovering over a vertex
40670           //     and displaying the turn restriction editor
40671
40672           osmEntity.id.next.way = origCount; // STEP 5:  Update arrays to point to vgraph entities
40673
40674           vertexIds = vertices.map(function (v) {
40675             return v.id;
40676           });
40677           vertices = [];
40678           ways = [];
40679           vertexIds.forEach(function (id) {
40680             var vertex = vgraph.entity(id);
40681             var parents = vgraph.parentWays(vertex);
40682             vertices.push(vertex);
40683             ways = ways.concat(parents);
40684           });
40685           vertices = utilArrayUniq(vertices);
40686           ways = utilArrayUniq(ways);
40687           vertexIds = vertices.map(function (v) {
40688             return v.id;
40689           });
40690           wayIds = ways.map(function (w) {
40691             return w.id;
40692           }); // STEP 6:  Update the ways with some metadata that will be useful for
40693           // walking the intersection graph later and rendering turn arrows.
40694
40695           function withMetadata(way, vertexIds) {
40696             var __oneWay = way.isOneWay(); // which affixes are key vertices?
40697
40698
40699             var __first = vertexIds.indexOf(way.first()) !== -1;
40700
40701             var __last = vertexIds.indexOf(way.last()) !== -1; // what roles is this way eligible for?
40702
40703
40704             var __via = __first && __last;
40705
40706             var __from = __first && !__oneWay || __last;
40707
40708             var __to = __first || __last && !__oneWay;
40709
40710             return way.update({
40711               __first: __first,
40712               __last: __last,
40713               __from: __from,
40714               __via: __via,
40715               __to: __to,
40716               __oneWay: __oneWay
40717             });
40718           }
40719
40720           ways = [];
40721           wayIds.forEach(function (id) {
40722             var way = withMetadata(vgraph.entity(id), vertexIds);
40723             vgraph = vgraph.replace(way);
40724             ways.push(way);
40725           }); // STEP 7:  Simplify - This is an iterative process where we:
40726           //  1. Find trivial vertices with only 2 parents
40727           //  2. trim off the leaf way from those vertices and remove from vgraph
40728
40729           var keepGoing;
40730           var removeWayIds = [];
40731           var removeVertexIds = [];
40732
40733           do {
40734             keepGoing = false;
40735             checkVertices = vertexIds.slice();
40736
40737             for (i = 0; i < checkVertices.length; i++) {
40738               var vertexId = checkVertices[i];
40739               vertex = vgraph.hasEntity(vertexId);
40740
40741               if (!vertex) {
40742                 if (vertexIds.indexOf(vertexId) !== -1) {
40743                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
40744                 }
40745
40746                 removeVertexIds.push(vertexId);
40747                 continue;
40748               }
40749
40750               parents = vgraph.parentWays(vertex);
40751
40752               if (parents.length < 3) {
40753                 if (vertexIds.indexOf(vertexId) !== -1) {
40754                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
40755                 }
40756               }
40757
40758               if (parents.length === 2) {
40759                 // vertex with 2 parents is trivial
40760                 var a = parents[0];
40761                 var b = parents[1];
40762                 var aIsLeaf = a && !a.__via;
40763                 var bIsLeaf = b && !b.__via;
40764                 var leaf, survivor;
40765
40766                 if (aIsLeaf && !bIsLeaf) {
40767                   leaf = a;
40768                   survivor = b;
40769                 } else if (!aIsLeaf && bIsLeaf) {
40770                   leaf = b;
40771                   survivor = a;
40772                 }
40773
40774                 if (leaf && survivor) {
40775                   survivor = withMetadata(survivor, vertexIds); // update survivor way
40776
40777                   vgraph = vgraph.replace(survivor).remove(leaf); // update graph
40778
40779                   removeWayIds.push(leaf.id);
40780                   keepGoing = true;
40781                 }
40782               }
40783
40784               parents = vgraph.parentWays(vertex);
40785
40786               if (parents.length < 2) {
40787                 // vertex is no longer a key vertex
40788                 if (vertexIds.indexOf(vertexId) !== -1) {
40789                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
40790                 }
40791
40792                 removeVertexIds.push(vertexId);
40793                 keepGoing = true;
40794               }
40795
40796               if (parents.length < 1) {
40797                 // vertex is no longer attached to anything
40798                 vgraph = vgraph.remove(vertex);
40799               }
40800             }
40801           } while (keepGoing);
40802
40803           vertices = vertices.filter(function (vertex) {
40804             return removeVertexIds.indexOf(vertex.id) === -1;
40805           }).map(function (vertex) {
40806             return vgraph.entity(vertex.id);
40807           });
40808           ways = ways.filter(function (way) {
40809             return removeWayIds.indexOf(way.id) === -1;
40810           }).map(function (way) {
40811             return vgraph.entity(way.id);
40812           }); // OK!  Here is our intersection..
40813
40814           var intersection = {
40815             graph: vgraph,
40816             actions: actions,
40817             vertices: vertices,
40818             ways: ways
40819           }; // Get all the valid turns through this intersection given a starting way id.
40820           // This operates on the virtual graph for everything.
40821           //
40822           // Basically, walk through all possible paths from starting way,
40823           //   honoring the existing turn restrictions as we go (watch out for loops!)
40824           //
40825           // For each path found, generate and return a `osmTurn` datastructure.
40826           //
40827
40828           intersection.turns = function (fromWayId, maxViaWay) {
40829             if (!fromWayId) return [];
40830             if (!maxViaWay) maxViaWay = 0;
40831             var vgraph = intersection.graph;
40832             var keyVertexIds = intersection.vertices.map(function (v) {
40833               return v.id;
40834             });
40835             var start = vgraph.entity(fromWayId);
40836             if (!start || !(start.__from || start.__via)) return []; // maxViaWay=0   from-*-to              (0 vias)
40837             // maxViaWay=1   from-*-via-*-to        (1 via max)
40838             // maxViaWay=2   from-*-via-*-via-*-to  (2 vias max)
40839
40840             var maxPathLength = maxViaWay * 2 + 3;
40841             var turns = [];
40842             step(start);
40843             return turns; // traverse the intersection graph and find all the valid paths
40844
40845             function step(entity, currPath, currRestrictions, matchedRestriction) {
40846               currPath = (currPath || []).slice(); // shallow copy
40847
40848               if (currPath.length >= maxPathLength) return;
40849               currPath.push(entity.id);
40850               currRestrictions = (currRestrictions || []).slice(); // shallow copy
40851
40852               var i, j;
40853
40854               if (entity.type === 'node') {
40855                 var parents = vgraph.parentWays(entity);
40856                 var nextWays = []; // which ways can we step into?
40857
40858                 for (i = 0; i < parents.length; i++) {
40859                   var way = parents[i]; // if next way is a oneway incoming to this vertex, skip
40860
40861                   if (way.__oneWay && way.nodes[0] !== entity.id) continue; // if we have seen it before (allowing for an initial u-turn), skip
40862
40863                   if (currPath.indexOf(way.id) !== -1 && currPath.length >= 3) continue; // Check all "current" restrictions (where we've already walked the `FROM`)
40864
40865                   var restrict = null;
40866
40867                   for (j = 0; j < currRestrictions.length; j++) {
40868                     var restriction = currRestrictions[j];
40869                     var f = restriction.memberByRole('from');
40870                     var v = restriction.membersByRole('via');
40871                     var t = restriction.memberByRole('to');
40872                     var isOnly = /^only_/.test(restriction.tags.restriction); // Does the current path match this turn restriction?
40873
40874                     var matchesFrom = f.id === fromWayId;
40875                     var matchesViaTo = false;
40876                     var isAlongOnlyPath = false;
40877
40878                     if (t.id === way.id) {
40879                       // match TO
40880                       if (v.length === 1 && v[0].type === 'node') {
40881                         // match VIA node
40882                         matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
40883                       } else {
40884                         // match all VIA ways
40885                         var pathVias = [];
40886
40887                         for (k = 2; k < currPath.length; k += 2) {
40888                           // k = 2 skips FROM
40889                           pathVias.push(currPath[k]); // (path goes way-node-way...)
40890                         }
40891
40892                         var restrictionVias = [];
40893
40894                         for (k = 0; k < v.length; k++) {
40895                           if (v[k].type === 'way') {
40896                             restrictionVias.push(v[k].id);
40897                           }
40898                         }
40899
40900                         var diff = utilArrayDifference(pathVias, restrictionVias);
40901                         matchesViaTo = !diff.length;
40902                       }
40903                     } else if (isOnly) {
40904                       for (k = 0; k < v.length; k++) {
40905                         // way doesn't match TO, but is one of the via ways along the path of an "only"
40906                         if (v[k].type === 'way' && v[k].id === way.id) {
40907                           isAlongOnlyPath = true;
40908                           break;
40909                         }
40910                       }
40911                     }
40912
40913                     if (matchesViaTo) {
40914                       if (isOnly) {
40915                         restrict = {
40916                           id: restriction.id,
40917                           direct: matchesFrom,
40918                           from: f.id,
40919                           only: true,
40920                           end: true
40921                         };
40922                       } else {
40923                         restrict = {
40924                           id: restriction.id,
40925                           direct: matchesFrom,
40926                           from: f.id,
40927                           no: true,
40928                           end: true
40929                         };
40930                       }
40931                     } else {
40932                       // indirect - caused by a different nearby restriction
40933                       if (isAlongOnlyPath) {
40934                         restrict = {
40935                           id: restriction.id,
40936                           direct: false,
40937                           from: f.id,
40938                           only: true,
40939                           end: false
40940                         };
40941                       } else if (isOnly) {
40942                         restrict = {
40943                           id: restriction.id,
40944                           direct: false,
40945                           from: f.id,
40946                           no: true,
40947                           end: true
40948                         };
40949                       }
40950                     } // stop looking if we find a "direct" restriction (matching FROM, VIA, TO)
40951
40952
40953                     if (restrict && restrict.direct) break;
40954                   }
40955
40956                   nextWays.push({
40957                     way: way,
40958                     restrict: restrict
40959                   });
40960                 }
40961
40962                 nextWays.forEach(function (nextWay) {
40963                   step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
40964                 });
40965               } else {
40966                 // entity.type === 'way'
40967                 if (currPath.length >= 3) {
40968                   // this is a "complete" path..
40969                   var turnPath = currPath.slice(); // shallow copy
40970                   // an indirect restriction - only include the partial path (starting at FROM)
40971
40972                   if (matchedRestriction && matchedRestriction.direct === false) {
40973                     for (i = 0; i < turnPath.length; i++) {
40974                       if (turnPath[i] === matchedRestriction.from) {
40975                         turnPath = turnPath.slice(i);
40976                         break;
40977                       }
40978                     }
40979                   }
40980
40981                   var turn = pathToTurn(turnPath);
40982
40983                   if (turn) {
40984                     if (matchedRestriction) {
40985                       turn.restrictionID = matchedRestriction.id;
40986                       turn.no = matchedRestriction.no;
40987                       turn.only = matchedRestriction.only;
40988                       turn.direct = matchedRestriction.direct;
40989                     }
40990
40991                     turns.push(osmTurn(turn));
40992                   }
40993
40994                   if (currPath[0] === currPath[2]) return; // if we made a u-turn - stop here
40995                 }
40996
40997                 if (matchedRestriction && matchedRestriction.end) return; // don't advance any further
40998                 // which nodes can we step into?
40999
41000                 var n1 = vgraph.entity(entity.first());
41001                 var n2 = vgraph.entity(entity.last());
41002                 var dist = geoSphericalDistance(n1.loc, n2.loc);
41003                 var nextNodes = [];
41004
41005                 if (currPath.length > 1) {
41006                   if (dist > maxDistance) return; // the next node is too far
41007
41008                   if (!entity.__via) return; // this way is a leaf / can't be a via
41009                 }
41010
41011                 if (!entity.__oneWay && // bidirectional..
41012                 keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
41013                 currPath.indexOf(n1.id) === -1) {
41014                   // haven't seen it yet..
41015                   nextNodes.push(n1); // can advance to first node
41016                 }
41017
41018                 if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
41019                 currPath.indexOf(n2.id) === -1) {
41020                   // haven't seen it yet..
41021                   nextNodes.push(n2); // can advance to last node
41022                 }
41023
41024                 nextNodes.forEach(function (nextNode) {
41025                   // gather restrictions FROM this way
41026                   var fromRestrictions = vgraph.parentRelations(entity).filter(function (r) {
41027                     if (!r.isRestriction()) return false;
41028                     var f = r.memberByRole('from');
41029                     if (!f || f.id !== entity.id) return false;
41030                     var isOnly = /^only_/.test(r.tags.restriction);
41031                     if (!isOnly) return true; // `only_` restrictions only matter along the direction of the VIA - #4849
41032
41033                     var isOnlyVia = false;
41034                     var v = r.membersByRole('via');
41035
41036                     if (v.length === 1 && v[0].type === 'node') {
41037                       // via node
41038                       isOnlyVia = v[0].id === nextNode.id;
41039                     } else {
41040                       // via way(s)
41041                       for (var i = 0; i < v.length; i++) {
41042                         if (v[i].type !== 'way') continue;
41043                         var viaWay = vgraph.entity(v[i].id);
41044
41045                         if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
41046                           isOnlyVia = true;
41047                           break;
41048                         }
41049                       }
41050                     }
41051
41052                     return isOnlyVia;
41053                   });
41054                   step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
41055                 });
41056               }
41057             } // assumes path is alternating way-node-way of odd length
41058
41059
41060             function pathToTurn(path) {
41061               if (path.length < 3) return;
41062               var fromWayId, fromNodeId, fromVertexId;
41063               var toWayId, toNodeId, toVertexId;
41064               var viaWayIds, viaNodeId, isUturn;
41065               fromWayId = path[0];
41066               toWayId = path[path.length - 1];
41067
41068               if (path.length === 3 && fromWayId === toWayId) {
41069                 // u turn
41070                 var way = vgraph.entity(fromWayId);
41071                 if (way.__oneWay) return null;
41072                 isUturn = true;
41073                 viaNodeId = fromVertexId = toVertexId = path[1];
41074                 fromNodeId = toNodeId = adjacentNode(fromWayId, viaNodeId);
41075               } else {
41076                 isUturn = false;
41077                 fromVertexId = path[1];
41078                 fromNodeId = adjacentNode(fromWayId, fromVertexId);
41079                 toVertexId = path[path.length - 2];
41080                 toNodeId = adjacentNode(toWayId, toVertexId);
41081
41082                 if (path.length === 3) {
41083                   viaNodeId = path[1];
41084                 } else {
41085                   viaWayIds = path.filter(function (entityId) {
41086                     return entityId[0] === 'w';
41087                   });
41088                   viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1); // remove first, last
41089                 }
41090               }
41091
41092               return {
41093                 key: path.join('_'),
41094                 path: path,
41095                 from: {
41096                   node: fromNodeId,
41097                   way: fromWayId,
41098                   vertex: fromVertexId
41099                 },
41100                 via: {
41101                   node: viaNodeId,
41102                   ways: viaWayIds
41103                 },
41104                 to: {
41105                   node: toNodeId,
41106                   way: toWayId,
41107                   vertex: toVertexId
41108                 },
41109                 u: isUturn
41110               };
41111
41112               function adjacentNode(wayId, affixId) {
41113                 var nodes = vgraph.entity(wayId).nodes;
41114                 return affixId === nodes[0] ? nodes[1] : nodes[nodes.length - 2];
41115               }
41116             }
41117           };
41118
41119           return intersection;
41120         }
41121         function osmInferRestriction(graph, turn, projection) {
41122           var fromWay = graph.entity(turn.from.way);
41123           var fromNode = graph.entity(turn.from.node);
41124           var fromVertex = graph.entity(turn.from.vertex);
41125           var toWay = graph.entity(turn.to.way);
41126           var toNode = graph.entity(turn.to.node);
41127           var toVertex = graph.entity(turn.to.vertex);
41128           var fromOneWay = fromWay.tags.oneway === 'yes';
41129           var toOneWay = toWay.tags.oneway === 'yes';
41130           var angle = (geoAngle(fromVertex, fromNode, projection) - geoAngle(toVertex, toNode, projection)) * 180 / Math.PI;
41131
41132           while (angle < 0) {
41133             angle += 360;
41134           }
41135
41136           if (fromNode === toNode) {
41137             return 'no_u_turn';
41138           }
41139
41140           if ((angle < 23 || angle > 336) && fromOneWay && toOneWay) {
41141             return 'no_u_turn'; // wider tolerance for u-turn if both ways are oneway
41142           }
41143
41144           if ((angle < 40 || angle > 319) && fromOneWay && toOneWay && turn.from.vertex !== turn.to.vertex) {
41145             return 'no_u_turn'; // even wider tolerance for u-turn if there is a via way (from !== to)
41146           }
41147
41148           if (angle < 158) {
41149             return 'no_right_turn';
41150           }
41151
41152           if (angle > 202) {
41153             return 'no_left_turn';
41154           }
41155
41156           return 'no_straight_on';
41157         }
41158
41159         function actionMergePolygon(ids, newRelationId) {
41160           function groupEntities(graph) {
41161             var entities = ids.map(function (id) {
41162               return graph.entity(id);
41163             });
41164             var geometryGroups = utilArrayGroupBy(entities, function (entity) {
41165               if (entity.type === 'way' && entity.isClosed()) {
41166                 return 'closedWay';
41167               } else if (entity.type === 'relation' && entity.isMultipolygon()) {
41168                 return 'multipolygon';
41169               } else {
41170                 return 'other';
41171               }
41172             });
41173             return Object.assign({
41174               closedWay: [],
41175               multipolygon: [],
41176               other: []
41177             }, geometryGroups);
41178           }
41179
41180           var action = function action(graph) {
41181             var entities = groupEntities(graph); // An array representing all the polygons that are part of the multipolygon.
41182             //
41183             // Each element is itself an array of objects with an id property, and has a
41184             // locs property which is an array of the locations forming the polygon.
41185
41186             var polygons = entities.multipolygon.reduce(function (polygons, m) {
41187               return polygons.concat(osmJoinWays(m.members, graph));
41188             }, []).concat(entities.closedWay.map(function (d) {
41189               var member = [{
41190                 id: d.id
41191               }];
41192               member.nodes = graph.childNodes(d);
41193               return member;
41194             })); // contained is an array of arrays of boolean values,
41195             // where contained[j][k] is true iff the jth way is
41196             // contained by the kth way.
41197
41198             var contained = polygons.map(function (w, i) {
41199               return polygons.map(function (d, n) {
41200                 if (i === n) return null;
41201                 return geoPolygonContainsPolygon(d.nodes.map(function (n) {
41202                   return n.loc;
41203                 }), w.nodes.map(function (n) {
41204                   return n.loc;
41205                 }));
41206               });
41207             }); // Sort all polygons as either outer or inner ways
41208
41209             var members = [];
41210             var outer = true;
41211
41212             while (polygons.length) {
41213               extractUncontained(polygons);
41214               polygons = polygons.filter(isContained);
41215               contained = contained.filter(isContained).map(filterContained);
41216             }
41217
41218             function isContained(d, i) {
41219               return contained[i].some(function (val) {
41220                 return val;
41221               });
41222             }
41223
41224             function filterContained(d) {
41225               return d.filter(isContained);
41226             }
41227
41228             function extractUncontained(polygons) {
41229               polygons.forEach(function (d, i) {
41230                 if (!isContained(d, i)) {
41231                   d.forEach(function (member) {
41232                     members.push({
41233                       type: 'way',
41234                       id: member.id,
41235                       role: outer ? 'outer' : 'inner'
41236                     });
41237                   });
41238                 }
41239               });
41240               outer = !outer;
41241             } // Move all tags to one relation
41242
41243
41244             var relation = entities.multipolygon[0] || osmRelation({
41245               id: newRelationId,
41246               tags: {
41247                 type: 'multipolygon'
41248               }
41249             });
41250             entities.multipolygon.slice(1).forEach(function (m) {
41251               relation = relation.mergeTags(m.tags);
41252               graph = graph.remove(m);
41253             });
41254             entities.closedWay.forEach(function (way) {
41255               function isThisOuter(m) {
41256                 return m.id === way.id && m.role !== 'inner';
41257               }
41258
41259               if (members.some(isThisOuter)) {
41260                 relation = relation.mergeTags(way.tags);
41261                 graph = graph.replace(way.update({
41262                   tags: {}
41263                 }));
41264               }
41265             });
41266             return graph.replace(relation.update({
41267               members: members,
41268               tags: utilObjectOmit(relation.tags, ['area'])
41269             }));
41270           };
41271
41272           action.disabled = function (graph) {
41273             var entities = groupEntities(graph);
41274
41275             if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
41276               return 'not_eligible';
41277             }
41278
41279             if (!entities.multipolygon.every(function (r) {
41280               return r.isComplete(graph);
41281             })) {
41282               return 'incomplete_relation';
41283             }
41284
41285             if (!entities.multipolygon.length) {
41286               var sharedMultipolygons = [];
41287               entities.closedWay.forEach(function (way, i) {
41288                 if (i === 0) {
41289                   sharedMultipolygons = graph.parentMultipolygons(way);
41290                 } else {
41291                   sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
41292                 }
41293               });
41294               sharedMultipolygons = sharedMultipolygons.filter(function (relation) {
41295                 return relation.members.length === entities.closedWay.length;
41296               });
41297
41298               if (sharedMultipolygons.length) {
41299                 // don't create a new multipolygon if it'd be redundant
41300                 return 'not_eligible';
41301               }
41302             } else if (entities.closedWay.some(function (way) {
41303               return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
41304             })) {
41305               // don't add a way to a multipolygon again if it's already a member
41306               return 'not_eligible';
41307             }
41308           };
41309
41310           return action;
41311         }
41312
41313         var DESCRIPTORS = descriptors;
41314         var objectDefinePropertyModule = objectDefineProperty;
41315         var regExpFlags = regexpFlags$1;
41316         var fails$4 = fails$N;
41317
41318         var FORCED$2 = DESCRIPTORS && fails$4(function () {
41319           // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
41320           return Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags').get.call({ dotAll: true, sticky: true }) !== 'sy';
41321         });
41322
41323         // `RegExp.prototype.flags` getter
41324         // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
41325         if (FORCED$2) objectDefinePropertyModule.f(RegExp.prototype, 'flags', {
41326           configurable: true,
41327           get: regExpFlags
41328         });
41329
41330         var fastDeepEqual = function equal(a, b) {
41331           if (a === b) return true;
41332
41333           if (a && b && _typeof(a) == 'object' && _typeof(b) == 'object') {
41334             if (a.constructor !== b.constructor) return false;
41335             var length, i, keys;
41336
41337             if (Array.isArray(a)) {
41338               length = a.length;
41339               if (length != b.length) return false;
41340
41341               for (i = length; i-- !== 0;) {
41342                 if (!equal(a[i], b[i])) return false;
41343               }
41344
41345               return true;
41346             }
41347
41348             if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
41349             if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
41350             if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
41351             keys = Object.keys(a);
41352             length = keys.length;
41353             if (length !== Object.keys(b).length) return false;
41354
41355             for (i = length; i-- !== 0;) {
41356               if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
41357             }
41358
41359             for (i = length; i-- !== 0;) {
41360               var key = keys[i];
41361               if (!equal(a[key], b[key])) return false;
41362             }
41363
41364             return true;
41365           } // true if both NaN, false otherwise
41366
41367
41368           return a !== a && b !== b;
41369         };
41370
41371         // J. W. Hunt and M. D. McIlroy, An algorithm for differential buffer
41372         // comparison, Bell Telephone Laboratories CSTR #41 (1976)
41373         // http://www.cs.dartmouth.edu/~doug/
41374         // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
41375         //
41376         // Expects two arrays, finds longest common sequence
41377
41378         function LCS(buffer1, buffer2) {
41379           var equivalenceClasses = {};
41380
41381           for (var j = 0; j < buffer2.length; j++) {
41382             var item = buffer2[j];
41383
41384             if (equivalenceClasses[item]) {
41385               equivalenceClasses[item].push(j);
41386             } else {
41387               equivalenceClasses[item] = [j];
41388             }
41389           }
41390
41391           var NULLRESULT = {
41392             buffer1index: -1,
41393             buffer2index: -1,
41394             chain: null
41395           };
41396           var candidates = [NULLRESULT];
41397
41398           for (var i = 0; i < buffer1.length; i++) {
41399             var _item = buffer1[i];
41400             var buffer2indices = equivalenceClasses[_item] || [];
41401             var r = 0;
41402             var c = candidates[0];
41403
41404             for (var jx = 0; jx < buffer2indices.length; jx++) {
41405               var _j = buffer2indices[jx];
41406               var s = void 0;
41407
41408               for (s = r; s < candidates.length; s++) {
41409                 if (candidates[s].buffer2index < _j && (s === candidates.length - 1 || candidates[s + 1].buffer2index > _j)) {
41410                   break;
41411                 }
41412               }
41413
41414               if (s < candidates.length) {
41415                 var newCandidate = {
41416                   buffer1index: i,
41417                   buffer2index: _j,
41418                   chain: candidates[s]
41419                 };
41420
41421                 if (r === candidates.length) {
41422                   candidates.push(c);
41423                 } else {
41424                   candidates[r] = c;
41425                 }
41426
41427                 r = s + 1;
41428                 c = newCandidate;
41429
41430                 if (r === candidates.length) {
41431                   break; // no point in examining further (j)s
41432                 }
41433               }
41434             }
41435
41436             candidates[r] = c;
41437           } // At this point, we know the LCS: it's in the reverse of the
41438           // linked-list through .chain of candidates[candidates.length - 1].
41439
41440
41441           return candidates[candidates.length - 1];
41442         } // We apply the LCS to build a 'comm'-style picture of the
41443         // offsets and lengths of mismatched chunks in the input
41444         // buffers. This is used by diff3MergeRegions.
41445
41446
41447         function diffIndices(buffer1, buffer2) {
41448           var lcs = LCS(buffer1, buffer2);
41449           var result = [];
41450           var tail1 = buffer1.length;
41451           var tail2 = buffer2.length;
41452
41453           for (var candidate = lcs; candidate !== null; candidate = candidate.chain) {
41454             var mismatchLength1 = tail1 - candidate.buffer1index - 1;
41455             var mismatchLength2 = tail2 - candidate.buffer2index - 1;
41456             tail1 = candidate.buffer1index;
41457             tail2 = candidate.buffer2index;
41458
41459             if (mismatchLength1 || mismatchLength2) {
41460               result.push({
41461                 buffer1: [tail1 + 1, mismatchLength1],
41462                 buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
41463                 buffer2: [tail2 + 1, mismatchLength2],
41464                 buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
41465               });
41466             }
41467           }
41468
41469           result.reverse();
41470           return result;
41471         } // We apply the LCS to build a JSON representation of a
41472         // independently derived from O, returns a fairly complicated
41473         // internal representation of merge decisions it's taken. The
41474         // interested reader may wish to consult
41475         //
41476         // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce.
41477         // 'A Formal Investigation of ' In Arvind and Prasad,
41478         // editors, Foundations of Software Technology and Theoretical
41479         // Computer Science (FSTTCS), December 2007.
41480         //
41481         // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
41482         //
41483
41484
41485         function diff3MergeRegions(a, o, b) {
41486           // "hunks" are array subsets where `a` or `b` are different from `o`
41487           // https://www.gnu.org/software/diffutils/manual/html_node/diff3-Hunks.html
41488           var hunks = [];
41489
41490           function addHunk(h, ab) {
41491             hunks.push({
41492               ab: ab,
41493               oStart: h.buffer1[0],
41494               oLength: h.buffer1[1],
41495               // length of o to remove
41496               abStart: h.buffer2[0],
41497               abLength: h.buffer2[1] // length of a/b to insert
41498               // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
41499
41500             });
41501           }
41502
41503           diffIndices(o, a).forEach(function (item) {
41504             return addHunk(item, 'a');
41505           });
41506           diffIndices(o, b).forEach(function (item) {
41507             return addHunk(item, 'b');
41508           });
41509           hunks.sort(function (x, y) {
41510             return x.oStart - y.oStart;
41511           });
41512           var results = [];
41513           var currOffset = 0;
41514
41515           function advanceTo(endOffset) {
41516             if (endOffset > currOffset) {
41517               results.push({
41518                 stable: true,
41519                 buffer: 'o',
41520                 bufferStart: currOffset,
41521                 bufferLength: endOffset - currOffset,
41522                 bufferContent: o.slice(currOffset, endOffset)
41523               });
41524               currOffset = endOffset;
41525             }
41526           }
41527
41528           while (hunks.length) {
41529             var hunk = hunks.shift();
41530             var regionStart = hunk.oStart;
41531             var regionEnd = hunk.oStart + hunk.oLength;
41532             var regionHunks = [hunk];
41533             advanceTo(regionStart); // Try to pull next overlapping hunk into this region
41534
41535             while (hunks.length) {
41536               var nextHunk = hunks[0];
41537               var nextHunkStart = nextHunk.oStart;
41538               if (nextHunkStart > regionEnd) break; // no overlap
41539
41540               regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
41541               regionHunks.push(hunks.shift());
41542             }
41543
41544             if (regionHunks.length === 1) {
41545               // Only one hunk touches this region, meaning that there is no conflict here.
41546               // Either `a` or `b` is inserting into a region of `o` unchanged by the other.
41547               if (hunk.abLength > 0) {
41548                 var buffer = hunk.ab === 'a' ? a : b;
41549                 results.push({
41550                   stable: true,
41551                   buffer: hunk.ab,
41552                   bufferStart: hunk.abStart,
41553                   bufferLength: hunk.abLength,
41554                   bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
41555                 });
41556               }
41557             } else {
41558               // A true a/b conflict. Determine the bounds involved from `a`, `o`, and `b`.
41559               // Effectively merge all the `a` hunks into one giant hunk, then do the
41560               // same for the `b` hunks; then, correct for skew in the regions of `o`
41561               // that each side changed, and report appropriate spans for the three sides.
41562               var bounds = {
41563                 a: [a.length, -1, o.length, -1],
41564                 b: [b.length, -1, o.length, -1]
41565               };
41566
41567               while (regionHunks.length) {
41568                 hunk = regionHunks.shift();
41569                 var oStart = hunk.oStart;
41570                 var oEnd = oStart + hunk.oLength;
41571                 var abStart = hunk.abStart;
41572                 var abEnd = abStart + hunk.abLength;
41573                 var _b = bounds[hunk.ab];
41574                 _b[0] = Math.min(abStart, _b[0]);
41575                 _b[1] = Math.max(abEnd, _b[1]);
41576                 _b[2] = Math.min(oStart, _b[2]);
41577                 _b[3] = Math.max(oEnd, _b[3]);
41578               }
41579
41580               var aStart = bounds.a[0] + (regionStart - bounds.a[2]);
41581               var aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
41582               var bStart = bounds.b[0] + (regionStart - bounds.b[2]);
41583               var bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
41584               var result = {
41585                 stable: false,
41586                 aStart: aStart,
41587                 aLength: aEnd - aStart,
41588                 aContent: a.slice(aStart, aEnd),
41589                 oStart: regionStart,
41590                 oLength: regionEnd - regionStart,
41591                 oContent: o.slice(regionStart, regionEnd),
41592                 bStart: bStart,
41593                 bLength: bEnd - bStart,
41594                 bContent: b.slice(bStart, bEnd)
41595               };
41596               results.push(result);
41597             }
41598
41599             currOffset = regionEnd;
41600           }
41601
41602           advanceTo(o.length);
41603           return results;
41604         } // Applies the output of diff3MergeRegions to actually
41605         // construct the merged buffer; the returned result alternates
41606         // between 'ok' and 'conflict' blocks.
41607         // A "false conflict" is where `a` and `b` both change the same from `o`
41608
41609
41610         function diff3Merge(a, o, b, options) {
41611           var defaults = {
41612             excludeFalseConflicts: true,
41613             stringSeparator: /\s+/
41614           };
41615           options = Object.assign(defaults, options);
41616           var aString = typeof a === 'string';
41617           var oString = typeof o === 'string';
41618           var bString = typeof b === 'string';
41619           if (aString) a = a.split(options.stringSeparator);
41620           if (oString) o = o.split(options.stringSeparator);
41621           if (bString) b = b.split(options.stringSeparator);
41622           var results = [];
41623           var regions = diff3MergeRegions(a, o, b);
41624           var okBuffer = [];
41625
41626           function flushOk() {
41627             if (okBuffer.length) {
41628               results.push({
41629                 ok: okBuffer
41630               });
41631             }
41632
41633             okBuffer = [];
41634           }
41635
41636           function isFalseConflict(a, b) {
41637             if (a.length !== b.length) return false;
41638
41639             for (var i = 0; i < a.length; i++) {
41640               if (a[i] !== b[i]) return false;
41641             }
41642
41643             return true;
41644           }
41645
41646           regions.forEach(function (region) {
41647             if (region.stable) {
41648               var _okBuffer;
41649
41650               (_okBuffer = okBuffer).push.apply(_okBuffer, _toConsumableArray(region.bufferContent));
41651             } else {
41652               if (options.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
41653                 var _okBuffer2;
41654
41655                 (_okBuffer2 = okBuffer).push.apply(_okBuffer2, _toConsumableArray(region.aContent));
41656               } else {
41657                 flushOk();
41658                 results.push({
41659                   conflict: {
41660                     a: region.aContent,
41661                     aIndex: region.aStart,
41662                     o: region.oContent,
41663                     oIndex: region.oStart,
41664                     b: region.bContent,
41665                     bIndex: region.bStart
41666                   }
41667                 });
41668               }
41669             }
41670           });
41671           flushOk();
41672           return results;
41673         }
41674
41675         function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTags, formatUser) {
41676           discardTags = discardTags || {};
41677           var _option = 'safe'; // 'safe', 'force_local', 'force_remote'
41678
41679           var _conflicts = [];
41680
41681           function user(d) {
41682             return typeof formatUser === 'function' ? formatUser(d) : d;
41683           }
41684
41685           function mergeLocation(remote, target) {
41686             function pointEqual(a, b) {
41687               var epsilon = 1e-6;
41688               return Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon;
41689             }
41690
41691             if (_option === 'force_local' || pointEqual(target.loc, remote.loc)) {
41692               return target;
41693             }
41694
41695             if (_option === 'force_remote') {
41696               return target.update({
41697                 loc: remote.loc
41698               });
41699             }
41700
41701             _conflicts.push(_t('merge_remote_changes.conflict.location', {
41702               user: user(remote.user)
41703             }));
41704
41705             return target;
41706           }
41707
41708           function mergeNodes(base, remote, target) {
41709             if (_option === 'force_local' || fastDeepEqual(target.nodes, remote.nodes)) {
41710               return target;
41711             }
41712
41713             if (_option === 'force_remote') {
41714               return target.update({
41715                 nodes: remote.nodes
41716               });
41717             }
41718
41719             var ccount = _conflicts.length;
41720             var o = base.nodes || [];
41721             var a = target.nodes || [];
41722             var b = remote.nodes || [];
41723             var nodes = [];
41724             var hunks = diff3Merge(a, o, b, {
41725               excludeFalseConflicts: true
41726             });
41727
41728             for (var i = 0; i < hunks.length; i++) {
41729               var hunk = hunks[i];
41730
41731               if (hunk.ok) {
41732                 nodes.push.apply(nodes, hunk.ok);
41733               } else {
41734                 // for all conflicts, we can assume c.a !== c.b
41735                 // because `diff3Merge` called with `true` option to exclude false conflicts..
41736                 var c = hunk.conflict;
41737
41738                 if (fastDeepEqual(c.o, c.a)) {
41739                   // only changed remotely
41740                   nodes.push.apply(nodes, c.b);
41741                 } else if (fastDeepEqual(c.o, c.b)) {
41742                   // only changed locally
41743                   nodes.push.apply(nodes, c.a);
41744                 } else {
41745                   // changed both locally and remotely
41746                   _conflicts.push(_t('merge_remote_changes.conflict.nodelist', {
41747                     user: user(remote.user)
41748                   }));
41749
41750                   break;
41751                 }
41752               }
41753             }
41754
41755             return _conflicts.length === ccount ? target.update({
41756               nodes: nodes
41757             }) : target;
41758           }
41759
41760           function mergeChildren(targetWay, children, updates, graph) {
41761             function isUsed(node, targetWay) {
41762               var hasInterestingParent = graph.parentWays(node).some(function (way) {
41763                 return way.id !== targetWay.id;
41764               });
41765               return node.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node).length > 0;
41766             }
41767
41768             var ccount = _conflicts.length;
41769
41770             for (var i = 0; i < children.length; i++) {
41771               var id = children[i];
41772               var node = graph.hasEntity(id); // remove unused childNodes..
41773
41774               if (targetWay.nodes.indexOf(id) === -1) {
41775                 if (node && !isUsed(node, targetWay)) {
41776                   updates.removeIds.push(id);
41777                 }
41778
41779                 continue;
41780               } // restore used childNodes..
41781
41782
41783               var local = localGraph.hasEntity(id);
41784               var remote = remoteGraph.hasEntity(id);
41785               var target;
41786
41787               if (_option === 'force_remote' && remote && remote.visible) {
41788                 updates.replacements.push(remote);
41789               } else if (_option === 'force_local' && local) {
41790                 target = osmEntity(local);
41791
41792                 if (remote) {
41793                   target = target.update({
41794                     version: remote.version
41795                   });
41796                 }
41797
41798                 updates.replacements.push(target);
41799               } else if (_option === 'safe' && local && remote && local.version !== remote.version) {
41800                 target = osmEntity(local, {
41801                   version: remote.version
41802                 });
41803
41804                 if (remote.visible) {
41805                   target = mergeLocation(remote, target);
41806                 } else {
41807                   _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
41808                     user: user(remote.user)
41809                   }));
41810                 }
41811
41812                 if (_conflicts.length !== ccount) break;
41813                 updates.replacements.push(target);
41814               }
41815             }
41816
41817             return targetWay;
41818           }
41819
41820           function updateChildren(updates, graph) {
41821             for (var i = 0; i < updates.replacements.length; i++) {
41822               graph = graph.replace(updates.replacements[i]);
41823             }
41824
41825             if (updates.removeIds.length) {
41826               graph = actionDeleteMultiple(updates.removeIds)(graph);
41827             }
41828
41829             return graph;
41830           }
41831
41832           function mergeMembers(remote, target) {
41833             if (_option === 'force_local' || fastDeepEqual(target.members, remote.members)) {
41834               return target;
41835             }
41836
41837             if (_option === 'force_remote') {
41838               return target.update({
41839                 members: remote.members
41840               });
41841             }
41842
41843             _conflicts.push(_t('merge_remote_changes.conflict.memberlist', {
41844               user: user(remote.user)
41845             }));
41846
41847             return target;
41848           }
41849
41850           function mergeTags(base, remote, target) {
41851             if (_option === 'force_local' || fastDeepEqual(target.tags, remote.tags)) {
41852               return target;
41853             }
41854
41855             if (_option === 'force_remote') {
41856               return target.update({
41857                 tags: remote.tags
41858               });
41859             }
41860
41861             var ccount = _conflicts.length;
41862             var o = base.tags || {};
41863             var a = target.tags || {};
41864             var b = remote.tags || {};
41865             var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function (k) {
41866               return !discardTags[k];
41867             });
41868             var tags = Object.assign({}, a); // shallow copy
41869
41870             var changed = false;
41871
41872             for (var i = 0; i < keys.length; i++) {
41873               var k = keys[i];
41874
41875               if (o[k] !== b[k] && a[k] !== b[k]) {
41876                 // changed remotely..
41877                 if (o[k] !== a[k]) {
41878                   // changed locally..
41879                   _conflicts.push(_t('merge_remote_changes.conflict.tags', {
41880                     tag: k,
41881                     local: a[k],
41882                     remote: b[k],
41883                     user: user(remote.user)
41884                   }));
41885                 } else {
41886                   // unchanged locally, accept remote change..
41887                   if (b.hasOwnProperty(k)) {
41888                     tags[k] = b[k];
41889                   } else {
41890                     delete tags[k];
41891                   }
41892
41893                   changed = true;
41894                 }
41895               }
41896             }
41897
41898             return changed && _conflicts.length === ccount ? target.update({
41899               tags: tags
41900             }) : target;
41901           } //  `graph.base()` is the common ancestor of the two graphs.
41902           //  `localGraph` contains user's edits up to saving
41903           //  `remoteGraph` contains remote edits to modified nodes
41904           //  `graph` must be a descendent of `localGraph` and may include
41905           //      some conflict resolution actions performed on it.
41906           //
41907           //                  --- ... --- `localGraph` -- ... -- `graph`
41908           //                 /
41909           //  `graph.base()` --- ... --- `remoteGraph`
41910           //
41911
41912
41913           var action = function action(graph) {
41914             var updates = {
41915               replacements: [],
41916               removeIds: []
41917             };
41918             var base = graph.base().entities[id];
41919             var local = localGraph.entity(id);
41920             var remote = remoteGraph.entity(id);
41921             var target = osmEntity(local, {
41922               version: remote.version
41923             }); // delete/undelete
41924
41925             if (!remote.visible) {
41926               if (_option === 'force_remote') {
41927                 return actionDeleteMultiple([id])(graph);
41928               } else if (_option === 'force_local') {
41929                 if (target.type === 'way') {
41930                   target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
41931                   graph = updateChildren(updates, graph);
41932                 }
41933
41934                 return graph.replace(target);
41935               } else {
41936                 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
41937                   user: user(remote.user)
41938                 }));
41939
41940                 return graph; // do nothing
41941               }
41942             } // merge
41943
41944
41945             if (target.type === 'node') {
41946               target = mergeLocation(remote, target);
41947             } else if (target.type === 'way') {
41948               // pull in any child nodes that may not be present locally..
41949               graph.rebase(remoteGraph.childNodes(remote), [graph], false);
41950               target = mergeNodes(base, remote, target);
41951               target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
41952             } else if (target.type === 'relation') {
41953               target = mergeMembers(remote, target);
41954             }
41955
41956             target = mergeTags(base, remote, target);
41957
41958             if (!_conflicts.length) {
41959               graph = updateChildren(updates, graph).replace(target);
41960             }
41961
41962             return graph;
41963           };
41964
41965           action.withOption = function (opt) {
41966             _option = opt;
41967             return action;
41968           };
41969
41970           action.conflicts = function () {
41971             return _conflicts;
41972           };
41973
41974           return action;
41975         }
41976
41977         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
41978
41979         function actionMove(moveIDs, tryDelta, projection, cache) {
41980           var _delta = tryDelta;
41981
41982           function setupCache(graph) {
41983             function canMove(nodeID) {
41984               // Allow movement of any node that is in the selectedIDs list..
41985               if (moveIDs.indexOf(nodeID) !== -1) return true; // Allow movement of a vertex where 2 ways meet..
41986
41987               var parents = graph.parentWays(graph.entity(nodeID));
41988               if (parents.length < 3) return true; // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
41989
41990               var parentsMoving = parents.every(function (way) {
41991                 return cache.moving[way.id];
41992               });
41993               if (!parentsMoving) delete cache.moving[nodeID];
41994               return parentsMoving;
41995             }
41996
41997             function cacheEntities(ids) {
41998               for (var i = 0; i < ids.length; i++) {
41999                 var id = ids[i];
42000                 if (cache.moving[id]) continue;
42001                 cache.moving[id] = true;
42002                 var entity = graph.hasEntity(id);
42003                 if (!entity) continue;
42004
42005                 if (entity.type === 'node') {
42006                   cache.nodes.push(id);
42007                   cache.startLoc[id] = entity.loc;
42008                 } else if (entity.type === 'way') {
42009                   cache.ways.push(id);
42010                   cacheEntities(entity.nodes);
42011                 } else {
42012                   cacheEntities(entity.members.map(function (member) {
42013                     return member.id;
42014                   }));
42015                 }
42016               }
42017             }
42018
42019             function cacheIntersections(ids) {
42020               function isEndpoint(way, id) {
42021                 return !way.isClosed() && !!way.affix(id);
42022               }
42023
42024               for (var i = 0; i < ids.length; i++) {
42025                 var id = ids[i]; // consider only intersections with 1 moved and 1 unmoved way.
42026
42027                 var childNodes = graph.childNodes(graph.entity(id));
42028
42029                 for (var j = 0; j < childNodes.length; j++) {
42030                   var node = childNodes[j];
42031                   var parents = graph.parentWays(node);
42032                   if (parents.length !== 2) continue;
42033                   var moved = graph.entity(id);
42034                   var unmoved = null;
42035
42036                   for (var k = 0; k < parents.length; k++) {
42037                     var way = parents[k];
42038
42039                     if (!cache.moving[way.id]) {
42040                       unmoved = way;
42041                       break;
42042                     }
42043                   }
42044
42045                   if (!unmoved) continue; // exclude ways that are overly connected..
42046
42047                   if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
42048                   if (moved.isArea() || unmoved.isArea()) continue;
42049                   cache.intersections.push({
42050                     nodeId: node.id,
42051                     movedId: moved.id,
42052                     unmovedId: unmoved.id,
42053                     movedIsEP: isEndpoint(moved, node.id),
42054                     unmovedIsEP: isEndpoint(unmoved, node.id)
42055                   });
42056                 }
42057               }
42058             }
42059
42060             if (!cache) {
42061               cache = {};
42062             }
42063
42064             if (!cache.ok) {
42065               cache.moving = {};
42066               cache.intersections = [];
42067               cache.replacedVertex = {};
42068               cache.startLoc = {};
42069               cache.nodes = [];
42070               cache.ways = [];
42071               cacheEntities(moveIDs);
42072               cacheIntersections(cache.ways);
42073               cache.nodes = cache.nodes.filter(canMove);
42074               cache.ok = true;
42075             }
42076           } // Place a vertex where the moved vertex used to be, to preserve way shape..
42077           //
42078           //  Start:
42079           //      b ---- e
42080           //     / \
42081           //    /   \
42082           //   /     \
42083           //  a       c
42084           //
42085           //      *               node '*' added to preserve shape
42086           //     / \
42087           //    /   b ---- e      way `b,e` moved here:
42088           //   /     \
42089           //  a       c
42090           //
42091           //
42092
42093
42094           function replaceMovedVertex(nodeId, wayId, graph, delta) {
42095             var way = graph.entity(wayId);
42096             var moved = graph.entity(nodeId);
42097             var movedIndex = way.nodes.indexOf(nodeId);
42098             var len, prevIndex, nextIndex;
42099
42100             if (way.isClosed()) {
42101               len = way.nodes.length - 1;
42102               prevIndex = (movedIndex + len - 1) % len;
42103               nextIndex = (movedIndex + len + 1) % len;
42104             } else {
42105               len = way.nodes.length;
42106               prevIndex = movedIndex - 1;
42107               nextIndex = movedIndex + 1;
42108             }
42109
42110             var prev = graph.hasEntity(way.nodes[prevIndex]);
42111             var next = graph.hasEntity(way.nodes[nextIndex]); // Don't add orig vertex at endpoint..
42112
42113             if (!prev || !next) return graph;
42114             var key = wayId + '_' + nodeId;
42115             var orig = cache.replacedVertex[key];
42116
42117             if (!orig) {
42118               orig = osmNode();
42119               cache.replacedVertex[key] = orig;
42120               cache.startLoc[orig.id] = cache.startLoc[nodeId];
42121             }
42122
42123             var start, end;
42124
42125             if (delta) {
42126               start = projection(cache.startLoc[nodeId]);
42127               end = projection.invert(geoVecAdd(start, delta));
42128             } else {
42129               end = cache.startLoc[nodeId];
42130             }
42131
42132             orig = orig.move(end);
42133             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..
42134
42135             if (angle > 175 && angle < 185) return graph; // moving forward or backward along way?
42136
42137             var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection);
42138             var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection);
42139             var d1 = geoPathLength(p1);
42140             var d2 = geoPathLength(p2);
42141             var insertAt = d1 <= d2 ? movedIndex : nextIndex; // moving around closed loop?
42142
42143             if (way.isClosed() && insertAt === 0) insertAt = len;
42144             way = way.addNode(orig.id, insertAt);
42145             return graph.replace(orig).replace(way);
42146           } // Remove duplicate vertex that might have been added by
42147           // replaceMovedVertex.  This is done after the unzorro checks.
42148
42149
42150           function removeDuplicateVertices(wayId, graph) {
42151             var way = graph.entity(wayId);
42152             var epsilon = 1e-6;
42153             var prev, curr;
42154
42155             function isInteresting(node, graph) {
42156               return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
42157             }
42158
42159             for (var i = 0; i < way.nodes.length; i++) {
42160               curr = graph.entity(way.nodes[i]);
42161
42162               if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon)) {
42163                 if (!isInteresting(prev, graph)) {
42164                   way = way.removeNode(prev.id);
42165                   graph = graph.replace(way).remove(prev);
42166                 } else if (!isInteresting(curr, graph)) {
42167                   way = way.removeNode(curr.id);
42168                   graph = graph.replace(way).remove(curr);
42169                 }
42170               }
42171
42172               prev = curr;
42173             }
42174
42175             return graph;
42176           } // Reorder nodes around intersections that have moved..
42177           //
42178           //  Start:                way1.nodes: b,e         (moving)
42179           //  a - b - c ----- d     way2.nodes: a,b,c,d     (static)
42180           //      |                 vertex: b
42181           //      e                 isEP1: true,  isEP2, false
42182           //
42183           //  way1 `b,e` moved here:
42184           //  a ----- c = b - d
42185           //              |
42186           //              e
42187           //
42188           //  reorder nodes         way1.nodes: b,e
42189           //  a ----- c - b - d     way2.nodes: a,c,b,d
42190           //              |
42191           //              e
42192           //
42193
42194
42195           function unZorroIntersection(intersection, graph) {
42196             var vertex = graph.entity(intersection.nodeId);
42197             var way1 = graph.entity(intersection.movedId);
42198             var way2 = graph.entity(intersection.unmovedId);
42199             var isEP1 = intersection.movedIsEP;
42200             var isEP2 = intersection.unmovedIsEP; // don't move the vertex if it is the endpoint of both ways.
42201
42202             if (isEP1 && isEP2) return graph;
42203             var nodes1 = graph.childNodes(way1).filter(function (n) {
42204               return n !== vertex;
42205             });
42206             var nodes2 = graph.childNodes(way2).filter(function (n) {
42207               return n !== vertex;
42208             });
42209             if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
42210             if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
42211             var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection);
42212             var edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection);
42213             var loc; // snap vertex to nearest edge (or some point between them)..
42214
42215             if (!isEP1 && !isEP2) {
42216               var epsilon = 1e-6,
42217                   maxIter = 10;
42218
42219               for (var i = 0; i < maxIter; i++) {
42220                 loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
42221                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
42222                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
42223                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
42224               }
42225             } else if (!isEP1) {
42226               loc = edge1.loc;
42227             } else {
42228               loc = edge2.loc;
42229             }
42230
42231             graph = graph.replace(vertex.move(loc)); // if zorro happened, reorder nodes..
42232
42233             if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
42234               way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
42235               graph = graph.replace(way1);
42236             }
42237
42238             if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
42239               way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
42240               graph = graph.replace(way2);
42241             }
42242
42243             return graph;
42244           }
42245
42246           function cleanupIntersections(graph) {
42247             for (var i = 0; i < cache.intersections.length; i++) {
42248               var obj = cache.intersections[i];
42249               graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
42250               graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
42251               graph = unZorroIntersection(obj, graph);
42252               graph = removeDuplicateVertices(obj.movedId, graph);
42253               graph = removeDuplicateVertices(obj.unmovedId, graph);
42254             }
42255
42256             return graph;
42257           } // check if moving way endpoint can cross an unmoved way, if so limit delta..
42258
42259
42260           function limitDelta(graph) {
42261             function moveNode(loc) {
42262               return geoVecAdd(projection(loc), _delta);
42263             }
42264
42265             for (var i = 0; i < cache.intersections.length; i++) {
42266               var obj = cache.intersections[i]; // Don't limit movement if this is vertex joins 2 endpoints..
42267
42268               if (obj.movedIsEP && obj.unmovedIsEP) continue; // Don't limit movement if this vertex is not an endpoint anyway..
42269
42270               if (!obj.movedIsEP) continue;
42271               var node = graph.entity(obj.nodeId);
42272               var start = projection(node.loc);
42273               var end = geoVecAdd(start, _delta);
42274               var movedNodes = graph.childNodes(graph.entity(obj.movedId));
42275               var movedPath = movedNodes.map(function (n) {
42276                 return moveNode(n.loc);
42277               });
42278               var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
42279               var unmovedPath = unmovedNodes.map(function (n) {
42280                 return projection(n.loc);
42281               });
42282               var hits = geoPathIntersections(movedPath, unmovedPath);
42283
42284               for (var j = 0; i < hits.length; i++) {
42285                 if (geoVecEqual(hits[j], end)) continue;
42286                 var edge = geoChooseEdge(unmovedNodes, end, projection);
42287                 _delta = geoVecSubtract(projection(edge.loc), start);
42288               }
42289             }
42290           }
42291
42292           var action = function action(graph) {
42293             if (_delta[0] === 0 && _delta[1] === 0) return graph;
42294             setupCache(graph);
42295
42296             if (cache.intersections.length) {
42297               limitDelta(graph);
42298             }
42299
42300             for (var i = 0; i < cache.nodes.length; i++) {
42301               var node = graph.entity(cache.nodes[i]);
42302               var start = projection(node.loc);
42303               var end = geoVecAdd(start, _delta);
42304               graph = graph.replace(node.move(projection.invert(end)));
42305             }
42306
42307             if (cache.intersections.length) {
42308               graph = cleanupIntersections(graph);
42309             }
42310
42311             return graph;
42312           };
42313
42314           action.delta = function () {
42315             return _delta;
42316           };
42317
42318           return action;
42319         }
42320
42321         function actionMoveMember(relationId, fromIndex, toIndex) {
42322           return function (graph) {
42323             return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
42324           };
42325         }
42326
42327         function actionMoveNode(nodeID, toLoc) {
42328           var action = function action(graph, t) {
42329             if (t === null || !isFinite(t)) t = 1;
42330             t = Math.min(Math.max(+t, 0), 1);
42331             var node = graph.entity(nodeID);
42332             return graph.replace(node.move(geoVecInterp(node.loc, toLoc, t)));
42333           };
42334
42335           action.transitionable = true;
42336           return action;
42337         }
42338
42339         function actionNoop() {
42340           return function (graph) {
42341             return graph;
42342           };
42343         }
42344
42345         function actionOrthogonalize(wayID, projection, vertexID, degThresh, ep) {
42346           var epsilon = ep || 1e-4;
42347           var threshold = degThresh || 13; // degrees within right or straight to alter
42348           // We test normalized dot products so we can compare as cos(angle)
42349
42350           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
42351           var upperThreshold = Math.cos(threshold * Math.PI / 180);
42352
42353           var action = function action(graph, t) {
42354             if (t === null || !isFinite(t)) t = 1;
42355             t = Math.min(Math.max(+t, 0), 1);
42356             var way = graph.entity(wayID);
42357             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
42358
42359             if (way.tags.nonsquare) {
42360               var tags = Object.assign({}, way.tags); // since we're squaring, remove indication that this is physically unsquare
42361
42362               delete tags.nonsquare;
42363               way = way.update({
42364                 tags: tags
42365               });
42366             }
42367
42368             graph = graph.replace(way);
42369             var isClosed = way.isClosed();
42370             var nodes = graph.childNodes(way).slice(); // shallow copy
42371
42372             if (isClosed) nodes.pop();
42373
42374             if (vertexID !== undefined) {
42375               nodes = nodeSubset(nodes, vertexID, isClosed);
42376               if (nodes.length !== 3) return graph;
42377             } // note: all geometry functions here use the unclosed node/point/coord list
42378
42379
42380             var nodeCount = {};
42381             var points = [];
42382             var corner = {
42383               i: 0,
42384               dotp: 1
42385             };
42386             var node, point, loc, score, motions, i, j;
42387
42388             for (i = 0; i < nodes.length; i++) {
42389               node = nodes[i];
42390               nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
42391               points.push({
42392                 id: node.id,
42393                 coord: projection(node.loc)
42394               });
42395             }
42396
42397             if (points.length === 3) {
42398               // move only one vertex for right triangle
42399               for (i = 0; i < 1000; i++) {
42400                 motions = points.map(calcMotion);
42401                 points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
42402                 score = corner.dotp;
42403
42404                 if (score < epsilon) {
42405                   break;
42406                 }
42407               }
42408
42409               node = graph.entity(nodes[corner.i].id);
42410               loc = projection.invert(points[corner.i].coord);
42411               graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
42412             } else {
42413               var straights = [];
42414               var simplified = []; // Remove points from nearly straight sections..
42415               // This produces a simplified shape to orthogonalize
42416
42417               for (i = 0; i < points.length; i++) {
42418                 point = points[i];
42419                 var dotp = 0;
42420
42421                 if (isClosed || i > 0 && i < points.length - 1) {
42422                   var a = points[(i - 1 + points.length) % points.length];
42423                   var b = points[(i + 1) % points.length];
42424                   dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
42425                 }
42426
42427                 if (dotp > upperThreshold) {
42428                   straights.push(point);
42429                 } else {
42430                   simplified.push(point);
42431                 }
42432               } // Orthogonalize the simplified shape
42433
42434
42435               var bestPoints = clonePoints(simplified);
42436               var originalPoints = clonePoints(simplified);
42437               score = Infinity;
42438
42439               for (i = 0; i < 1000; i++) {
42440                 motions = simplified.map(calcMotion);
42441
42442                 for (j = 0; j < motions.length; j++) {
42443                   simplified[j].coord = geoVecAdd(simplified[j].coord, motions[j]);
42444                 }
42445
42446                 var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon, threshold);
42447
42448                 if (newScore < score) {
42449                   bestPoints = clonePoints(simplified);
42450                   score = newScore;
42451                 }
42452
42453                 if (score < epsilon) {
42454                   break;
42455                 }
42456               }
42457
42458               var bestCoords = bestPoints.map(function (p) {
42459                 return p.coord;
42460               });
42461               if (isClosed) bestCoords.push(bestCoords[0]); // move the nodes that should move
42462
42463               for (i = 0; i < bestPoints.length; i++) {
42464                 point = bestPoints[i];
42465
42466                 if (!geoVecEqual(originalPoints[i].coord, point.coord)) {
42467                   node = graph.entity(point.id);
42468                   loc = projection.invert(point.coord);
42469                   graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
42470                 }
42471               } // move the nodes along straight segments
42472
42473
42474               for (i = 0; i < straights.length; i++) {
42475                 point = straights[i];
42476                 if (nodeCount[point.id] > 1) continue; // skip self-intersections
42477
42478                 node = graph.entity(point.id);
42479
42480                 if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
42481                   // remove uninteresting points..
42482                   graph = actionDeleteNode(node.id)(graph);
42483                 } else {
42484                   // move interesting points to the nearest edge..
42485                   var choice = geoVecProject(point.coord, bestCoords);
42486
42487                   if (choice) {
42488                     loc = projection.invert(choice.target);
42489                     graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
42490                   }
42491                 }
42492               }
42493             }
42494
42495             return graph;
42496
42497             function clonePoints(array) {
42498               return array.map(function (p) {
42499                 return {
42500                   id: p.id,
42501                   coord: [p.coord[0], p.coord[1]]
42502                 };
42503               });
42504             }
42505
42506             function calcMotion(point, i, array) {
42507               // don't try to move the endpoints of a non-closed way.
42508               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)
42509
42510               if (nodeCount[array[i].id] > 1) return [0, 0];
42511               var a = array[(i - 1 + array.length) % array.length].coord;
42512               var origin = point.coord;
42513               var b = array[(i + 1) % array.length].coord;
42514               var p = geoVecSubtract(a, origin);
42515               var q = geoVecSubtract(b, origin);
42516               var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
42517               p = geoVecNormalize(p);
42518               q = geoVecNormalize(q);
42519               var dotp = p[0] * q[0] + p[1] * q[1];
42520               var val = Math.abs(dotp);
42521
42522               if (val < lowerThreshold) {
42523                 // nearly orthogonal
42524                 corner.i = i;
42525                 corner.dotp = val;
42526                 var vec = geoVecNormalize(geoVecAdd(p, q));
42527                 return geoVecScale(vec, 0.1 * dotp * scale);
42528               }
42529
42530               return [0, 0]; // do nothing
42531             }
42532           }; // if we are only orthogonalizing one vertex,
42533           // get that vertex and the previous and next
42534
42535
42536           function nodeSubset(nodes, vertexID, isClosed) {
42537             var first = isClosed ? 0 : 1;
42538             var last = isClosed ? nodes.length : nodes.length - 1;
42539
42540             for (var i = first; i < last; i++) {
42541               if (nodes[i].id === vertexID) {
42542                 return [nodes[(i - 1 + nodes.length) % nodes.length], nodes[i], nodes[(i + 1) % nodes.length]];
42543               }
42544             }
42545
42546             return [];
42547           }
42548
42549           action.disabled = function (graph) {
42550             var way = graph.entity(wayID);
42551             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
42552
42553             graph = graph.replace(way);
42554             var isClosed = way.isClosed();
42555             var nodes = graph.childNodes(way).slice(); // shallow copy
42556
42557             if (isClosed) nodes.pop();
42558             var allowStraightAngles = false;
42559
42560             if (vertexID !== undefined) {
42561               allowStraightAngles = true;
42562               nodes = nodeSubset(nodes, vertexID, isClosed);
42563               if (nodes.length !== 3) return 'end_vertex';
42564             }
42565
42566             var coords = nodes.map(function (n) {
42567               return projection(n.loc);
42568             });
42569             var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles);
42570
42571             if (score === null) {
42572               return 'not_squarish';
42573             } else if (score === 0) {
42574               return 'square_enough';
42575             } else {
42576               return false;
42577             }
42578           };
42579
42580           action.transitionable = true;
42581           return action;
42582         }
42583
42584         //
42585         // `turn` must be an `osmTurn` object
42586         // see osm/intersection.js, pathToTurn()
42587         //
42588         // This specifies a restriction of type `restriction` when traveling from
42589         // `turn.from.way` toward `turn.to.way` via `turn.via.node` OR `turn.via.ways`.
42590         // (The action does not check that these entities form a valid intersection.)
42591         //
42592         // From, to, and via ways should be split before calling this action.
42593         // (old versions of the code would split the ways here, but we no longer do it)
42594         //
42595         // For testing convenience, accepts a restrictionID to assign to the new
42596         // relation. Normally, this will be undefined and the relation will
42597         // automatically be assigned a new ID.
42598         //
42599
42600         function actionRestrictTurn(turn, restrictionType, restrictionID) {
42601           return function (graph) {
42602             var fromWay = graph.entity(turn.from.way);
42603             var toWay = graph.entity(turn.to.way);
42604             var viaNode = turn.via.node && graph.entity(turn.via.node);
42605             var viaWays = turn.via.ways && turn.via.ways.map(function (id) {
42606               return graph.entity(id);
42607             });
42608             var members = [];
42609             members.push({
42610               id: fromWay.id,
42611               type: 'way',
42612               role: 'from'
42613             });
42614
42615             if (viaNode) {
42616               members.push({
42617                 id: viaNode.id,
42618                 type: 'node',
42619                 role: 'via'
42620               });
42621             } else if (viaWays) {
42622               viaWays.forEach(function (viaWay) {
42623                 members.push({
42624                   id: viaWay.id,
42625                   type: 'way',
42626                   role: 'via'
42627                 });
42628               });
42629             }
42630
42631             members.push({
42632               id: toWay.id,
42633               type: 'way',
42634               role: 'to'
42635             });
42636             return graph.replace(osmRelation({
42637               id: restrictionID,
42638               tags: {
42639                 type: 'restriction',
42640                 restriction: restrictionType
42641               },
42642               members: members
42643             }));
42644           };
42645         }
42646
42647         function actionRevert(id) {
42648           var action = function action(graph) {
42649             var entity = graph.hasEntity(id),
42650                 base = graph.base().entities[id];
42651
42652             if (entity && !base) {
42653               // entity will be removed..
42654               if (entity.type === 'node') {
42655                 graph.parentWays(entity).forEach(function (parent) {
42656                   parent = parent.removeNode(id);
42657                   graph = graph.replace(parent);
42658
42659                   if (parent.isDegenerate()) {
42660                     graph = actionDeleteWay(parent.id)(graph);
42661                   }
42662                 });
42663               }
42664
42665               graph.parentRelations(entity).forEach(function (parent) {
42666                 parent = parent.removeMembersWithID(id);
42667                 graph = graph.replace(parent);
42668
42669                 if (parent.isDegenerate()) {
42670                   graph = actionDeleteRelation(parent.id)(graph);
42671                 }
42672               });
42673             }
42674
42675             return graph.revert(id);
42676           };
42677
42678           return action;
42679         }
42680
42681         function actionRotate(rotateIds, pivot, angle, projection) {
42682           var action = function action(graph) {
42683             return graph.update(function (graph) {
42684               utilGetAllNodes(rotateIds, graph).forEach(function (node) {
42685                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
42686                 graph = graph.replace(node.move(projection.invert(point)));
42687               });
42688             });
42689           };
42690
42691           return action;
42692         }
42693
42694         function actionScale(ids, pivotLoc, scaleFactor, projection) {
42695           return function (graph) {
42696             return graph.update(function (graph) {
42697               var point, radial;
42698               utilGetAllNodes(ids, graph).forEach(function (node) {
42699                 point = projection(node.loc);
42700                 radial = [point[0] - pivotLoc[0], point[1] - pivotLoc[1]];
42701                 point = [pivotLoc[0] + scaleFactor * radial[0], pivotLoc[1] + scaleFactor * radial[1]];
42702                 graph = graph.replace(node.move(projection.invert(point)));
42703               });
42704             });
42705           };
42706         }
42707
42708         /* Align nodes along their common axis */
42709
42710         function actionStraightenNodes(nodeIDs, projection) {
42711           function positionAlongWay(a, o, b) {
42712             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
42713           } // returns the endpoints of the long axis of symmetry of the `points` bounding rect
42714
42715
42716           function getEndpoints(points) {
42717             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
42718             // The shape's surrounding rectangle has 2 axes of symmetry.
42719             // Snap points to the long axis
42720
42721             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
42722             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
42723             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
42724             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
42725             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
42726
42727             if (isLong) {
42728               return [p1, q1];
42729             }
42730
42731             return [p2, q2];
42732           }
42733
42734           var action = function action(graph, t) {
42735             if (t === null || !isFinite(t)) t = 1;
42736             t = Math.min(Math.max(+t, 0), 1);
42737             var nodes = nodeIDs.map(function (id) {
42738               return graph.entity(id);
42739             });
42740             var points = nodes.map(function (n) {
42741               return projection(n.loc);
42742             });
42743             var endpoints = getEndpoints(points);
42744             var startPoint = endpoints[0];
42745             var endPoint = endpoints[1]; // Move points onto the line connecting the endpoints
42746
42747             for (var i = 0; i < points.length; i++) {
42748               var node = nodes[i];
42749               var point = points[i];
42750               var u = positionAlongWay(point, startPoint, endPoint);
42751               var point2 = geoVecInterp(startPoint, endPoint, u);
42752               var loc2 = projection.invert(point2);
42753               graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
42754             }
42755
42756             return graph;
42757           };
42758
42759           action.disabled = function (graph) {
42760             var nodes = nodeIDs.map(function (id) {
42761               return graph.entity(id);
42762             });
42763             var points = nodes.map(function (n) {
42764               return projection(n.loc);
42765             });
42766             var endpoints = getEndpoints(points);
42767             var startPoint = endpoints[0];
42768             var endPoint = endpoints[1];
42769             var maxDistance = 0;
42770
42771             for (var i = 0; i < points.length; i++) {
42772               var point = points[i];
42773               var u = positionAlongWay(point, startPoint, endPoint);
42774               var p = geoVecInterp(startPoint, endPoint, u);
42775               var dist = geoVecLength(p, point);
42776
42777               if (!isNaN(dist) && dist > maxDistance) {
42778                 maxDistance = dist;
42779               }
42780             }
42781
42782             if (maxDistance < 0.0001) {
42783               return 'straight_enough';
42784             }
42785           };
42786
42787           action.transitionable = true;
42788           return action;
42789         }
42790
42791         /*
42792          * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
42793          */
42794
42795         function actionStraightenWay(selectedIDs, projection) {
42796           function positionAlongWay(a, o, b) {
42797             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
42798           } // Return all selected ways as a continuous, ordered array of nodes
42799
42800
42801           function allNodes(graph) {
42802             var nodes = [];
42803             var startNodes = [];
42804             var endNodes = [];
42805             var remainingWays = [];
42806             var selectedWays = selectedIDs.filter(function (w) {
42807               return graph.entity(w).type === 'way';
42808             });
42809             var selectedNodes = selectedIDs.filter(function (n) {
42810               return graph.entity(n).type === 'node';
42811             });
42812
42813             for (var i = 0; i < selectedWays.length; i++) {
42814               var way = graph.entity(selectedWays[i]);
42815               nodes = way.nodes.slice(0);
42816               remainingWays.push(nodes);
42817               startNodes.push(nodes[0]);
42818               endNodes.push(nodes[nodes.length - 1]);
42819             } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end,
42820             //   and need to be removed so currNode difference calculation below works)
42821             // i.e. ["n-1", "n-1", "n-2"] => ["n-2"]
42822
42823
42824             startNodes = startNodes.filter(function (n) {
42825               return startNodes.indexOf(n) === startNodes.lastIndexOf(n);
42826             });
42827             endNodes = endNodes.filter(function (n) {
42828               return endNodes.indexOf(n) === endNodes.lastIndexOf(n);
42829             }); // Choose the initial endpoint to start from
42830
42831             var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
42832             var nextWay = [];
42833             nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error
42834
42835             var getNextWay = function getNextWay(currNode, remainingWays) {
42836               return remainingWays.filter(function (way) {
42837                 return way[0] === currNode || way[way.length - 1] === currNode;
42838               })[0];
42839             }; // Add nodes to end of nodes array, until all ways are added
42840
42841
42842             while (remainingWays.length) {
42843               nextWay = getNextWay(currNode, remainingWays);
42844               remainingWays = utilArrayDifference(remainingWays, [nextWay]);
42845
42846               if (nextWay[0] !== currNode) {
42847                 nextWay.reverse();
42848               }
42849
42850               nodes = nodes.concat(nextWay);
42851               currNode = nodes[nodes.length - 1];
42852             } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes
42853
42854
42855             if (selectedNodes.length === 2) {
42856               var startNodeIdx = nodes.indexOf(selectedNodes[0]);
42857               var endNodeIdx = nodes.indexOf(selectedNodes[1]);
42858               var sortedStartEnd = [startNodeIdx, endNodeIdx];
42859               sortedStartEnd.sort(function (a, b) {
42860                 return a - b;
42861               });
42862               nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
42863             }
42864
42865             return nodes.map(function (n) {
42866               return graph.entity(n);
42867             });
42868           }
42869
42870           function shouldKeepNode(node, graph) {
42871             return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
42872           }
42873
42874           var action = function action(graph, t) {
42875             if (t === null || !isFinite(t)) t = 1;
42876             t = Math.min(Math.max(+t, 0), 1);
42877             var nodes = allNodes(graph);
42878             var points = nodes.map(function (n) {
42879               return projection(n.loc);
42880             });
42881             var startPoint = points[0];
42882             var endPoint = points[points.length - 1];
42883             var toDelete = [];
42884             var i;
42885
42886             for (i = 1; i < points.length - 1; i++) {
42887               var node = nodes[i];
42888               var point = points[i];
42889
42890               if (t < 1 || shouldKeepNode(node, graph)) {
42891                 var u = positionAlongWay(point, startPoint, endPoint);
42892                 var p = geoVecInterp(startPoint, endPoint, u);
42893                 var loc2 = projection.invert(p);
42894                 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
42895               } else {
42896                 // safe to delete
42897                 if (toDelete.indexOf(node) === -1) {
42898                   toDelete.push(node);
42899                 }
42900               }
42901             }
42902
42903             for (i = 0; i < toDelete.length; i++) {
42904               graph = actionDeleteNode(toDelete[i].id)(graph);
42905             }
42906
42907             return graph;
42908           };
42909
42910           action.disabled = function (graph) {
42911             // check way isn't too bendy
42912             var nodes = allNodes(graph);
42913             var points = nodes.map(function (n) {
42914               return projection(n.loc);
42915             });
42916             var startPoint = points[0];
42917             var endPoint = points[points.length - 1];
42918             var threshold = 0.2 * geoVecLength(startPoint, endPoint);
42919             var i;
42920
42921             if (threshold === 0) {
42922               return 'too_bendy';
42923             }
42924
42925             var maxDistance = 0;
42926
42927             for (i = 1; i < points.length - 1; i++) {
42928               var point = points[i];
42929               var u = positionAlongWay(point, startPoint, endPoint);
42930               var p = geoVecInterp(startPoint, endPoint, u);
42931               var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space
42932
42933               if (isNaN(dist) || dist > threshold) {
42934                 return 'too_bendy';
42935               } else if (dist > maxDistance) {
42936                 maxDistance = dist;
42937               }
42938             }
42939
42940             var keepingAllNodes = nodes.every(function (node, i) {
42941               return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph);
42942             });
42943
42944             if (maxDistance < 0.0001 && // Allow straightening even if already straight in order to remove extraneous nodes
42945             keepingAllNodes) {
42946               return 'straight_enough';
42947             }
42948           };
42949
42950           action.transitionable = true;
42951           return action;
42952         }
42953
42954         //
42955         // `turn` must be an `osmTurn` object with a `restrictionID` property.
42956         // see osm/intersection.js, pathToTurn()
42957         //
42958
42959         function actionUnrestrictTurn(turn) {
42960           return function (graph) {
42961             return actionDeleteRelation(turn.restrictionID)(graph);
42962           };
42963         }
42964
42965         /* Reflect the given area around its axis of symmetry */
42966
42967         function actionReflect(reflectIds, projection) {
42968           var _useLongAxis = true;
42969
42970           var action = function action(graph, t) {
42971             if (t === null || !isFinite(t)) t = 1;
42972             t = Math.min(Math.max(+t, 0), 1);
42973             var nodes = utilGetAllNodes(reflectIds, graph);
42974             var points = nodes.map(function (n) {
42975               return projection(n.loc);
42976             });
42977             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
42978             // The shape's surrounding rectangle has 2 axes of symmetry.
42979             // Reflect across the longer axis by default.
42980
42981             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
42982             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
42983             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
42984             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
42985             var p, q;
42986             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
42987
42988             if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
42989               p = p1;
42990               q = q1;
42991             } else {
42992               p = p2;
42993               q = q2;
42994             } // reflect c across pq
42995             // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
42996
42997
42998             var dx = q[0] - p[0];
42999             var dy = q[1] - p[1];
43000             var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
43001             var b = 2 * dx * dy / (dx * dx + dy * dy);
43002
43003             for (var i = 0; i < nodes.length; i++) {
43004               var node = nodes[i];
43005               var c = projection(node.loc);
43006               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]];
43007               var loc2 = projection.invert(c2);
43008               node = node.move(geoVecInterp(node.loc, loc2, t));
43009               graph = graph.replace(node);
43010             }
43011
43012             return graph;
43013           };
43014
43015           action.useLongAxis = function (val) {
43016             if (!arguments.length) return _useLongAxis;
43017             _useLongAxis = val;
43018             return action;
43019           };
43020
43021           action.transitionable = true;
43022           return action;
43023         }
43024
43025         function actionUpgradeTags(entityId, oldTags, replaceTags) {
43026           return function (graph) {
43027             var entity = graph.entity(entityId);
43028             var tags = Object.assign({}, entity.tags); // shallow copy
43029
43030             var transferValue;
43031             var semiIndex;
43032
43033             for (var oldTagKey in oldTags) {
43034               if (!(oldTagKey in tags)) continue; // wildcard match
43035
43036               if (oldTags[oldTagKey] === '*') {
43037                 // note the value since we might need to transfer it
43038                 transferValue = tags[oldTagKey];
43039                 delete tags[oldTagKey]; // exact match
43040               } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
43041                 delete tags[oldTagKey]; // match is within semicolon-delimited values
43042               } else {
43043                 var vals = tags[oldTagKey].split(';').filter(Boolean);
43044                 var oldIndex = vals.indexOf(oldTags[oldTagKey]);
43045
43046                 if (vals.length === 1 || oldIndex === -1) {
43047                   delete tags[oldTagKey];
43048                 } else {
43049                   if (replaceTags && replaceTags[oldTagKey]) {
43050                     // replacing a value within a semicolon-delimited value, note the index
43051                     semiIndex = oldIndex;
43052                   }
43053
43054                   vals.splice(oldIndex, 1);
43055                   tags[oldTagKey] = vals.join(';');
43056                 }
43057               }
43058             }
43059
43060             if (replaceTags) {
43061               for (var replaceKey in replaceTags) {
43062                 var replaceValue = replaceTags[replaceKey];
43063
43064                 if (replaceValue === '*') {
43065                   if (tags[replaceKey] && tags[replaceKey] !== 'no') {
43066                     // allow any pre-existing value except `no` (troll tag)
43067                     continue;
43068                   } else {
43069                     // otherwise assume `yes` is okay
43070                     tags[replaceKey] = 'yes';
43071                   }
43072                 } else if (replaceValue === '$1') {
43073                   tags[replaceKey] = transferValue;
43074                 } else {
43075                   if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== undefined) {
43076                     // don't override preexisting values
43077                     var existingVals = tags[replaceKey].split(';').filter(Boolean);
43078
43079                     if (existingVals.indexOf(replaceValue) === -1) {
43080                       existingVals.splice(semiIndex, 0, replaceValue);
43081                       tags[replaceKey] = existingVals.join(';');
43082                     }
43083                   } else {
43084                     tags[replaceKey] = replaceValue;
43085                   }
43086                 }
43087               }
43088             }
43089
43090             return graph.replace(entity.update({
43091               tags: tags
43092             }));
43093           };
43094         }
43095
43096         function behaviorEdit(context) {
43097           function behavior() {
43098             context.map().minzoom(context.minEditableZoom());
43099           }
43100
43101           behavior.off = function () {
43102             context.map().minzoom(0);
43103           };
43104
43105           return behavior;
43106         }
43107
43108         /*
43109            The hover behavior adds the `.hover` class on pointerover to all elements to which
43110            the identical datum is bound, and removes it on pointerout.
43111
43112            The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
43113            representation may consist of several elements scattered throughout the DOM hierarchy.
43114            Only one of these elements can have the :hover pseudo-class, but all of them will
43115            have the .hover class.
43116          */
43117
43118         function behaviorHover(context) {
43119           var dispatch = dispatch$8('hover');
43120
43121           var _selection = select(null);
43122
43123           var _newNodeId = null;
43124           var _initialNodeID = null;
43125
43126           var _altDisables;
43127
43128           var _ignoreVertex;
43129
43130           var _targets = []; // use pointer events on supported platforms; fallback to mouse events
43131
43132           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
43133
43134           function keydown(d3_event) {
43135             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
43136               _selection.selectAll('.hover').classed('hover-suppressed', true).classed('hover', false);
43137
43138               _selection.classed('hover-disabled', true);
43139
43140               dispatch.call('hover', this, null);
43141             }
43142           }
43143
43144           function keyup(d3_event) {
43145             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
43146               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false).classed('hover', true);
43147
43148               _selection.classed('hover-disabled', false);
43149
43150               dispatch.call('hover', this, _targets);
43151             }
43152           }
43153
43154           function behavior(selection) {
43155             _selection = selection;
43156             _targets = [];
43157
43158             if (_initialNodeID) {
43159               _newNodeId = _initialNodeID;
43160               _initialNodeID = null;
43161             } else {
43162               _newNodeId = null;
43163             }
43164
43165             _selection.on(_pointerPrefix + 'over.hover', pointerover).on(_pointerPrefix + 'out.hover', pointerout) // treat pointerdown as pointerover for touch devices
43166             .on(_pointerPrefix + 'down.hover', pointerover);
43167
43168             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', pointerout, true).on('keydown.hover', keydown).on('keyup.hover', keyup);
43169
43170             function eventTarget(d3_event) {
43171               var datum = d3_event.target && d3_event.target.__data__;
43172               if (_typeof(datum) !== 'object') return null;
43173
43174               if (!(datum instanceof osmEntity) && datum.properties && datum.properties.entity instanceof osmEntity) {
43175                 return datum.properties.entity;
43176               }
43177
43178               return datum;
43179             }
43180
43181             function pointerover(d3_event) {
43182               // ignore mouse hovers with buttons pressed unless dragging
43183               if (context.mode().id.indexOf('drag') === -1 && (!d3_event.pointerType || d3_event.pointerType === 'mouse') && d3_event.buttons) return;
43184               var target = eventTarget(d3_event);
43185
43186               if (target && _targets.indexOf(target) === -1) {
43187                 _targets.push(target);
43188
43189                 updateHover(d3_event, _targets);
43190               }
43191             }
43192
43193             function pointerout(d3_event) {
43194               var target = eventTarget(d3_event);
43195
43196               var index = _targets.indexOf(target);
43197
43198               if (index !== -1) {
43199                 _targets.splice(index);
43200
43201                 updateHover(d3_event, _targets);
43202               }
43203             }
43204
43205             function allowsVertex(d) {
43206               return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
43207             }
43208
43209             function modeAllowsHover(target) {
43210               var mode = context.mode();
43211
43212               if (mode.id === 'add-point') {
43213                 return mode.preset.matchGeometry('vertex') || target.type !== 'way' && target.geometry(context.graph()) !== 'vertex';
43214               }
43215
43216               return true;
43217             }
43218
43219             function updateHover(d3_event, targets) {
43220               _selection.selectAll('.hover').classed('hover', false);
43221
43222               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
43223
43224               var mode = context.mode();
43225
43226               if (!_newNodeId && (mode.id === 'draw-line' || mode.id === 'draw-area')) {
43227                 var node = targets.find(function (target) {
43228                   return target instanceof osmEntity && target.type === 'node';
43229                 });
43230                 _newNodeId = node && node.id;
43231               }
43232
43233               targets = targets.filter(function (datum) {
43234                 if (datum instanceof osmEntity) {
43235                   // If drawing a way, don't hover on a node that was just placed. #3974
43236                   return datum.id !== _newNodeId && (datum.type !== 'node' || !_ignoreVertex || allowsVertex(datum)) && modeAllowsHover(datum);
43237                 }
43238
43239                 return true;
43240               });
43241               var selector = '';
43242
43243               for (var i in targets) {
43244                 var datum = targets[i]; // What are we hovering over?
43245
43246                 if (datum.__featurehash__) {
43247                   // hovering custom data
43248                   selector += ', .data' + datum.__featurehash__;
43249                 } else if (datum instanceof QAItem) {
43250                   selector += ', .' + datum.service + '.itemId-' + datum.id;
43251                 } else if (datum instanceof osmNote) {
43252                   selector += ', .note-' + datum.id;
43253                 } else if (datum instanceof osmEntity) {
43254                   selector += ', .' + datum.id;
43255
43256                   if (datum.type === 'relation') {
43257                     for (var j in datum.members) {
43258                       selector += ', .' + datum.members[j].id;
43259                     }
43260                   }
43261                 }
43262               }
43263
43264               var suppressed = _altDisables && d3_event && d3_event.altKey;
43265
43266               if (selector.trim().length) {
43267                 // remove the first comma
43268                 selector = selector.slice(1);
43269
43270                 _selection.selectAll(selector).classed(suppressed ? 'hover-suppressed' : 'hover', true);
43271               }
43272
43273               dispatch.call('hover', this, !suppressed && targets);
43274             }
43275           }
43276
43277           behavior.off = function (selection) {
43278             selection.selectAll('.hover').classed('hover', false);
43279             selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
43280             selection.classed('hover-disabled', false);
43281             selection.on(_pointerPrefix + 'over.hover', null).on(_pointerPrefix + 'out.hover', null).on(_pointerPrefix + 'down.hover', null);
43282             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', null, true).on('keydown.hover', null).on('keyup.hover', null);
43283           };
43284
43285           behavior.altDisables = function (val) {
43286             if (!arguments.length) return _altDisables;
43287             _altDisables = val;
43288             return behavior;
43289           };
43290
43291           behavior.ignoreVertex = function (val) {
43292             if (!arguments.length) return _ignoreVertex;
43293             _ignoreVertex = val;
43294             return behavior;
43295           };
43296
43297           behavior.initialNodeID = function (nodeId) {
43298             _initialNodeID = nodeId;
43299             return behavior;
43300           };
43301
43302           return utilRebind(behavior, dispatch, 'on');
43303         }
43304
43305         var _disableSpace = false;
43306         var _lastSpace = null;
43307         function behaviorDraw(context) {
43308           var dispatch = dispatch$8('move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish');
43309           var keybinding = utilKeybinding('draw');
43310
43311           var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on('hover', context.ui().sidebar.hover);
43312
43313           var _edit = behaviorEdit(context);
43314
43315           var _closeTolerance = 4;
43316           var _tolerance = 12;
43317           var _mouseLeave = false;
43318           var _lastMouse = null;
43319
43320           var _lastPointerUpEvent;
43321
43322           var _downPointer; // use pointer events on supported platforms; fallback to mouse events
43323
43324
43325           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // related code
43326           // - `mode/drag_node.js` `datum()`
43327
43328
43329           function datum(d3_event) {
43330             var mode = context.mode();
43331             var isNote = mode && mode.id.indexOf('note') !== -1;
43332             if (d3_event.altKey || isNote) return {};
43333             var element;
43334
43335             if (d3_event.type === 'keydown') {
43336               element = _lastMouse && _lastMouse.target;
43337             } else {
43338               element = d3_event.target;
43339             } // When drawing, snap only to touch targets..
43340             // (this excludes area fills and active drawing elements)
43341
43342
43343             var d = element.__data__;
43344             return d && d.properties && d.properties.target ? d : {};
43345           }
43346
43347           function pointerdown(d3_event) {
43348             if (_downPointer) return;
43349             var pointerLocGetter = utilFastMouse(this);
43350             _downPointer = {
43351               id: d3_event.pointerId || 'mouse',
43352               pointerLocGetter: pointerLocGetter,
43353               downTime: +new Date(),
43354               downLoc: pointerLocGetter(d3_event)
43355             };
43356             dispatch.call('down', this, d3_event, datum(d3_event));
43357           }
43358
43359           function pointerup(d3_event) {
43360             if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
43361             var downPointer = _downPointer;
43362             _downPointer = null;
43363             _lastPointerUpEvent = d3_event;
43364             if (downPointer.isCancelled) return;
43365             var t2 = +new Date();
43366             var p2 = downPointer.pointerLocGetter(d3_event);
43367             var dist = geoVecLength(downPointer.downLoc, p2);
43368
43369             if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
43370               // Prevent a quick second click
43371               select(window).on('click.draw-block', function () {
43372                 d3_event.stopPropagation();
43373               }, true);
43374               context.map().dblclickZoomEnable(false);
43375               window.setTimeout(function () {
43376                 context.map().dblclickZoomEnable(true);
43377                 select(window).on('click.draw-block', null);
43378               }, 500);
43379               click(d3_event, p2);
43380             }
43381           }
43382
43383           function pointermove(d3_event) {
43384             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse') && !_downPointer.isCancelled) {
43385               var p2 = _downPointer.pointerLocGetter(d3_event);
43386
43387               var dist = geoVecLength(_downPointer.downLoc, p2);
43388
43389               if (dist >= _closeTolerance) {
43390                 _downPointer.isCancelled = true;
43391                 dispatch.call('downcancel', this);
43392               }
43393             }
43394
43395             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
43396             // events immediately after non-mouse pointerup events; detect and ignore them.
43397
43398             if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== 'mouse' && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
43399             _lastMouse = d3_event;
43400             dispatch.call('move', this, d3_event, datum(d3_event));
43401           }
43402
43403           function pointercancel(d3_event) {
43404             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse')) {
43405               if (!_downPointer.isCancelled) {
43406                 dispatch.call('downcancel', this);
43407               }
43408
43409               _downPointer = null;
43410             }
43411           }
43412
43413           function mouseenter() {
43414             _mouseLeave = false;
43415           }
43416
43417           function mouseleave() {
43418             _mouseLeave = true;
43419           }
43420
43421           function allowsVertex(d) {
43422             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
43423           } // related code
43424           // - `mode/drag_node.js`     `doMove()`
43425           // - `behavior/draw.js`      `click()`
43426           // - `behavior/draw_way.js`  `move()`
43427
43428
43429           function click(d3_event, loc) {
43430             var d = datum(d3_event);
43431             var target = d && d.properties && d.properties.entity;
43432             var mode = context.mode();
43433
43434             if (target && target.type === 'node' && allowsVertex(target)) {
43435               // Snap to a node
43436               dispatch.call('clickNode', this, target, d);
43437               return;
43438             } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) {
43439               // Snap to a way
43440               var choice = geoChooseEdge(context.graph().childNodes(target), loc, context.projection, context.activeID());
43441
43442               if (choice) {
43443                 var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
43444                 dispatch.call('clickWay', this, choice.loc, edge, d);
43445                 return;
43446               }
43447             } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) {
43448               var locLatLng = context.projection.invert(loc);
43449               dispatch.call('click', this, locLatLng, d);
43450             }
43451           } // treat a spacebar press like a click
43452
43453
43454           function space(d3_event) {
43455             d3_event.preventDefault();
43456             d3_event.stopPropagation();
43457             var currSpace = context.map().mouse();
43458
43459             if (_disableSpace && _lastSpace) {
43460               var dist = geoVecLength(_lastSpace, currSpace);
43461
43462               if (dist > _tolerance) {
43463                 _disableSpace = false;
43464               }
43465             }
43466
43467             if (_disableSpace || _mouseLeave || !_lastMouse) return; // user must move mouse or release space bar to allow another click
43468
43469             _lastSpace = currSpace;
43470             _disableSpace = true;
43471             select(window).on('keyup.space-block', function () {
43472               d3_event.preventDefault();
43473               d3_event.stopPropagation();
43474               _disableSpace = false;
43475               select(window).on('keyup.space-block', null);
43476             }); // get the current mouse position
43477
43478             var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
43479             context.projection(context.map().center());
43480             click(d3_event, loc);
43481           }
43482
43483           function backspace(d3_event) {
43484             d3_event.preventDefault();
43485             dispatch.call('undo');
43486           }
43487
43488           function del(d3_event) {
43489             d3_event.preventDefault();
43490             dispatch.call('cancel');
43491           }
43492
43493           function ret(d3_event) {
43494             d3_event.preventDefault();
43495             dispatch.call('finish');
43496           }
43497
43498           function behavior(selection) {
43499             context.install(_hover);
43500             context.install(_edit);
43501             _downPointer = null;
43502             keybinding.on('⌫', backspace).on('⌦', del).on('⎋', ret).on('↩', ret).on('space', space).on('⌥space', space);
43503             selection.on('mouseenter.draw', mouseenter).on('mouseleave.draw', mouseleave).on(_pointerPrefix + 'down.draw', pointerdown).on(_pointerPrefix + 'move.draw', pointermove);
43504             select(window).on(_pointerPrefix + 'up.draw', pointerup, true).on('pointercancel.draw', pointercancel, true);
43505             select(document).call(keybinding);
43506             return behavior;
43507           }
43508
43509           behavior.off = function (selection) {
43510             context.ui().sidebar.hover.cancel();
43511             context.uninstall(_hover);
43512             context.uninstall(_edit);
43513             selection.on('mouseenter.draw', null).on('mouseleave.draw', null).on(_pointerPrefix + 'down.draw', null).on(_pointerPrefix + 'move.draw', null);
43514             select(window).on(_pointerPrefix + 'up.draw', null).on('pointercancel.draw', null); // note: keyup.space-block, click.draw-block should remain
43515
43516             select(document).call(keybinding.unbind);
43517           };
43518
43519           behavior.hover = function () {
43520             return _hover;
43521           };
43522
43523           return utilRebind(behavior, dispatch, 'on');
43524         }
43525
43526         function initRange(domain, range) {
43527           switch (arguments.length) {
43528             case 0:
43529               break;
43530
43531             case 1:
43532               this.range(domain);
43533               break;
43534
43535             default:
43536               this.range(range).domain(domain);
43537               break;
43538           }
43539
43540           return this;
43541         }
43542
43543         function constants(x) {
43544           return function () {
43545             return x;
43546           };
43547         }
43548
43549         function number(x) {
43550           return +x;
43551         }
43552
43553         var unit = [0, 1];
43554         function identity$1(x) {
43555           return x;
43556         }
43557
43558         function normalize(a, b) {
43559           return (b -= a = +a) ? function (x) {
43560             return (x - a) / b;
43561           } : constants(isNaN(b) ? NaN : 0.5);
43562         }
43563
43564         function clamper(a, b) {
43565           var t;
43566           if (a > b) t = a, a = b, b = t;
43567           return function (x) {
43568             return Math.max(a, Math.min(b, x));
43569           };
43570         } // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
43571         // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
43572
43573
43574         function bimap(domain, range, interpolate) {
43575           var d0 = domain[0],
43576               d1 = domain[1],
43577               r0 = range[0],
43578               r1 = range[1];
43579           if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
43580           return function (x) {
43581             return r0(d0(x));
43582           };
43583         }
43584
43585         function polymap(domain, range, interpolate) {
43586           var j = Math.min(domain.length, range.length) - 1,
43587               d = new Array(j),
43588               r = new Array(j),
43589               i = -1; // Reverse descending domains.
43590
43591           if (domain[j] < domain[0]) {
43592             domain = domain.slice().reverse();
43593             range = range.slice().reverse();
43594           }
43595
43596           while (++i < j) {
43597             d[i] = normalize(domain[i], domain[i + 1]);
43598             r[i] = interpolate(range[i], range[i + 1]);
43599           }
43600
43601           return function (x) {
43602             var i = bisectRight(domain, x, 1, j) - 1;
43603             return r[i](d[i](x));
43604           };
43605         }
43606
43607         function copy(source, target) {
43608           return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
43609         }
43610         function transformer() {
43611           var domain = unit,
43612               range = unit,
43613               interpolate = interpolate$1,
43614               transform,
43615               untransform,
43616               unknown,
43617               clamp = identity$1,
43618               piecewise,
43619               output,
43620               input;
43621
43622           function rescale() {
43623             var n = Math.min(domain.length, range.length);
43624             if (clamp !== identity$1) clamp = clamper(domain[0], domain[n - 1]);
43625             piecewise = n > 2 ? polymap : bimap;
43626             output = input = null;
43627             return scale;
43628           }
43629
43630           function scale(x) {
43631             return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
43632           }
43633
43634           scale.invert = function (y) {
43635             return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3_interpolateNumber)))(y)));
43636           };
43637
43638           scale.domain = function (_) {
43639             return arguments.length ? (domain = Array.from(_, number), rescale()) : domain.slice();
43640           };
43641
43642           scale.range = function (_) {
43643             return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
43644           };
43645
43646           scale.rangeRound = function (_) {
43647             return range = Array.from(_), interpolate = interpolateRound, rescale();
43648           };
43649
43650           scale.clamp = function (_) {
43651             return arguments.length ? (clamp = _ ? true : identity$1, rescale()) : clamp !== identity$1;
43652           };
43653
43654           scale.interpolate = function (_) {
43655             return arguments.length ? (interpolate = _, rescale()) : interpolate;
43656           };
43657
43658           scale.unknown = function (_) {
43659             return arguments.length ? (unknown = _, scale) : unknown;
43660           };
43661
43662           return function (t, u) {
43663             transform = t, untransform = u;
43664             return rescale();
43665           };
43666         }
43667         function continuous() {
43668           return transformer()(identity$1, identity$1);
43669         }
43670
43671         function formatDecimal (x) {
43672           return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
43673         } // Computes the decimal coefficient and exponent of the specified number x with
43674         // significant digits p, where x is positive and p is in [1, 21] or undefined.
43675         // For example, formatDecimalParts(1.23) returns ["123", 0].
43676
43677         function formatDecimalParts(x, p) {
43678           if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
43679
43680           var i,
43681               coefficient = x.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
43682           // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
43683
43684           return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
43685         }
43686
43687         function exponent (x) {
43688           return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
43689         }
43690
43691         function formatGroup (grouping, thousands) {
43692           return function (value, width) {
43693             var i = value.length,
43694                 t = [],
43695                 j = 0,
43696                 g = grouping[0],
43697                 length = 0;
43698
43699             while (i > 0 && g > 0) {
43700               if (length + g + 1 > width) g = Math.max(1, width - length);
43701               t.push(value.substring(i -= g, i + g));
43702               if ((length += g + 1) > width) break;
43703               g = grouping[j = (j + 1) % grouping.length];
43704             }
43705
43706             return t.reverse().join(thousands);
43707           };
43708         }
43709
43710         function formatNumerals (numerals) {
43711           return function (value) {
43712             return value.replace(/[0-9]/g, function (i) {
43713               return numerals[+i];
43714             });
43715           };
43716         }
43717
43718         // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
43719         var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
43720         function formatSpecifier(specifier) {
43721           if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
43722           var match;
43723           return new FormatSpecifier({
43724             fill: match[1],
43725             align: match[2],
43726             sign: match[3],
43727             symbol: match[4],
43728             zero: match[5],
43729             width: match[6],
43730             comma: match[7],
43731             precision: match[8] && match[8].slice(1),
43732             trim: match[9],
43733             type: match[10]
43734           });
43735         }
43736         formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
43737
43738         function FormatSpecifier(specifier) {
43739           this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
43740           this.align = specifier.align === undefined ? ">" : specifier.align + "";
43741           this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
43742           this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
43743           this.zero = !!specifier.zero;
43744           this.width = specifier.width === undefined ? undefined : +specifier.width;
43745           this.comma = !!specifier.comma;
43746           this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
43747           this.trim = !!specifier.trim;
43748           this.type = specifier.type === undefined ? "" : specifier.type + "";
43749         }
43750
43751         FormatSpecifier.prototype.toString = function () {
43752           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;
43753         };
43754
43755         // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
43756         function formatTrim (s) {
43757           out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
43758             switch (s[i]) {
43759               case ".":
43760                 i0 = i1 = i;
43761                 break;
43762
43763               case "0":
43764                 if (i0 === 0) i0 = i;
43765                 i1 = i;
43766                 break;
43767
43768               default:
43769                 if (!+s[i]) break out;
43770                 if (i0 > 0) i0 = 0;
43771                 break;
43772             }
43773           }
43774
43775           return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
43776         }
43777
43778         var $$7 = _export;
43779         var fails$3 = fails$N;
43780         var thisNumberValue = thisNumberValue$2;
43781
43782         var nativeToPrecision = 1.0.toPrecision;
43783
43784         var FORCED$1 = fails$3(function () {
43785           // IE7-
43786           return nativeToPrecision.call(1, undefined) !== '1';
43787         }) || !fails$3(function () {
43788           // V8 ~ Android 4.3-
43789           nativeToPrecision.call({});
43790         });
43791
43792         // `Number.prototype.toPrecision` method
43793         // https://tc39.es/ecma262/#sec-number.prototype.toprecision
43794         $$7({ target: 'Number', proto: true, forced: FORCED$1 }, {
43795           toPrecision: function toPrecision(precision) {
43796             return precision === undefined
43797               ? nativeToPrecision.call(thisNumberValue(this))
43798               : nativeToPrecision.call(thisNumberValue(this), precision);
43799           }
43800         });
43801
43802         var prefixExponent;
43803         function formatPrefixAuto (x, p) {
43804           var d = formatDecimalParts(x, p);
43805           if (!d) return x + "";
43806           var coefficient = d[0],
43807               exponent = d[1],
43808               i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
43809               n = coefficient.length;
43810           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!
43811         }
43812
43813         function formatRounded (x, p) {
43814           var d = formatDecimalParts(x, p);
43815           if (!d) return x + "";
43816           var coefficient = d[0],
43817               exponent = d[1];
43818           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");
43819         }
43820
43821         var formatTypes = {
43822           "%": function _(x, p) {
43823             return (x * 100).toFixed(p);
43824           },
43825           "b": function b(x) {
43826             return Math.round(x).toString(2);
43827           },
43828           "c": function c(x) {
43829             return x + "";
43830           },
43831           "d": formatDecimal,
43832           "e": function e(x, p) {
43833             return x.toExponential(p);
43834           },
43835           "f": function f(x, p) {
43836             return x.toFixed(p);
43837           },
43838           "g": function g(x, p) {
43839             return x.toPrecision(p);
43840           },
43841           "o": function o(x) {
43842             return Math.round(x).toString(8);
43843           },
43844           "p": function p(x, _p) {
43845             return formatRounded(x * 100, _p);
43846           },
43847           "r": formatRounded,
43848           "s": formatPrefixAuto,
43849           "X": function X(x) {
43850             return Math.round(x).toString(16).toUpperCase();
43851           },
43852           "x": function x(_x) {
43853             return Math.round(_x).toString(16);
43854           }
43855         };
43856
43857         function identity (x) {
43858           return x;
43859         }
43860
43861         var map$1 = Array.prototype.map,
43862             prefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
43863         function formatLocale (locale) {
43864           var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map$1.call(locale.grouping, Number), locale.thousands + ""),
43865               currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
43866               currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
43867               decimal = locale.decimal === undefined ? "." : locale.decimal + "",
43868               numerals = locale.numerals === undefined ? identity : formatNumerals(map$1.call(locale.numerals, String)),
43869               percent = locale.percent === undefined ? "%" : locale.percent + "",
43870               minus = locale.minus === undefined ? "−" : locale.minus + "",
43871               nan = locale.nan === undefined ? "NaN" : locale.nan + "";
43872
43873           function newFormat(specifier) {
43874             specifier = formatSpecifier(specifier);
43875             var fill = specifier.fill,
43876                 align = specifier.align,
43877                 sign = specifier.sign,
43878                 symbol = specifier.symbol,
43879                 zero = specifier.zero,
43880                 width = specifier.width,
43881                 comma = specifier.comma,
43882                 precision = specifier.precision,
43883                 trim = specifier.trim,
43884                 type = specifier.type; // The "n" type is an alias for ",g".
43885
43886             if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g".
43887             else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits.
43888
43889             if (zero || fill === "0" && align === "=") zero = true, fill = "0", align = "="; // Compute the prefix and suffix.
43890             // For SI-prefix, the suffix is lazily computed.
43891
43892             var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
43893                 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use?
43894             // Is this an integer type?
43895             // Can this type generate exponential notation?
43896
43897             var formatType = formatTypes[type],
43898                 maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified,
43899             // or clamp the specified precision to the supported range.
43900             // For significant precision, it must be in [1, 21].
43901             // For fixed precision, it must be in [0, 20].
43902
43903             precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
43904
43905             function format(value) {
43906               var valuePrefix = prefix,
43907                   valueSuffix = suffix,
43908                   i,
43909                   n,
43910                   c;
43911
43912               if (type === "c") {
43913                 valueSuffix = formatType(value) + valueSuffix;
43914                 value = "";
43915               } else {
43916                 value = +value; // Determine the sign. -0 is not less than 0, but 1 / -0 is!
43917
43918                 var valueNegative = value < 0 || 1 / value < 0; // Perform the initial formatting.
43919
43920                 value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros.
43921
43922                 if (trim) value = formatTrim(value); // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
43923
43924                 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix.
43925
43926                 valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
43927                 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be
43928                 // grouped, and fractional or exponential “suffix” part that is not.
43929
43930                 if (maybeSuffix) {
43931                   i = -1, n = value.length;
43932
43933                   while (++i < n) {
43934                     if (c = value.charCodeAt(i), 48 > c || c > 57) {
43935                       valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
43936                       value = value.slice(0, i);
43937                       break;
43938                     }
43939                   }
43940                 }
43941               } // If the fill character is not "0", grouping is applied before padding.
43942
43943
43944               if (comma && !zero) value = group(value, Infinity); // Compute the padding.
43945
43946               var length = valuePrefix.length + value.length + valueSuffix.length,
43947                   padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding.
43948
43949               if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment.
43950
43951               switch (align) {
43952                 case "<":
43953                   value = valuePrefix + value + valueSuffix + padding;
43954                   break;
43955
43956                 case "=":
43957                   value = valuePrefix + padding + value + valueSuffix;
43958                   break;
43959
43960                 case "^":
43961                   value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
43962                   break;
43963
43964                 default:
43965                   value = padding + valuePrefix + value + valueSuffix;
43966                   break;
43967               }
43968
43969               return numerals(value);
43970             }
43971
43972             format.toString = function () {
43973               return specifier + "";
43974             };
43975
43976             return format;
43977           }
43978
43979           function formatPrefix(specifier, value) {
43980             var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
43981                 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
43982                 k = Math.pow(10, -e),
43983                 prefix = prefixes[8 + e / 3];
43984             return function (value) {
43985               return f(k * value) + prefix;
43986             };
43987           }
43988
43989           return {
43990             format: newFormat,
43991             formatPrefix: formatPrefix
43992           };
43993         }
43994
43995         var locale;
43996         var format$1;
43997         var formatPrefix;
43998         defaultLocale({
43999           thousands: ",",
44000           grouping: [3],
44001           currency: ["$", ""]
44002         });
44003         function defaultLocale(definition) {
44004           locale = formatLocale(definition);
44005           format$1 = locale.format;
44006           formatPrefix = locale.formatPrefix;
44007           return locale;
44008         }
44009
44010         function precisionFixed (step) {
44011           return Math.max(0, -exponent(Math.abs(step)));
44012         }
44013
44014         function precisionPrefix (step, value) {
44015           return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
44016         }
44017
44018         function precisionRound (step, max) {
44019           step = Math.abs(step), max = Math.abs(max) - step;
44020           return Math.max(0, exponent(max) - exponent(step)) + 1;
44021         }
44022
44023         function tickFormat(start, stop, count, specifier) {
44024           var step = tickStep(start, stop, count),
44025               precision;
44026           specifier = formatSpecifier(specifier == null ? ",f" : specifier);
44027
44028           switch (specifier.type) {
44029             case "s":
44030               {
44031                 var value = Math.max(Math.abs(start), Math.abs(stop));
44032                 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
44033                 return formatPrefix(specifier, value);
44034               }
44035
44036             case "":
44037             case "e":
44038             case "g":
44039             case "p":
44040             case "r":
44041               {
44042                 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
44043                 break;
44044               }
44045
44046             case "f":
44047             case "%":
44048               {
44049                 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
44050                 break;
44051               }
44052           }
44053
44054           return format$1(specifier);
44055         }
44056
44057         function linearish(scale) {
44058           var domain = scale.domain;
44059
44060           scale.ticks = function (count) {
44061             var d = domain();
44062             return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
44063           };
44064
44065           scale.tickFormat = function (count, specifier) {
44066             var d = domain();
44067             return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
44068           };
44069
44070           scale.nice = function (count) {
44071             if (count == null) count = 10;
44072             var d = domain();
44073             var i0 = 0;
44074             var i1 = d.length - 1;
44075             var start = d[i0];
44076             var stop = d[i1];
44077             var prestep;
44078             var step;
44079             var maxIter = 10;
44080
44081             if (stop < start) {
44082               step = start, start = stop, stop = step;
44083               step = i0, i0 = i1, i1 = step;
44084             }
44085
44086             while (maxIter-- > 0) {
44087               step = tickIncrement(start, stop, count);
44088
44089               if (step === prestep) {
44090                 d[i0] = start;
44091                 d[i1] = stop;
44092                 return domain(d);
44093               } else if (step > 0) {
44094                 start = Math.floor(start / step) * step;
44095                 stop = Math.ceil(stop / step) * step;
44096               } else if (step < 0) {
44097                 start = Math.ceil(start * step) / step;
44098                 stop = Math.floor(stop * step) / step;
44099               } else {
44100                 break;
44101               }
44102
44103               prestep = step;
44104             }
44105
44106             return scale;
44107           };
44108
44109           return scale;
44110         }
44111         function linear() {
44112           var scale = continuous();
44113
44114           scale.copy = function () {
44115             return copy(scale, linear());
44116           };
44117
44118           initRange.apply(scale, arguments);
44119           return linearish(scale);
44120         }
44121
44122         // eslint-disable-next-line es/no-math-expm1 -- safe
44123         var $expm1 = Math.expm1;
44124         var exp$1 = Math.exp;
44125
44126         // `Math.expm1` method implementation
44127         // https://tc39.es/ecma262/#sec-math.expm1
44128         var mathExpm1 = (!$expm1
44129           // Old FF bug
44130           || $expm1(10) > 22025.465794806719 || $expm1(10) < 22025.4657948067165168
44131           // Tor Browser bug
44132           || $expm1(-2e-17) != -2e-17
44133         ) ? function expm1(x) {
44134           return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp$1(x) - 1;
44135         } : $expm1;
44136
44137         function quantize() {
44138           var x0 = 0,
44139               x1 = 1,
44140               n = 1,
44141               domain = [0.5],
44142               range = [0, 1],
44143               unknown;
44144
44145           function scale(x) {
44146             return x != null && x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
44147           }
44148
44149           function rescale() {
44150             var i = -1;
44151             domain = new Array(n);
44152
44153             while (++i < n) {
44154               domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
44155             }
44156
44157             return scale;
44158           }
44159
44160           scale.domain = function (_) {
44161             var _ref, _ref2;
44162
44163             return arguments.length ? ((_ref = _, _ref2 = _slicedToArray(_ref, 2), x0 = _ref2[0], x1 = _ref2[1], _ref), x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
44164           };
44165
44166           scale.range = function (_) {
44167             return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
44168           };
44169
44170           scale.invertExtent = function (y) {
44171             var i = range.indexOf(y);
44172             return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
44173           };
44174
44175           scale.unknown = function (_) {
44176             return arguments.length ? (unknown = _, scale) : scale;
44177           };
44178
44179           scale.thresholds = function () {
44180             return domain.slice();
44181           };
44182
44183           scale.copy = function () {
44184             return quantize().domain([x0, x1]).range(range).unknown(unknown);
44185           };
44186
44187           return initRange.apply(linearish(scale), arguments);
44188         }
44189
44190         // https://github.com/tc39/proposal-string-pad-start-end
44191         var toLength$2 = toLength$q;
44192         var repeat$1 = stringRepeat;
44193         var requireObjectCoercible$2 = requireObjectCoercible$e;
44194
44195         var ceil = Math.ceil;
44196
44197         // `String.prototype.{ padStart, padEnd }` methods implementation
44198         var createMethod = function (IS_END) {
44199           return function ($this, maxLength, fillString) {
44200             var S = String(requireObjectCoercible$2($this));
44201             var stringLength = S.length;
44202             var fillStr = fillString === undefined ? ' ' : String(fillString);
44203             var intMaxLength = toLength$2(maxLength);
44204             var fillLen, stringFiller;
44205             if (intMaxLength <= stringLength || fillStr == '') return S;
44206             fillLen = intMaxLength - stringLength;
44207             stringFiller = repeat$1.call(fillStr, ceil(fillLen / fillStr.length));
44208             if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen);
44209             return IS_END ? S + stringFiller : stringFiller + S;
44210           };
44211         };
44212
44213         var stringPad = {
44214           // `String.prototype.padStart` method
44215           // https://tc39.es/ecma262/#sec-string.prototype.padstart
44216           start: createMethod(false),
44217           // `String.prototype.padEnd` method
44218           // https://tc39.es/ecma262/#sec-string.prototype.padend
44219           end: createMethod(true)
44220         };
44221
44222         var fails$2 = fails$N;
44223         var padStart = stringPad.start;
44224
44225         var abs$1 = Math.abs;
44226         var DatePrototype = Date.prototype;
44227         var getTime = DatePrototype.getTime;
44228         var nativeDateToISOString = DatePrototype.toISOString;
44229
44230         // `Date.prototype.toISOString` method implementation
44231         // https://tc39.es/ecma262/#sec-date.prototype.toisostring
44232         // PhantomJS / old WebKit fails here:
44233         var dateToIsoString = (fails$2(function () {
44234           return nativeDateToISOString.call(new Date(-5e13 - 1)) != '0385-07-25T07:06:39.999Z';
44235         }) || !fails$2(function () {
44236           nativeDateToISOString.call(new Date(NaN));
44237         })) ? function toISOString() {
44238           if (!isFinite(getTime.call(this))) throw RangeError('Invalid time value');
44239           var date = this;
44240           var year = date.getUTCFullYear();
44241           var milliseconds = date.getUTCMilliseconds();
44242           var sign = year < 0 ? '-' : year > 9999 ? '+' : '';
44243           return sign + padStart(abs$1(year), sign ? 6 : 4, 0) +
44244             '-' + padStart(date.getUTCMonth() + 1, 2, 0) +
44245             '-' + padStart(date.getUTCDate(), 2, 0) +
44246             'T' + padStart(date.getUTCHours(), 2, 0) +
44247             ':' + padStart(date.getUTCMinutes(), 2, 0) +
44248             ':' + padStart(date.getUTCSeconds(), 2, 0) +
44249             '.' + padStart(milliseconds, 3, 0) +
44250             'Z';
44251         } : nativeDateToISOString;
44252
44253         var $$6 = _export;
44254         var toISOString = dateToIsoString;
44255
44256         // `Date.prototype.toISOString` method
44257         // https://tc39.es/ecma262/#sec-date.prototype.toisostring
44258         // PhantomJS / old WebKit has a broken implementations
44259         $$6({ target: 'Date', proto: true, forced: Date.prototype.toISOString !== toISOString }, {
44260           toISOString: toISOString
44261         });
44262
44263         function behaviorBreathe() {
44264           var duration = 800;
44265           var steps = 4;
44266           var selector = '.selected.shadow, .selected .shadow';
44267
44268           var _selected = select(null);
44269
44270           var _classed = '';
44271           var _params = {};
44272           var _done = false;
44273
44274           var _timer;
44275
44276           function ratchetyInterpolator(a, b, steps, units) {
44277             a = parseFloat(a);
44278             b = parseFloat(b);
44279             var sample = quantize().domain([0, 1]).range(d3_quantize(d3_interpolateNumber(a, b), steps));
44280             return function (t) {
44281               return String(sample(t)) + (units || '');
44282             };
44283           }
44284
44285           function reset(selection) {
44286             selection.style('stroke-opacity', null).style('stroke-width', null).style('fill-opacity', null).style('r', null);
44287           }
44288
44289           function setAnimationParams(transition, fromTo) {
44290             var toFrom = fromTo === 'from' ? 'to' : 'from';
44291             transition.styleTween('stroke-opacity', function (d) {
44292               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
44293             }).styleTween('stroke-width', function (d) {
44294               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
44295             }).styleTween('fill-opacity', function (d) {
44296               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
44297             }).styleTween('r', function (d) {
44298               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
44299             });
44300           }
44301
44302           function calcAnimationParams(selection) {
44303             selection.call(reset).each(function (d) {
44304               var s = select(this);
44305               var tag = s.node().tagName;
44306               var p = {
44307                 'from': {},
44308                 'to': {}
44309               };
44310               var opacity;
44311               var width; // determine base opacity and width
44312
44313               if (tag === 'circle') {
44314                 opacity = parseFloat(s.style('fill-opacity') || 0.5);
44315                 width = parseFloat(s.style('r') || 15.5);
44316               } else {
44317                 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
44318                 width = parseFloat(s.style('stroke-width') || 10);
44319               } // calculate from/to interpolation params..
44320
44321
44322               p.tag = tag;
44323               p.from.opacity = opacity * 0.6;
44324               p.to.opacity = opacity * 1.25;
44325               p.from.width = width * 0.7;
44326               p.to.width = width * (tag === 'circle' ? 1.5 : 1);
44327               _params[d.id] = p;
44328             });
44329           }
44330
44331           function run(surface, fromTo) {
44332             var toFrom = fromTo === 'from' ? 'to' : 'from';
44333             var currSelected = surface.selectAll(selector);
44334             var currClassed = surface.attr('class');
44335
44336             if (_done || currSelected.empty()) {
44337               _selected.call(reset);
44338
44339               _selected = select(null);
44340               return;
44341             }
44342
44343             if (!fastDeepEqual(currSelected.data(), _selected.data()) || currClassed !== _classed) {
44344               _selected.call(reset);
44345
44346               _classed = currClassed;
44347               _selected = currSelected.call(calcAnimationParams);
44348             }
44349
44350             var didCallNextRun = false;
44351
44352             _selected.transition().duration(duration).call(setAnimationParams, fromTo).on('end', function () {
44353               // `end` event is called for each selected element, but we want
44354               // it to run only once
44355               if (!didCallNextRun) {
44356                 surface.call(run, toFrom);
44357                 didCallNextRun = true;
44358               } // if entity was deselected, remove breathe styling
44359
44360
44361               if (!select(this).classed('selected')) {
44362                 reset(select(this));
44363               }
44364             });
44365           }
44366
44367           function behavior(surface) {
44368             _done = false;
44369             _timer = timer(function () {
44370               // wait for elements to actually become selected
44371               if (surface.selectAll(selector).empty()) {
44372                 return false;
44373               }
44374
44375               surface.call(run, 'from');
44376
44377               _timer.stop();
44378
44379               return true;
44380             }, 20);
44381           }
44382
44383           behavior.restartIfNeeded = function (surface) {
44384             if (_selected.empty()) {
44385               surface.call(run, 'from');
44386
44387               if (_timer) {
44388                 _timer.stop();
44389               }
44390             }
44391           };
44392
44393           behavior.off = function () {
44394             _done = true;
44395
44396             if (_timer) {
44397               _timer.stop();
44398             }
44399
44400             _selected.interrupt().call(reset);
44401           };
44402
44403           return behavior;
44404         }
44405
44406         /* Creates a keybinding behavior for an operation */
44407         function behaviorOperation(context) {
44408           var _operation;
44409
44410           function keypress(d3_event) {
44411             // prevent operations during low zoom selection
44412             if (!context.map().withinEditableZoom()) return;
44413             if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
44414             d3_event.preventDefault();
44415
44416             var disabled = _operation.disabled();
44417
44418             if (disabled) {
44419               context.ui().flash.duration(4000).iconName('#iD-operation-' + _operation.id).iconClass('operation disabled').label(_operation.tooltip)();
44420             } else {
44421               context.ui().flash.duration(2000).iconName('#iD-operation-' + _operation.id).iconClass('operation').label(_operation.annotation() || _operation.title)();
44422               if (_operation.point) _operation.point(null);
44423
44424               _operation();
44425             }
44426           }
44427
44428           function behavior() {
44429             if (_operation && _operation.available()) {
44430               context.keybinding().on(_operation.keys, keypress);
44431             }
44432
44433             return behavior;
44434           }
44435
44436           behavior.off = function () {
44437             context.keybinding().off(_operation.keys);
44438           };
44439
44440           behavior.which = function (_) {
44441             if (!arguments.length) return _operation;
44442             _operation = _;
44443             return behavior;
44444           };
44445
44446           return behavior;
44447         }
44448
44449         function operationCircularize(context, selectedIDs) {
44450           var _extent;
44451
44452           var _actions = selectedIDs.map(getAction).filter(Boolean);
44453
44454           var _amount = _actions.length === 1 ? 'single' : 'multiple';
44455
44456           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
44457             return n.loc;
44458           });
44459
44460           function getAction(entityID) {
44461             var entity = context.entity(entityID);
44462             if (entity.type !== 'way' || new Set(entity.nodes).size <= 1) return null;
44463
44464             if (!_extent) {
44465               _extent = entity.extent(context.graph());
44466             } else {
44467               _extent = _extent.extend(entity.extent(context.graph()));
44468             }
44469
44470             return actionCircularize(entityID, context.projection);
44471           }
44472
44473           var operation = function operation() {
44474             if (!_actions.length) return;
44475
44476             var combinedAction = function combinedAction(graph, t) {
44477               _actions.forEach(function (action) {
44478                 if (!action.disabled(graph)) {
44479                   graph = action(graph, t);
44480                 }
44481               });
44482
44483               return graph;
44484             };
44485
44486             combinedAction.transitionable = true;
44487             context.perform(combinedAction, operation.annotation());
44488             window.setTimeout(function () {
44489               context.validator().validate();
44490             }, 300); // after any transition
44491           };
44492
44493           operation.available = function () {
44494             return _actions.length && selectedIDs.length === _actions.length;
44495           }; // don't cache this because the visible extent could change
44496
44497
44498           operation.disabled = function () {
44499             if (!_actions.length) return '';
44500
44501             var actionDisableds = _actions.map(function (action) {
44502               return action.disabled(context.graph());
44503             }).filter(Boolean);
44504
44505             if (actionDisableds.length === _actions.length) {
44506               // none of the features can be circularized
44507               if (new Set(actionDisableds).size > 1) {
44508                 return 'multiple_blockers';
44509               }
44510
44511               return actionDisableds[0];
44512             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
44513               return 'too_large';
44514             } else if (someMissing()) {
44515               return 'not_downloaded';
44516             } else if (selectedIDs.some(context.hasHiddenConnections)) {
44517               return 'connected_to_hidden';
44518             }
44519
44520             return false;
44521
44522             function someMissing() {
44523               if (context.inIntro()) return false;
44524               var osm = context.connection();
44525
44526               if (osm) {
44527                 var missing = _coords.filter(function (loc) {
44528                   return !osm.isDataLoaded(loc);
44529                 });
44530
44531                 if (missing.length) {
44532                   missing.forEach(function (loc) {
44533                     context.loadTileAtLoc(loc);
44534                   });
44535                   return true;
44536                 }
44537               }
44538
44539               return false;
44540             }
44541           };
44542
44543           operation.tooltip = function () {
44544             var disable = operation.disabled();
44545             return disable ? _t('operations.circularize.' + disable + '.' + _amount) : _t('operations.circularize.description.' + _amount);
44546           };
44547
44548           operation.annotation = function () {
44549             return _t('operations.circularize.annotation.feature', {
44550               n: _actions.length
44551             });
44552           };
44553
44554           operation.id = 'circularize';
44555           operation.keys = [_t('operations.circularize.key')];
44556           operation.title = _t('operations.circularize.title');
44557           operation.behavior = behaviorOperation(context).which(operation);
44558           return operation;
44559         }
44560
44561         // For example, ⌘Z -> Ctrl+Z
44562
44563         var uiCmd = function uiCmd(code) {
44564           var detected = utilDetect();
44565
44566           if (detected.os === 'mac') {
44567             return code;
44568           }
44569
44570           if (detected.os === 'win') {
44571             if (code === '⌘⇧Z') return 'Ctrl+Y';
44572           }
44573
44574           var result = '',
44575               replacements = {
44576             '⌘': 'Ctrl',
44577             '⇧': 'Shift',
44578             '⌥': 'Alt',
44579             '⌫': 'Backspace',
44580             '⌦': 'Delete'
44581           };
44582
44583           for (var i = 0; i < code.length; i++) {
44584             if (code[i] in replacements) {
44585               result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
44586             } else {
44587               result += code[i];
44588             }
44589           }
44590
44591           return result;
44592         }; // return a display-focused string for a given keyboard code
44593
44594         uiCmd.display = function (code) {
44595           if (code.length !== 1) return code;
44596           var detected = utilDetect();
44597           var mac = detected.os === 'mac';
44598           var replacements = {
44599             '⌘': mac ? '⌘ ' + _t('shortcuts.key.cmd') : _t('shortcuts.key.ctrl'),
44600             '⇧': mac ? '⇧ ' + _t('shortcuts.key.shift') : _t('shortcuts.key.shift'),
44601             '⌥': mac ? '⌥ ' + _t('shortcuts.key.option') : _t('shortcuts.key.alt'),
44602             '⌃': mac ? '⌃ ' + _t('shortcuts.key.ctrl') : _t('shortcuts.key.ctrl'),
44603             '⌫': mac ? '⌫ ' + _t('shortcuts.key.delete') : _t('shortcuts.key.backspace'),
44604             '⌦': mac ? '⌦ ' + _t('shortcuts.key.del') : _t('shortcuts.key.del'),
44605             '↖': mac ? '↖ ' + _t('shortcuts.key.pgup') : _t('shortcuts.key.pgup'),
44606             '↘': mac ? '↘ ' + _t('shortcuts.key.pgdn') : _t('shortcuts.key.pgdn'),
44607             '⇞': mac ? '⇞ ' + _t('shortcuts.key.home') : _t('shortcuts.key.home'),
44608             '⇟': mac ? '⇟ ' + _t('shortcuts.key.end') : _t('shortcuts.key.end'),
44609             '↵': mac ? '⏎ ' + _t('shortcuts.key.return') : _t('shortcuts.key.enter'),
44610             '⎋': mac ? '⎋ ' + _t('shortcuts.key.esc') : _t('shortcuts.key.esc'),
44611             '☰': mac ? '☰ ' + _t('shortcuts.key.menu') : _t('shortcuts.key.menu')
44612           };
44613           return replacements[code] || code;
44614         };
44615
44616         function operationDelete(context, selectedIDs) {
44617           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44618           var action = actionDeleteMultiple(selectedIDs);
44619           var nodes = utilGetAllNodes(selectedIDs, context.graph());
44620           var coords = nodes.map(function (n) {
44621             return n.loc;
44622           });
44623           var extent = utilTotalExtent(selectedIDs, context.graph());
44624
44625           var operation = function operation() {
44626             var nextSelectedID;
44627             var nextSelectedLoc;
44628
44629             if (selectedIDs.length === 1) {
44630               var id = selectedIDs[0];
44631               var entity = context.entity(id);
44632               var geometry = entity.geometry(context.graph());
44633               var parents = context.graph().parentWays(entity);
44634               var parent = parents[0]; // Select the next closest node in the way.
44635
44636               if (geometry === 'vertex') {
44637                 var nodes = parent.nodes;
44638                 var i = nodes.indexOf(id);
44639
44640                 if (i === 0) {
44641                   i++;
44642                 } else if (i === nodes.length - 1) {
44643                   i--;
44644                 } else {
44645                   var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
44646                   var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
44647                   i = a < b ? i - 1 : i + 1;
44648                 }
44649
44650                 nextSelectedID = nodes[i];
44651                 nextSelectedLoc = context.entity(nextSelectedID).loc;
44652               }
44653             }
44654
44655             context.perform(action, operation.annotation());
44656             context.validator().validate();
44657
44658             if (nextSelectedID && nextSelectedLoc) {
44659               if (context.hasEntity(nextSelectedID)) {
44660                 context.enter(modeSelect(context, [nextSelectedID]).follow(true));
44661               } else {
44662                 context.map().centerEase(nextSelectedLoc);
44663                 context.enter(modeBrowse(context));
44664               }
44665             } else {
44666               context.enter(modeBrowse(context));
44667             }
44668           };
44669
44670           operation.available = function () {
44671             return true;
44672           };
44673
44674           operation.disabled = function () {
44675             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44676               return 'too_large';
44677             } else if (someMissing()) {
44678               return 'not_downloaded';
44679             } else if (selectedIDs.some(context.hasHiddenConnections)) {
44680               return 'connected_to_hidden';
44681             } else if (selectedIDs.some(protectedMember)) {
44682               return 'part_of_relation';
44683             } else if (selectedIDs.some(incompleteRelation)) {
44684               return 'incomplete_relation';
44685             } else if (selectedIDs.some(hasWikidataTag)) {
44686               return 'has_wikidata_tag';
44687             }
44688
44689             return false;
44690
44691             function someMissing() {
44692               if (context.inIntro()) return false;
44693               var osm = context.connection();
44694
44695               if (osm) {
44696                 var missing = coords.filter(function (loc) {
44697                   return !osm.isDataLoaded(loc);
44698                 });
44699
44700                 if (missing.length) {
44701                   missing.forEach(function (loc) {
44702                     context.loadTileAtLoc(loc);
44703                   });
44704                   return true;
44705                 }
44706               }
44707
44708               return false;
44709             }
44710
44711             function hasWikidataTag(id) {
44712               var entity = context.entity(id);
44713               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
44714             }
44715
44716             function incompleteRelation(id) {
44717               var entity = context.entity(id);
44718               return entity.type === 'relation' && !entity.isComplete(context.graph());
44719             }
44720
44721             function protectedMember(id) {
44722               var entity = context.entity(id);
44723               if (entity.type !== 'way') return false;
44724               var parents = context.graph().parentRelations(entity);
44725
44726               for (var i = 0; i < parents.length; i++) {
44727                 var parent = parents[i];
44728                 var type = parent.tags.type;
44729                 var role = parent.memberById(id).role || 'outer';
44730
44731                 if (type === 'route' || type === 'boundary' || type === 'multipolygon' && role === 'outer') {
44732                   return true;
44733                 }
44734               }
44735
44736               return false;
44737             }
44738           };
44739
44740           operation.tooltip = function () {
44741             var disable = operation.disabled();
44742             return disable ? _t('operations.delete.' + disable + '.' + multi) : _t('operations.delete.description.' + multi);
44743           };
44744
44745           operation.annotation = function () {
44746             return selectedIDs.length === 1 ? _t('operations.delete.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.delete.annotation.feature', {
44747               n: selectedIDs.length
44748             });
44749           };
44750
44751           operation.id = 'delete';
44752           operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
44753           operation.title = _t('operations.delete.title');
44754           operation.behavior = behaviorOperation(context).which(operation);
44755           return operation;
44756         }
44757
44758         function operationOrthogonalize(context, selectedIDs) {
44759           var _extent;
44760
44761           var _type;
44762
44763           var _actions = selectedIDs.map(chooseAction).filter(Boolean);
44764
44765           var _amount = _actions.length === 1 ? 'single' : 'multiple';
44766
44767           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
44768             return n.loc;
44769           });
44770
44771           function chooseAction(entityID) {
44772             var entity = context.entity(entityID);
44773             var geometry = entity.geometry(context.graph());
44774
44775             if (!_extent) {
44776               _extent = entity.extent(context.graph());
44777             } else {
44778               _extent = _extent.extend(entity.extent(context.graph()));
44779             } // square a line/area
44780
44781
44782             if (entity.type === 'way' && new Set(entity.nodes).size > 2) {
44783               if (_type && _type !== 'feature') return null;
44784               _type = 'feature';
44785               return actionOrthogonalize(entityID, context.projection); // square a single vertex
44786             } else if (geometry === 'vertex') {
44787               if (_type && _type !== 'corner') return null;
44788               _type = 'corner';
44789               var graph = context.graph();
44790               var parents = graph.parentWays(entity);
44791
44792               if (parents.length === 1) {
44793                 var way = parents[0];
44794
44795                 if (way.nodes.indexOf(entityID) !== -1) {
44796                   return actionOrthogonalize(way.id, context.projection, entityID);
44797                 }
44798               }
44799             }
44800
44801             return null;
44802           }
44803
44804           var operation = function operation() {
44805             if (!_actions.length) return;
44806
44807             var combinedAction = function combinedAction(graph, t) {
44808               _actions.forEach(function (action) {
44809                 if (!action.disabled(graph)) {
44810                   graph = action(graph, t);
44811                 }
44812               });
44813
44814               return graph;
44815             };
44816
44817             combinedAction.transitionable = true;
44818             context.perform(combinedAction, operation.annotation());
44819             window.setTimeout(function () {
44820               context.validator().validate();
44821             }, 300); // after any transition
44822           };
44823
44824           operation.available = function () {
44825             return _actions.length && selectedIDs.length === _actions.length;
44826           }; // don't cache this because the visible extent could change
44827
44828
44829           operation.disabled = function () {
44830             if (!_actions.length) return '';
44831
44832             var actionDisableds = _actions.map(function (action) {
44833               return action.disabled(context.graph());
44834             }).filter(Boolean);
44835
44836             if (actionDisableds.length === _actions.length) {
44837               // none of the features can be squared
44838               if (new Set(actionDisableds).size > 1) {
44839                 return 'multiple_blockers';
44840               }
44841
44842               return actionDisableds[0];
44843             } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
44844               return 'too_large';
44845             } else if (someMissing()) {
44846               return 'not_downloaded';
44847             } else if (selectedIDs.some(context.hasHiddenConnections)) {
44848               return 'connected_to_hidden';
44849             }
44850
44851             return false;
44852
44853             function someMissing() {
44854               if (context.inIntro()) return false;
44855               var osm = context.connection();
44856
44857               if (osm) {
44858                 var missing = _coords.filter(function (loc) {
44859                   return !osm.isDataLoaded(loc);
44860                 });
44861
44862                 if (missing.length) {
44863                   missing.forEach(function (loc) {
44864                     context.loadTileAtLoc(loc);
44865                   });
44866                   return true;
44867                 }
44868               }
44869
44870               return false;
44871             }
44872           };
44873
44874           operation.tooltip = function () {
44875             var disable = operation.disabled();
44876             return disable ? _t('operations.orthogonalize.' + disable + '.' + _amount) : _t('operations.orthogonalize.description.' + _type + '.' + _amount);
44877           };
44878
44879           operation.annotation = function () {
44880             return _t('operations.orthogonalize.annotation.' + _type, {
44881               n: _actions.length
44882             });
44883           };
44884
44885           operation.id = 'orthogonalize';
44886           operation.keys = [_t('operations.orthogonalize.key')];
44887           operation.title = _t('operations.orthogonalize.title');
44888           operation.behavior = behaviorOperation(context).which(operation);
44889           return operation;
44890         }
44891
44892         function operationReflectShort(context, selectedIDs) {
44893           return operationReflect(context, selectedIDs, 'short');
44894         }
44895         function operationReflectLong(context, selectedIDs) {
44896           return operationReflect(context, selectedIDs, 'long');
44897         }
44898         function operationReflect(context, selectedIDs, axis) {
44899           axis = axis || 'long';
44900           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44901           var nodes = utilGetAllNodes(selectedIDs, context.graph());
44902           var coords = nodes.map(function (n) {
44903             return n.loc;
44904           });
44905           var extent = utilTotalExtent(selectedIDs, context.graph());
44906
44907           var operation = function operation() {
44908             var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === 'long'));
44909             context.perform(action, operation.annotation());
44910             window.setTimeout(function () {
44911               context.validator().validate();
44912             }, 300); // after any transition
44913           };
44914
44915           operation.available = function () {
44916             return nodes.length >= 3;
44917           }; // don't cache this because the visible extent could change
44918
44919
44920           operation.disabled = function () {
44921             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44922               return 'too_large';
44923             } else if (someMissing()) {
44924               return 'not_downloaded';
44925             } else if (selectedIDs.some(context.hasHiddenConnections)) {
44926               return 'connected_to_hidden';
44927             } else if (selectedIDs.some(incompleteRelation)) {
44928               return 'incomplete_relation';
44929             }
44930
44931             return false;
44932
44933             function someMissing() {
44934               if (context.inIntro()) return false;
44935               var osm = context.connection();
44936
44937               if (osm) {
44938                 var missing = coords.filter(function (loc) {
44939                   return !osm.isDataLoaded(loc);
44940                 });
44941
44942                 if (missing.length) {
44943                   missing.forEach(function (loc) {
44944                     context.loadTileAtLoc(loc);
44945                   });
44946                   return true;
44947                 }
44948               }
44949
44950               return false;
44951             }
44952
44953             function incompleteRelation(id) {
44954               var entity = context.entity(id);
44955               return entity.type === 'relation' && !entity.isComplete(context.graph());
44956             }
44957           };
44958
44959           operation.tooltip = function () {
44960             var disable = operation.disabled();
44961             return disable ? _t('operations.reflect.' + disable + '.' + multi) : _t('operations.reflect.description.' + axis + '.' + multi);
44962           };
44963
44964           operation.annotation = function () {
44965             return _t('operations.reflect.annotation.' + axis + '.feature', {
44966               n: selectedIDs.length
44967             });
44968           };
44969
44970           operation.id = 'reflect-' + axis;
44971           operation.keys = [_t('operations.reflect.key.' + axis)];
44972           operation.title = _t('operations.reflect.title.' + axis);
44973           operation.behavior = behaviorOperation(context).which(operation);
44974           return operation;
44975         }
44976
44977         function operationMove(context, selectedIDs) {
44978           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44979           var nodes = utilGetAllNodes(selectedIDs, context.graph());
44980           var coords = nodes.map(function (n) {
44981             return n.loc;
44982           });
44983           var extent = utilTotalExtent(selectedIDs, context.graph());
44984
44985           var operation = function operation() {
44986             context.enter(modeMove(context, selectedIDs));
44987           };
44988
44989           operation.available = function () {
44990             return selectedIDs.length > 0;
44991           };
44992
44993           operation.disabled = function () {
44994             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44995               return 'too_large';
44996             } else if (someMissing()) {
44997               return 'not_downloaded';
44998             } else if (selectedIDs.some(context.hasHiddenConnections)) {
44999               return 'connected_to_hidden';
45000             } else if (selectedIDs.some(incompleteRelation)) {
45001               return 'incomplete_relation';
45002             }
45003
45004             return false;
45005
45006             function someMissing() {
45007               if (context.inIntro()) return false;
45008               var osm = context.connection();
45009
45010               if (osm) {
45011                 var missing = coords.filter(function (loc) {
45012                   return !osm.isDataLoaded(loc);
45013                 });
45014
45015                 if (missing.length) {
45016                   missing.forEach(function (loc) {
45017                     context.loadTileAtLoc(loc);
45018                   });
45019                   return true;
45020                 }
45021               }
45022
45023               return false;
45024             }
45025
45026             function incompleteRelation(id) {
45027               var entity = context.entity(id);
45028               return entity.type === 'relation' && !entity.isComplete(context.graph());
45029             }
45030           };
45031
45032           operation.tooltip = function () {
45033             var disable = operation.disabled();
45034             return disable ? _t('operations.move.' + disable + '.' + multi) : _t('operations.move.description.' + multi);
45035           };
45036
45037           operation.annotation = function () {
45038             return selectedIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.move.annotation.feature', {
45039               n: selectedIDs.length
45040             });
45041           };
45042
45043           operation.id = 'move';
45044           operation.keys = [_t('operations.move.key')];
45045           operation.title = _t('operations.move.title');
45046           operation.behavior = behaviorOperation(context).which(operation);
45047           operation.mouseOnly = true;
45048           return operation;
45049         }
45050
45051         function modeRotate(context, entityIDs) {
45052           var _tolerancePx = 4; // see also behaviorDrag, behaviorSelect, modeMove
45053
45054           var mode = {
45055             id: 'rotate',
45056             button: 'browse'
45057           };
45058           var keybinding = utilKeybinding('rotate');
45059           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];
45060           var annotation = entityIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.rotate.annotation.feature', {
45061             n: entityIDs.length
45062           });
45063
45064           var _prevGraph;
45065
45066           var _prevAngle;
45067
45068           var _prevTransform;
45069
45070           var _pivot; // use pointer events on supported platforms; fallback to mouse events
45071
45072
45073           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
45074
45075           function doRotate(d3_event) {
45076             var fn;
45077
45078             if (context.graph() !== _prevGraph) {
45079               fn = context.perform;
45080             } else {
45081               fn = context.replace;
45082             } // projection changed, recalculate _pivot
45083
45084
45085             var projection = context.projection;
45086             var currTransform = projection.transform();
45087
45088             if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
45089               var nodes = utilGetAllNodes(entityIDs, context.graph());
45090               var points = nodes.map(function (n) {
45091                 return projection(n.loc);
45092               });
45093               _pivot = getPivot(points);
45094               _prevAngle = undefined;
45095             }
45096
45097             var currMouse = context.map().mouse(d3_event);
45098             var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
45099             if (typeof _prevAngle === 'undefined') _prevAngle = currAngle;
45100             var delta = currAngle - _prevAngle;
45101             fn(actionRotate(entityIDs, _pivot, delta, projection));
45102             _prevTransform = currTransform;
45103             _prevAngle = currAngle;
45104             _prevGraph = context.graph();
45105           }
45106
45107           function getPivot(points) {
45108             var _pivot;
45109
45110             if (points.length === 1) {
45111               _pivot = points[0];
45112             } else if (points.length === 2) {
45113               _pivot = geoVecInterp(points[0], points[1], 0.5);
45114             } else {
45115               var polygonHull = d3_polygonHull(points);
45116
45117               if (polygonHull.length === 2) {
45118                 _pivot = geoVecInterp(points[0], points[1], 0.5);
45119               } else {
45120                 _pivot = d3_polygonCentroid(d3_polygonHull(points));
45121               }
45122             }
45123
45124             return _pivot;
45125           }
45126
45127           function finish(d3_event) {
45128             d3_event.stopPropagation();
45129             context.replace(actionNoop(), annotation);
45130             context.enter(modeSelect(context, entityIDs));
45131           }
45132
45133           function cancel() {
45134             if (_prevGraph) context.pop(); // remove the rotate
45135
45136             context.enter(modeSelect(context, entityIDs));
45137           }
45138
45139           function undone() {
45140             context.enter(modeBrowse(context));
45141           }
45142
45143           mode.enter = function () {
45144             _prevGraph = null;
45145             context.features().forceVisible(entityIDs);
45146             behaviors.forEach(context.install);
45147             var downEvent;
45148             context.surface().on(_pointerPrefix + 'down.modeRotate', function (d3_event) {
45149               downEvent = d3_event;
45150             });
45151             select(window).on(_pointerPrefix + 'move.modeRotate', doRotate, true).on(_pointerPrefix + 'up.modeRotate', function (d3_event) {
45152               if (!downEvent) return;
45153               var mapNode = context.container().select('.main-map').node();
45154               var pointGetter = utilFastMouse(mapNode);
45155               var p1 = pointGetter(downEvent);
45156               var p2 = pointGetter(d3_event);
45157               var dist = geoVecLength(p1, p2);
45158               if (dist <= _tolerancePx) finish(d3_event);
45159               downEvent = null;
45160             }, true);
45161             context.history().on('undone.modeRotate', undone);
45162             keybinding.on('⎋', cancel).on('↩', finish);
45163             select(document).call(keybinding);
45164           };
45165
45166           mode.exit = function () {
45167             behaviors.forEach(context.uninstall);
45168             context.surface().on(_pointerPrefix + 'down.modeRotate', null);
45169             select(window).on(_pointerPrefix + 'move.modeRotate', null, true).on(_pointerPrefix + 'up.modeRotate', null, true);
45170             context.history().on('undone.modeRotate', null);
45171             select(document).call(keybinding.unbind);
45172             context.features().forceVisible([]);
45173           };
45174
45175           mode.selectedIDs = function () {
45176             if (!arguments.length) return entityIDs; // no assign
45177
45178             return mode;
45179           };
45180
45181           return mode;
45182         }
45183
45184         function operationRotate(context, selectedIDs) {
45185           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
45186           var nodes = utilGetAllNodes(selectedIDs, context.graph());
45187           var coords = nodes.map(function (n) {
45188             return n.loc;
45189           });
45190           var extent = utilTotalExtent(selectedIDs, context.graph());
45191
45192           var operation = function operation() {
45193             context.enter(modeRotate(context, selectedIDs));
45194           };
45195
45196           operation.available = function () {
45197             return nodes.length >= 2;
45198           };
45199
45200           operation.disabled = function () {
45201             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
45202               return 'too_large';
45203             } else if (someMissing()) {
45204               return 'not_downloaded';
45205             } else if (selectedIDs.some(context.hasHiddenConnections)) {
45206               return 'connected_to_hidden';
45207             } else if (selectedIDs.some(incompleteRelation)) {
45208               return 'incomplete_relation';
45209             }
45210
45211             return false;
45212
45213             function someMissing() {
45214               if (context.inIntro()) return false;
45215               var osm = context.connection();
45216
45217               if (osm) {
45218                 var missing = coords.filter(function (loc) {
45219                   return !osm.isDataLoaded(loc);
45220                 });
45221
45222                 if (missing.length) {
45223                   missing.forEach(function (loc) {
45224                     context.loadTileAtLoc(loc);
45225                   });
45226                   return true;
45227                 }
45228               }
45229
45230               return false;
45231             }
45232
45233             function incompleteRelation(id) {
45234               var entity = context.entity(id);
45235               return entity.type === 'relation' && !entity.isComplete(context.graph());
45236             }
45237           };
45238
45239           operation.tooltip = function () {
45240             var disable = operation.disabled();
45241             return disable ? _t('operations.rotate.' + disable + '.' + multi) : _t('operations.rotate.description.' + multi);
45242           };
45243
45244           operation.annotation = function () {
45245             return selectedIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.rotate.annotation.feature', {
45246               n: selectedIDs.length
45247             });
45248           };
45249
45250           operation.id = 'rotate';
45251           operation.keys = [_t('operations.rotate.key')];
45252           operation.title = _t('operations.rotate.title');
45253           operation.behavior = behaviorOperation(context).which(operation);
45254           operation.mouseOnly = true;
45255           return operation;
45256         }
45257
45258         function modeMove(context, entityIDs, baseGraph) {
45259           var _tolerancePx = 4; // see also behaviorDrag, behaviorSelect, modeRotate
45260
45261           var mode = {
45262             id: 'move',
45263             button: 'browse'
45264           };
45265           var keybinding = utilKeybinding('move');
45266           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];
45267           var annotation = entityIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.move.annotation.feature', {
45268             n: entityIDs.length
45269           });
45270
45271           var _prevGraph;
45272
45273           var _cache;
45274
45275           var _origin;
45276
45277           var _nudgeInterval; // use pointer events on supported platforms; fallback to mouse events
45278
45279
45280           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
45281
45282           function doMove(nudge) {
45283             nudge = nudge || [0, 0];
45284             var fn;
45285
45286             if (_prevGraph !== context.graph()) {
45287               _cache = {};
45288               _origin = context.map().mouseCoordinates();
45289               fn = context.perform;
45290             } else {
45291               fn = context.overwrite;
45292             }
45293
45294             var currMouse = context.map().mouse();
45295             var origMouse = context.projection(_origin);
45296             var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
45297             fn(actionMove(entityIDs, delta, context.projection, _cache));
45298             _prevGraph = context.graph();
45299           }
45300
45301           function startNudge(nudge) {
45302             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
45303             _nudgeInterval = window.setInterval(function () {
45304               context.map().pan(nudge);
45305               doMove(nudge);
45306             }, 50);
45307           }
45308
45309           function stopNudge() {
45310             if (_nudgeInterval) {
45311               window.clearInterval(_nudgeInterval);
45312               _nudgeInterval = null;
45313             }
45314           }
45315
45316           function move() {
45317             doMove();
45318             var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
45319
45320             if (nudge) {
45321               startNudge(nudge);
45322             } else {
45323               stopNudge();
45324             }
45325           }
45326
45327           function finish(d3_event) {
45328             d3_event.stopPropagation();
45329             context.replace(actionNoop(), annotation);
45330             context.enter(modeSelect(context, entityIDs));
45331             stopNudge();
45332           }
45333
45334           function cancel() {
45335             if (baseGraph) {
45336               while (context.graph() !== baseGraph) {
45337                 context.pop();
45338               } // reset to baseGraph
45339
45340
45341               context.enter(modeBrowse(context));
45342             } else {
45343               if (_prevGraph) context.pop(); // remove the move
45344
45345               context.enter(modeSelect(context, entityIDs));
45346             }
45347
45348             stopNudge();
45349           }
45350
45351           function undone() {
45352             context.enter(modeBrowse(context));
45353           }
45354
45355           mode.enter = function () {
45356             _origin = context.map().mouseCoordinates();
45357             _prevGraph = null;
45358             _cache = {};
45359             context.features().forceVisible(entityIDs);
45360             behaviors.forEach(context.install);
45361             var downEvent;
45362             context.surface().on(_pointerPrefix + 'down.modeMove', function (d3_event) {
45363               downEvent = d3_event;
45364             });
45365             select(window).on(_pointerPrefix + 'move.modeMove', move, true).on(_pointerPrefix + 'up.modeMove', function (d3_event) {
45366               if (!downEvent) return;
45367               var mapNode = context.container().select('.main-map').node();
45368               var pointGetter = utilFastMouse(mapNode);
45369               var p1 = pointGetter(downEvent);
45370               var p2 = pointGetter(d3_event);
45371               var dist = geoVecLength(p1, p2);
45372               if (dist <= _tolerancePx) finish(d3_event);
45373               downEvent = null;
45374             }, true);
45375             context.history().on('undone.modeMove', undone);
45376             keybinding.on('⎋', cancel).on('↩', finish);
45377             select(document).call(keybinding);
45378           };
45379
45380           mode.exit = function () {
45381             stopNudge();
45382             behaviors.forEach(function (behavior) {
45383               context.uninstall(behavior);
45384             });
45385             context.surface().on(_pointerPrefix + 'down.modeMove', null);
45386             select(window).on(_pointerPrefix + 'move.modeMove', null, true).on(_pointerPrefix + 'up.modeMove', null, true);
45387             context.history().on('undone.modeMove', null);
45388             select(document).call(keybinding.unbind);
45389             context.features().forceVisible([]);
45390           };
45391
45392           mode.selectedIDs = function () {
45393             if (!arguments.length) return entityIDs; // no assign
45394
45395             return mode;
45396           };
45397
45398           return mode;
45399         }
45400
45401         function behaviorPaste(context) {
45402           function doPaste(d3_event) {
45403             // prevent paste during low zoom selection
45404             if (!context.map().withinEditableZoom()) return;
45405             d3_event.preventDefault();
45406             var baseGraph = context.graph();
45407             var mouse = context.map().mouse();
45408             var projection = context.projection;
45409             var viewport = geoExtent(projection.clipExtent()).polygon();
45410             if (!geoPointInPolygon(mouse, viewport)) return;
45411             var oldIDs = context.copyIDs();
45412             if (!oldIDs.length) return;
45413             var extent = geoExtent();
45414             var oldGraph = context.copyGraph();
45415             var newIDs = [];
45416             var action = actionCopyEntities(oldIDs, oldGraph);
45417             context.perform(action);
45418             var copies = action.copies();
45419             var originals = new Set();
45420             Object.values(copies).forEach(function (entity) {
45421               originals.add(entity.id);
45422             });
45423
45424             for (var id in copies) {
45425               var oldEntity = oldGraph.entity(id);
45426               var newEntity = copies[id];
45427
45428               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
45429
45430
45431               var parents = context.graph().parentWays(newEntity);
45432               var parentCopied = parents.some(function (parent) {
45433                 return originals.has(parent.id);
45434               });
45435
45436               if (!parentCopied) {
45437                 newIDs.push(newEntity.id);
45438               }
45439             } // Put pasted objects where mouse pointer is..
45440
45441
45442             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
45443             var delta = geoVecSubtract(mouse, copyPoint);
45444             context.perform(actionMove(newIDs, delta, projection));
45445             context.enter(modeMove(context, newIDs, baseGraph));
45446           }
45447
45448           function behavior() {
45449             context.keybinding().on(uiCmd('⌘V'), doPaste);
45450             return behavior;
45451           }
45452
45453           behavior.off = function () {
45454             context.keybinding().off(uiCmd('⌘V'));
45455           };
45456
45457           return behavior;
45458         }
45459
45460         var $$5 = _export;
45461         var repeat = stringRepeat;
45462
45463         // `String.prototype.repeat` method
45464         // https://tc39.es/ecma262/#sec-string.prototype.repeat
45465         $$5({ target: 'String', proto: true }, {
45466           repeat: repeat
45467         });
45468
45469         /*
45470             `behaviorDrag` is like `d3_behavior.drag`, with the following differences:
45471
45472             * The `origin` function is expected to return an [x, y] tuple rather than an
45473               {x, y} object.
45474             * The events are `start`, `move`, and `end`.
45475               (https://github.com/mbostock/d3/issues/563)
45476             * The `start` event is not dispatched until the first cursor movement occurs.
45477               (https://github.com/mbostock/d3/pull/368)
45478             * The `move` event has a `point` and `delta` [x, y] tuple properties rather
45479               than `x`, `y`, `dx`, and `dy` properties.
45480             * The `end` event is not dispatched if no movement occurs.
45481             * An `off` function is available that unbinds the drag's internal event handlers.
45482          */
45483
45484         function behaviorDrag() {
45485           var dispatch = dispatch$8('start', 'move', 'end'); // see also behaviorSelect
45486
45487           var _tolerancePx = 1; // keep this low to facilitate pixel-perfect micromapping
45488
45489           var _penTolerancePx = 4; // styluses can be touchy so require greater movement - #1981
45490
45491           var _origin = null;
45492           var _selector = '';
45493
45494           var _targetNode;
45495
45496           var _targetEntity;
45497
45498           var _surface;
45499
45500           var _pointerId; // use pointer events on supported platforms; fallback to mouse events
45501
45502
45503           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
45504
45505           var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect');
45506
45507           var d3_event_userSelectSuppress = function d3_event_userSelectSuppress() {
45508             var selection$1 = selection();
45509             var select = selection$1.style(d3_event_userSelectProperty);
45510             selection$1.style(d3_event_userSelectProperty, 'none');
45511             return function () {
45512               selection$1.style(d3_event_userSelectProperty, select);
45513             };
45514           };
45515
45516           function pointerdown(d3_event) {
45517             if (_pointerId) return;
45518             _pointerId = d3_event.pointerId || 'mouse';
45519             _targetNode = this; // only force reflow once per drag
45520
45521             var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
45522             var offset;
45523             var startOrigin = pointerLocGetter(d3_event);
45524             var started = false;
45525             var selectEnable = d3_event_userSelectSuppress();
45526             select(window).on(_pointerPrefix + 'move.drag', pointermove).on(_pointerPrefix + 'up.drag pointercancel.drag', pointerup, true);
45527
45528             if (_origin) {
45529               offset = _origin.call(_targetNode, _targetEntity);
45530               offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
45531             } else {
45532               offset = [0, 0];
45533             }
45534
45535             d3_event.stopPropagation();
45536
45537             function pointermove(d3_event) {
45538               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
45539               var p = pointerLocGetter(d3_event);
45540
45541               if (!started) {
45542                 var dist = geoVecLength(startOrigin, p);
45543                 var tolerance = d3_event.pointerType === 'pen' ? _penTolerancePx : _tolerancePx; // don't start until the drag has actually moved somewhat
45544
45545                 if (dist < tolerance) return;
45546                 started = true;
45547                 dispatch.call('start', this, d3_event, _targetEntity); // Don't send a `move` event in the same cycle as `start` since dragging
45548                 // a midpoint will convert the target to a node.
45549               } else {
45550                 startOrigin = p;
45551                 d3_event.stopPropagation();
45552                 d3_event.preventDefault();
45553                 var dx = p[0] - startOrigin[0];
45554                 var dy = p[1] - startOrigin[1];
45555                 dispatch.call('move', this, d3_event, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
45556               }
45557             }
45558
45559             function pointerup(d3_event) {
45560               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
45561               _pointerId = null;
45562
45563               if (started) {
45564                 dispatch.call('end', this, d3_event, _targetEntity);
45565                 d3_event.preventDefault();
45566               }
45567
45568               select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
45569               selectEnable();
45570             }
45571           }
45572
45573           function behavior(selection) {
45574             var matchesSelector = utilPrefixDOMProperty('matchesSelector');
45575             var delegate = pointerdown;
45576
45577             if (_selector) {
45578               delegate = function delegate(d3_event) {
45579                 var root = this;
45580                 var target = d3_event.target;
45581
45582                 for (; target && target !== root; target = target.parentNode) {
45583                   var datum = target.__data__;
45584                   _targetEntity = datum instanceof osmNote ? datum : datum && datum.properties && datum.properties.entity;
45585
45586                   if (_targetEntity && target[matchesSelector](_selector)) {
45587                     return pointerdown.call(target, d3_event);
45588                   }
45589                 }
45590               };
45591             }
45592
45593             selection.on(_pointerPrefix + 'down.drag' + _selector, delegate);
45594           }
45595
45596           behavior.off = function (selection) {
45597             selection.on(_pointerPrefix + 'down.drag' + _selector, null);
45598           };
45599
45600           behavior.selector = function (_) {
45601             if (!arguments.length) return _selector;
45602             _selector = _;
45603             return behavior;
45604           };
45605
45606           behavior.origin = function (_) {
45607             if (!arguments.length) return _origin;
45608             _origin = _;
45609             return behavior;
45610           };
45611
45612           behavior.cancel = function () {
45613             select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
45614             return behavior;
45615           };
45616
45617           behavior.targetNode = function (_) {
45618             if (!arguments.length) return _targetNode;
45619             _targetNode = _;
45620             return behavior;
45621           };
45622
45623           behavior.targetEntity = function (_) {
45624             if (!arguments.length) return _targetEntity;
45625             _targetEntity = _;
45626             return behavior;
45627           };
45628
45629           behavior.surface = function (_) {
45630             if (!arguments.length) return _surface;
45631             _surface = _;
45632             return behavior;
45633           };
45634
45635           return utilRebind(behavior, dispatch, 'on');
45636         }
45637
45638         function modeDragNode(context) {
45639           var mode = {
45640             id: 'drag-node',
45641             button: 'browse'
45642           };
45643           var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover);
45644           var edit = behaviorEdit(context);
45645
45646           var _nudgeInterval;
45647
45648           var _restoreSelectedIDs = [];
45649           var _wasMidpoint = false;
45650           var _isCancelled = false;
45651
45652           var _activeEntity;
45653
45654           var _startLoc;
45655
45656           var _lastLoc;
45657
45658           function startNudge(d3_event, entity, nudge) {
45659             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
45660             _nudgeInterval = window.setInterval(function () {
45661               context.map().pan(nudge);
45662               doMove(d3_event, entity, nudge);
45663             }, 50);
45664           }
45665
45666           function stopNudge() {
45667             if (_nudgeInterval) {
45668               window.clearInterval(_nudgeInterval);
45669               _nudgeInterval = null;
45670             }
45671           }
45672
45673           function moveAnnotation(entity) {
45674             return _t('operations.move.annotation.' + entity.geometry(context.graph()));
45675           }
45676
45677           function connectAnnotation(nodeEntity, targetEntity) {
45678             var nodeGeometry = nodeEntity.geometry(context.graph());
45679             var targetGeometry = targetEntity.geometry(context.graph());
45680
45681             if (nodeGeometry === 'vertex' && targetGeometry === 'vertex') {
45682               var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
45683               var targetParentWayIDs = context.graph().parentWays(targetEntity);
45684               var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs); // if both vertices are part of the same way
45685
45686               if (sharedParentWays.length !== 0) {
45687                 // if the nodes are next to each other, they are merged
45688                 if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
45689                   return _t('operations.connect.annotation.from_vertex.to_adjacent_vertex');
45690                 }
45691
45692                 return _t('operations.connect.annotation.from_vertex.to_sibling_vertex');
45693               }
45694             }
45695
45696             return _t('operations.connect.annotation.from_' + nodeGeometry + '.to_' + targetGeometry);
45697           }
45698
45699           function shouldSnapToNode(target) {
45700             if (!_activeEntity) return false;
45701             return _activeEntity.geometry(context.graph()) !== 'vertex' || target.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(target, context.graph());
45702           }
45703
45704           function origin(entity) {
45705             return context.projection(entity.loc);
45706           }
45707
45708           function keydown(d3_event) {
45709             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
45710               if (context.surface().classed('nope')) {
45711                 context.surface().classed('nope-suppressed', true);
45712               }
45713
45714               context.surface().classed('nope', false).classed('nope-disabled', true);
45715             }
45716           }
45717
45718           function keyup(d3_event) {
45719             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
45720               if (context.surface().classed('nope-suppressed')) {
45721                 context.surface().classed('nope', true);
45722               }
45723
45724               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
45725             }
45726           }
45727
45728           function start(d3_event, entity) {
45729             _wasMidpoint = entity.type === 'midpoint';
45730             var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
45731             _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
45732
45733             if (_isCancelled) {
45734               if (hasHidden) {
45735                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('modes.drag_node.connected_to_hidden'))();
45736               }
45737
45738               return drag.cancel();
45739             }
45740
45741             if (_wasMidpoint) {
45742               var midpoint = entity;
45743               entity = osmNode();
45744               context.perform(actionAddMidpoint(midpoint, entity));
45745               entity = context.entity(entity.id); // get post-action entity
45746
45747               var vertex = context.surface().selectAll('.' + entity.id);
45748               drag.targetNode(vertex.node()).targetEntity(entity);
45749             } else {
45750               context.perform(actionNoop());
45751             }
45752
45753             _activeEntity = entity;
45754             _startLoc = entity.loc;
45755             hover.ignoreVertex(entity.geometry(context.graph()) === 'vertex');
45756             context.surface().selectAll('.' + _activeEntity.id).classed('active', true);
45757             context.enter(mode);
45758           } // related code
45759           // - `behavior/draw.js` `datum()`
45760
45761
45762           function datum(d3_event) {
45763             if (!d3_event || d3_event.altKey) {
45764               return {};
45765             } else {
45766               // When dragging, snap only to touch targets..
45767               // (this excludes area fills and active drawing elements)
45768               var d = d3_event.target.__data__;
45769               return d && d.properties && d.properties.target ? d : {};
45770             }
45771           }
45772
45773           function doMove(d3_event, entity, nudge) {
45774             nudge = nudge || [0, 0];
45775             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
45776             var currMouse = geoVecSubtract(currPoint, nudge);
45777             var loc = context.projection.invert(currMouse);
45778             var target, edge;
45779
45780             if (!_nudgeInterval) {
45781               // If not nudging at the edge of the viewport, try to snap..
45782               // related code
45783               // - `mode/drag_node.js`     `doMove()`
45784               // - `behavior/draw.js`      `click()`
45785               // - `behavior/draw_way.js`  `move()`
45786               var d = datum(d3_event);
45787               target = d && d.properties && d.properties.entity;
45788               var targetLoc = target && target.loc;
45789               var targetNodes = d && d.properties && d.properties.nodes;
45790
45791               if (targetLoc) {
45792                 // snap to node/vertex - a point target with `.loc`
45793                 if (shouldSnapToNode(target)) {
45794                   loc = targetLoc;
45795                 }
45796               } else if (targetNodes) {
45797                 // snap to way - a line target with `.nodes`
45798                 edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
45799
45800                 if (edge) {
45801                   loc = edge.loc;
45802                 }
45803               }
45804             }
45805
45806             context.replace(actionMoveNode(entity.id, loc)); // Below here: validations
45807
45808             var isInvalid = false; // Check if this connection to `target` could cause relations to break..
45809
45810             if (target) {
45811               isInvalid = hasRelationConflict(entity, target, edge, context.graph());
45812             } // Check if this drag causes the geometry to break..
45813
45814
45815             if (!isInvalid) {
45816               isInvalid = hasInvalidGeometry(entity, context.graph());
45817             }
45818
45819             var nope = context.surface().classed('nope');
45820
45821             if (isInvalid === 'relation' || isInvalid === 'restriction') {
45822               if (!nope) {
45823                 // about to nope - show hint
45824                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.connect.' + isInvalid, {
45825                   relation: _mainPresetIndex.item('type/restriction').name()
45826                 }))();
45827               }
45828             } else if (isInvalid) {
45829               var errorID = isInvalid === 'line' ? 'lines' : 'areas';
45830               context.ui().flash.duration(3000).iconName('#iD-icon-no').label(_t('self_intersection.error.' + errorID))();
45831             } else {
45832               if (nope) {
45833                 // about to un-nope, remove hint
45834                 context.ui().flash.duration(1).label('')();
45835               }
45836             }
45837
45838             var nopeDisabled = context.surface().classed('nope-disabled');
45839
45840             if (nopeDisabled) {
45841               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
45842             } else {
45843               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
45844             }
45845
45846             _lastLoc = loc;
45847           } // Uses `actionConnect.disabled()` to know whether this connection is ok..
45848
45849
45850           function hasRelationConflict(entity, target, edge, graph) {
45851             var testGraph = graph.update(); // copy
45852             // if snapping to way - add midpoint there and consider that the target..
45853
45854             if (edge) {
45855               var midpoint = osmNode();
45856               var action = actionAddMidpoint({
45857                 loc: edge.loc,
45858                 edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
45859               }, midpoint);
45860               testGraph = action(testGraph);
45861               target = midpoint;
45862             } // can we connect to it?
45863
45864
45865             var ids = [entity.id, target.id];
45866             return actionConnect(ids).disabled(testGraph);
45867           }
45868
45869           function hasInvalidGeometry(entity, graph) {
45870             var parents = graph.parentWays(entity);
45871             var i, j, k;
45872
45873             for (i = 0; i < parents.length; i++) {
45874               var parent = parents[i];
45875               var nodes = [];
45876               var activeIndex = null; // which multipolygon ring contains node being dragged
45877               // test any parent multipolygons for valid geometry
45878
45879               var relations = graph.parentRelations(parent);
45880
45881               for (j = 0; j < relations.length; j++) {
45882                 if (!relations[j].isMultipolygon()) continue;
45883                 var rings = osmJoinWays(relations[j].members, graph); // find active ring and test it for self intersections
45884
45885                 for (k = 0; k < rings.length; k++) {
45886                   nodes = rings[k].nodes;
45887
45888                   if (nodes.find(function (n) {
45889                     return n.id === entity.id;
45890                   })) {
45891                     activeIndex = k;
45892
45893                     if (geoHasSelfIntersections(nodes, entity.id)) {
45894                       return 'multipolygonMember';
45895                     }
45896                   }
45897
45898                   rings[k].coords = nodes.map(function (n) {
45899                     return n.loc;
45900                   });
45901                 } // test active ring for intersections with other rings in the multipolygon
45902
45903
45904                 for (k = 0; k < rings.length; k++) {
45905                   if (k === activeIndex) continue; // make sure active ring doesn't cross passive rings
45906
45907                   if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
45908                     return 'multipolygonRing';
45909                   }
45910                 }
45911               } // If we still haven't tested this node's parent way for self-intersections.
45912               // (because it's not a member of a multipolygon), test it now.
45913
45914
45915               if (activeIndex === null) {
45916                 nodes = parent.nodes.map(function (nodeID) {
45917                   return graph.entity(nodeID);
45918                 });
45919
45920                 if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
45921                   return parent.geometry(graph);
45922                 }
45923               }
45924             }
45925
45926             return false;
45927           }
45928
45929           function move(d3_event, entity, point) {
45930             if (_isCancelled) return;
45931             d3_event.stopPropagation();
45932             context.surface().classed('nope-disabled', d3_event.altKey);
45933             _lastLoc = context.projection.invert(point);
45934             doMove(d3_event, entity);
45935             var nudge = geoViewportEdge(point, context.map().dimensions());
45936
45937             if (nudge) {
45938               startNudge(d3_event, entity, nudge);
45939             } else {
45940               stopNudge();
45941             }
45942           }
45943
45944           function end(d3_event, entity) {
45945             if (_isCancelled) return;
45946             var wasPoint = entity.geometry(context.graph()) === 'point';
45947             var d = datum(d3_event);
45948             var nope = d && d.properties && d.properties.nope || context.surface().classed('nope');
45949             var target = d && d.properties && d.properties.entity; // entity to snap to
45950
45951             if (nope) {
45952               // bounce back
45953               context.perform(_actionBounceBack(entity.id, _startLoc));
45954             } else if (target && target.type === 'way') {
45955               var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
45956               context.replace(actionAddMidpoint({
45957                 loc: choice.loc,
45958                 edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
45959               }, entity), connectAnnotation(entity, target));
45960             } else if (target && target.type === 'node' && shouldSnapToNode(target)) {
45961               context.replace(actionConnect([target.id, entity.id]), connectAnnotation(entity, target));
45962             } else if (_wasMidpoint) {
45963               context.replace(actionNoop(), _t('operations.add.annotation.vertex'));
45964             } else {
45965               context.replace(actionNoop(), moveAnnotation(entity));
45966             }
45967
45968             if (wasPoint) {
45969               context.enter(modeSelect(context, [entity.id]));
45970             } else {
45971               var reselection = _restoreSelectedIDs.filter(function (id) {
45972                 return context.graph().hasEntity(id);
45973               });
45974
45975               if (reselection.length) {
45976                 context.enter(modeSelect(context, reselection));
45977               } else {
45978                 context.enter(modeBrowse(context));
45979               }
45980             }
45981           }
45982
45983           function _actionBounceBack(nodeID, toLoc) {
45984             var moveNode = actionMoveNode(nodeID, toLoc);
45985
45986             var action = function action(graph, t) {
45987               // last time through, pop off the bounceback perform.
45988               // it will then overwrite the initial perform with a moveNode that does nothing
45989               if (t === 1) context.pop();
45990               return moveNode(graph, t);
45991             };
45992
45993             action.transitionable = true;
45994             return action;
45995           }
45996
45997           function cancel() {
45998             drag.cancel();
45999             context.enter(modeBrowse(context));
46000           }
46001
46002           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);
46003
46004           mode.enter = function () {
46005             context.install(hover);
46006             context.install(edit);
46007             select(window).on('keydown.dragNode', keydown).on('keyup.dragNode', keyup);
46008             context.history().on('undone.drag-node', cancel);
46009           };
46010
46011           mode.exit = function () {
46012             context.ui().sidebar.hover.cancel();
46013             context.uninstall(hover);
46014             context.uninstall(edit);
46015             select(window).on('keydown.dragNode', null).on('keyup.dragNode', null);
46016             context.history().on('undone.drag-node', null);
46017             _activeEntity = null;
46018             context.surface().classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false).selectAll('.active').classed('active', false);
46019             stopNudge();
46020           };
46021
46022           mode.selectedIDs = function () {
46023             if (!arguments.length) return _activeEntity ? [_activeEntity.id] : []; // no assign
46024
46025             return mode;
46026           };
46027
46028           mode.activeID = function () {
46029             if (!arguments.length) return _activeEntity && _activeEntity.id; // no assign
46030
46031             return mode;
46032           };
46033
46034           mode.restoreSelectedIDs = function (_) {
46035             if (!arguments.length) return _restoreSelectedIDs;
46036             _restoreSelectedIDs = _;
46037             return mode;
46038           };
46039
46040           mode.behavior = drag;
46041           return mode;
46042         }
46043
46044         var $$4 = _export;
46045         var NativePromise = nativePromiseConstructor;
46046         var fails$1 = fails$N;
46047         var getBuiltIn = getBuiltIn$9;
46048         var speciesConstructor = speciesConstructor$8;
46049         var promiseResolve = promiseResolve$2;
46050         var redefine = redefine$g.exports;
46051
46052         // Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
46053         var NON_GENERIC = !!NativePromise && fails$1(function () {
46054           NativePromise.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
46055         });
46056
46057         // `Promise.prototype.finally` method
46058         // https://tc39.es/ecma262/#sec-promise.prototype.finally
46059         $$4({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
46060           'finally': function (onFinally) {
46061             var C = speciesConstructor(this, getBuiltIn('Promise'));
46062             var isFunction = typeof onFinally == 'function';
46063             return this.then(
46064               isFunction ? function (x) {
46065                 return promiseResolve(C, onFinally()).then(function () { return x; });
46066               } : onFinally,
46067               isFunction ? function (e) {
46068                 return promiseResolve(C, onFinally()).then(function () { throw e; });
46069               } : onFinally
46070             );
46071           }
46072         });
46073
46074         // makes sure that native promise-based APIs `Promise#finally` properly works with patched `Promise#then`
46075         if (typeof NativePromise == 'function') {
46076           var method = getBuiltIn('Promise').prototype['finally'];
46077           if (NativePromise.prototype['finally'] !== method) {
46078             redefine(NativePromise.prototype, 'finally', method, { unsafe: true });
46079           }
46080         }
46081
46082         function quickselect(arr, k, left, right, compare) {
46083           quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
46084         }
46085
46086         function quickselectStep(arr, k, left, right, compare) {
46087           while (right > left) {
46088             if (right - left > 600) {
46089               var n = right - left + 1;
46090               var m = k - left + 1;
46091               var z = Math.log(n);
46092               var s = 0.5 * Math.exp(2 * z / 3);
46093               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
46094               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
46095               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
46096               quickselectStep(arr, k, newLeft, newRight, compare);
46097             }
46098
46099             var t = arr[k];
46100             var i = left;
46101             var j = right;
46102             swap(arr, left, k);
46103             if (compare(arr[right], t) > 0) swap(arr, left, right);
46104
46105             while (i < j) {
46106               swap(arr, i, j);
46107               i++;
46108               j--;
46109
46110               while (compare(arr[i], t) < 0) {
46111                 i++;
46112               }
46113
46114               while (compare(arr[j], t) > 0) {
46115                 j--;
46116               }
46117             }
46118
46119             if (compare(arr[left], t) === 0) swap(arr, left, j);else {
46120               j++;
46121               swap(arr, j, right);
46122             }
46123             if (j <= k) left = j + 1;
46124             if (k <= j) right = j - 1;
46125           }
46126         }
46127
46128         function swap(arr, i, j) {
46129           var tmp = arr[i];
46130           arr[i] = arr[j];
46131           arr[j] = tmp;
46132         }
46133
46134         function defaultCompare(a, b) {
46135           return a < b ? -1 : a > b ? 1 : 0;
46136         }
46137
46138         var RBush = /*#__PURE__*/function () {
46139           function RBush() {
46140             var maxEntries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 9;
46141
46142             _classCallCheck$1(this, RBush);
46143
46144             // max entries in a node is 9 by default; min node fill is 40% for best performance
46145             this._maxEntries = Math.max(4, maxEntries);
46146             this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
46147             this.clear();
46148           }
46149
46150           _createClass$1(RBush, [{
46151             key: "all",
46152             value: function all() {
46153               return this._all(this.data, []);
46154             }
46155           }, {
46156             key: "search",
46157             value: function search(bbox) {
46158               var node = this.data;
46159               var result = [];
46160               if (!intersects(bbox, node)) return result;
46161               var toBBox = this.toBBox;
46162               var nodesToSearch = [];
46163
46164               while (node) {
46165                 for (var i = 0; i < node.children.length; i++) {
46166                   var child = node.children[i];
46167                   var childBBox = node.leaf ? toBBox(child) : child;
46168
46169                   if (intersects(bbox, childBBox)) {
46170                     if (node.leaf) result.push(child);else if (contains(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
46171                   }
46172                 }
46173
46174                 node = nodesToSearch.pop();
46175               }
46176
46177               return result;
46178             }
46179           }, {
46180             key: "collides",
46181             value: function collides(bbox) {
46182               var node = this.data;
46183               if (!intersects(bbox, node)) return false;
46184               var nodesToSearch = [];
46185
46186               while (node) {
46187                 for (var i = 0; i < node.children.length; i++) {
46188                   var child = node.children[i];
46189                   var childBBox = node.leaf ? this.toBBox(child) : child;
46190
46191                   if (intersects(bbox, childBBox)) {
46192                     if (node.leaf || contains(bbox, childBBox)) return true;
46193                     nodesToSearch.push(child);
46194                   }
46195                 }
46196
46197                 node = nodesToSearch.pop();
46198               }
46199
46200               return false;
46201             }
46202           }, {
46203             key: "load",
46204             value: function load(data) {
46205               if (!(data && data.length)) return this;
46206
46207               if (data.length < this._minEntries) {
46208                 for (var i = 0; i < data.length; i++) {
46209                   this.insert(data[i]);
46210                 }
46211
46212                 return this;
46213               } // recursively build the tree with the given data from scratch using OMT algorithm
46214
46215
46216               var node = this._build(data.slice(), 0, data.length - 1, 0);
46217
46218               if (!this.data.children.length) {
46219                 // save as is if tree is empty
46220                 this.data = node;
46221               } else if (this.data.height === node.height) {
46222                 // split root if trees have the same height
46223                 this._splitRoot(this.data, node);
46224               } else {
46225                 if (this.data.height < node.height) {
46226                   // swap trees if inserted one is bigger
46227                   var tmpNode = this.data;
46228                   this.data = node;
46229                   node = tmpNode;
46230                 } // insert the small tree into the large tree at appropriate level
46231
46232
46233                 this._insert(node, this.data.height - node.height - 1, true);
46234               }
46235
46236               return this;
46237             }
46238           }, {
46239             key: "insert",
46240             value: function insert(item) {
46241               if (item) this._insert(item, this.data.height - 1);
46242               return this;
46243             }
46244           }, {
46245             key: "clear",
46246             value: function clear() {
46247               this.data = createNode([]);
46248               return this;
46249             }
46250           }, {
46251             key: "remove",
46252             value: function remove(item, equalsFn) {
46253               if (!item) return this;
46254               var node = this.data;
46255               var bbox = this.toBBox(item);
46256               var path = [];
46257               var indexes = [];
46258               var i, parent, goingUp; // depth-first iterative tree traversal
46259
46260               while (node || path.length) {
46261                 if (!node) {
46262                   // go up
46263                   node = path.pop();
46264                   parent = path[path.length - 1];
46265                   i = indexes.pop();
46266                   goingUp = true;
46267                 }
46268
46269                 if (node.leaf) {
46270                   // check current node
46271                   var index = findItem(item, node.children, equalsFn);
46272
46273                   if (index !== -1) {
46274                     // item found, remove the item and condense tree upwards
46275                     node.children.splice(index, 1);
46276                     path.push(node);
46277
46278                     this._condense(path);
46279
46280                     return this;
46281                   }
46282                 }
46283
46284                 if (!goingUp && !node.leaf && contains(node, bbox)) {
46285                   // go down
46286                   path.push(node);
46287                   indexes.push(i);
46288                   i = 0;
46289                   parent = node;
46290                   node = node.children[0];
46291                 } else if (parent) {
46292                   // go right
46293                   i++;
46294                   node = parent.children[i];
46295                   goingUp = false;
46296                 } else node = null; // nothing found
46297
46298               }
46299
46300               return this;
46301             }
46302           }, {
46303             key: "toBBox",
46304             value: function toBBox(item) {
46305               return item;
46306             }
46307           }, {
46308             key: "compareMinX",
46309             value: function compareMinX(a, b) {
46310               return a.minX - b.minX;
46311             }
46312           }, {
46313             key: "compareMinY",
46314             value: function compareMinY(a, b) {
46315               return a.minY - b.minY;
46316             }
46317           }, {
46318             key: "toJSON",
46319             value: function toJSON() {
46320               return this.data;
46321             }
46322           }, {
46323             key: "fromJSON",
46324             value: function fromJSON(data) {
46325               this.data = data;
46326               return this;
46327             }
46328           }, {
46329             key: "_all",
46330             value: function _all(node, result) {
46331               var nodesToSearch = [];
46332
46333               while (node) {
46334                 if (node.leaf) result.push.apply(result, _toConsumableArray(node.children));else nodesToSearch.push.apply(nodesToSearch, _toConsumableArray(node.children));
46335                 node = nodesToSearch.pop();
46336               }
46337
46338               return result;
46339             }
46340           }, {
46341             key: "_build",
46342             value: function _build(items, left, right, height) {
46343               var N = right - left + 1;
46344               var M = this._maxEntries;
46345               var node;
46346
46347               if (N <= M) {
46348                 // reached leaf level; return leaf
46349                 node = createNode(items.slice(left, right + 1));
46350                 calcBBox(node, this.toBBox);
46351                 return node;
46352               }
46353
46354               if (!height) {
46355                 // target height of the bulk-loaded tree
46356                 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
46357
46358                 M = Math.ceil(N / Math.pow(M, height - 1));
46359               }
46360
46361               node = createNode([]);
46362               node.leaf = false;
46363               node.height = height; // split the items into M mostly square tiles
46364
46365               var N2 = Math.ceil(N / M);
46366               var N1 = N2 * Math.ceil(Math.sqrt(M));
46367               multiSelect(items, left, right, N1, this.compareMinX);
46368
46369               for (var i = left; i <= right; i += N1) {
46370                 var right2 = Math.min(i + N1 - 1, right);
46371                 multiSelect(items, i, right2, N2, this.compareMinY);
46372
46373                 for (var j = i; j <= right2; j += N2) {
46374                   var right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
46375
46376                   node.children.push(this._build(items, j, right3, height - 1));
46377                 }
46378               }
46379
46380               calcBBox(node, this.toBBox);
46381               return node;
46382             }
46383           }, {
46384             key: "_chooseSubtree",
46385             value: function _chooseSubtree(bbox, node, level, path) {
46386               while (true) {
46387                 path.push(node);
46388                 if (node.leaf || path.length - 1 === level) break;
46389                 var minArea = Infinity;
46390                 var minEnlargement = Infinity;
46391                 var targetNode = void 0;
46392
46393                 for (var i = 0; i < node.children.length; i++) {
46394                   var child = node.children[i];
46395                   var area = bboxArea(child);
46396                   var enlargement = enlargedArea(bbox, child) - area; // choose entry with the least area enlargement
46397
46398                   if (enlargement < minEnlargement) {
46399                     minEnlargement = enlargement;
46400                     minArea = area < minArea ? area : minArea;
46401                     targetNode = child;
46402                   } else if (enlargement === minEnlargement) {
46403                     // otherwise choose one with the smallest area
46404                     if (area < minArea) {
46405                       minArea = area;
46406                       targetNode = child;
46407                     }
46408                   }
46409                 }
46410
46411                 node = targetNode || node.children[0];
46412               }
46413
46414               return node;
46415             }
46416           }, {
46417             key: "_insert",
46418             value: function _insert(item, level, isNode) {
46419               var bbox = isNode ? item : this.toBBox(item);
46420               var insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
46421
46422               var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
46423
46424
46425               node.children.push(item);
46426               extend$1(node, bbox); // split on node overflow; propagate upwards if necessary
46427
46428               while (level >= 0) {
46429                 if (insertPath[level].children.length > this._maxEntries) {
46430                   this._split(insertPath, level);
46431
46432                   level--;
46433                 } else break;
46434               } // adjust bboxes along the insertion path
46435
46436
46437               this._adjustParentBBoxes(bbox, insertPath, level);
46438             } // split overflowed node into two
46439
46440           }, {
46441             key: "_split",
46442             value: function _split(insertPath, level) {
46443               var node = insertPath[level];
46444               var M = node.children.length;
46445               var m = this._minEntries;
46446
46447               this._chooseSplitAxis(node, m, M);
46448
46449               var splitIndex = this._chooseSplitIndex(node, m, M);
46450
46451               var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
46452               newNode.height = node.height;
46453               newNode.leaf = node.leaf;
46454               calcBBox(node, this.toBBox);
46455               calcBBox(newNode, this.toBBox);
46456               if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
46457             }
46458           }, {
46459             key: "_splitRoot",
46460             value: function _splitRoot(node, newNode) {
46461               // split root node
46462               this.data = createNode([node, newNode]);
46463               this.data.height = node.height + 1;
46464               this.data.leaf = false;
46465               calcBBox(this.data, this.toBBox);
46466             }
46467           }, {
46468             key: "_chooseSplitIndex",
46469             value: function _chooseSplitIndex(node, m, M) {
46470               var index;
46471               var minOverlap = Infinity;
46472               var minArea = Infinity;
46473
46474               for (var i = m; i <= M - m; i++) {
46475                 var bbox1 = distBBox(node, 0, i, this.toBBox);
46476                 var bbox2 = distBBox(node, i, M, this.toBBox);
46477                 var overlap = intersectionArea(bbox1, bbox2);
46478                 var area = bboxArea(bbox1) + bboxArea(bbox2); // choose distribution with minimum overlap
46479
46480                 if (overlap < minOverlap) {
46481                   minOverlap = overlap;
46482                   index = i;
46483                   minArea = area < minArea ? area : minArea;
46484                 } else if (overlap === minOverlap) {
46485                   // otherwise choose distribution with minimum area
46486                   if (area < minArea) {
46487                     minArea = area;
46488                     index = i;
46489                   }
46490                 }
46491               }
46492
46493               return index || M - m;
46494             } // sorts node children by the best axis for split
46495
46496           }, {
46497             key: "_chooseSplitAxis",
46498             value: function _chooseSplitAxis(node, m, M) {
46499               var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
46500               var compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
46501
46502               var xMargin = this._allDistMargin(node, m, M, compareMinX);
46503
46504               var yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
46505               // otherwise it's already sorted by minY
46506
46507
46508               if (xMargin < yMargin) node.children.sort(compareMinX);
46509             } // total margin of all possible split distributions where each node is at least m full
46510
46511           }, {
46512             key: "_allDistMargin",
46513             value: function _allDistMargin(node, m, M, compare) {
46514               node.children.sort(compare);
46515               var toBBox = this.toBBox;
46516               var leftBBox = distBBox(node, 0, m, toBBox);
46517               var rightBBox = distBBox(node, M - m, M, toBBox);
46518               var margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
46519
46520               for (var i = m; i < M - m; i++) {
46521                 var child = node.children[i];
46522                 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
46523                 margin += bboxMargin(leftBBox);
46524               }
46525
46526               for (var _i = M - m - 1; _i >= m; _i--) {
46527                 var _child = node.children[_i];
46528                 extend$1(rightBBox, node.leaf ? toBBox(_child) : _child);
46529                 margin += bboxMargin(rightBBox);
46530               }
46531
46532               return margin;
46533             }
46534           }, {
46535             key: "_adjustParentBBoxes",
46536             value: function _adjustParentBBoxes(bbox, path, level) {
46537               // adjust bboxes along the given tree path
46538               for (var i = level; i >= 0; i--) {
46539                 extend$1(path[i], bbox);
46540               }
46541             }
46542           }, {
46543             key: "_condense",
46544             value: function _condense(path) {
46545               // go through the path, removing empty nodes and updating bboxes
46546               for (var i = path.length - 1, siblings; i >= 0; i--) {
46547                 if (path[i].children.length === 0) {
46548                   if (i > 0) {
46549                     siblings = path[i - 1].children;
46550                     siblings.splice(siblings.indexOf(path[i]), 1);
46551                   } else this.clear();
46552                 } else calcBBox(path[i], this.toBBox);
46553               }
46554             }
46555           }]);
46556
46557           return RBush;
46558         }();
46559
46560         function findItem(item, items, equalsFn) {
46561           if (!equalsFn) return items.indexOf(item);
46562
46563           for (var i = 0; i < items.length; i++) {
46564             if (equalsFn(item, items[i])) return i;
46565           }
46566
46567           return -1;
46568         } // calculate node's bbox from bboxes of its children
46569
46570
46571         function calcBBox(node, toBBox) {
46572           distBBox(node, 0, node.children.length, toBBox, node);
46573         } // min bounding rectangle of node children from k to p-1
46574
46575
46576         function distBBox(node, k, p, toBBox, destNode) {
46577           if (!destNode) destNode = createNode(null);
46578           destNode.minX = Infinity;
46579           destNode.minY = Infinity;
46580           destNode.maxX = -Infinity;
46581           destNode.maxY = -Infinity;
46582
46583           for (var i = k; i < p; i++) {
46584             var child = node.children[i];
46585             extend$1(destNode, node.leaf ? toBBox(child) : child);
46586           }
46587
46588           return destNode;
46589         }
46590
46591         function extend$1(a, b) {
46592           a.minX = Math.min(a.minX, b.minX);
46593           a.minY = Math.min(a.minY, b.minY);
46594           a.maxX = Math.max(a.maxX, b.maxX);
46595           a.maxY = Math.max(a.maxY, b.maxY);
46596           return a;
46597         }
46598
46599         function compareNodeMinX(a, b) {
46600           return a.minX - b.minX;
46601         }
46602
46603         function compareNodeMinY(a, b) {
46604           return a.minY - b.minY;
46605         }
46606
46607         function bboxArea(a) {
46608           return (a.maxX - a.minX) * (a.maxY - a.minY);
46609         }
46610
46611         function bboxMargin(a) {
46612           return a.maxX - a.minX + (a.maxY - a.minY);
46613         }
46614
46615         function enlargedArea(a, b) {
46616           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));
46617         }
46618
46619         function intersectionArea(a, b) {
46620           var minX = Math.max(a.minX, b.minX);
46621           var minY = Math.max(a.minY, b.minY);
46622           var maxX = Math.min(a.maxX, b.maxX);
46623           var maxY = Math.min(a.maxY, b.maxY);
46624           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
46625         }
46626
46627         function contains(a, b) {
46628           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
46629         }
46630
46631         function intersects(a, b) {
46632           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
46633         }
46634
46635         function createNode(children) {
46636           return {
46637             children: children,
46638             height: 1,
46639             leaf: true,
46640             minX: Infinity,
46641             minY: Infinity,
46642             maxX: -Infinity,
46643             maxY: -Infinity
46644           };
46645         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
46646         // combines selection algorithm with binary divide & conquer approach
46647
46648
46649         function multiSelect(arr, left, right, n, compare) {
46650           var stack = [left, right];
46651
46652           while (stack.length) {
46653             right = stack.pop();
46654             left = stack.pop();
46655             if (right - left <= n) continue;
46656             var mid = left + Math.ceil((right - left) / n / 2) * n;
46657             quickselect(arr, mid, left, right, compare);
46658             stack.push(left, mid, mid, right);
46659           }
46660         }
46661
46662         function responseText(response) {
46663           if (!response.ok) throw new Error(response.status + " " + response.statusText);
46664           return response.text();
46665         }
46666
46667         function d3_text (input, init) {
46668           return fetch(input, init).then(responseText);
46669         }
46670
46671         function responseJson(response) {
46672           if (!response.ok) throw new Error(response.status + " " + response.statusText);
46673           if (response.status === 204 || response.status === 205) return;
46674           return response.json();
46675         }
46676
46677         function d3_json (input, init) {
46678           return fetch(input, init).then(responseJson);
46679         }
46680
46681         function parser(type) {
46682           return function (input, init) {
46683             return d3_text(input, init).then(function (text) {
46684               return new DOMParser().parseFromString(text, type);
46685             });
46686           };
46687         }
46688
46689         var d3_xml = parser("application/xml");
46690         var svg = parser("image/svg+xml");
46691
46692         var tiler$6 = utilTiler();
46693         var dispatch$7 = dispatch$8('loaded');
46694         var _tileZoom$3 = 14;
46695         var _krUrlRoot = 'https://www.keepright.at';
46696         var _krData = {
46697           errorTypes: {},
46698           localizeStrings: {}
46699         }; // This gets reassigned if reset
46700
46701         var _cache$2;
46702
46703         var _krRuleset = [// no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
46704         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];
46705
46706         function abortRequest$6(controller) {
46707           if (controller) {
46708             controller.abort();
46709           }
46710         }
46711
46712         function abortUnwantedRequests$3(cache, tiles) {
46713           Object.keys(cache.inflightTile).forEach(function (k) {
46714             var wanted = tiles.find(function (tile) {
46715               return k === tile.id;
46716             });
46717
46718             if (!wanted) {
46719               abortRequest$6(cache.inflightTile[k]);
46720               delete cache.inflightTile[k];
46721             }
46722           });
46723         }
46724
46725         function encodeIssueRtree$2(d) {
46726           return {
46727             minX: d.loc[0],
46728             minY: d.loc[1],
46729             maxX: d.loc[0],
46730             maxY: d.loc[1],
46731             data: d
46732           };
46733         } // Replace or remove QAItem from rtree
46734
46735
46736         function updateRtree$3(item, replace) {
46737           _cache$2.rtree.remove(item, function (a, b) {
46738             return a.data.id === b.data.id;
46739           });
46740
46741           if (replace) {
46742             _cache$2.rtree.insert(item);
46743           }
46744         }
46745
46746         function tokenReplacements(d) {
46747           if (!(d instanceof QAItem)) return;
46748           var htmlRegex = new RegExp(/<\/[a-z][\s\S]*>/);
46749           var replacements = {};
46750           var issueTemplate = _krData.errorTypes[d.whichType];
46751
46752           if (!issueTemplate) {
46753             /* eslint-disable no-console */
46754             console.log('No Template: ', d.whichType);
46755             console.log('  ', d.description);
46756             /* eslint-enable no-console */
46757
46758             return;
46759           } // some descriptions are just fixed text
46760
46761
46762           if (!issueTemplate.regex) return; // regex pattern should match description with variable details captured
46763
46764           var errorRegex = new RegExp(issueTemplate.regex, 'i');
46765           var errorMatch = errorRegex.exec(d.description);
46766
46767           if (!errorMatch) {
46768             /* eslint-disable no-console */
46769             console.log('Unmatched: ', d.whichType);
46770             console.log('  ', d.description);
46771             console.log('  ', errorRegex);
46772             /* eslint-enable no-console */
46773
46774             return;
46775           }
46776
46777           for (var i = 1; i < errorMatch.length; i++) {
46778             // skip first
46779             var capture = errorMatch[i];
46780             var idType = void 0;
46781             idType = 'IDs' in issueTemplate ? issueTemplate.IDs[i - 1] : '';
46782
46783             if (idType && capture) {
46784               // link IDs if present in the capture
46785               capture = parseError(capture, idType);
46786             } else if (htmlRegex.test(capture)) {
46787               // escape any html in non-IDs
46788               capture = '\\' + capture + '\\';
46789             } else {
46790               var compare = capture.toLowerCase();
46791
46792               if (_krData.localizeStrings[compare]) {
46793                 // some replacement strings can be localized
46794                 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
46795               }
46796             }
46797
46798             replacements['var' + i] = capture;
46799           }
46800
46801           return replacements;
46802         }
46803
46804         function parseError(capture, idType) {
46805           var compare = capture.toLowerCase();
46806
46807           if (_krData.localizeStrings[compare]) {
46808             // some replacement strings can be localized
46809             capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
46810           }
46811
46812           switch (idType) {
46813             // link a string like "this node"
46814             case 'this':
46815               capture = linkErrorObject(capture);
46816               break;
46817
46818             case 'url':
46819               capture = linkURL(capture);
46820               break;
46821             // link an entity ID
46822
46823             case 'n':
46824             case 'w':
46825             case 'r':
46826               capture = linkEntity(idType + capture);
46827               break;
46828             // some errors have more complex ID lists/variance
46829
46830             case '20':
46831               capture = parse20(capture);
46832               break;
46833
46834             case '211':
46835               capture = parse211(capture);
46836               break;
46837
46838             case '231':
46839               capture = parse231(capture);
46840               break;
46841
46842             case '294':
46843               capture = parse294(capture);
46844               break;
46845
46846             case '370':
46847               capture = parse370(capture);
46848               break;
46849           }
46850
46851           return capture;
46852
46853           function linkErrorObject(d) {
46854             return "<a class=\"error_object_link\">".concat(d, "</a>");
46855           }
46856
46857           function linkEntity(d) {
46858             return "<a class=\"error_entity_link\">".concat(d, "</a>");
46859           }
46860
46861           function linkURL(d) {
46862             return "<a class=\"kr_external_link\" target=\"_blank\" href=\"".concat(d, "\">").concat(d, "</a>");
46863           } // arbitrary node list of form: #ID, #ID, #ID...
46864
46865
46866           function parse211(capture) {
46867             var newList = [];
46868             var items = capture.split(', ');
46869             items.forEach(function (item) {
46870               // ID has # at the front
46871               var id = linkEntity('n' + item.slice(1));
46872               newList.push(id);
46873             });
46874             return newList.join(', ');
46875           } // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
46876
46877
46878           function parse231(capture) {
46879             var newList = []; // unfortunately 'layer' can itself contain commas, so we split on '),'
46880
46881             var items = capture.split('),');
46882             items.forEach(function (item) {
46883               var match = item.match(/\#(\d+)\((.+)\)?/);
46884
46885               if (match !== null && match.length > 2) {
46886                 newList.push(linkEntity('w' + match[1]) + ' ' + _t('QA.keepRight.errorTypes.231.layer', {
46887                   layer: match[2]
46888                 }));
46889               }
46890             });
46891             return newList.join(', ');
46892           } // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
46893
46894
46895           function parse294(capture) {
46896             var newList = [];
46897             var items = capture.split(',');
46898             items.forEach(function (item) {
46899               // item of form "from/to node/relation #ID"
46900               item = item.split(' '); // to/from role is more clear in quotes
46901
46902               var role = "\"".concat(item[0], "\""); // first letter of node/relation provides the type
46903
46904               var idType = item[1].slice(0, 1); // ID has # at the front
46905
46906               var id = item[2].slice(1);
46907               id = linkEntity(idType + id);
46908               newList.push("".concat(role, " ").concat(item[1], " ").concat(id));
46909             });
46910             return newList.join(', ');
46911           } // may or may not include the string "(including the name 'name')"
46912
46913
46914           function parse370(capture) {
46915             if (!capture) return '';
46916             var match = capture.match(/\(including the name (\'.+\')\)/);
46917
46918             if (match && match.length) {
46919               return _t('QA.keepRight.errorTypes.370.including_the_name', {
46920                 name: match[1]
46921               });
46922             }
46923
46924             return '';
46925           } // arbitrary node list of form: #ID,#ID,#ID...
46926
46927
46928           function parse20(capture) {
46929             var newList = [];
46930             var items = capture.split(',');
46931             items.forEach(function (item) {
46932               // ID has # at the front
46933               var id = linkEntity('n' + item.slice(1));
46934               newList.push(id);
46935             });
46936             return newList.join(', ');
46937           }
46938         }
46939
46940         var serviceKeepRight = {
46941           title: 'keepRight',
46942           init: function init() {
46943             _mainFileFetcher.get('keepRight').then(function (d) {
46944               return _krData = d;
46945             });
46946
46947             if (!_cache$2) {
46948               this.reset();
46949             }
46950
46951             this.event = utilRebind(this, dispatch$7, 'on');
46952           },
46953           reset: function reset() {
46954             if (_cache$2) {
46955               Object.values(_cache$2.inflightTile).forEach(abortRequest$6);
46956             }
46957
46958             _cache$2 = {
46959               data: {},
46960               loadedTile: {},
46961               inflightTile: {},
46962               inflightPost: {},
46963               closed: {},
46964               rtree: new RBush()
46965             };
46966           },
46967           // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
46968           loadIssues: function loadIssues(projection) {
46969             var _this = this;
46970
46971             var options = {
46972               format: 'geojson',
46973               ch: _krRuleset
46974             }; // determine the needed tiles to cover the view
46975
46976             var tiles = tiler$6.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
46977
46978             abortUnwantedRequests$3(_cache$2, tiles); // issue new requests..
46979
46980             tiles.forEach(function (tile) {
46981               if (_cache$2.loadedTile[tile.id] || _cache$2.inflightTile[tile.id]) return;
46982
46983               var _tile$extent$rectangl = tile.extent.rectangle(),
46984                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
46985                   left = _tile$extent$rectangl2[0],
46986                   top = _tile$extent$rectangl2[1],
46987                   right = _tile$extent$rectangl2[2],
46988                   bottom = _tile$extent$rectangl2[3];
46989
46990               var params = Object.assign({}, options, {
46991                 left: left,
46992                 bottom: bottom,
46993                 right: right,
46994                 top: top
46995               });
46996               var url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
46997               var controller = new AbortController();
46998               _cache$2.inflightTile[tile.id] = controller;
46999               d3_json(url, {
47000                 signal: controller.signal
47001               }).then(function (data) {
47002                 delete _cache$2.inflightTile[tile.id];
47003                 _cache$2.loadedTile[tile.id] = true;
47004
47005                 if (!data || !data.features || !data.features.length) {
47006                   throw new Error('No Data');
47007                 }
47008
47009                 data.features.forEach(function (feature) {
47010                   var _feature$properties = feature.properties,
47011                       itemType = _feature$properties.error_type,
47012                       id = _feature$properties.error_id,
47013                       _feature$properties$c = _feature$properties.comment,
47014                       comment = _feature$properties$c === void 0 ? null : _feature$properties$c,
47015                       objectId = _feature$properties.object_id,
47016                       objectType = _feature$properties.object_type,
47017                       schema = _feature$properties.schema,
47018                       title = _feature$properties.title;
47019                   var loc = feature.geometry.coordinates,
47020                       _feature$properties$d = feature.properties.description,
47021                       description = _feature$properties$d === void 0 ? '' : _feature$properties$d; // if there is a parent, save its error type e.g.:
47022                   //  Error 191 = "highway-highway"
47023                   //  Error 190 = "intersections without junctions"  (parent)
47024
47025                   var issueTemplate = _krData.errorTypes[itemType];
47026                   var parentIssueType = (Math.floor(itemType / 10) * 10).toString(); // try to handle error type directly, fallback to parent error type.
47027
47028                   var whichType = issueTemplate ? itemType : parentIssueType;
47029                   var whichTemplate = _krData.errorTypes[whichType]; // Rewrite a few of the errors at this point..
47030                   // This is done to make them easier to linkify and translate.
47031
47032                   switch (whichType) {
47033                     case '170':
47034                       description = "This feature has a FIXME tag: ".concat(description);
47035                       break;
47036
47037                     case '292':
47038                     case '293':
47039                       description = description.replace('A turn-', 'This turn-');
47040                       break;
47041
47042                     case '294':
47043                     case '295':
47044                     case '296':
47045                     case '297':
47046                     case '298':
47047                       description = "This turn-restriction~".concat(description);
47048                       break;
47049
47050                     case '300':
47051                       description = 'This highway is missing a maxspeed tag';
47052                       break;
47053
47054                     case '411':
47055                     case '412':
47056                     case '413':
47057                       description = "This feature~".concat(description);
47058                       break;
47059                   } // move markers slightly so it doesn't obscure the geometry,
47060                   // then move markers away from other coincident markers
47061
47062
47063                   var coincident = false;
47064
47065                   do {
47066                     // first time, move marker up. after that, move marker right.
47067                     var delta = coincident ? [0.00001, 0] : [0, 0.00001];
47068                     loc = geoVecAdd(loc, delta);
47069                     var bbox = geoExtent(loc).bbox();
47070                     coincident = _cache$2.rtree.search(bbox).length;
47071                   } while (coincident);
47072
47073                   var d = new QAItem(loc, _this, itemType, id, {
47074                     comment: comment,
47075                     description: description,
47076                     whichType: whichType,
47077                     parentIssueType: parentIssueType,
47078                     severity: whichTemplate.severity || 'error',
47079                     objectId: objectId,
47080                     objectType: objectType,
47081                     schema: schema,
47082                     title: title
47083                   });
47084                   d.replacements = tokenReplacements(d);
47085                   _cache$2.data[id] = d;
47086
47087                   _cache$2.rtree.insert(encodeIssueRtree$2(d));
47088                 });
47089                 dispatch$7.call('loaded');
47090               })["catch"](function () {
47091                 delete _cache$2.inflightTile[tile.id];
47092                 _cache$2.loadedTile[tile.id] = true;
47093               });
47094             });
47095           },
47096           postUpdate: function postUpdate(d, callback) {
47097             var _this2 = this;
47098
47099             if (_cache$2.inflightPost[d.id]) {
47100               return callback({
47101                 message: 'Error update already inflight',
47102                 status: -2
47103               }, d);
47104             }
47105
47106             var params = {
47107               schema: d.schema,
47108               id: d.id
47109             };
47110
47111             if (d.newStatus) {
47112               params.st = d.newStatus;
47113             }
47114
47115             if (d.newComment !== undefined) {
47116               params.co = d.newComment;
47117             } // NOTE: This throws a CORS err, but it seems successful.
47118             // We don't care too much about the response, so this is fine.
47119
47120
47121             var url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
47122             var controller = new AbortController();
47123             _cache$2.inflightPost[d.id] = controller; // Since this is expected to throw an error just continue as if it worked
47124             // (worst case scenario the request truly fails and issue will show up if iD restarts)
47125
47126             d3_json(url, {
47127               signal: controller.signal
47128             })["finally"](function () {
47129               delete _cache$2.inflightPost[d.id];
47130
47131               if (d.newStatus === 'ignore') {
47132                 // ignore permanently (false positive)
47133                 _this2.removeItem(d);
47134               } else if (d.newStatus === 'ignore_t') {
47135                 // ignore temporarily (error fixed)
47136                 _this2.removeItem(d);
47137
47138                 _cache$2.closed["".concat(d.schema, ":").concat(d.id)] = true;
47139               } else {
47140                 d = _this2.replaceItem(d.update({
47141                   comment: d.newComment,
47142                   newComment: undefined,
47143                   newState: undefined
47144                 }));
47145               }
47146
47147               if (callback) callback(null, d);
47148             });
47149           },
47150           // Get all cached QAItems covering the viewport
47151           getItems: function getItems(projection) {
47152             var viewport = projection.clipExtent();
47153             var min = [viewport[0][0], viewport[1][1]];
47154             var max = [viewport[1][0], viewport[0][1]];
47155             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
47156             return _cache$2.rtree.search(bbox).map(function (d) {
47157               return d.data;
47158             });
47159           },
47160           // Get a QAItem from cache
47161           // NOTE: Don't change method name until UI v3 is merged
47162           getError: function getError(id) {
47163             return _cache$2.data[id];
47164           },
47165           // Replace a single QAItem in the cache
47166           replaceItem: function replaceItem(item) {
47167             if (!(item instanceof QAItem) || !item.id) return;
47168             _cache$2.data[item.id] = item;
47169             updateRtree$3(encodeIssueRtree$2(item), true); // true = replace
47170
47171             return item;
47172           },
47173           // Remove a single QAItem from the cache
47174           removeItem: function removeItem(item) {
47175             if (!(item instanceof QAItem) || !item.id) return;
47176             delete _cache$2.data[item.id];
47177             updateRtree$3(encodeIssueRtree$2(item), false); // false = remove
47178           },
47179           issueURL: function issueURL(item) {
47180             return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
47181           },
47182           // Get an array of issues closed during this session.
47183           // Used to populate `closed:keepright` changeset tag
47184           getClosedIDs: function getClosedIDs() {
47185             return Object.keys(_cache$2.closed).sort();
47186           }
47187         };
47188
47189         var tiler$5 = utilTiler();
47190         var dispatch$6 = dispatch$8('loaded');
47191         var _tileZoom$2 = 14;
47192         var _impOsmUrls = {
47193           ow: 'https://grab.community.improve-osm.org/directionOfFlowService',
47194           mr: 'https://grab.community.improve-osm.org/missingGeoService',
47195           tr: 'https://grab.community.improve-osm.org/turnRestrictionService'
47196         };
47197         var _impOsmData = {
47198           icons: {}
47199         }; // This gets reassigned if reset
47200
47201         var _cache$1;
47202
47203         function abortRequest$5(i) {
47204           Object.values(i).forEach(function (controller) {
47205             if (controller) {
47206               controller.abort();
47207             }
47208           });
47209         }
47210
47211         function abortUnwantedRequests$2(cache, tiles) {
47212           Object.keys(cache.inflightTile).forEach(function (k) {
47213             var wanted = tiles.find(function (tile) {
47214               return k === tile.id;
47215             });
47216
47217             if (!wanted) {
47218               abortRequest$5(cache.inflightTile[k]);
47219               delete cache.inflightTile[k];
47220             }
47221           });
47222         }
47223
47224         function encodeIssueRtree$1(d) {
47225           return {
47226             minX: d.loc[0],
47227             minY: d.loc[1],
47228             maxX: d.loc[0],
47229             maxY: d.loc[1],
47230             data: d
47231           };
47232         } // Replace or remove QAItem from rtree
47233
47234
47235         function updateRtree$2(item, replace) {
47236           _cache$1.rtree.remove(item, function (a, b) {
47237             return a.data.id === b.data.id;
47238           });
47239
47240           if (replace) {
47241             _cache$1.rtree.insert(item);
47242           }
47243         }
47244
47245         function linkErrorObject(d) {
47246           return "<a class=\"error_object_link\">".concat(d, "</a>");
47247         }
47248
47249         function linkEntity(d) {
47250           return "<a class=\"error_entity_link\">".concat(d, "</a>");
47251         }
47252
47253         function pointAverage(points) {
47254           if (points.length) {
47255             var sum = points.reduce(function (acc, point) {
47256               return geoVecAdd(acc, [point.lon, point.lat]);
47257             }, [0, 0]);
47258             return geoVecScale(sum, 1 / points.length);
47259           } else {
47260             return [0, 0];
47261           }
47262         }
47263
47264         function relativeBearing(p1, p2) {
47265           var angle = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
47266
47267           if (angle < 0) {
47268             angle += 2 * Math.PI;
47269           } // Return degrees
47270
47271
47272           return angle * 180 / Math.PI;
47273         } // Assuming range [0,360)
47274
47275
47276         function cardinalDirection(bearing) {
47277           var dir = 45 * Math.round(bearing / 45);
47278           var compass = {
47279             0: 'north',
47280             45: 'northeast',
47281             90: 'east',
47282             135: 'southeast',
47283             180: 'south',
47284             225: 'southwest',
47285             270: 'west',
47286             315: 'northwest',
47287             360: 'north'
47288           };
47289           return _t("QA.improveOSM.directions.".concat(compass[dir]));
47290         } // Errors shouldn't obscure each other
47291
47292
47293         function preventCoincident$1(loc, bumpUp) {
47294           var coincident = false;
47295
47296           do {
47297             // first time, move marker up. after that, move marker right.
47298             var delta = coincident ? [0.00001, 0] : bumpUp ? [0, 0.00001] : [0, 0];
47299             loc = geoVecAdd(loc, delta);
47300             var bbox = geoExtent(loc).bbox();
47301             coincident = _cache$1.rtree.search(bbox).length;
47302           } while (coincident);
47303
47304           return loc;
47305         }
47306
47307         var serviceImproveOSM = {
47308           title: 'improveOSM',
47309           init: function init() {
47310             _mainFileFetcher.get('qa_data').then(function (d) {
47311               return _impOsmData = d.improveOSM;
47312             });
47313
47314             if (!_cache$1) {
47315               this.reset();
47316             }
47317
47318             this.event = utilRebind(this, dispatch$6, 'on');
47319           },
47320           reset: function reset() {
47321             if (_cache$1) {
47322               Object.values(_cache$1.inflightTile).forEach(abortRequest$5);
47323             }
47324
47325             _cache$1 = {
47326               data: {},
47327               loadedTile: {},
47328               inflightTile: {},
47329               inflightPost: {},
47330               closed: {},
47331               rtree: new RBush()
47332             };
47333           },
47334           loadIssues: function loadIssues(projection) {
47335             var _this = this;
47336
47337             var options = {
47338               client: 'iD',
47339               status: 'OPEN',
47340               zoom: '19' // Use a high zoom so that clusters aren't returned
47341
47342             }; // determine the needed tiles to cover the view
47343
47344             var tiles = tiler$5.zoomExtent([_tileZoom$2, _tileZoom$2]).getTiles(projection); // abort inflight requests that are no longer needed
47345
47346             abortUnwantedRequests$2(_cache$1, tiles); // issue new requests..
47347
47348             tiles.forEach(function (tile) {
47349               if (_cache$1.loadedTile[tile.id] || _cache$1.inflightTile[tile.id]) return;
47350
47351               var _tile$extent$rectangl = tile.extent.rectangle(),
47352                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
47353                   east = _tile$extent$rectangl2[0],
47354                   north = _tile$extent$rectangl2[1],
47355                   west = _tile$extent$rectangl2[2],
47356                   south = _tile$extent$rectangl2[3];
47357
47358               var params = Object.assign({}, options, {
47359                 east: east,
47360                 south: south,
47361                 west: west,
47362                 north: north
47363               }); // 3 separate requests to store for each tile
47364
47365               var requests = {};
47366               Object.keys(_impOsmUrls).forEach(function (k) {
47367                 // We exclude WATER from missing geometry as it doesn't seem useful
47368                 // We use most confident one-way and turn restrictions only, still have false positives
47369                 var kParams = Object.assign({}, params, k === 'mr' ? {
47370                   type: 'PARKING,ROAD,BOTH,PATH'
47371                 } : {
47372                   confidenceLevel: 'C1'
47373                 });
47374                 var url = "".concat(_impOsmUrls[k], "/search?") + utilQsString(kParams);
47375                 var controller = new AbortController();
47376                 requests[k] = controller;
47377                 d3_json(url, {
47378                   signal: controller.signal
47379                 }).then(function (data) {
47380                   delete _cache$1.inflightTile[tile.id][k];
47381
47382                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
47383                     delete _cache$1.inflightTile[tile.id];
47384                     _cache$1.loadedTile[tile.id] = true;
47385                   } // Road segments at high zoom == oneways
47386
47387
47388                   if (data.roadSegments) {
47389                     data.roadSegments.forEach(function (feature) {
47390                       // Position error at the approximate middle of the segment
47391                       var points = feature.points,
47392                           wayId = feature.wayId,
47393                           fromNodeId = feature.fromNodeId,
47394                           toNodeId = feature.toNodeId;
47395                       var itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
47396                       var mid = points.length / 2;
47397                       var loc; // Even number of points, find midpoint of the middle two
47398                       // Odd number of points, use position of very middle point
47399
47400                       if (mid % 1 === 0) {
47401                         loc = pointAverage([points[mid - 1], points[mid]]);
47402                       } else {
47403                         mid = points[Math.floor(mid)];
47404                         loc = [mid.lon, mid.lat];
47405                       } // One-ways can land on same segment in opposite direction
47406
47407
47408                       loc = preventCoincident$1(loc, false);
47409                       var d = new QAItem(loc, _this, k, itemId, {
47410                         issueKey: k,
47411                         // used as a category
47412                         identifier: {
47413                           // used to post changes
47414                           wayId: wayId,
47415                           fromNodeId: fromNodeId,
47416                           toNodeId: toNodeId
47417                         },
47418                         objectId: wayId,
47419                         objectType: 'way'
47420                       }); // Variables used in the description
47421
47422                       d.replacements = {
47423                         percentage: feature.percentOfTrips,
47424                         num_trips: feature.numberOfTrips,
47425                         highway: linkErrorObject(_t('QA.keepRight.error_parts.highway')),
47426                         from_node: linkEntity('n' + feature.fromNodeId),
47427                         to_node: linkEntity('n' + feature.toNodeId)
47428                       };
47429                       _cache$1.data[d.id] = d;
47430
47431                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
47432                     });
47433                   } // Tiles at high zoom == missing roads
47434
47435
47436                   if (data.tiles) {
47437                     data.tiles.forEach(function (feature) {
47438                       var type = feature.type,
47439                           x = feature.x,
47440                           y = feature.y,
47441                           numberOfTrips = feature.numberOfTrips;
47442                       var geoType = type.toLowerCase();
47443                       var itemId = "".concat(geoType).concat(x).concat(y).concat(numberOfTrips); // Average of recorded points should land on the missing geometry
47444                       // Missing geometry could happen to land on another error
47445
47446                       var loc = pointAverage(feature.points);
47447                       loc = preventCoincident$1(loc, false);
47448                       var d = new QAItem(loc, _this, "".concat(k, "-").concat(geoType), itemId, {
47449                         issueKey: k,
47450                         identifier: {
47451                           x: x,
47452                           y: y
47453                         }
47454                       });
47455                       d.replacements = {
47456                         num_trips: numberOfTrips,
47457                         geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
47458                       }; // -1 trips indicates data came from a 3rd party
47459
47460                       if (numberOfTrips === -1) {
47461                         d.desc = _t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
47462                       }
47463
47464                       _cache$1.data[d.id] = d;
47465
47466                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
47467                     });
47468                   } // Entities at high zoom == turn restrictions
47469
47470
47471                   if (data.entities) {
47472                     data.entities.forEach(function (feature) {
47473                       var point = feature.point,
47474                           id = feature.id,
47475                           segments = feature.segments,
47476                           numberOfPasses = feature.numberOfPasses,
47477                           turnType = feature.turnType;
47478                       var itemId = "".concat(id.replace(/[,:+#]/g, '_')); // Turn restrictions could be missing at same junction
47479                       // We also want to bump the error up so node is accessible
47480
47481                       var loc = preventCoincident$1([point.lon, point.lat], true); // Elements are presented in a strange way
47482
47483                       var ids = id.split(',');
47484                       var from_way = ids[0];
47485                       var via_node = ids[3];
47486                       var to_way = ids[2].split(':')[1];
47487                       var d = new QAItem(loc, _this, k, itemId, {
47488                         issueKey: k,
47489                         identifier: id,
47490                         objectId: via_node,
47491                         objectType: 'node'
47492                       }); // Travel direction along from_way clarifies the turn restriction
47493
47494                       var _segments$0$points = _slicedToArray(segments[0].points, 2),
47495                           p1 = _segments$0$points[0],
47496                           p2 = _segments$0$points[1];
47497
47498                       var dir_of_travel = cardinalDirection(relativeBearing(p1, p2)); // Variables used in the description
47499
47500                       d.replacements = {
47501                         num_passed: numberOfPasses,
47502                         num_trips: segments[0].numberOfTrips,
47503                         turn_restriction: turnType.toLowerCase(),
47504                         from_way: linkEntity('w' + from_way),
47505                         to_way: linkEntity('w' + to_way),
47506                         travel_direction: dir_of_travel,
47507                         junction: linkErrorObject(_t('QA.keepRight.error_parts.this_node'))
47508                       };
47509                       _cache$1.data[d.id] = d;
47510
47511                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
47512
47513                       dispatch$6.call('loaded');
47514                     });
47515                   }
47516                 })["catch"](function () {
47517                   delete _cache$1.inflightTile[tile.id][k];
47518
47519                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
47520                     delete _cache$1.inflightTile[tile.id];
47521                     _cache$1.loadedTile[tile.id] = true;
47522                   }
47523                 });
47524               });
47525               _cache$1.inflightTile[tile.id] = requests;
47526             });
47527           },
47528           getComments: function getComments(item) {
47529             var _this2 = this;
47530
47531             // If comments already retrieved no need to do so again
47532             if (item.comments) {
47533               return Promise.resolve(item);
47534             }
47535
47536             var key = item.issueKey;
47537             var qParams = {};
47538
47539             if (key === 'ow') {
47540               qParams = item.identifier;
47541             } else if (key === 'mr') {
47542               qParams.tileX = item.identifier.x;
47543               qParams.tileY = item.identifier.y;
47544             } else if (key === 'tr') {
47545               qParams.targetId = item.identifier;
47546             }
47547
47548             var url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
47549
47550             var cacheComments = function cacheComments(data) {
47551               // Assign directly for immediate use afterwards
47552               // comments are served newest to oldest
47553               item.comments = data.comments ? data.comments.reverse() : [];
47554
47555               _this2.replaceItem(item);
47556             };
47557
47558             return d3_json(url).then(cacheComments).then(function () {
47559               return item;
47560             });
47561           },
47562           postUpdate: function postUpdate(d, callback) {
47563             if (!serviceOsm.authenticated()) {
47564               // Username required in payload
47565               return callback({
47566                 message: 'Not Authenticated',
47567                 status: -3
47568               }, d);
47569             }
47570
47571             if (_cache$1.inflightPost[d.id]) {
47572               return callback({
47573                 message: 'Error update already inflight',
47574                 status: -2
47575               }, d);
47576             } // Payload can only be sent once username is established
47577
47578
47579             serviceOsm.userDetails(sendPayload.bind(this));
47580
47581             function sendPayload(err, user) {
47582               var _this3 = this;
47583
47584               if (err) {
47585                 return callback(err, d);
47586               }
47587
47588               var key = d.issueKey;
47589               var url = "".concat(_impOsmUrls[key], "/comment");
47590               var payload = {
47591                 username: user.display_name,
47592                 targetIds: [d.identifier]
47593               };
47594
47595               if (d.newStatus) {
47596                 payload.status = d.newStatus;
47597                 payload.text = 'status changed';
47598               } // Comment take place of default text
47599
47600
47601               if (d.newComment) {
47602                 payload.text = d.newComment;
47603               }
47604
47605               var controller = new AbortController();
47606               _cache$1.inflightPost[d.id] = controller;
47607               var options = {
47608                 method: 'POST',
47609                 signal: controller.signal,
47610                 body: JSON.stringify(payload)
47611               };
47612               d3_json(url, options).then(function () {
47613                 delete _cache$1.inflightPost[d.id]; // Just a comment, update error in cache
47614
47615                 if (!d.newStatus) {
47616                   var now = new Date();
47617                   var comments = d.comments ? d.comments : [];
47618                   comments.push({
47619                     username: payload.username,
47620                     text: payload.text,
47621                     timestamp: now.getTime() / 1000
47622                   });
47623
47624                   _this3.replaceItem(d.update({
47625                     comments: comments,
47626                     newComment: undefined
47627                   }));
47628                 } else {
47629                   _this3.removeItem(d);
47630
47631                   if (d.newStatus === 'SOLVED') {
47632                     // Keep track of the number of issues closed per type to tag the changeset
47633                     if (!(d.issueKey in _cache$1.closed)) {
47634                       _cache$1.closed[d.issueKey] = 0;
47635                     }
47636
47637                     _cache$1.closed[d.issueKey] += 1;
47638                   }
47639                 }
47640
47641                 if (callback) callback(null, d);
47642               })["catch"](function (err) {
47643                 delete _cache$1.inflightPost[d.id];
47644                 if (callback) callback(err.message);
47645               });
47646             }
47647           },
47648           // Get all cached QAItems covering the viewport
47649           getItems: function getItems(projection) {
47650             var viewport = projection.clipExtent();
47651             var min = [viewport[0][0], viewport[1][1]];
47652             var max = [viewport[1][0], viewport[0][1]];
47653             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
47654             return _cache$1.rtree.search(bbox).map(function (d) {
47655               return d.data;
47656             });
47657           },
47658           // Get a QAItem from cache
47659           // NOTE: Don't change method name until UI v3 is merged
47660           getError: function getError(id) {
47661             return _cache$1.data[id];
47662           },
47663           // get the name of the icon to display for this item
47664           getIcon: function getIcon(itemType) {
47665             return _impOsmData.icons[itemType];
47666           },
47667           // Replace a single QAItem in the cache
47668           replaceItem: function replaceItem(issue) {
47669             if (!(issue instanceof QAItem) || !issue.id) return;
47670             _cache$1.data[issue.id] = issue;
47671             updateRtree$2(encodeIssueRtree$1(issue), true); // true = replace
47672
47673             return issue;
47674           },
47675           // Remove a single QAItem from the cache
47676           removeItem: function removeItem(issue) {
47677             if (!(issue instanceof QAItem) || !issue.id) return;
47678             delete _cache$1.data[issue.id];
47679             updateRtree$2(encodeIssueRtree$1(issue), false); // false = remove
47680           },
47681           // Used to populate `closed:improveosm:*` changeset tags
47682           getClosedCounts: function getClosedCounts() {
47683             return _cache$1.closed;
47684           }
47685         };
47686
47687         var defaults$5 = {exports: {}};
47688
47689         function getDefaults$1() {
47690           return {
47691             baseUrl: null,
47692             breaks: false,
47693             gfm: true,
47694             headerIds: true,
47695             headerPrefix: '',
47696             highlight: null,
47697             langPrefix: 'language-',
47698             mangle: true,
47699             pedantic: false,
47700             renderer: null,
47701             sanitize: false,
47702             sanitizer: null,
47703             silent: false,
47704             smartLists: false,
47705             smartypants: false,
47706             tokenizer: null,
47707             walkTokens: null,
47708             xhtml: false
47709           };
47710         }
47711
47712         function changeDefaults$1(newDefaults) {
47713           defaults$5.exports.defaults = newDefaults;
47714         }
47715
47716         defaults$5.exports = {
47717           defaults: getDefaults$1(),
47718           getDefaults: getDefaults$1,
47719           changeDefaults: changeDefaults$1
47720         };
47721
47722         var escapeTest = /[&<>"']/;
47723         var escapeReplace = /[&<>"']/g;
47724         var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
47725         var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
47726         var escapeReplacements = {
47727           '&': '&amp;',
47728           '<': '&lt;',
47729           '>': '&gt;',
47730           '"': '&quot;',
47731           "'": '&#39;'
47732         };
47733
47734         var getEscapeReplacement = function getEscapeReplacement(ch) {
47735           return escapeReplacements[ch];
47736         };
47737
47738         function escape$3(html, encode) {
47739           if (encode) {
47740             if (escapeTest.test(html)) {
47741               return html.replace(escapeReplace, getEscapeReplacement);
47742             }
47743           } else {
47744             if (escapeTestNoEncode.test(html)) {
47745               return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
47746             }
47747           }
47748
47749           return html;
47750         }
47751
47752         var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
47753
47754         function unescape$2(html) {
47755           // explicitly match decimal, hex, and named HTML entities
47756           return html.replace(unescapeTest, function (_, n) {
47757             n = n.toLowerCase();
47758             if (n === 'colon') return ':';
47759
47760             if (n.charAt(0) === '#') {
47761               return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));
47762             }
47763
47764             return '';
47765           });
47766         }
47767
47768         var caret = /(^|[^\[])\^/g;
47769
47770         function edit$1(regex, opt) {
47771           regex = regex.source || regex;
47772           opt = opt || '';
47773           var obj = {
47774             replace: function replace(name, val) {
47775               val = val.source || val;
47776               val = val.replace(caret, '$1');
47777               regex = regex.replace(name, val);
47778               return obj;
47779             },
47780             getRegex: function getRegex() {
47781               return new RegExp(regex, opt);
47782             }
47783           };
47784           return obj;
47785         }
47786
47787         var nonWordAndColonTest = /[^\w:]/g;
47788         var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
47789
47790         function cleanUrl$1(sanitize, base, href) {
47791           if (sanitize) {
47792             var prot;
47793
47794             try {
47795               prot = decodeURIComponent(unescape$2(href)).replace(nonWordAndColonTest, '').toLowerCase();
47796             } catch (e) {
47797               return null;
47798             }
47799
47800             if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
47801               return null;
47802             }
47803           }
47804
47805           if (base && !originIndependentUrl.test(href)) {
47806             href = resolveUrl$2(base, href);
47807           }
47808
47809           try {
47810             href = encodeURI(href).replace(/%25/g, '%');
47811           } catch (e) {
47812             return null;
47813           }
47814
47815           return href;
47816         }
47817
47818         var baseUrls = {};
47819         var justDomain = /^[^:]+:\/*[^/]*$/;
47820         var protocol = /^([^:]+:)[\s\S]*$/;
47821         var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
47822
47823         function resolveUrl$2(base, href) {
47824           if (!baseUrls[' ' + base]) {
47825             // we can ignore everything in base after the last slash of its path component,
47826             // but we might need to add _that_
47827             // https://tools.ietf.org/html/rfc3986#section-3
47828             if (justDomain.test(base)) {
47829               baseUrls[' ' + base] = base + '/';
47830             } else {
47831               baseUrls[' ' + base] = rtrim$1(base, '/', true);
47832             }
47833           }
47834
47835           base = baseUrls[' ' + base];
47836           var relativeBase = base.indexOf(':') === -1;
47837
47838           if (href.substring(0, 2) === '//') {
47839             if (relativeBase) {
47840               return href;
47841             }
47842
47843             return base.replace(protocol, '$1') + href;
47844           } else if (href.charAt(0) === '/') {
47845             if (relativeBase) {
47846               return href;
47847             }
47848
47849             return base.replace(domain, '$1') + href;
47850           } else {
47851             return base + href;
47852           }
47853         }
47854
47855         var noopTest$1 = {
47856           exec: function noopTest() {}
47857         };
47858
47859         function merge$2(obj) {
47860           var i = 1,
47861               target,
47862               key;
47863
47864           for (; i < arguments.length; i++) {
47865             target = arguments[i];
47866
47867             for (key in target) {
47868               if (Object.prototype.hasOwnProperty.call(target, key)) {
47869                 obj[key] = target[key];
47870               }
47871             }
47872           }
47873
47874           return obj;
47875         }
47876
47877         function splitCells$1(tableRow, count) {
47878           // ensure that every cell-delimiting pipe has a space
47879           // before it to distinguish it from an escaped pipe
47880           var row = tableRow.replace(/\|/g, function (match, offset, str) {
47881             var escaped = false,
47882                 curr = offset;
47883
47884             while (--curr >= 0 && str[curr] === '\\') {
47885               escaped = !escaped;
47886             }
47887
47888             if (escaped) {
47889               // odd number of slashes means | is escaped
47890               // so we leave it alone
47891               return '|';
47892             } else {
47893               // add space before unescaped |
47894               return ' |';
47895             }
47896           }),
47897               cells = row.split(/ \|/);
47898           var i = 0;
47899
47900           if (cells.length > count) {
47901             cells.splice(count);
47902           } else {
47903             while (cells.length < count) {
47904               cells.push('');
47905             }
47906           }
47907
47908           for (; i < cells.length; i++) {
47909             // leading or trailing whitespace is ignored per the gfm spec
47910             cells[i] = cells[i].trim().replace(/\\\|/g, '|');
47911           }
47912
47913           return cells;
47914         } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
47915         // /c*$/ is vulnerable to REDOS.
47916         // invert: Remove suffix of non-c chars instead. Default falsey.
47917
47918
47919         function rtrim$1(str, c, invert) {
47920           var l = str.length;
47921
47922           if (l === 0) {
47923             return '';
47924           } // Length of suffix matching the invert condition.
47925
47926
47927           var suffLen = 0; // Step left until we fail to match the invert condition.
47928
47929           while (suffLen < l) {
47930             var currChar = str.charAt(l - suffLen - 1);
47931
47932             if (currChar === c && !invert) {
47933               suffLen++;
47934             } else if (currChar !== c && invert) {
47935               suffLen++;
47936             } else {
47937               break;
47938             }
47939           }
47940
47941           return str.substr(0, l - suffLen);
47942         }
47943
47944         function findClosingBracket$1(str, b) {
47945           if (str.indexOf(b[1]) === -1) {
47946             return -1;
47947           }
47948
47949           var l = str.length;
47950           var level = 0,
47951               i = 0;
47952
47953           for (; i < l; i++) {
47954             if (str[i] === '\\') {
47955               i++;
47956             } else if (str[i] === b[0]) {
47957               level++;
47958             } else if (str[i] === b[1]) {
47959               level--;
47960
47961               if (level < 0) {
47962                 return i;
47963               }
47964             }
47965           }
47966
47967           return -1;
47968         }
47969
47970         function checkSanitizeDeprecation$1(opt) {
47971           if (opt && opt.sanitize && !opt.silent) {
47972             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');
47973           }
47974         } // copied from https://stackoverflow.com/a/5450113/806777
47975
47976
47977         function repeatString$1(pattern, count) {
47978           if (count < 1) {
47979             return '';
47980           }
47981
47982           var result = '';
47983
47984           while (count > 1) {
47985             if (count & 1) {
47986               result += pattern;
47987             }
47988
47989             count >>= 1;
47990             pattern += pattern;
47991           }
47992
47993           return result + pattern;
47994         }
47995
47996         var helpers = {
47997           escape: escape$3,
47998           unescape: unescape$2,
47999           edit: edit$1,
48000           cleanUrl: cleanUrl$1,
48001           resolveUrl: resolveUrl$2,
48002           noopTest: noopTest$1,
48003           merge: merge$2,
48004           splitCells: splitCells$1,
48005           rtrim: rtrim$1,
48006           findClosingBracket: findClosingBracket$1,
48007           checkSanitizeDeprecation: checkSanitizeDeprecation$1,
48008           repeatString: repeatString$1
48009         };
48010
48011         var defaults$4 = defaults$5.exports.defaults;
48012         var rtrim = helpers.rtrim,
48013             splitCells = helpers.splitCells,
48014             _escape = helpers.escape,
48015             findClosingBracket = helpers.findClosingBracket;
48016
48017         function outputLink(cap, link, raw) {
48018           var href = link.href;
48019           var title = link.title ? _escape(link.title) : null;
48020           var text = cap[1].replace(/\\([\[\]])/g, '$1');
48021
48022           if (cap[0].charAt(0) !== '!') {
48023             return {
48024               type: 'link',
48025               raw: raw,
48026               href: href,
48027               title: title,
48028               text: text
48029             };
48030           } else {
48031             return {
48032               type: 'image',
48033               raw: raw,
48034               href: href,
48035               title: title,
48036               text: _escape(text)
48037             };
48038           }
48039         }
48040
48041         function indentCodeCompensation(raw, text) {
48042           var matchIndentToCode = raw.match(/^(\s+)(?:```)/);
48043
48044           if (matchIndentToCode === null) {
48045             return text;
48046           }
48047
48048           var indentToCode = matchIndentToCode[1];
48049           return text.split('\n').map(function (node) {
48050             var matchIndentInNode = node.match(/^\s+/);
48051
48052             if (matchIndentInNode === null) {
48053               return node;
48054             }
48055
48056             var _matchIndentInNode = _slicedToArray(matchIndentInNode, 1),
48057                 indentInNode = _matchIndentInNode[0];
48058
48059             if (indentInNode.length >= indentToCode.length) {
48060               return node.slice(indentToCode.length);
48061             }
48062
48063             return node;
48064           }).join('\n');
48065         }
48066         /**
48067          * Tokenizer
48068          */
48069
48070
48071         var Tokenizer_1 = /*#__PURE__*/function () {
48072           function Tokenizer(options) {
48073             _classCallCheck$1(this, Tokenizer);
48074
48075             this.options = options || defaults$4;
48076           }
48077
48078           _createClass$1(Tokenizer, [{
48079             key: "space",
48080             value: function space(src) {
48081               var cap = this.rules.block.newline.exec(src);
48082
48083               if (cap) {
48084                 if (cap[0].length > 1) {
48085                   return {
48086                     type: 'space',
48087                     raw: cap[0]
48088                   };
48089                 }
48090
48091                 return {
48092                   raw: '\n'
48093                 };
48094               }
48095             }
48096           }, {
48097             key: "code",
48098             value: function code(src) {
48099               var cap = this.rules.block.code.exec(src);
48100
48101               if (cap) {
48102                 var text = cap[0].replace(/^ {1,4}/gm, '');
48103                 return {
48104                   type: 'code',
48105                   raw: cap[0],
48106                   codeBlockStyle: 'indented',
48107                   text: !this.options.pedantic ? rtrim(text, '\n') : text
48108                 };
48109               }
48110             }
48111           }, {
48112             key: "fences",
48113             value: function fences(src) {
48114               var cap = this.rules.block.fences.exec(src);
48115
48116               if (cap) {
48117                 var raw = cap[0];
48118                 var text = indentCodeCompensation(raw, cap[3] || '');
48119                 return {
48120                   type: 'code',
48121                   raw: raw,
48122                   lang: cap[2] ? cap[2].trim() : cap[2],
48123                   text: text
48124                 };
48125               }
48126             }
48127           }, {
48128             key: "heading",
48129             value: function heading(src) {
48130               var cap = this.rules.block.heading.exec(src);
48131
48132               if (cap) {
48133                 var text = cap[2].trim(); // remove trailing #s
48134
48135                 if (/#$/.test(text)) {
48136                   var trimmed = rtrim(text, '#');
48137
48138                   if (this.options.pedantic) {
48139                     text = trimmed.trim();
48140                   } else if (!trimmed || / $/.test(trimmed)) {
48141                     // CommonMark requires space before trailing #s
48142                     text = trimmed.trim();
48143                   }
48144                 }
48145
48146                 return {
48147                   type: 'heading',
48148                   raw: cap[0],
48149                   depth: cap[1].length,
48150                   text: text
48151                 };
48152               }
48153             }
48154           }, {
48155             key: "nptable",
48156             value: function nptable(src) {
48157               var cap = this.rules.block.nptable.exec(src);
48158
48159               if (cap) {
48160                 var item = {
48161                   type: 'table',
48162                   header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
48163                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
48164                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
48165                   raw: cap[0]
48166                 };
48167
48168                 if (item.header.length === item.align.length) {
48169                   var l = item.align.length;
48170                   var i;
48171
48172                   for (i = 0; i < l; i++) {
48173                     if (/^ *-+: *$/.test(item.align[i])) {
48174                       item.align[i] = 'right';
48175                     } else if (/^ *:-+: *$/.test(item.align[i])) {
48176                       item.align[i] = 'center';
48177                     } else if (/^ *:-+ *$/.test(item.align[i])) {
48178                       item.align[i] = 'left';
48179                     } else {
48180                       item.align[i] = null;
48181                     }
48182                   }
48183
48184                   l = item.cells.length;
48185
48186                   for (i = 0; i < l; i++) {
48187                     item.cells[i] = splitCells(item.cells[i], item.header.length);
48188                   }
48189
48190                   return item;
48191                 }
48192               }
48193             }
48194           }, {
48195             key: "hr",
48196             value: function hr(src) {
48197               var cap = this.rules.block.hr.exec(src);
48198
48199               if (cap) {
48200                 return {
48201                   type: 'hr',
48202                   raw: cap[0]
48203                 };
48204               }
48205             }
48206           }, {
48207             key: "blockquote",
48208             value: function blockquote(src) {
48209               var cap = this.rules.block.blockquote.exec(src);
48210
48211               if (cap) {
48212                 var text = cap[0].replace(/^ *> ?/gm, '');
48213                 return {
48214                   type: 'blockquote',
48215                   raw: cap[0],
48216                   text: text
48217                 };
48218               }
48219             }
48220           }, {
48221             key: "list",
48222             value: function list(src) {
48223               var cap = this.rules.block.list.exec(src);
48224
48225               if (cap) {
48226                 var raw = cap[0];
48227                 var bull = cap[2];
48228                 var isordered = bull.length > 1;
48229                 var list = {
48230                   type: 'list',
48231                   raw: raw,
48232                   ordered: isordered,
48233                   start: isordered ? +bull.slice(0, -1) : '',
48234                   loose: false,
48235                   items: []
48236                 }; // Get each top-level item.
48237
48238                 var itemMatch = cap[0].match(this.rules.block.item);
48239                 var next = false,
48240                     item,
48241                     space,
48242                     bcurr,
48243                     bnext,
48244                     addBack,
48245                     loose,
48246                     istask,
48247                     ischecked,
48248                     endMatch;
48249                 var l = itemMatch.length;
48250                 bcurr = this.rules.block.listItemStart.exec(itemMatch[0]);
48251
48252                 for (var i = 0; i < l; i++) {
48253                   item = itemMatch[i];
48254                   raw = item;
48255
48256                   if (!this.options.pedantic) {
48257                     // Determine if current item contains the end of the list
48258                     endMatch = item.match(new RegExp('\\n\\s*\\n {0,' + (bcurr[0].length - 1) + '}\\S'));
48259
48260                     if (endMatch) {
48261                       addBack = item.length - endMatch.index + itemMatch.slice(i + 1).join('\n').length;
48262                       list.raw = list.raw.substring(0, list.raw.length - addBack);
48263                       item = item.substring(0, endMatch.index);
48264                       raw = item;
48265                       l = i + 1;
48266                     }
48267                   } // Determine whether the next list item belongs here.
48268                   // Backpedal if it does not belong in this list.
48269
48270
48271                   if (i !== l - 1) {
48272                     bnext = this.rules.block.listItemStart.exec(itemMatch[i + 1]);
48273
48274                     if (!this.options.pedantic ? bnext[1].length >= bcurr[0].length || bnext[1].length > 3 : bnext[1].length > bcurr[1].length) {
48275                       // nested list or continuation
48276                       itemMatch.splice(i, 2, itemMatch[i] + (!this.options.pedantic && bnext[1].length < bcurr[0].length && !itemMatch[i].match(/\n$/) ? '' : '\n') + itemMatch[i + 1]);
48277                       i--;
48278                       l--;
48279                       continue;
48280                     } else if ( // different bullet style
48281                     !this.options.pedantic || this.options.smartLists ? bnext[2][bnext[2].length - 1] !== bull[bull.length - 1] : isordered === (bnext[2].length === 1)) {
48282                       addBack = itemMatch.slice(i + 1).join('\n').length;
48283                       list.raw = list.raw.substring(0, list.raw.length - addBack);
48284                       i = l - 1;
48285                     }
48286
48287                     bcurr = bnext;
48288                   } // Remove the list item's bullet
48289                   // so it is seen as the next token.
48290
48291
48292                   space = item.length;
48293                   item = item.replace(/^ *([*+-]|\d+[.)]) ?/, ''); // Outdent whatever the
48294                   // list item contains. Hacky.
48295
48296                   if (~item.indexOf('\n ')) {
48297                     space -= item.length;
48298                     item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');
48299                   } // trim item newlines at end
48300
48301
48302                   item = rtrim(item, '\n');
48303
48304                   if (i !== l - 1) {
48305                     raw = raw + '\n';
48306                   } // Determine whether item is loose or not.
48307                   // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
48308                   // for discount behavior.
48309
48310
48311                   loose = next || /\n\n(?!\s*$)/.test(raw);
48312
48313                   if (i !== l - 1) {
48314                     next = raw.slice(-2) === '\n\n';
48315                     if (!loose) loose = next;
48316                   }
48317
48318                   if (loose) {
48319                     list.loose = true;
48320                   } // Check for task list items
48321
48322
48323                   if (this.options.gfm) {
48324                     istask = /^\[[ xX]\] /.test(item);
48325                     ischecked = undefined;
48326
48327                     if (istask) {
48328                       ischecked = item[1] !== ' ';
48329                       item = item.replace(/^\[[ xX]\] +/, '');
48330                     }
48331                   }
48332
48333                   list.items.push({
48334                     type: 'list_item',
48335                     raw: raw,
48336                     task: istask,
48337                     checked: ischecked,
48338                     loose: loose,
48339                     text: item
48340                   });
48341                 }
48342
48343                 return list;
48344               }
48345             }
48346           }, {
48347             key: "html",
48348             value: function html(src) {
48349               var cap = this.rules.block.html.exec(src);
48350
48351               if (cap) {
48352                 return {
48353                   type: this.options.sanitize ? 'paragraph' : 'html',
48354                   raw: cap[0],
48355                   pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
48356                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
48357                 };
48358               }
48359             }
48360           }, {
48361             key: "def",
48362             value: function def(src) {
48363               var cap = this.rules.block.def.exec(src);
48364
48365               if (cap) {
48366                 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
48367                 var tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
48368                 return {
48369                   type: 'def',
48370                   tag: tag,
48371                   raw: cap[0],
48372                   href: cap[2],
48373                   title: cap[3]
48374                 };
48375               }
48376             }
48377           }, {
48378             key: "table",
48379             value: function table(src) {
48380               var cap = this.rules.block.table.exec(src);
48381
48382               if (cap) {
48383                 var item = {
48384                   type: 'table',
48385                   header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
48386                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
48387                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
48388                 };
48389
48390                 if (item.header.length === item.align.length) {
48391                   item.raw = cap[0];
48392                   var l = item.align.length;
48393                   var i;
48394
48395                   for (i = 0; i < l; i++) {
48396                     if (/^ *-+: *$/.test(item.align[i])) {
48397                       item.align[i] = 'right';
48398                     } else if (/^ *:-+: *$/.test(item.align[i])) {
48399                       item.align[i] = 'center';
48400                     } else if (/^ *:-+ *$/.test(item.align[i])) {
48401                       item.align[i] = 'left';
48402                     } else {
48403                       item.align[i] = null;
48404                     }
48405                   }
48406
48407                   l = item.cells.length;
48408
48409                   for (i = 0; i < l; i++) {
48410                     item.cells[i] = splitCells(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length);
48411                   }
48412
48413                   return item;
48414                 }
48415               }
48416             }
48417           }, {
48418             key: "lheading",
48419             value: function lheading(src) {
48420               var cap = this.rules.block.lheading.exec(src);
48421
48422               if (cap) {
48423                 return {
48424                   type: 'heading',
48425                   raw: cap[0],
48426                   depth: cap[2].charAt(0) === '=' ? 1 : 2,
48427                   text: cap[1]
48428                 };
48429               }
48430             }
48431           }, {
48432             key: "paragraph",
48433             value: function paragraph(src) {
48434               var cap = this.rules.block.paragraph.exec(src);
48435
48436               if (cap) {
48437                 return {
48438                   type: 'paragraph',
48439                   raw: cap[0],
48440                   text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
48441                 };
48442               }
48443             }
48444           }, {
48445             key: "text",
48446             value: function text(src) {
48447               var cap = this.rules.block.text.exec(src);
48448
48449               if (cap) {
48450                 return {
48451                   type: 'text',
48452                   raw: cap[0],
48453                   text: cap[0]
48454                 };
48455               }
48456             }
48457           }, {
48458             key: "escape",
48459             value: function escape(src) {
48460               var cap = this.rules.inline.escape.exec(src);
48461
48462               if (cap) {
48463                 return {
48464                   type: 'escape',
48465                   raw: cap[0],
48466                   text: _escape(cap[1])
48467                 };
48468               }
48469             }
48470           }, {
48471             key: "tag",
48472             value: function tag(src, inLink, inRawBlock) {
48473               var cap = this.rules.inline.tag.exec(src);
48474
48475               if (cap) {
48476                 if (!inLink && /^<a /i.test(cap[0])) {
48477                   inLink = true;
48478                 } else if (inLink && /^<\/a>/i.test(cap[0])) {
48479                   inLink = false;
48480                 }
48481
48482                 if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
48483                   inRawBlock = true;
48484                 } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
48485                   inRawBlock = false;
48486                 }
48487
48488                 return {
48489                   type: this.options.sanitize ? 'text' : 'html',
48490                   raw: cap[0],
48491                   inLink: inLink,
48492                   inRawBlock: inRawBlock,
48493                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
48494                 };
48495               }
48496             }
48497           }, {
48498             key: "link",
48499             value: function link(src) {
48500               var cap = this.rules.inline.link.exec(src);
48501
48502               if (cap) {
48503                 var trimmedUrl = cap[2].trim();
48504
48505                 if (!this.options.pedantic && /^</.test(trimmedUrl)) {
48506                   // commonmark requires matching angle brackets
48507                   if (!/>$/.test(trimmedUrl)) {
48508                     return;
48509                   } // ending angle bracket cannot be escaped
48510
48511
48512                   var rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
48513
48514                   if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
48515                     return;
48516                   }
48517                 } else {
48518                   // find closing parenthesis
48519                   var lastParenIndex = findClosingBracket(cap[2], '()');
48520
48521                   if (lastParenIndex > -1) {
48522                     var start = cap[0].indexOf('!') === 0 ? 5 : 4;
48523                     var linkLen = start + cap[1].length + lastParenIndex;
48524                     cap[2] = cap[2].substring(0, lastParenIndex);
48525                     cap[0] = cap[0].substring(0, linkLen).trim();
48526                     cap[3] = '';
48527                   }
48528                 }
48529
48530                 var href = cap[2];
48531                 var title = '';
48532
48533                 if (this.options.pedantic) {
48534                   // split pedantic href and title
48535                   var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
48536
48537                   if (link) {
48538                     href = link[1];
48539                     title = link[3];
48540                   }
48541                 } else {
48542                   title = cap[3] ? cap[3].slice(1, -1) : '';
48543                 }
48544
48545                 href = href.trim();
48546
48547                 if (/^</.test(href)) {
48548                   if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
48549                     // pedantic allows starting angle bracket without ending angle bracket
48550                     href = href.slice(1);
48551                   } else {
48552                     href = href.slice(1, -1);
48553                   }
48554                 }
48555
48556                 return outputLink(cap, {
48557                   href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
48558                   title: title ? title.replace(this.rules.inline._escapes, '$1') : title
48559                 }, cap[0]);
48560               }
48561             }
48562           }, {
48563             key: "reflink",
48564             value: function reflink(src, links) {
48565               var cap;
48566
48567               if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
48568                 var link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
48569                 link = links[link.toLowerCase()];
48570
48571                 if (!link || !link.href) {
48572                   var text = cap[0].charAt(0);
48573                   return {
48574                     type: 'text',
48575                     raw: text,
48576                     text: text
48577                   };
48578                 }
48579
48580                 return outputLink(cap, link, cap[0]);
48581               }
48582             }
48583           }, {
48584             key: "emStrong",
48585             value: function emStrong(src, maskedSrc) {
48586               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
48587               var match = this.rules.inline.emStrong.lDelim.exec(src);
48588               if (!match) return; // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
48589
48590               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;
48591               var nextChar = match[1] || match[2] || '';
48592
48593               if (!nextChar || nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar))) {
48594                 var lLength = match[0].length - 1;
48595                 var rDelim,
48596                     rLength,
48597                     delimTotal = lLength,
48598                     midDelimTotal = 0;
48599                 var endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
48600                 endReg.lastIndex = 0; // Clip maskedSrc to same section of string as src (move to lexer?)
48601
48602                 maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
48603
48604                 while ((match = endReg.exec(maskedSrc)) != null) {
48605                   rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
48606                   if (!rDelim) continue; // skip single * in __abc*abc__
48607
48608                   rLength = rDelim.length;
48609
48610                   if (match[3] || match[4]) {
48611                     // found another Left Delim
48612                     delimTotal += rLength;
48613                     continue;
48614                   } else if (match[5] || match[6]) {
48615                     // either Left or Right Delim
48616                     if (lLength % 3 && !((lLength + rLength) % 3)) {
48617                       midDelimTotal += rLength;
48618                       continue; // CommonMark Emphasis Rules 9-10
48619                     }
48620                   }
48621
48622                   delimTotal -= rLength;
48623                   if (delimTotal > 0) continue; // Haven't found enough closing delimiters
48624                   // Remove extra characters. *a*** -> *a*
48625
48626                   rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal); // Create `em` if smallest delimiter has odd char count. *a***
48627
48628                   if (Math.min(lLength, rLength) % 2) {
48629                     return {
48630                       type: 'em',
48631                       raw: src.slice(0, lLength + match.index + rLength + 1),
48632                       text: src.slice(1, lLength + match.index + rLength)
48633                     };
48634                   } // Create 'strong' if smallest delimiter has even char count. **a***
48635
48636
48637                   return {
48638                     type: 'strong',
48639                     raw: src.slice(0, lLength + match.index + rLength + 1),
48640                     text: src.slice(2, lLength + match.index + rLength - 1)
48641                   };
48642                 }
48643               }
48644             }
48645           }, {
48646             key: "codespan",
48647             value: function codespan(src) {
48648               var cap = this.rules.inline.code.exec(src);
48649
48650               if (cap) {
48651                 var text = cap[2].replace(/\n/g, ' ');
48652                 var hasNonSpaceChars = /[^ ]/.test(text);
48653                 var hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
48654
48655                 if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
48656                   text = text.substring(1, text.length - 1);
48657                 }
48658
48659                 text = _escape(text, true);
48660                 return {
48661                   type: 'codespan',
48662                   raw: cap[0],
48663                   text: text
48664                 };
48665               }
48666             }
48667           }, {
48668             key: "br",
48669             value: function br(src) {
48670               var cap = this.rules.inline.br.exec(src);
48671
48672               if (cap) {
48673                 return {
48674                   type: 'br',
48675                   raw: cap[0]
48676                 };
48677               }
48678             }
48679           }, {
48680             key: "del",
48681             value: function del(src) {
48682               var cap = this.rules.inline.del.exec(src);
48683
48684               if (cap) {
48685                 return {
48686                   type: 'del',
48687                   raw: cap[0],
48688                   text: cap[2]
48689                 };
48690               }
48691             }
48692           }, {
48693             key: "autolink",
48694             value: function autolink(src, mangle) {
48695               var cap = this.rules.inline.autolink.exec(src);
48696
48697               if (cap) {
48698                 var text, href;
48699
48700                 if (cap[2] === '@') {
48701                   text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
48702                   href = 'mailto:' + text;
48703                 } else {
48704                   text = _escape(cap[1]);
48705                   href = text;
48706                 }
48707
48708                 return {
48709                   type: 'link',
48710                   raw: cap[0],
48711                   text: text,
48712                   href: href,
48713                   tokens: [{
48714                     type: 'text',
48715                     raw: text,
48716                     text: text
48717                   }]
48718                 };
48719               }
48720             }
48721           }, {
48722             key: "url",
48723             value: function url(src, mangle) {
48724               var cap;
48725
48726               if (cap = this.rules.inline.url.exec(src)) {
48727                 var text, href;
48728
48729                 if (cap[2] === '@') {
48730                   text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
48731                   href = 'mailto:' + text;
48732                 } else {
48733                   // do extended autolink path validation
48734                   var prevCapZero;
48735
48736                   do {
48737                     prevCapZero = cap[0];
48738                     cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
48739                   } while (prevCapZero !== cap[0]);
48740
48741                   text = _escape(cap[0]);
48742
48743                   if (cap[1] === 'www.') {
48744                     href = 'http://' + text;
48745                   } else {
48746                     href = text;
48747                   }
48748                 }
48749
48750                 return {
48751                   type: 'link',
48752                   raw: cap[0],
48753                   text: text,
48754                   href: href,
48755                   tokens: [{
48756                     type: 'text',
48757                     raw: text,
48758                     text: text
48759                   }]
48760                 };
48761               }
48762             }
48763           }, {
48764             key: "inlineText",
48765             value: function inlineText(src, inRawBlock, smartypants) {
48766               var cap = this.rules.inline.text.exec(src);
48767
48768               if (cap) {
48769                 var text;
48770
48771                 if (inRawBlock) {
48772                   text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];
48773                 } else {
48774                   text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
48775                 }
48776
48777                 return {
48778                   type: 'text',
48779                   raw: cap[0],
48780                   text: text
48781                 };
48782               }
48783             }
48784           }]);
48785
48786           return Tokenizer;
48787         }();
48788
48789         var noopTest = helpers.noopTest,
48790             edit = helpers.edit,
48791             merge$1 = helpers.merge;
48792         /**
48793          * Block-Level Grammar
48794          */
48795
48796         var block$1 = {
48797           newline: /^(?: *(?:\n|$))+/,
48798           code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
48799           fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
48800           hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
48801           heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
48802           blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
48803           list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
48804           html: '^ {0,3}(?:' // optional indentation
48805           + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
48806           + '|comment[^\\n]*(\\n+|$)' // (2)
48807           + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
48808           + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
48809           + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
48810           + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
48811           + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
48812           + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
48813           + ')',
48814           def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
48815           nptable: noopTest,
48816           table: noopTest,
48817           lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
48818           // regex template, placeholders will be replaced according to different paragraph
48819           // interruption rules of commonmark and the original markdown spec:
48820           _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
48821           text: /^[^\n]+/
48822         };
48823         block$1._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
48824         block$1._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
48825         block$1.def = edit(block$1.def).replace('label', block$1._label).replace('title', block$1._title).getRegex();
48826         block$1.bullet = /(?:[*+-]|\d{1,9}[.)])/;
48827         block$1.item = /^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/;
48828         block$1.item = edit(block$1.item, 'gm').replace(/bull/g, block$1.bullet).getRegex();
48829         block$1.listItemStart = edit(/^( *)(bull) */).replace('bull', block$1.bullet).getRegex();
48830         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();
48831         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';
48832         block$1._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
48833         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();
48834         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
48835         .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
48836         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // pars can be interrupted by type (6) html blocks
48837         .getRegex();
48838         block$1.blockquote = edit(block$1.blockquote).replace('paragraph', block$1.paragraph).getRegex();
48839         /**
48840          * Normal Block Grammar
48841          */
48842
48843         block$1.normal = merge$1({}, block$1);
48844         /**
48845          * GFM Block Grammar
48846          */
48847
48848         block$1.gfm = merge$1({}, block$1.normal, {
48849           nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
48850           + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
48851           + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)',
48852           // Cells
48853           table: '^ *\\|(.+)\\n' // Header
48854           + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
48855           + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
48856
48857         });
48858         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
48859         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // tables can be interrupted by type (6) html blocks
48860         .getRegex();
48861         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
48862         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // tables can be interrupted by type (6) html blocks
48863         .getRegex();
48864         /**
48865          * Pedantic grammar (original John Gruber's loose markdown specification)
48866          */
48867
48868         block$1.pedantic = merge$1({}, block$1.normal, {
48869           html: edit('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
48870           + '|<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(),
48871           def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
48872           heading: /^(#{1,6})(.*)(?:\n+|$)/,
48873           fences: noopTest,
48874           // fences not supported
48875           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()
48876         });
48877         /**
48878          * Inline-Level Grammar
48879          */
48880
48881         var inline$1 = {
48882           escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
48883           autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
48884           url: noopTest,
48885           tag: '^comment' + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
48886           + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
48887           + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
48888           + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
48889           + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
48890           // CDATA section
48891           link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
48892           reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
48893           nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
48894           reflinkSearch: 'reflink|nolink(?!\\()',
48895           emStrong: {
48896             lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
48897             //        (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.
48898             //        () Skip other delimiter (1) #***                   (2) a***#, a***                   (3) #***a, ***a                 (4) ***#              (5) #***#                 (6) a***a
48899             rDelimAst: /\_\_[^_*]*?\*[^_*]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
48900             rDelimUnd: /\*\*[^_*]*?\_[^_*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
48901
48902           },
48903           code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
48904           br: /^( {2,}|\\)\n(?!\s*$)/,
48905           del: noopTest,
48906           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
48907           punctuation: /^([\spunctuation])/
48908         }; // list of punctuation marks from CommonMark spec
48909         // without * and _ to handle the different emphasis markers * and _
48910
48911         inline$1._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
48912         inline$1.punctuation = edit(inline$1.punctuation).replace(/punctuation/g, inline$1._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, <html>
48913
48914         inline$1.blockSkip = /\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g;
48915         inline$1.escapedEmSt = /\\\*|\\_/g;
48916         inline$1._comment = edit(block$1._comment).replace('(?:-->|$)', '-->').getRegex();
48917         inline$1.emStrong.lDelim = edit(inline$1.emStrong.lDelim).replace(/punct/g, inline$1._punctuation).getRegex();
48918         inline$1.emStrong.rDelimAst = edit(inline$1.emStrong.rDelimAst, 'g').replace(/punct/g, inline$1._punctuation).getRegex();
48919         inline$1.emStrong.rDelimUnd = edit(inline$1.emStrong.rDelimUnd, 'g').replace(/punct/g, inline$1._punctuation).getRegex();
48920         inline$1._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
48921         inline$1._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
48922         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])?)+(?![-_])/;
48923         inline$1.autolink = edit(inline$1.autolink).replace('scheme', inline$1._scheme).replace('email', inline$1._email).getRegex();
48924         inline$1._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
48925         inline$1.tag = edit(inline$1.tag).replace('comment', inline$1._comment).replace('attribute', inline$1._attribute).getRegex();
48926         inline$1._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
48927         inline$1._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
48928         inline$1._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
48929         inline$1.link = edit(inline$1.link).replace('label', inline$1._label).replace('href', inline$1._href).replace('title', inline$1._title).getRegex();
48930         inline$1.reflink = edit(inline$1.reflink).replace('label', inline$1._label).getRegex();
48931         inline$1.reflinkSearch = edit(inline$1.reflinkSearch, 'g').replace('reflink', inline$1.reflink).replace('nolink', inline$1.nolink).getRegex();
48932         /**
48933          * Normal Inline Grammar
48934          */
48935
48936         inline$1.normal = merge$1({}, inline$1);
48937         /**
48938          * Pedantic Inline Grammar
48939          */
48940
48941         inline$1.pedantic = merge$1({}, inline$1.normal, {
48942           strong: {
48943             start: /^__|\*\*/,
48944             middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
48945             endAst: /\*\*(?!\*)/g,
48946             endUnd: /__(?!_)/g
48947           },
48948           em: {
48949             start: /^_|\*/,
48950             middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
48951             endAst: /\*(?!\*)/g,
48952             endUnd: /_(?!_)/g
48953           },
48954           link: edit(/^!?\[(label)\]\((.*?)\)/).replace('label', inline$1._label).getRegex(),
48955           reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline$1._label).getRegex()
48956         });
48957         /**
48958          * GFM Inline Grammar
48959          */
48960
48961         inline$1.gfm = merge$1({}, inline$1.normal, {
48962           escape: edit(inline$1.escape).replace('])', '~|])').getRegex(),
48963           _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
48964           url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
48965           _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
48966           del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
48967           text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
48968         });
48969         inline$1.gfm.url = edit(inline$1.gfm.url, 'i').replace('email', inline$1.gfm._extended_email).getRegex();
48970         /**
48971          * GFM + Line Breaks Inline Grammar
48972          */
48973
48974         inline$1.breaks = merge$1({}, inline$1.gfm, {
48975           br: edit(inline$1.br).replace('{2,}', '*').getRegex(),
48976           text: edit(inline$1.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
48977         });
48978         var rules = {
48979           block: block$1,
48980           inline: inline$1
48981         };
48982
48983         var Tokenizer$1 = Tokenizer_1;
48984         var defaults$3 = defaults$5.exports.defaults;
48985         var block = rules.block,
48986             inline = rules.inline;
48987         var repeatString = helpers.repeatString;
48988         /**
48989          * smartypants text replacement
48990          */
48991
48992         function smartypants(text) {
48993           return text // em-dashes
48994           .replace(/---/g, "\u2014") // en-dashes
48995           .replace(/--/g, "\u2013") // opening singles
48996           .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes
48997           .replace(/'/g, "\u2019") // opening doubles
48998           .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles
48999           .replace(/"/g, "\u201D") // ellipses
49000           .replace(/\.{3}/g, "\u2026");
49001         }
49002         /**
49003          * mangle email addresses
49004          */
49005
49006
49007         function mangle(text) {
49008           var out = '',
49009               i,
49010               ch;
49011           var l = text.length;
49012
49013           for (i = 0; i < l; i++) {
49014             ch = text.charCodeAt(i);
49015
49016             if (Math.random() > 0.5) {
49017               ch = 'x' + ch.toString(16);
49018             }
49019
49020             out += '&#' + ch + ';';
49021           }
49022
49023           return out;
49024         }
49025         /**
49026          * Block Lexer
49027          */
49028
49029
49030         var Lexer_1 = /*#__PURE__*/function () {
49031           function Lexer(options) {
49032             _classCallCheck$1(this, Lexer);
49033
49034             this.tokens = [];
49035             this.tokens.links = Object.create(null);
49036             this.options = options || defaults$3;
49037             this.options.tokenizer = this.options.tokenizer || new Tokenizer$1();
49038             this.tokenizer = this.options.tokenizer;
49039             this.tokenizer.options = this.options;
49040             var rules = {
49041               block: block.normal,
49042               inline: inline.normal
49043             };
49044
49045             if (this.options.pedantic) {
49046               rules.block = block.pedantic;
49047               rules.inline = inline.pedantic;
49048             } else if (this.options.gfm) {
49049               rules.block = block.gfm;
49050
49051               if (this.options.breaks) {
49052                 rules.inline = inline.breaks;
49053               } else {
49054                 rules.inline = inline.gfm;
49055               }
49056             }
49057
49058             this.tokenizer.rules = rules;
49059           }
49060           /**
49061            * Expose Rules
49062            */
49063
49064
49065           _createClass$1(Lexer, [{
49066             key: "lex",
49067             value:
49068             /**
49069              * Preprocessing
49070              */
49071             function lex(src) {
49072               src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, '    ');
49073               this.blockTokens(src, this.tokens, true);
49074               this.inline(this.tokens);
49075               return this.tokens;
49076             }
49077             /**
49078              * Lexing
49079              */
49080
49081           }, {
49082             key: "blockTokens",
49083             value: function blockTokens(src) {
49084               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
49085               var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
49086
49087               if (this.options.pedantic) {
49088                 src = src.replace(/^ +$/gm, '');
49089               }
49090
49091               var token, i, l, lastToken;
49092
49093               while (src) {
49094                 // newline
49095                 if (token = this.tokenizer.space(src)) {
49096                   src = src.substring(token.raw.length);
49097
49098                   if (token.type) {
49099                     tokens.push(token);
49100                   }
49101
49102                   continue;
49103                 } // code
49104
49105
49106                 if (token = this.tokenizer.code(src)) {
49107                   src = src.substring(token.raw.length);
49108                   lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.
49109
49110                   if (lastToken && lastToken.type === 'paragraph') {
49111                     lastToken.raw += '\n' + token.raw;
49112                     lastToken.text += '\n' + token.text;
49113                   } else {
49114                     tokens.push(token);
49115                   }
49116
49117                   continue;
49118                 } // fences
49119
49120
49121                 if (token = this.tokenizer.fences(src)) {
49122                   src = src.substring(token.raw.length);
49123                   tokens.push(token);
49124                   continue;
49125                 } // heading
49126
49127
49128                 if (token = this.tokenizer.heading(src)) {
49129                   src = src.substring(token.raw.length);
49130                   tokens.push(token);
49131                   continue;
49132                 } // table no leading pipe (gfm)
49133
49134
49135                 if (token = this.tokenizer.nptable(src)) {
49136                   src = src.substring(token.raw.length);
49137                   tokens.push(token);
49138                   continue;
49139                 } // hr
49140
49141
49142                 if (token = this.tokenizer.hr(src)) {
49143                   src = src.substring(token.raw.length);
49144                   tokens.push(token);
49145                   continue;
49146                 } // blockquote
49147
49148
49149                 if (token = this.tokenizer.blockquote(src)) {
49150                   src = src.substring(token.raw.length);
49151                   token.tokens = this.blockTokens(token.text, [], top);
49152                   tokens.push(token);
49153                   continue;
49154                 } // list
49155
49156
49157                 if (token = this.tokenizer.list(src)) {
49158                   src = src.substring(token.raw.length);
49159                   l = token.items.length;
49160
49161                   for (i = 0; i < l; i++) {
49162                     token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
49163                   }
49164
49165                   tokens.push(token);
49166                   continue;
49167                 } // html
49168
49169
49170                 if (token = this.tokenizer.html(src)) {
49171                   src = src.substring(token.raw.length);
49172                   tokens.push(token);
49173                   continue;
49174                 } // def
49175
49176
49177                 if (top && (token = this.tokenizer.def(src))) {
49178                   src = src.substring(token.raw.length);
49179
49180                   if (!this.tokens.links[token.tag]) {
49181                     this.tokens.links[token.tag] = {
49182                       href: token.href,
49183                       title: token.title
49184                     };
49185                   }
49186
49187                   continue;
49188                 } // table (gfm)
49189
49190
49191                 if (token = this.tokenizer.table(src)) {
49192                   src = src.substring(token.raw.length);
49193                   tokens.push(token);
49194                   continue;
49195                 } // lheading
49196
49197
49198                 if (token = this.tokenizer.lheading(src)) {
49199                   src = src.substring(token.raw.length);
49200                   tokens.push(token);
49201                   continue;
49202                 } // top-level paragraph
49203
49204
49205                 if (top && (token = this.tokenizer.paragraph(src))) {
49206                   src = src.substring(token.raw.length);
49207                   tokens.push(token);
49208                   continue;
49209                 } // text
49210
49211
49212                 if (token = this.tokenizer.text(src)) {
49213                   src = src.substring(token.raw.length);
49214                   lastToken = tokens[tokens.length - 1];
49215
49216                   if (lastToken && lastToken.type === 'text') {
49217                     lastToken.raw += '\n' + token.raw;
49218                     lastToken.text += '\n' + token.text;
49219                   } else {
49220                     tokens.push(token);
49221                   }
49222
49223                   continue;
49224                 }
49225
49226                 if (src) {
49227                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
49228
49229                   if (this.options.silent) {
49230                     console.error(errMsg);
49231                     break;
49232                   } else {
49233                     throw new Error(errMsg);
49234                   }
49235                 }
49236               }
49237
49238               return tokens;
49239             }
49240           }, {
49241             key: "inline",
49242             value: function inline(tokens) {
49243               var i, j, k, l2, row, token;
49244               var l = tokens.length;
49245
49246               for (i = 0; i < l; i++) {
49247                 token = tokens[i];
49248
49249                 switch (token.type) {
49250                   case 'paragraph':
49251                   case 'text':
49252                   case 'heading':
49253                     {
49254                       token.tokens = [];
49255                       this.inlineTokens(token.text, token.tokens);
49256                       break;
49257                     }
49258
49259                   case 'table':
49260                     {
49261                       token.tokens = {
49262                         header: [],
49263                         cells: []
49264                       }; // header
49265
49266                       l2 = token.header.length;
49267
49268                       for (j = 0; j < l2; j++) {
49269                         token.tokens.header[j] = [];
49270                         this.inlineTokens(token.header[j], token.tokens.header[j]);
49271                       } // cells
49272
49273
49274                       l2 = token.cells.length;
49275
49276                       for (j = 0; j < l2; j++) {
49277                         row = token.cells[j];
49278                         token.tokens.cells[j] = [];
49279
49280                         for (k = 0; k < row.length; k++) {
49281                           token.tokens.cells[j][k] = [];
49282                           this.inlineTokens(row[k], token.tokens.cells[j][k]);
49283                         }
49284                       }
49285
49286                       break;
49287                     }
49288
49289                   case 'blockquote':
49290                     {
49291                       this.inline(token.tokens);
49292                       break;
49293                     }
49294
49295                   case 'list':
49296                     {
49297                       l2 = token.items.length;
49298
49299                       for (j = 0; j < l2; j++) {
49300                         this.inline(token.items[j].tokens);
49301                       }
49302
49303                       break;
49304                     }
49305                 }
49306               }
49307
49308               return tokens;
49309             }
49310             /**
49311              * Lexing/Compiling
49312              */
49313
49314           }, {
49315             key: "inlineTokens",
49316             value: function inlineTokens(src) {
49317               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
49318               var inLink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
49319               var inRawBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
49320               var token, lastToken; // String with links masked to avoid interference with em and strong
49321
49322               var maskedSrc = src;
49323               var match;
49324               var keepPrevChar, prevChar; // Mask out reflinks
49325
49326               if (this.tokens.links) {
49327                 var links = Object.keys(this.tokens.links);
49328
49329                 if (links.length > 0) {
49330                   while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
49331                     if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
49332                       maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
49333                     }
49334                   }
49335                 }
49336               } // Mask out other blocks
49337
49338
49339               while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
49340                 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
49341               } // Mask out escaped em & strong delimiters
49342
49343
49344               while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
49345                 maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
49346               }
49347
49348               while (src) {
49349                 if (!keepPrevChar) {
49350                   prevChar = '';
49351                 }
49352
49353                 keepPrevChar = false; // escape
49354
49355                 if (token = this.tokenizer.escape(src)) {
49356                   src = src.substring(token.raw.length);
49357                   tokens.push(token);
49358                   continue;
49359                 } // tag
49360
49361
49362                 if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {
49363                   src = src.substring(token.raw.length);
49364                   inLink = token.inLink;
49365                   inRawBlock = token.inRawBlock;
49366                   var _lastToken = tokens[tokens.length - 1];
49367
49368                   if (_lastToken && token.type === 'text' && _lastToken.type === 'text') {
49369                     _lastToken.raw += token.raw;
49370                     _lastToken.text += token.text;
49371                   } else {
49372                     tokens.push(token);
49373                   }
49374
49375                   continue;
49376                 } // link
49377
49378
49379                 if (token = this.tokenizer.link(src)) {
49380                   src = src.substring(token.raw.length);
49381
49382                   if (token.type === 'link') {
49383                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
49384                   }
49385
49386                   tokens.push(token);
49387                   continue;
49388                 } // reflink, nolink
49389
49390
49391                 if (token = this.tokenizer.reflink(src, this.tokens.links)) {
49392                   src = src.substring(token.raw.length);
49393                   var _lastToken2 = tokens[tokens.length - 1];
49394
49395                   if (token.type === 'link') {
49396                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
49397                     tokens.push(token);
49398                   } else if (_lastToken2 && token.type === 'text' && _lastToken2.type === 'text') {
49399                     _lastToken2.raw += token.raw;
49400                     _lastToken2.text += token.text;
49401                   } else {
49402                     tokens.push(token);
49403                   }
49404
49405                   continue;
49406                 } // em & strong
49407
49408
49409                 if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
49410                   src = src.substring(token.raw.length);
49411                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
49412                   tokens.push(token);
49413                   continue;
49414                 } // code
49415
49416
49417                 if (token = this.tokenizer.codespan(src)) {
49418                   src = src.substring(token.raw.length);
49419                   tokens.push(token);
49420                   continue;
49421                 } // br
49422
49423
49424                 if (token = this.tokenizer.br(src)) {
49425                   src = src.substring(token.raw.length);
49426                   tokens.push(token);
49427                   continue;
49428                 } // del (gfm)
49429
49430
49431                 if (token = this.tokenizer.del(src)) {
49432                   src = src.substring(token.raw.length);
49433                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
49434                   tokens.push(token);
49435                   continue;
49436                 } // autolink
49437
49438
49439                 if (token = this.tokenizer.autolink(src, mangle)) {
49440                   src = src.substring(token.raw.length);
49441                   tokens.push(token);
49442                   continue;
49443                 } // url (gfm)
49444
49445
49446                 if (!inLink && (token = this.tokenizer.url(src, mangle))) {
49447                   src = src.substring(token.raw.length);
49448                   tokens.push(token);
49449                   continue;
49450                 } // text
49451
49452
49453                 if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
49454                   src = src.substring(token.raw.length);
49455
49456                   if (token.raw.slice(-1) !== '_') {
49457                     // Track prevChar before string of ____ started
49458                     prevChar = token.raw.slice(-1);
49459                   }
49460
49461                   keepPrevChar = true;
49462                   lastToken = tokens[tokens.length - 1];
49463
49464                   if (lastToken && lastToken.type === 'text') {
49465                     lastToken.raw += token.raw;
49466                     lastToken.text += token.text;
49467                   } else {
49468                     tokens.push(token);
49469                   }
49470
49471                   continue;
49472                 }
49473
49474                 if (src) {
49475                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
49476
49477                   if (this.options.silent) {
49478                     console.error(errMsg);
49479                     break;
49480                   } else {
49481                     throw new Error(errMsg);
49482                   }
49483                 }
49484               }
49485
49486               return tokens;
49487             }
49488           }], [{
49489             key: "rules",
49490             get: function get() {
49491               return {
49492                 block: block,
49493                 inline: inline
49494               };
49495             }
49496             /**
49497              * Static Lex Method
49498              */
49499
49500           }, {
49501             key: "lex",
49502             value: function lex(src, options) {
49503               var lexer = new Lexer(options);
49504               return lexer.lex(src);
49505             }
49506             /**
49507              * Static Lex Inline Method
49508              */
49509
49510           }, {
49511             key: "lexInline",
49512             value: function lexInline(src, options) {
49513               var lexer = new Lexer(options);
49514               return lexer.inlineTokens(src);
49515             }
49516           }]);
49517
49518           return Lexer;
49519         }();
49520
49521         var defaults$2 = defaults$5.exports.defaults;
49522         var cleanUrl = helpers.cleanUrl,
49523             escape$2 = helpers.escape;
49524         /**
49525          * Renderer
49526          */
49527
49528         var Renderer_1 = /*#__PURE__*/function () {
49529           function Renderer(options) {
49530             _classCallCheck$1(this, Renderer);
49531
49532             this.options = options || defaults$2;
49533           }
49534
49535           _createClass$1(Renderer, [{
49536             key: "code",
49537             value: function code(_code, infostring, escaped) {
49538               var lang = (infostring || '').match(/\S*/)[0];
49539
49540               if (this.options.highlight) {
49541                 var out = this.options.highlight(_code, lang);
49542
49543                 if (out != null && out !== _code) {
49544                   escaped = true;
49545                   _code = out;
49546                 }
49547               }
49548
49549               _code = _code.replace(/\n$/, '') + '\n';
49550
49551               if (!lang) {
49552                 return '<pre><code>' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
49553               }
49554
49555               return '<pre><code class="' + this.options.langPrefix + escape$2(lang, true) + '">' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
49556             }
49557           }, {
49558             key: "blockquote",
49559             value: function blockquote(quote) {
49560               return '<blockquote>\n' + quote + '</blockquote>\n';
49561             }
49562           }, {
49563             key: "html",
49564             value: function html(_html) {
49565               return _html;
49566             }
49567           }, {
49568             key: "heading",
49569             value: function heading(text, level, raw, slugger) {
49570               if (this.options.headerIds) {
49571                 return '<h' + level + ' id="' + this.options.headerPrefix + slugger.slug(raw) + '">' + text + '</h' + level + '>\n';
49572               } // ignore IDs
49573
49574
49575               return '<h' + level + '>' + text + '</h' + level + '>\n';
49576             }
49577           }, {
49578             key: "hr",
49579             value: function hr() {
49580               return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
49581             }
49582           }, {
49583             key: "list",
49584             value: function list(body, ordered, start) {
49585               var type = ordered ? 'ol' : 'ul',
49586                   startatt = ordered && start !== 1 ? ' start="' + start + '"' : '';
49587               return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
49588             }
49589           }, {
49590             key: "listitem",
49591             value: function listitem(text) {
49592               return '<li>' + text + '</li>\n';
49593             }
49594           }, {
49595             key: "checkbox",
49596             value: function checkbox(checked) {
49597               return '<input ' + (checked ? 'checked="" ' : '') + 'disabled="" type="checkbox"' + (this.options.xhtml ? ' /' : '') + '> ';
49598             }
49599           }, {
49600             key: "paragraph",
49601             value: function paragraph(text) {
49602               return '<p>' + text + '</p>\n';
49603             }
49604           }, {
49605             key: "table",
49606             value: function table(header, body) {
49607               if (body) body = '<tbody>' + body + '</tbody>';
49608               return '<table>\n' + '<thead>\n' + header + '</thead>\n' + body + '</table>\n';
49609             }
49610           }, {
49611             key: "tablerow",
49612             value: function tablerow(content) {
49613               return '<tr>\n' + content + '</tr>\n';
49614             }
49615           }, {
49616             key: "tablecell",
49617             value: function tablecell(content, flags) {
49618               var type = flags.header ? 'th' : 'td';
49619               var tag = flags.align ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
49620               return tag + content + '</' + type + '>\n';
49621             } // span level renderer
49622
49623           }, {
49624             key: "strong",
49625             value: function strong(text) {
49626               return '<strong>' + text + '</strong>';
49627             }
49628           }, {
49629             key: "em",
49630             value: function em(text) {
49631               return '<em>' + text + '</em>';
49632             }
49633           }, {
49634             key: "codespan",
49635             value: function codespan(text) {
49636               return '<code>' + text + '</code>';
49637             }
49638           }, {
49639             key: "br",
49640             value: function br() {
49641               return this.options.xhtml ? '<br/>' : '<br>';
49642             }
49643           }, {
49644             key: "del",
49645             value: function del(text) {
49646               return '<del>' + text + '</del>';
49647             }
49648           }, {
49649             key: "link",
49650             value: function link(href, title, text) {
49651               href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
49652
49653               if (href === null) {
49654                 return text;
49655               }
49656
49657               var out = '<a href="' + escape$2(href) + '"';
49658
49659               if (title) {
49660                 out += ' title="' + title + '"';
49661               }
49662
49663               out += '>' + text + '</a>';
49664               return out;
49665             }
49666           }, {
49667             key: "image",
49668             value: function image(href, title, text) {
49669               href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
49670
49671               if (href === null) {
49672                 return text;
49673               }
49674
49675               var out = '<img src="' + href + '" alt="' + text + '"';
49676
49677               if (title) {
49678                 out += ' title="' + title + '"';
49679               }
49680
49681               out += this.options.xhtml ? '/>' : '>';
49682               return out;
49683             }
49684           }, {
49685             key: "text",
49686             value: function text(_text) {
49687               return _text;
49688             }
49689           }]);
49690
49691           return Renderer;
49692         }();
49693
49694         var TextRenderer_1 = /*#__PURE__*/function () {
49695           function TextRenderer() {
49696             _classCallCheck$1(this, TextRenderer);
49697           }
49698
49699           _createClass$1(TextRenderer, [{
49700             key: "strong",
49701             value: // no need for block level renderers
49702             function strong(text) {
49703               return text;
49704             }
49705           }, {
49706             key: "em",
49707             value: function em(text) {
49708               return text;
49709             }
49710           }, {
49711             key: "codespan",
49712             value: function codespan(text) {
49713               return text;
49714             }
49715           }, {
49716             key: "del",
49717             value: function del(text) {
49718               return text;
49719             }
49720           }, {
49721             key: "html",
49722             value: function html(text) {
49723               return text;
49724             }
49725           }, {
49726             key: "text",
49727             value: function text(_text) {
49728               return _text;
49729             }
49730           }, {
49731             key: "link",
49732             value: function link(href, title, text) {
49733               return '' + text;
49734             }
49735           }, {
49736             key: "image",
49737             value: function image(href, title, text) {
49738               return '' + text;
49739             }
49740           }, {
49741             key: "br",
49742             value: function br() {
49743               return '';
49744             }
49745           }]);
49746
49747           return TextRenderer;
49748         }();
49749
49750         var Slugger_1 = /*#__PURE__*/function () {
49751           function Slugger() {
49752             _classCallCheck$1(this, Slugger);
49753
49754             this.seen = {};
49755           }
49756
49757           _createClass$1(Slugger, [{
49758             key: "serialize",
49759             value: function serialize(value) {
49760               return value.toLowerCase().trim() // remove html tags
49761               .replace(/<[!\/a-z].*?>/ig, '') // remove unwanted chars
49762               .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '').replace(/\s/g, '-');
49763             }
49764             /**
49765              * Finds the next safe (unique) slug to use
49766              */
49767
49768           }, {
49769             key: "getNextSafeSlug",
49770             value: function getNextSafeSlug(originalSlug, isDryRun) {
49771               var slug = originalSlug;
49772               var occurenceAccumulator = 0;
49773
49774               if (this.seen.hasOwnProperty(slug)) {
49775                 occurenceAccumulator = this.seen[originalSlug];
49776
49777                 do {
49778                   occurenceAccumulator++;
49779                   slug = originalSlug + '-' + occurenceAccumulator;
49780                 } while (this.seen.hasOwnProperty(slug));
49781               }
49782
49783               if (!isDryRun) {
49784                 this.seen[originalSlug] = occurenceAccumulator;
49785                 this.seen[slug] = 0;
49786               }
49787
49788               return slug;
49789             }
49790             /**
49791              * Convert string to unique id
49792              * @param {object} options
49793              * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.
49794              */
49795
49796           }, {
49797             key: "slug",
49798             value: function slug(value) {
49799               var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
49800               var slug = this.serialize(value);
49801               return this.getNextSafeSlug(slug, options.dryrun);
49802             }
49803           }]);
49804
49805           return Slugger;
49806         }();
49807
49808         var Renderer$1 = Renderer_1;
49809         var TextRenderer$1 = TextRenderer_1;
49810         var Slugger$1 = Slugger_1;
49811         var defaults$1 = defaults$5.exports.defaults;
49812         var unescape$1 = helpers.unescape;
49813         /**
49814          * Parsing & Compiling
49815          */
49816
49817         var Parser_1 = /*#__PURE__*/function () {
49818           function Parser(options) {
49819             _classCallCheck$1(this, Parser);
49820
49821             this.options = options || defaults$1;
49822             this.options.renderer = this.options.renderer || new Renderer$1();
49823             this.renderer = this.options.renderer;
49824             this.renderer.options = this.options;
49825             this.textRenderer = new TextRenderer$1();
49826             this.slugger = new Slugger$1();
49827           }
49828           /**
49829            * Static Parse Method
49830            */
49831
49832
49833           _createClass$1(Parser, [{
49834             key: "parse",
49835             value:
49836             /**
49837              * Parse Loop
49838              */
49839             function parse(tokens) {
49840               var top = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
49841               var out = '',
49842                   i,
49843                   j,
49844                   k,
49845                   l2,
49846                   l3,
49847                   row,
49848                   cell,
49849                   header,
49850                   body,
49851                   token,
49852                   ordered,
49853                   start,
49854                   loose,
49855                   itemBody,
49856                   item,
49857                   checked,
49858                   task,
49859                   checkbox;
49860               var l = tokens.length;
49861
49862               for (i = 0; i < l; i++) {
49863                 token = tokens[i];
49864
49865                 switch (token.type) {
49866                   case 'space':
49867                     {
49868                       continue;
49869                     }
49870
49871                   case 'hr':
49872                     {
49873                       out += this.renderer.hr();
49874                       continue;
49875                     }
49876
49877                   case 'heading':
49878                     {
49879                       out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$1(this.parseInline(token.tokens, this.textRenderer)), this.slugger);
49880                       continue;
49881                     }
49882
49883                   case 'code':
49884                     {
49885                       out += this.renderer.code(token.text, token.lang, token.escaped);
49886                       continue;
49887                     }
49888
49889                   case 'table':
49890                     {
49891                       header = ''; // header
49892
49893                       cell = '';
49894                       l2 = token.header.length;
49895
49896                       for (j = 0; j < l2; j++) {
49897                         cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {
49898                           header: true,
49899                           align: token.align[j]
49900                         });
49901                       }
49902
49903                       header += this.renderer.tablerow(cell);
49904                       body = '';
49905                       l2 = token.cells.length;
49906
49907                       for (j = 0; j < l2; j++) {
49908                         row = token.tokens.cells[j];
49909                         cell = '';
49910                         l3 = row.length;
49911
49912                         for (k = 0; k < l3; k++) {
49913                           cell += this.renderer.tablecell(this.parseInline(row[k]), {
49914                             header: false,
49915                             align: token.align[k]
49916                           });
49917                         }
49918
49919                         body += this.renderer.tablerow(cell);
49920                       }
49921
49922                       out += this.renderer.table(header, body);
49923                       continue;
49924                     }
49925
49926                   case 'blockquote':
49927                     {
49928                       body = this.parse(token.tokens);
49929                       out += this.renderer.blockquote(body);
49930                       continue;
49931                     }
49932
49933                   case 'list':
49934                     {
49935                       ordered = token.ordered;
49936                       start = token.start;
49937                       loose = token.loose;
49938                       l2 = token.items.length;
49939                       body = '';
49940
49941                       for (j = 0; j < l2; j++) {
49942                         item = token.items[j];
49943                         checked = item.checked;
49944                         task = item.task;
49945                         itemBody = '';
49946
49947                         if (item.task) {
49948                           checkbox = this.renderer.checkbox(checked);
49949
49950                           if (loose) {
49951                             if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
49952                               item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
49953
49954                               if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
49955                                 item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
49956                               }
49957                             } else {
49958                               item.tokens.unshift({
49959                                 type: 'text',
49960                                 text: checkbox
49961                               });
49962                             }
49963                           } else {
49964                             itemBody += checkbox;
49965                           }
49966                         }
49967
49968                         itemBody += this.parse(item.tokens, loose);
49969                         body += this.renderer.listitem(itemBody, task, checked);
49970                       }
49971
49972                       out += this.renderer.list(body, ordered, start);
49973                       continue;
49974                     }
49975
49976                   case 'html':
49977                     {
49978                       // TODO parse inline content if parameter markdown=1
49979                       out += this.renderer.html(token.text);
49980                       continue;
49981                     }
49982
49983                   case 'paragraph':
49984                     {
49985                       out += this.renderer.paragraph(this.parseInline(token.tokens));
49986                       continue;
49987                     }
49988
49989                   case 'text':
49990                     {
49991                       body = token.tokens ? this.parseInline(token.tokens) : token.text;
49992
49993                       while (i + 1 < l && tokens[i + 1].type === 'text') {
49994                         token = tokens[++i];
49995                         body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
49996                       }
49997
49998                       out += top ? this.renderer.paragraph(body) : body;
49999                       continue;
50000                     }
50001
50002                   default:
50003                     {
50004                       var errMsg = 'Token with "' + token.type + '" type was not found.';
50005
50006                       if (this.options.silent) {
50007                         console.error(errMsg);
50008                         return;
50009                       } else {
50010                         throw new Error(errMsg);
50011                       }
50012                     }
50013                 }
50014               }
50015
50016               return out;
50017             }
50018             /**
50019              * Parse Inline Tokens
50020              */
50021
50022           }, {
50023             key: "parseInline",
50024             value: function parseInline(tokens, renderer) {
50025               renderer = renderer || this.renderer;
50026               var out = '',
50027                   i,
50028                   token;
50029               var l = tokens.length;
50030
50031               for (i = 0; i < l; i++) {
50032                 token = tokens[i];
50033
50034                 switch (token.type) {
50035                   case 'escape':
50036                     {
50037                       out += renderer.text(token.text);
50038                       break;
50039                     }
50040
50041                   case 'html':
50042                     {
50043                       out += renderer.html(token.text);
50044                       break;
50045                     }
50046
50047                   case 'link':
50048                     {
50049                       out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
50050                       break;
50051                     }
50052
50053                   case 'image':
50054                     {
50055                       out += renderer.image(token.href, token.title, token.text);
50056                       break;
50057                     }
50058
50059                   case 'strong':
50060                     {
50061                       out += renderer.strong(this.parseInline(token.tokens, renderer));
50062                       break;
50063                     }
50064
50065                   case 'em':
50066                     {
50067                       out += renderer.em(this.parseInline(token.tokens, renderer));
50068                       break;
50069                     }
50070
50071                   case 'codespan':
50072                     {
50073                       out += renderer.codespan(token.text);
50074                       break;
50075                     }
50076
50077                   case 'br':
50078                     {
50079                       out += renderer.br();
50080                       break;
50081                     }
50082
50083                   case 'del':
50084                     {
50085                       out += renderer.del(this.parseInline(token.tokens, renderer));
50086                       break;
50087                     }
50088
50089                   case 'text':
50090                     {
50091                       out += renderer.text(token.text);
50092                       break;
50093                     }
50094
50095                   default:
50096                     {
50097                       var errMsg = 'Token with "' + token.type + '" type was not found.';
50098
50099                       if (this.options.silent) {
50100                         console.error(errMsg);
50101                         return;
50102                       } else {
50103                         throw new Error(errMsg);
50104                       }
50105                     }
50106                 }
50107               }
50108
50109               return out;
50110             }
50111           }], [{
50112             key: "parse",
50113             value: function parse(tokens, options) {
50114               var parser = new Parser(options);
50115               return parser.parse(tokens);
50116             }
50117             /**
50118              * Static Parse Inline Method
50119              */
50120
50121           }, {
50122             key: "parseInline",
50123             value: function parseInline(tokens, options) {
50124               var parser = new Parser(options);
50125               return parser.parseInline(tokens);
50126             }
50127           }]);
50128
50129           return Parser;
50130         }();
50131
50132         var Lexer = Lexer_1;
50133         var Parser = Parser_1;
50134         var Tokenizer = Tokenizer_1;
50135         var Renderer = Renderer_1;
50136         var TextRenderer = TextRenderer_1;
50137         var Slugger = Slugger_1;
50138         var merge = helpers.merge,
50139             checkSanitizeDeprecation = helpers.checkSanitizeDeprecation,
50140             escape$1 = helpers.escape;
50141         var getDefaults = defaults$5.exports.getDefaults,
50142             changeDefaults = defaults$5.exports.changeDefaults,
50143             defaults = defaults$5.exports.defaults;
50144         /**
50145          * Marked
50146          */
50147
50148         function marked(src, opt, callback) {
50149           // throw error in case of non string input
50150           if (typeof src === 'undefined' || src === null) {
50151             throw new Error('marked(): input parameter is undefined or null');
50152           }
50153
50154           if (typeof src !== 'string') {
50155             throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
50156           }
50157
50158           if (typeof opt === 'function') {
50159             callback = opt;
50160             opt = null;
50161           }
50162
50163           opt = merge({}, marked.defaults, opt || {});
50164           checkSanitizeDeprecation(opt);
50165
50166           if (callback) {
50167             var highlight = opt.highlight;
50168             var tokens;
50169
50170             try {
50171               tokens = Lexer.lex(src, opt);
50172             } catch (e) {
50173               return callback(e);
50174             }
50175
50176             var done = function done(err) {
50177               var out;
50178
50179               if (!err) {
50180                 try {
50181                   if (opt.walkTokens) {
50182                     marked.walkTokens(tokens, opt.walkTokens);
50183                   }
50184
50185                   out = Parser.parse(tokens, opt);
50186                 } catch (e) {
50187                   err = e;
50188                 }
50189               }
50190
50191               opt.highlight = highlight;
50192               return err ? callback(err) : callback(null, out);
50193             };
50194
50195             if (!highlight || highlight.length < 3) {
50196               return done();
50197             }
50198
50199             delete opt.highlight;
50200             if (!tokens.length) return done();
50201             var pending = 0;
50202             marked.walkTokens(tokens, function (token) {
50203               if (token.type === 'code') {
50204                 pending++;
50205                 setTimeout(function () {
50206                   highlight(token.text, token.lang, function (err, code) {
50207                     if (err) {
50208                       return done(err);
50209                     }
50210
50211                     if (code != null && code !== token.text) {
50212                       token.text = code;
50213                       token.escaped = true;
50214                     }
50215
50216                     pending--;
50217
50218                     if (pending === 0) {
50219                       done();
50220                     }
50221                   });
50222                 }, 0);
50223               }
50224             });
50225
50226             if (pending === 0) {
50227               done();
50228             }
50229
50230             return;
50231           }
50232
50233           try {
50234             var _tokens = Lexer.lex(src, opt);
50235
50236             if (opt.walkTokens) {
50237               marked.walkTokens(_tokens, opt.walkTokens);
50238             }
50239
50240             return Parser.parse(_tokens, opt);
50241           } catch (e) {
50242             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
50243
50244             if (opt.silent) {
50245               return '<p>An error occurred:</p><pre>' + escape$1(e.message + '', true) + '</pre>';
50246             }
50247
50248             throw e;
50249           }
50250         }
50251         /**
50252          * Options
50253          */
50254
50255
50256         marked.options = marked.setOptions = function (opt) {
50257           merge(marked.defaults, opt);
50258           changeDefaults(marked.defaults);
50259           return marked;
50260         };
50261
50262         marked.getDefaults = getDefaults;
50263         marked.defaults = defaults;
50264         /**
50265          * Use Extension
50266          */
50267
50268         marked.use = function (extension) {
50269           var opts = merge({}, extension);
50270
50271           if (extension.renderer) {
50272             (function () {
50273               var renderer = marked.defaults.renderer || new Renderer();
50274
50275               var _loop = function _loop(prop) {
50276                 var prevRenderer = renderer[prop];
50277
50278                 renderer[prop] = function () {
50279                   for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
50280                     args[_key] = arguments[_key];
50281                   }
50282
50283                   var ret = extension.renderer[prop].apply(renderer, args);
50284
50285                   if (ret === false) {
50286                     ret = prevRenderer.apply(renderer, args);
50287                   }
50288
50289                   return ret;
50290                 };
50291               };
50292
50293               for (var prop in extension.renderer) {
50294                 _loop(prop);
50295               }
50296
50297               opts.renderer = renderer;
50298             })();
50299           }
50300
50301           if (extension.tokenizer) {
50302             (function () {
50303               var tokenizer = marked.defaults.tokenizer || new Tokenizer();
50304
50305               var _loop2 = function _loop2(prop) {
50306                 var prevTokenizer = tokenizer[prop];
50307
50308                 tokenizer[prop] = function () {
50309                   for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
50310                     args[_key2] = arguments[_key2];
50311                   }
50312
50313                   var ret = extension.tokenizer[prop].apply(tokenizer, args);
50314
50315                   if (ret === false) {
50316                     ret = prevTokenizer.apply(tokenizer, args);
50317                   }
50318
50319                   return ret;
50320                 };
50321               };
50322
50323               for (var prop in extension.tokenizer) {
50324                 _loop2(prop);
50325               }
50326
50327               opts.tokenizer = tokenizer;
50328             })();
50329           }
50330
50331           if (extension.walkTokens) {
50332             var walkTokens = marked.defaults.walkTokens;
50333
50334             opts.walkTokens = function (token) {
50335               extension.walkTokens(token);
50336
50337               if (walkTokens) {
50338                 walkTokens(token);
50339               }
50340             };
50341           }
50342
50343           marked.setOptions(opts);
50344         };
50345         /**
50346          * Run callback for every token
50347          */
50348
50349
50350         marked.walkTokens = function (tokens, callback) {
50351           var _iterator = _createForOfIteratorHelper(tokens),
50352               _step;
50353
50354           try {
50355             for (_iterator.s(); !(_step = _iterator.n()).done;) {
50356               var token = _step.value;
50357               callback(token);
50358
50359               switch (token.type) {
50360                 case 'table':
50361                   {
50362                     var _iterator2 = _createForOfIteratorHelper(token.tokens.header),
50363                         _step2;
50364
50365                     try {
50366                       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
50367                         var cell = _step2.value;
50368                         marked.walkTokens(cell, callback);
50369                       }
50370                     } catch (err) {
50371                       _iterator2.e(err);
50372                     } finally {
50373                       _iterator2.f();
50374                     }
50375
50376                     var _iterator3 = _createForOfIteratorHelper(token.tokens.cells),
50377                         _step3;
50378
50379                     try {
50380                       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
50381                         var row = _step3.value;
50382
50383                         var _iterator4 = _createForOfIteratorHelper(row),
50384                             _step4;
50385
50386                         try {
50387                           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
50388                             var _cell = _step4.value;
50389                             marked.walkTokens(_cell, callback);
50390                           }
50391                         } catch (err) {
50392                           _iterator4.e(err);
50393                         } finally {
50394                           _iterator4.f();
50395                         }
50396                       }
50397                     } catch (err) {
50398                       _iterator3.e(err);
50399                     } finally {
50400                       _iterator3.f();
50401                     }
50402
50403                     break;
50404                   }
50405
50406                 case 'list':
50407                   {
50408                     marked.walkTokens(token.items, callback);
50409                     break;
50410                   }
50411
50412                 default:
50413                   {
50414                     if (token.tokens) {
50415                       marked.walkTokens(token.tokens, callback);
50416                     }
50417                   }
50418               }
50419             }
50420           } catch (err) {
50421             _iterator.e(err);
50422           } finally {
50423             _iterator.f();
50424           }
50425         };
50426         /**
50427          * Parse Inline
50428          */
50429
50430
50431         marked.parseInline = function (src, opt) {
50432           // throw error in case of non string input
50433           if (typeof src === 'undefined' || src === null) {
50434             throw new Error('marked.parseInline(): input parameter is undefined or null');
50435           }
50436
50437           if (typeof src !== 'string') {
50438             throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
50439           }
50440
50441           opt = merge({}, marked.defaults, opt || {});
50442           checkSanitizeDeprecation(opt);
50443
50444           try {
50445             var tokens = Lexer.lexInline(src, opt);
50446
50447             if (opt.walkTokens) {
50448               marked.walkTokens(tokens, opt.walkTokens);
50449             }
50450
50451             return Parser.parseInline(tokens, opt);
50452           } catch (e) {
50453             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
50454
50455             if (opt.silent) {
50456               return '<p>An error occurred:</p><pre>' + escape$1(e.message + '', true) + '</pre>';
50457             }
50458
50459             throw e;
50460           }
50461         };
50462         /**
50463          * Expose
50464          */
50465
50466
50467         marked.Parser = Parser;
50468         marked.parser = Parser.parse;
50469         marked.Renderer = Renderer;
50470         marked.TextRenderer = TextRenderer;
50471         marked.Lexer = Lexer;
50472         marked.lexer = Lexer.lex;
50473         marked.Tokenizer = Tokenizer;
50474         marked.Slugger = Slugger;
50475         marked.parse = marked;
50476         var marked_1 = marked;
50477
50478         var tiler$4 = utilTiler();
50479         var dispatch$5 = dispatch$8('loaded');
50480         var _tileZoom$1 = 14;
50481         var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/api/0.3';
50482         var _osmoseData = {
50483           icons: {},
50484           items: []
50485         }; // This gets reassigned if reset
50486
50487         var _cache;
50488
50489         function abortRequest$4(controller) {
50490           if (controller) {
50491             controller.abort();
50492           }
50493         }
50494
50495         function abortUnwantedRequests$1(cache, tiles) {
50496           Object.keys(cache.inflightTile).forEach(function (k) {
50497             var wanted = tiles.find(function (tile) {
50498               return k === tile.id;
50499             });
50500
50501             if (!wanted) {
50502               abortRequest$4(cache.inflightTile[k]);
50503               delete cache.inflightTile[k];
50504             }
50505           });
50506         }
50507
50508         function encodeIssueRtree(d) {
50509           return {
50510             minX: d.loc[0],
50511             minY: d.loc[1],
50512             maxX: d.loc[0],
50513             maxY: d.loc[1],
50514             data: d
50515           };
50516         } // Replace or remove QAItem from rtree
50517
50518
50519         function updateRtree$1(item, replace) {
50520           _cache.rtree.remove(item, function (a, b) {
50521             return a.data.id === b.data.id;
50522           });
50523
50524           if (replace) {
50525             _cache.rtree.insert(item);
50526           }
50527         } // Issues shouldn't obscure each other
50528
50529
50530         function preventCoincident(loc) {
50531           var coincident = false;
50532
50533           do {
50534             // first time, move marker up. after that, move marker right.
50535             var delta = coincident ? [0.00001, 0] : [0, 0.00001];
50536             loc = geoVecAdd(loc, delta);
50537             var bbox = geoExtent(loc).bbox();
50538             coincident = _cache.rtree.search(bbox).length;
50539           } while (coincident);
50540
50541           return loc;
50542         }
50543
50544         var serviceOsmose = {
50545           title: 'osmose',
50546           init: function init() {
50547             _mainFileFetcher.get('qa_data').then(function (d) {
50548               _osmoseData = d.osmose;
50549               _osmoseData.items = Object.keys(d.osmose.icons).map(function (s) {
50550                 return s.split('-')[0];
50551               }).reduce(function (unique, item) {
50552                 return unique.indexOf(item) !== -1 ? unique : [].concat(_toConsumableArray(unique), [item]);
50553               }, []);
50554             });
50555
50556             if (!_cache) {
50557               this.reset();
50558             }
50559
50560             this.event = utilRebind(this, dispatch$5, 'on');
50561           },
50562           reset: function reset() {
50563             var _strings = {};
50564             var _colors = {};
50565
50566             if (_cache) {
50567               Object.values(_cache.inflightTile).forEach(abortRequest$4); // Strings and colors are static and should not be re-populated
50568
50569               _strings = _cache.strings;
50570               _colors = _cache.colors;
50571             }
50572
50573             _cache = {
50574               data: {},
50575               loadedTile: {},
50576               inflightTile: {},
50577               inflightPost: {},
50578               closed: {},
50579               rtree: new RBush(),
50580               strings: _strings,
50581               colors: _colors
50582             };
50583           },
50584           loadIssues: function loadIssues(projection) {
50585             var _this = this;
50586
50587             var params = {
50588               // Tiles return a maximum # of issues
50589               // So we want to filter our request for only types iD supports
50590               item: _osmoseData.items
50591             }; // determine the needed tiles to cover the view
50592
50593             var tiles = tiler$4.zoomExtent([_tileZoom$1, _tileZoom$1]).getTiles(projection); // abort inflight requests that are no longer needed
50594
50595             abortUnwantedRequests$1(_cache, tiles); // issue new requests..
50596
50597             tiles.forEach(function (tile) {
50598               if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
50599
50600               var _tile$xyz = _slicedToArray(tile.xyz, 3),
50601                   x = _tile$xyz[0],
50602                   y = _tile$xyz[1],
50603                   z = _tile$xyz[2];
50604
50605               var url = "".concat(_osmoseUrlRoot, "/issues/").concat(z, "/").concat(x, "/").concat(y, ".json?") + utilQsString(params);
50606               var controller = new AbortController();
50607               _cache.inflightTile[tile.id] = controller;
50608               d3_json(url, {
50609                 signal: controller.signal
50610               }).then(function (data) {
50611                 delete _cache.inflightTile[tile.id];
50612                 _cache.loadedTile[tile.id] = true;
50613
50614                 if (data.features) {
50615                   data.features.forEach(function (issue) {
50616                     var _issue$properties = issue.properties,
50617                         item = _issue$properties.item,
50618                         cl = _issue$properties["class"],
50619                         id = _issue$properties.uuid;
50620                     /* Osmose issues are uniquely identified by a unique
50621                       `item` and `class` combination (both integer values) */
50622
50623                     var itemType = "".concat(item, "-").concat(cl); // Filter out unsupported issue types (some are too specific or advanced)
50624
50625                     if (itemType in _osmoseData.icons) {
50626                       var loc = issue.geometry.coordinates; // lon, lat
50627
50628                       loc = preventCoincident(loc);
50629                       var d = new QAItem(loc, _this, itemType, id, {
50630                         item: item
50631                       }); // Setting elems here prevents UI detail requests
50632
50633                       if (item === 8300 || item === 8360) {
50634                         d.elems = [];
50635                       }
50636
50637                       _cache.data[d.id] = d;
50638
50639                       _cache.rtree.insert(encodeIssueRtree(d));
50640                     }
50641                   });
50642                 }
50643
50644                 dispatch$5.call('loaded');
50645               })["catch"](function () {
50646                 delete _cache.inflightTile[tile.id];
50647                 _cache.loadedTile[tile.id] = true;
50648               });
50649             });
50650           },
50651           loadIssueDetail: function loadIssueDetail(issue) {
50652             var _this2 = this;
50653
50654             // Issue details only need to be fetched once
50655             if (issue.elems !== undefined) {
50656               return Promise.resolve(issue);
50657             }
50658
50659             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
50660
50661             var cacheDetails = function cacheDetails(data) {
50662               // Associated elements used for highlighting
50663               // Assign directly for immediate use in the callback
50664               issue.elems = data.elems.map(function (e) {
50665                 return e.type.substring(0, 1) + e.id;
50666               }); // Some issues have instance specific detail in a subtitle
50667
50668               issue.detail = data.subtitle ? marked_1(data.subtitle.auto) : '';
50669
50670               _this2.replaceItem(issue);
50671             };
50672
50673             return d3_json(url).then(cacheDetails).then(function () {
50674               return issue;
50675             });
50676           },
50677           loadStrings: function loadStrings() {
50678             var locale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _mainLocalizer.localeCode();
50679             var items = Object.keys(_osmoseData.icons);
50680
50681             if (locale in _cache.strings && Object.keys(_cache.strings[locale]).length === items.length) {
50682               return Promise.resolve(_cache.strings[locale]);
50683             } // May be partially populated already if some requests were successful
50684
50685
50686             if (!(locale in _cache.strings)) {
50687               _cache.strings[locale] = {};
50688             } // Only need to cache strings for supported issue types
50689             // Using multiple individual item + class requests to reduce fetched data size
50690
50691
50692             var allRequests = items.map(function (itemType) {
50693               // No need to request data we already have
50694               if (itemType in _cache.strings[locale]) return null;
50695
50696               var cacheData = function cacheData(data) {
50697                 // Bunch of nested single value arrays of objects
50698                 var _data$categories = _slicedToArray(data.categories, 1),
50699                     _data$categories$ = _data$categories[0],
50700                     cat = _data$categories$ === void 0 ? {
50701                   items: []
50702                 } : _data$categories$;
50703
50704                 var _cat$items = _slicedToArray(cat.items, 1),
50705                     _cat$items$ = _cat$items[0],
50706                     item = _cat$items$ === void 0 ? {
50707                   "class": []
50708                 } : _cat$items$;
50709
50710                 var _item$class = _slicedToArray(item["class"], 1),
50711                     _item$class$ = _item$class[0],
50712                     cl = _item$class$ === void 0 ? null : _item$class$; // If null default value is reached, data wasn't as expected (or was empty)
50713
50714
50715                 if (!cl) {
50716                   /* eslint-disable no-console */
50717                   console.log("Osmose strings request (".concat(itemType, ") had unexpected data"));
50718                   /* eslint-enable no-console */
50719
50720                   return;
50721                 } // Cache served item colors to automatically style issue markers later
50722
50723
50724                 var itemInt = item.item,
50725                     color = item.color;
50726
50727                 if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
50728                   _cache.colors[itemInt] = color;
50729                 } // Value of root key will be null if no string exists
50730                 // If string exists, value is an object with key 'auto' for string
50731
50732
50733                 var title = cl.title,
50734                     detail = cl.detail,
50735                     fix = cl.fix,
50736                     trap = cl.trap; // Osmose titles shouldn't contain markdown
50737
50738                 var issueStrings = {};
50739                 if (title) issueStrings.title = title.auto;
50740                 if (detail) issueStrings.detail = marked_1(detail.auto);
50741                 if (trap) issueStrings.trap = marked_1(trap.auto);
50742                 if (fix) issueStrings.fix = marked_1(fix.auto);
50743                 _cache.strings[locale][itemType] = issueStrings;
50744               };
50745
50746               var _itemType$split = itemType.split('-'),
50747                   _itemType$split2 = _slicedToArray(_itemType$split, 2),
50748                   item = _itemType$split2[0],
50749                   cl = _itemType$split2[1]; // Osmose API falls back to English strings where untranslated or if locale doesn't exist
50750
50751
50752               var url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale);
50753               return d3_json(url).then(cacheData);
50754             }).filter(Boolean);
50755             return Promise.all(allRequests).then(function () {
50756               return _cache.strings[locale];
50757             });
50758           },
50759           getStrings: function getStrings(itemType) {
50760             var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _mainLocalizer.localeCode();
50761             // No need to fallback to English, Osmose API handles this for us
50762             return locale in _cache.strings ? _cache.strings[locale][itemType] : {};
50763           },
50764           getColor: function getColor(itemType) {
50765             return itemType in _cache.colors ? _cache.colors[itemType] : '#FFFFFF';
50766           },
50767           postUpdate: function postUpdate(issue, callback) {
50768             var _this3 = this;
50769
50770             if (_cache.inflightPost[issue.id]) {
50771               return callback({
50772                 message: 'Issue update already inflight',
50773                 status: -2
50774               }, issue);
50775             } // UI sets the status to either 'done' or 'false'
50776
50777
50778             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
50779             var controller = new AbortController();
50780
50781             var after = function after() {
50782               delete _cache.inflightPost[issue.id];
50783
50784               _this3.removeItem(issue);
50785
50786               if (issue.newStatus === 'done') {
50787                 // Keep track of the number of issues closed per `item` to tag the changeset
50788                 if (!(issue.item in _cache.closed)) {
50789                   _cache.closed[issue.item] = 0;
50790                 }
50791
50792                 _cache.closed[issue.item] += 1;
50793               }
50794
50795               if (callback) callback(null, issue);
50796             };
50797
50798             _cache.inflightPost[issue.id] = controller;
50799             fetch(url, {
50800               signal: controller.signal
50801             }).then(after)["catch"](function (err) {
50802               delete _cache.inflightPost[issue.id];
50803               if (callback) callback(err.message);
50804             });
50805           },
50806           // Get all cached QAItems covering the viewport
50807           getItems: function getItems(projection) {
50808             var viewport = projection.clipExtent();
50809             var min = [viewport[0][0], viewport[1][1]];
50810             var max = [viewport[1][0], viewport[0][1]];
50811             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
50812             return _cache.rtree.search(bbox).map(function (d) {
50813               return d.data;
50814             });
50815           },
50816           // Get a QAItem from cache
50817           // NOTE: Don't change method name until UI v3 is merged
50818           getError: function getError(id) {
50819             return _cache.data[id];
50820           },
50821           // get the name of the icon to display for this item
50822           getIcon: function getIcon(itemType) {
50823             return _osmoseData.icons[itemType];
50824           },
50825           // Replace a single QAItem in the cache
50826           replaceItem: function replaceItem(item) {
50827             if (!(item instanceof QAItem) || !item.id) return;
50828             _cache.data[item.id] = item;
50829             updateRtree$1(encodeIssueRtree(item), true); // true = replace
50830
50831             return item;
50832           },
50833           // Remove a single QAItem from the cache
50834           removeItem: function removeItem(item) {
50835             if (!(item instanceof QAItem) || !item.id) return;
50836             delete _cache.data[item.id];
50837             updateRtree$1(encodeIssueRtree(item), false); // false = remove
50838           },
50839           // Used to populate `closed:osmose:*` changeset tags
50840           getClosedCounts: function getClosedCounts() {
50841             return _cache.closed;
50842           },
50843           itemURL: function itemURL(item) {
50844             return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
50845           }
50846         };
50847
50848         var ieee754$1 = {};
50849
50850         /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
50851
50852         ieee754$1.read = function (buffer, offset, isLE, mLen, nBytes) {
50853           var e, m;
50854           var eLen = nBytes * 8 - mLen - 1;
50855           var eMax = (1 << eLen) - 1;
50856           var eBias = eMax >> 1;
50857           var nBits = -7;
50858           var i = isLE ? nBytes - 1 : 0;
50859           var d = isLE ? -1 : 1;
50860           var s = buffer[offset + i];
50861           i += d;
50862           e = s & (1 << -nBits) - 1;
50863           s >>= -nBits;
50864           nBits += eLen;
50865
50866           for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50867
50868           m = e & (1 << -nBits) - 1;
50869           e >>= -nBits;
50870           nBits += mLen;
50871
50872           for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50873
50874           if (e === 0) {
50875             e = 1 - eBias;
50876           } else if (e === eMax) {
50877             return m ? NaN : (s ? -1 : 1) * Infinity;
50878           } else {
50879             m = m + Math.pow(2, mLen);
50880             e = e - eBias;
50881           }
50882
50883           return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
50884         };
50885
50886         ieee754$1.write = function (buffer, value, offset, isLE, mLen, nBytes) {
50887           var e, m, c;
50888           var eLen = nBytes * 8 - mLen - 1;
50889           var eMax = (1 << eLen) - 1;
50890           var eBias = eMax >> 1;
50891           var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
50892           var i = isLE ? 0 : nBytes - 1;
50893           var d = isLE ? 1 : -1;
50894           var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
50895           value = Math.abs(value);
50896
50897           if (isNaN(value) || value === Infinity) {
50898             m = isNaN(value) ? 1 : 0;
50899             e = eMax;
50900           } else {
50901             e = Math.floor(Math.log(value) / Math.LN2);
50902
50903             if (value * (c = Math.pow(2, -e)) < 1) {
50904               e--;
50905               c *= 2;
50906             }
50907
50908             if (e + eBias >= 1) {
50909               value += rt / c;
50910             } else {
50911               value += rt * Math.pow(2, 1 - eBias);
50912             }
50913
50914             if (value * c >= 2) {
50915               e++;
50916               c /= 2;
50917             }
50918
50919             if (e + eBias >= eMax) {
50920               m = 0;
50921               e = eMax;
50922             } else if (e + eBias >= 1) {
50923               m = (value * c - 1) * Math.pow(2, mLen);
50924               e = e + eBias;
50925             } else {
50926               m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
50927               e = 0;
50928             }
50929           }
50930
50931           for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
50932
50933           e = e << mLen | m;
50934           eLen += mLen;
50935
50936           for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
50937
50938           buffer[offset + i - d] |= s * 128;
50939         };
50940
50941         var pbf = Pbf;
50942         var ieee754 = ieee754$1;
50943
50944         function Pbf(buf) {
50945           this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
50946           this.pos = 0;
50947           this.type = 0;
50948           this.length = this.buf.length;
50949         }
50950
50951         Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
50952
50953         Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
50954
50955         Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
50956
50957         Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
50958
50959         var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
50960             SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; // Threshold chosen based on both benchmarking and knowledge about browser string
50961         // data structures (which currently switch structure types at 12 bytes or more)
50962
50963         var TEXT_DECODER_MIN_LENGTH = 12;
50964         var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
50965         Pbf.prototype = {
50966           destroy: function destroy() {
50967             this.buf = null;
50968           },
50969           // === READING =================================================================
50970           readFields: function readFields(readField, result, end) {
50971             end = end || this.length;
50972
50973             while (this.pos < end) {
50974               var val = this.readVarint(),
50975                   tag = val >> 3,
50976                   startPos = this.pos;
50977               this.type = val & 0x7;
50978               readField(tag, result, this);
50979               if (this.pos === startPos) this.skip(val);
50980             }
50981
50982             return result;
50983           },
50984           readMessage: function readMessage(readField, result) {
50985             return this.readFields(readField, result, this.readVarint() + this.pos);
50986           },
50987           readFixed32: function readFixed32() {
50988             var val = readUInt32(this.buf, this.pos);
50989             this.pos += 4;
50990             return val;
50991           },
50992           readSFixed32: function readSFixed32() {
50993             var val = readInt32(this.buf, this.pos);
50994             this.pos += 4;
50995             return val;
50996           },
50997           // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
50998           readFixed64: function readFixed64() {
50999             var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
51000             this.pos += 8;
51001             return val;
51002           },
51003           readSFixed64: function readSFixed64() {
51004             var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
51005             this.pos += 8;
51006             return val;
51007           },
51008           readFloat: function readFloat() {
51009             var val = ieee754.read(this.buf, this.pos, true, 23, 4);
51010             this.pos += 4;
51011             return val;
51012           },
51013           readDouble: function readDouble() {
51014             var val = ieee754.read(this.buf, this.pos, true, 52, 8);
51015             this.pos += 8;
51016             return val;
51017           },
51018           readVarint: function readVarint(isSigned) {
51019             var buf = this.buf,
51020                 val,
51021                 b;
51022             b = buf[this.pos++];
51023             val = b & 0x7f;
51024             if (b < 0x80) return val;
51025             b = buf[this.pos++];
51026             val |= (b & 0x7f) << 7;
51027             if (b < 0x80) return val;
51028             b = buf[this.pos++];
51029             val |= (b & 0x7f) << 14;
51030             if (b < 0x80) return val;
51031             b = buf[this.pos++];
51032             val |= (b & 0x7f) << 21;
51033             if (b < 0x80) return val;
51034             b = buf[this.pos];
51035             val |= (b & 0x0f) << 28;
51036             return readVarintRemainder(val, isSigned, this);
51037           },
51038           readVarint64: function readVarint64() {
51039             // for compatibility with v2.0.1
51040             return this.readVarint(true);
51041           },
51042           readSVarint: function readSVarint() {
51043             var num = this.readVarint();
51044             return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
51045           },
51046           readBoolean: function readBoolean() {
51047             return Boolean(this.readVarint());
51048           },
51049           readString: function readString() {
51050             var end = this.readVarint() + this.pos;
51051             var pos = this.pos;
51052             this.pos = end;
51053
51054             if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
51055               // longer strings are fast with the built-in browser TextDecoder API
51056               return readUtf8TextDecoder(this.buf, pos, end);
51057             } // short strings are fast with our custom implementation
51058
51059
51060             return readUtf8(this.buf, pos, end);
51061           },
51062           readBytes: function readBytes() {
51063             var end = this.readVarint() + this.pos,
51064                 buffer = this.buf.subarray(this.pos, end);
51065             this.pos = end;
51066             return buffer;
51067           },
51068           // verbose for performance reasons; doesn't affect gzipped size
51069           readPackedVarint: function readPackedVarint(arr, isSigned) {
51070             if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
51071             var end = readPackedEnd(this);
51072             arr = arr || [];
51073
51074             while (this.pos < end) {
51075               arr.push(this.readVarint(isSigned));
51076             }
51077
51078             return arr;
51079           },
51080           readPackedSVarint: function readPackedSVarint(arr) {
51081             if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
51082             var end = readPackedEnd(this);
51083             arr = arr || [];
51084
51085             while (this.pos < end) {
51086               arr.push(this.readSVarint());
51087             }
51088
51089             return arr;
51090           },
51091           readPackedBoolean: function readPackedBoolean(arr) {
51092             if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
51093             var end = readPackedEnd(this);
51094             arr = arr || [];
51095
51096             while (this.pos < end) {
51097               arr.push(this.readBoolean());
51098             }
51099
51100             return arr;
51101           },
51102           readPackedFloat: function readPackedFloat(arr) {
51103             if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
51104             var end = readPackedEnd(this);
51105             arr = arr || [];
51106
51107             while (this.pos < end) {
51108               arr.push(this.readFloat());
51109             }
51110
51111             return arr;
51112           },
51113           readPackedDouble: function readPackedDouble(arr) {
51114             if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
51115             var end = readPackedEnd(this);
51116             arr = arr || [];
51117
51118             while (this.pos < end) {
51119               arr.push(this.readDouble());
51120             }
51121
51122             return arr;
51123           },
51124           readPackedFixed32: function readPackedFixed32(arr) {
51125             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
51126             var end = readPackedEnd(this);
51127             arr = arr || [];
51128
51129             while (this.pos < end) {
51130               arr.push(this.readFixed32());
51131             }
51132
51133             return arr;
51134           },
51135           readPackedSFixed32: function readPackedSFixed32(arr) {
51136             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
51137             var end = readPackedEnd(this);
51138             arr = arr || [];
51139
51140             while (this.pos < end) {
51141               arr.push(this.readSFixed32());
51142             }
51143
51144             return arr;
51145           },
51146           readPackedFixed64: function readPackedFixed64(arr) {
51147             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
51148             var end = readPackedEnd(this);
51149             arr = arr || [];
51150
51151             while (this.pos < end) {
51152               arr.push(this.readFixed64());
51153             }
51154
51155             return arr;
51156           },
51157           readPackedSFixed64: function readPackedSFixed64(arr) {
51158             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
51159             var end = readPackedEnd(this);
51160             arr = arr || [];
51161
51162             while (this.pos < end) {
51163               arr.push(this.readSFixed64());
51164             }
51165
51166             return arr;
51167           },
51168           skip: function skip(val) {
51169             var type = val & 0x7;
51170             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);
51171           },
51172           // === WRITING =================================================================
51173           writeTag: function writeTag(tag, type) {
51174             this.writeVarint(tag << 3 | type);
51175           },
51176           realloc: function realloc(min) {
51177             var length = this.length || 16;
51178
51179             while (length < this.pos + min) {
51180               length *= 2;
51181             }
51182
51183             if (length !== this.length) {
51184               var buf = new Uint8Array(length);
51185               buf.set(this.buf);
51186               this.buf = buf;
51187               this.length = length;
51188             }
51189           },
51190           finish: function finish() {
51191             this.length = this.pos;
51192             this.pos = 0;
51193             return this.buf.subarray(0, this.length);
51194           },
51195           writeFixed32: function writeFixed32(val) {
51196             this.realloc(4);
51197             writeInt32(this.buf, val, this.pos);
51198             this.pos += 4;
51199           },
51200           writeSFixed32: function writeSFixed32(val) {
51201             this.realloc(4);
51202             writeInt32(this.buf, val, this.pos);
51203             this.pos += 4;
51204           },
51205           writeFixed64: function writeFixed64(val) {
51206             this.realloc(8);
51207             writeInt32(this.buf, val & -1, this.pos);
51208             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51209             this.pos += 8;
51210           },
51211           writeSFixed64: function writeSFixed64(val) {
51212             this.realloc(8);
51213             writeInt32(this.buf, val & -1, this.pos);
51214             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51215             this.pos += 8;
51216           },
51217           writeVarint: function writeVarint(val) {
51218             val = +val || 0;
51219
51220             if (val > 0xfffffff || val < 0) {
51221               writeBigVarint(val, this);
51222               return;
51223             }
51224
51225             this.realloc(4);
51226             this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
51227             if (val <= 0x7f) return;
51228             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51229             if (val <= 0x7f) return;
51230             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51231             if (val <= 0x7f) return;
51232             this.buf[this.pos++] = val >>> 7 & 0x7f;
51233           },
51234           writeSVarint: function writeSVarint(val) {
51235             this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
51236           },
51237           writeBoolean: function writeBoolean(val) {
51238             this.writeVarint(Boolean(val));
51239           },
51240           writeString: function writeString(str) {
51241             str = String(str);
51242             this.realloc(str.length * 4);
51243             this.pos++; // reserve 1 byte for short string length
51244
51245             var startPos = this.pos; // write the string directly to the buffer and see how much was written
51246
51247             this.pos = writeUtf8(this.buf, str, this.pos);
51248             var len = this.pos - startPos;
51249             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51250
51251             this.pos = startPos - 1;
51252             this.writeVarint(len);
51253             this.pos += len;
51254           },
51255           writeFloat: function writeFloat(val) {
51256             this.realloc(4);
51257             ieee754.write(this.buf, val, this.pos, true, 23, 4);
51258             this.pos += 4;
51259           },
51260           writeDouble: function writeDouble(val) {
51261             this.realloc(8);
51262             ieee754.write(this.buf, val, this.pos, true, 52, 8);
51263             this.pos += 8;
51264           },
51265           writeBytes: function writeBytes(buffer) {
51266             var len = buffer.length;
51267             this.writeVarint(len);
51268             this.realloc(len);
51269
51270             for (var i = 0; i < len; i++) {
51271               this.buf[this.pos++] = buffer[i];
51272             }
51273           },
51274           writeRawMessage: function writeRawMessage(fn, obj) {
51275             this.pos++; // reserve 1 byte for short message length
51276             // write the message directly to the buffer and see how much was written
51277
51278             var startPos = this.pos;
51279             fn(obj, this);
51280             var len = this.pos - startPos;
51281             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51282
51283             this.pos = startPos - 1;
51284             this.writeVarint(len);
51285             this.pos += len;
51286           },
51287           writeMessage: function writeMessage(tag, fn, obj) {
51288             this.writeTag(tag, Pbf.Bytes);
51289             this.writeRawMessage(fn, obj);
51290           },
51291           writePackedVarint: function writePackedVarint(tag, arr) {
51292             if (arr.length) this.writeMessage(tag, _writePackedVarint, arr);
51293           },
51294           writePackedSVarint: function writePackedSVarint(tag, arr) {
51295             if (arr.length) this.writeMessage(tag, _writePackedSVarint, arr);
51296           },
51297           writePackedBoolean: function writePackedBoolean(tag, arr) {
51298             if (arr.length) this.writeMessage(tag, _writePackedBoolean, arr);
51299           },
51300           writePackedFloat: function writePackedFloat(tag, arr) {
51301             if (arr.length) this.writeMessage(tag, _writePackedFloat, arr);
51302           },
51303           writePackedDouble: function writePackedDouble(tag, arr) {
51304             if (arr.length) this.writeMessage(tag, _writePackedDouble, arr);
51305           },
51306           writePackedFixed32: function writePackedFixed32(tag, arr) {
51307             if (arr.length) this.writeMessage(tag, _writePackedFixed, arr);
51308           },
51309           writePackedSFixed32: function writePackedSFixed32(tag, arr) {
51310             if (arr.length) this.writeMessage(tag, _writePackedSFixed, arr);
51311           },
51312           writePackedFixed64: function writePackedFixed64(tag, arr) {
51313             if (arr.length) this.writeMessage(tag, _writePackedFixed2, arr);
51314           },
51315           writePackedSFixed64: function writePackedSFixed64(tag, arr) {
51316             if (arr.length) this.writeMessage(tag, _writePackedSFixed2, arr);
51317           },
51318           writeBytesField: function writeBytesField(tag, buffer) {
51319             this.writeTag(tag, Pbf.Bytes);
51320             this.writeBytes(buffer);
51321           },
51322           writeFixed32Field: function writeFixed32Field(tag, val) {
51323             this.writeTag(tag, Pbf.Fixed32);
51324             this.writeFixed32(val);
51325           },
51326           writeSFixed32Field: function writeSFixed32Field(tag, val) {
51327             this.writeTag(tag, Pbf.Fixed32);
51328             this.writeSFixed32(val);
51329           },
51330           writeFixed64Field: function writeFixed64Field(tag, val) {
51331             this.writeTag(tag, Pbf.Fixed64);
51332             this.writeFixed64(val);
51333           },
51334           writeSFixed64Field: function writeSFixed64Field(tag, val) {
51335             this.writeTag(tag, Pbf.Fixed64);
51336             this.writeSFixed64(val);
51337           },
51338           writeVarintField: function writeVarintField(tag, val) {
51339             this.writeTag(tag, Pbf.Varint);
51340             this.writeVarint(val);
51341           },
51342           writeSVarintField: function writeSVarintField(tag, val) {
51343             this.writeTag(tag, Pbf.Varint);
51344             this.writeSVarint(val);
51345           },
51346           writeStringField: function writeStringField(tag, str) {
51347             this.writeTag(tag, Pbf.Bytes);
51348             this.writeString(str);
51349           },
51350           writeFloatField: function writeFloatField(tag, val) {
51351             this.writeTag(tag, Pbf.Fixed32);
51352             this.writeFloat(val);
51353           },
51354           writeDoubleField: function writeDoubleField(tag, val) {
51355             this.writeTag(tag, Pbf.Fixed64);
51356             this.writeDouble(val);
51357           },
51358           writeBooleanField: function writeBooleanField(tag, val) {
51359             this.writeVarintField(tag, Boolean(val));
51360           }
51361         };
51362
51363         function readVarintRemainder(l, s, p) {
51364           var buf = p.buf,
51365               h,
51366               b;
51367           b = buf[p.pos++];
51368           h = (b & 0x70) >> 4;
51369           if (b < 0x80) return toNum(l, h, s);
51370           b = buf[p.pos++];
51371           h |= (b & 0x7f) << 3;
51372           if (b < 0x80) return toNum(l, h, s);
51373           b = buf[p.pos++];
51374           h |= (b & 0x7f) << 10;
51375           if (b < 0x80) return toNum(l, h, s);
51376           b = buf[p.pos++];
51377           h |= (b & 0x7f) << 17;
51378           if (b < 0x80) return toNum(l, h, s);
51379           b = buf[p.pos++];
51380           h |= (b & 0x7f) << 24;
51381           if (b < 0x80) return toNum(l, h, s);
51382           b = buf[p.pos++];
51383           h |= (b & 0x01) << 31;
51384           if (b < 0x80) return toNum(l, h, s);
51385           throw new Error('Expected varint not more than 10 bytes');
51386         }
51387
51388         function readPackedEnd(pbf) {
51389           return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
51390         }
51391
51392         function toNum(low, high, isSigned) {
51393           if (isSigned) {
51394             return high * 0x100000000 + (low >>> 0);
51395           }
51396
51397           return (high >>> 0) * 0x100000000 + (low >>> 0);
51398         }
51399
51400         function writeBigVarint(val, pbf) {
51401           var low, high;
51402
51403           if (val >= 0) {
51404             low = val % 0x100000000 | 0;
51405             high = val / 0x100000000 | 0;
51406           } else {
51407             low = ~(-val % 0x100000000);
51408             high = ~(-val / 0x100000000);
51409
51410             if (low ^ 0xffffffff) {
51411               low = low + 1 | 0;
51412             } else {
51413               low = 0;
51414               high = high + 1 | 0;
51415             }
51416           }
51417
51418           if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
51419             throw new Error('Given varint doesn\'t fit into 10 bytes');
51420           }
51421
51422           pbf.realloc(10);
51423           writeBigVarintLow(low, high, pbf);
51424           writeBigVarintHigh(high, pbf);
51425         }
51426
51427         function writeBigVarintLow(low, high, pbf) {
51428           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51429           low >>>= 7;
51430           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51431           low >>>= 7;
51432           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51433           low >>>= 7;
51434           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51435           low >>>= 7;
51436           pbf.buf[pbf.pos] = low & 0x7f;
51437         }
51438
51439         function writeBigVarintHigh(high, pbf) {
51440           var lsb = (high & 0x07) << 4;
51441           pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0);
51442           if (!high) return;
51443           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51444           if (!high) return;
51445           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51446           if (!high) return;
51447           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51448           if (!high) return;
51449           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51450           if (!high) return;
51451           pbf.buf[pbf.pos++] = high & 0x7f;
51452         }
51453
51454         function makeRoomForExtraLength(startPos, len, pbf) {
51455           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
51456
51457           pbf.realloc(extraLen);
51458
51459           for (var i = pbf.pos - 1; i >= startPos; i--) {
51460             pbf.buf[i + extraLen] = pbf.buf[i];
51461           }
51462         }
51463
51464         function _writePackedVarint(arr, pbf) {
51465           for (var i = 0; i < arr.length; i++) {
51466             pbf.writeVarint(arr[i]);
51467           }
51468         }
51469
51470         function _writePackedSVarint(arr, pbf) {
51471           for (var i = 0; i < arr.length; i++) {
51472             pbf.writeSVarint(arr[i]);
51473           }
51474         }
51475
51476         function _writePackedFloat(arr, pbf) {
51477           for (var i = 0; i < arr.length; i++) {
51478             pbf.writeFloat(arr[i]);
51479           }
51480         }
51481
51482         function _writePackedDouble(arr, pbf) {
51483           for (var i = 0; i < arr.length; i++) {
51484             pbf.writeDouble(arr[i]);
51485           }
51486         }
51487
51488         function _writePackedBoolean(arr, pbf) {
51489           for (var i = 0; i < arr.length; i++) {
51490             pbf.writeBoolean(arr[i]);
51491           }
51492         }
51493
51494         function _writePackedFixed(arr, pbf) {
51495           for (var i = 0; i < arr.length; i++) {
51496             pbf.writeFixed32(arr[i]);
51497           }
51498         }
51499
51500         function _writePackedSFixed(arr, pbf) {
51501           for (var i = 0; i < arr.length; i++) {
51502             pbf.writeSFixed32(arr[i]);
51503           }
51504         }
51505
51506         function _writePackedFixed2(arr, pbf) {
51507           for (var i = 0; i < arr.length; i++) {
51508             pbf.writeFixed64(arr[i]);
51509           }
51510         }
51511
51512         function _writePackedSFixed2(arr, pbf) {
51513           for (var i = 0; i < arr.length; i++) {
51514             pbf.writeSFixed64(arr[i]);
51515           }
51516         } // Buffer code below from https://github.com/feross/buffer, MIT-licensed
51517
51518
51519         function readUInt32(buf, pos) {
51520           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 0x1000000;
51521         }
51522
51523         function writeInt32(buf, val, pos) {
51524           buf[pos] = val;
51525           buf[pos + 1] = val >>> 8;
51526           buf[pos + 2] = val >>> 16;
51527           buf[pos + 3] = val >>> 24;
51528         }
51529
51530         function readInt32(buf, pos) {
51531           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
51532         }
51533
51534         function readUtf8(buf, pos, end) {
51535           var str = '';
51536           var i = pos;
51537
51538           while (i < end) {
51539             var b0 = buf[i];
51540             var c = null; // codepoint
51541
51542             var bytesPerSequence = b0 > 0xEF ? 4 : b0 > 0xDF ? 3 : b0 > 0xBF ? 2 : 1;
51543             if (i + bytesPerSequence > end) break;
51544             var b1, b2, b3;
51545
51546             if (bytesPerSequence === 1) {
51547               if (b0 < 0x80) {
51548                 c = b0;
51549               }
51550             } else if (bytesPerSequence === 2) {
51551               b1 = buf[i + 1];
51552
51553               if ((b1 & 0xC0) === 0x80) {
51554                 c = (b0 & 0x1F) << 0x6 | b1 & 0x3F;
51555
51556                 if (c <= 0x7F) {
51557                   c = null;
51558                 }
51559               }
51560             } else if (bytesPerSequence === 3) {
51561               b1 = buf[i + 1];
51562               b2 = buf[i + 2];
51563
51564               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
51565                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | b2 & 0x3F;
51566
51567                 if (c <= 0x7FF || c >= 0xD800 && c <= 0xDFFF) {
51568                   c = null;
51569                 }
51570               }
51571             } else if (bytesPerSequence === 4) {
51572               b1 = buf[i + 1];
51573               b2 = buf[i + 2];
51574               b3 = buf[i + 3];
51575
51576               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
51577                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | b3 & 0x3F;
51578
51579                 if (c <= 0xFFFF || c >= 0x110000) {
51580                   c = null;
51581                 }
51582               }
51583             }
51584
51585             if (c === null) {
51586               c = 0xFFFD;
51587               bytesPerSequence = 1;
51588             } else if (c > 0xFFFF) {
51589               c -= 0x10000;
51590               str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
51591               c = 0xDC00 | c & 0x3FF;
51592             }
51593
51594             str += String.fromCharCode(c);
51595             i += bytesPerSequence;
51596           }
51597
51598           return str;
51599         }
51600
51601         function readUtf8TextDecoder(buf, pos, end) {
51602           return utf8TextDecoder.decode(buf.subarray(pos, end));
51603         }
51604
51605         function writeUtf8(buf, str, pos) {
51606           for (var i = 0, c, lead; i < str.length; i++) {
51607             c = str.charCodeAt(i); // code point
51608
51609             if (c > 0xD7FF && c < 0xE000) {
51610               if (lead) {
51611                 if (c < 0xDC00) {
51612                   buf[pos++] = 0xEF;
51613                   buf[pos++] = 0xBF;
51614                   buf[pos++] = 0xBD;
51615                   lead = c;
51616                   continue;
51617                 } else {
51618                   c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
51619                   lead = null;
51620                 }
51621               } else {
51622                 if (c > 0xDBFF || i + 1 === str.length) {
51623                   buf[pos++] = 0xEF;
51624                   buf[pos++] = 0xBF;
51625                   buf[pos++] = 0xBD;
51626                 } else {
51627                   lead = c;
51628                 }
51629
51630                 continue;
51631               }
51632             } else if (lead) {
51633               buf[pos++] = 0xEF;
51634               buf[pos++] = 0xBF;
51635               buf[pos++] = 0xBD;
51636               lead = null;
51637             }
51638
51639             if (c < 0x80) {
51640               buf[pos++] = c;
51641             } else {
51642               if (c < 0x800) {
51643                 buf[pos++] = c >> 0x6 | 0xC0;
51644               } else {
51645                 if (c < 0x10000) {
51646                   buf[pos++] = c >> 0xC | 0xE0;
51647                 } else {
51648                   buf[pos++] = c >> 0x12 | 0xF0;
51649                   buf[pos++] = c >> 0xC & 0x3F | 0x80;
51650                 }
51651
51652                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
51653               }
51654
51655               buf[pos++] = c & 0x3F | 0x80;
51656             }
51657           }
51658
51659           return pos;
51660         }
51661
51662         var vectorTile = {};
51663
51664         var pointGeometry = Point$1;
51665         /**
51666          * A standalone point geometry with useful accessor, comparison, and
51667          * modification methods.
51668          *
51669          * @class Point
51670          * @param {Number} x the x-coordinate. this could be longitude or screen
51671          * pixels, or any other sort of unit.
51672          * @param {Number} y the y-coordinate. this could be latitude or screen
51673          * pixels, or any other sort of unit.
51674          * @example
51675          * var point = new Point(-77, 38);
51676          */
51677
51678         function Point$1(x, y) {
51679           this.x = x;
51680           this.y = y;
51681         }
51682
51683         Point$1.prototype = {
51684           /**
51685            * Clone this point, returning a new point that can be modified
51686            * without affecting the old one.
51687            * @return {Point} the clone
51688            */
51689           clone: function clone() {
51690             return new Point$1(this.x, this.y);
51691           },
51692
51693           /**
51694            * Add this point's x & y coordinates to another point,
51695            * yielding a new point.
51696            * @param {Point} p the other point
51697            * @return {Point} output point
51698            */
51699           add: function add(p) {
51700             return this.clone()._add(p);
51701           },
51702
51703           /**
51704            * Subtract this point's x & y coordinates to from point,
51705            * yielding a new point.
51706            * @param {Point} p the other point
51707            * @return {Point} output point
51708            */
51709           sub: function sub(p) {
51710             return this.clone()._sub(p);
51711           },
51712
51713           /**
51714            * Multiply this point's x & y coordinates by point,
51715            * yielding a new point.
51716            * @param {Point} p the other point
51717            * @return {Point} output point
51718            */
51719           multByPoint: function multByPoint(p) {
51720             return this.clone()._multByPoint(p);
51721           },
51722
51723           /**
51724            * Divide this point's x & y coordinates by point,
51725            * yielding a new point.
51726            * @param {Point} p the other point
51727            * @return {Point} output point
51728            */
51729           divByPoint: function divByPoint(p) {
51730             return this.clone()._divByPoint(p);
51731           },
51732
51733           /**
51734            * Multiply this point's x & y coordinates by a factor,
51735            * yielding a new point.
51736            * @param {Point} k factor
51737            * @return {Point} output point
51738            */
51739           mult: function mult(k) {
51740             return this.clone()._mult(k);
51741           },
51742
51743           /**
51744            * Divide this point's x & y coordinates by a factor,
51745            * yielding a new point.
51746            * @param {Point} k factor
51747            * @return {Point} output point
51748            */
51749           div: function div(k) {
51750             return this.clone()._div(k);
51751           },
51752
51753           /**
51754            * Rotate this point around the 0, 0 origin by an angle a,
51755            * given in radians
51756            * @param {Number} a angle to rotate around, in radians
51757            * @return {Point} output point
51758            */
51759           rotate: function rotate(a) {
51760             return this.clone()._rotate(a);
51761           },
51762
51763           /**
51764            * Rotate this point around p point by an angle a,
51765            * given in radians
51766            * @param {Number} a angle to rotate around, in radians
51767            * @param {Point} p Point to rotate around
51768            * @return {Point} output point
51769            */
51770           rotateAround: function rotateAround(a, p) {
51771             return this.clone()._rotateAround(a, p);
51772           },
51773
51774           /**
51775            * Multiply this point by a 4x1 transformation matrix
51776            * @param {Array<Number>} m transformation matrix
51777            * @return {Point} output point
51778            */
51779           matMult: function matMult(m) {
51780             return this.clone()._matMult(m);
51781           },
51782
51783           /**
51784            * Calculate this point but as a unit vector from 0, 0, meaning
51785            * that the distance from the resulting point to the 0, 0
51786            * coordinate will be equal to 1 and the angle from the resulting
51787            * point to the 0, 0 coordinate will be the same as before.
51788            * @return {Point} unit vector point
51789            */
51790           unit: function unit() {
51791             return this.clone()._unit();
51792           },
51793
51794           /**
51795            * Compute a perpendicular point, where the new y coordinate
51796            * is the old x coordinate and the new x coordinate is the old y
51797            * coordinate multiplied by -1
51798            * @return {Point} perpendicular point
51799            */
51800           perp: function perp() {
51801             return this.clone()._perp();
51802           },
51803
51804           /**
51805            * Return a version of this point with the x & y coordinates
51806            * rounded to integers.
51807            * @return {Point} rounded point
51808            */
51809           round: function round() {
51810             return this.clone()._round();
51811           },
51812
51813           /**
51814            * Return the magitude of this point: this is the Euclidean
51815            * distance from the 0, 0 coordinate to this point's x and y
51816            * coordinates.
51817            * @return {Number} magnitude
51818            */
51819           mag: function mag() {
51820             return Math.sqrt(this.x * this.x + this.y * this.y);
51821           },
51822
51823           /**
51824            * Judge whether this point is equal to another point, returning
51825            * true or false.
51826            * @param {Point} other the other point
51827            * @return {boolean} whether the points are equal
51828            */
51829           equals: function equals(other) {
51830             return this.x === other.x && this.y === other.y;
51831           },
51832
51833           /**
51834            * Calculate the distance from this point to another point
51835            * @param {Point} p the other point
51836            * @return {Number} distance
51837            */
51838           dist: function dist(p) {
51839             return Math.sqrt(this.distSqr(p));
51840           },
51841
51842           /**
51843            * Calculate the distance from this point to another point,
51844            * without the square root step. Useful if you're comparing
51845            * relative distances.
51846            * @param {Point} p the other point
51847            * @return {Number} distance
51848            */
51849           distSqr: function distSqr(p) {
51850             var dx = p.x - this.x,
51851                 dy = p.y - this.y;
51852             return dx * dx + dy * dy;
51853           },
51854
51855           /**
51856            * Get the angle from the 0, 0 coordinate to this point, in radians
51857            * coordinates.
51858            * @return {Number} angle
51859            */
51860           angle: function angle() {
51861             return Math.atan2(this.y, this.x);
51862           },
51863
51864           /**
51865            * Get the angle from this point to another point, in radians
51866            * @param {Point} b the other point
51867            * @return {Number} angle
51868            */
51869           angleTo: function angleTo(b) {
51870             return Math.atan2(this.y - b.y, this.x - b.x);
51871           },
51872
51873           /**
51874            * Get the angle between this point and another point, in radians
51875            * @param {Point} b the other point
51876            * @return {Number} angle
51877            */
51878           angleWith: function angleWith(b) {
51879             return this.angleWithSep(b.x, b.y);
51880           },
51881
51882           /*
51883            * Find the angle of the two vectors, solving the formula for
51884            * the cross product a x b = |a||b|sin(θ) for θ.
51885            * @param {Number} x the x-coordinate
51886            * @param {Number} y the y-coordinate
51887            * @return {Number} the angle in radians
51888            */
51889           angleWithSep: function angleWithSep(x, y) {
51890             return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
51891           },
51892           _matMult: function _matMult(m) {
51893             var x = m[0] * this.x + m[1] * this.y,
51894                 y = m[2] * this.x + m[3] * this.y;
51895             this.x = x;
51896             this.y = y;
51897             return this;
51898           },
51899           _add: function _add(p) {
51900             this.x += p.x;
51901             this.y += p.y;
51902             return this;
51903           },
51904           _sub: function _sub(p) {
51905             this.x -= p.x;
51906             this.y -= p.y;
51907             return this;
51908           },
51909           _mult: function _mult(k) {
51910             this.x *= k;
51911             this.y *= k;
51912             return this;
51913           },
51914           _div: function _div(k) {
51915             this.x /= k;
51916             this.y /= k;
51917             return this;
51918           },
51919           _multByPoint: function _multByPoint(p) {
51920             this.x *= p.x;
51921             this.y *= p.y;
51922             return this;
51923           },
51924           _divByPoint: function _divByPoint(p) {
51925             this.x /= p.x;
51926             this.y /= p.y;
51927             return this;
51928           },
51929           _unit: function _unit() {
51930             this._div(this.mag());
51931
51932             return this;
51933           },
51934           _perp: function _perp() {
51935             var y = this.y;
51936             this.y = this.x;
51937             this.x = -y;
51938             return this;
51939           },
51940           _rotate: function _rotate(angle) {
51941             var cos = Math.cos(angle),
51942                 sin = Math.sin(angle),
51943                 x = cos * this.x - sin * this.y,
51944                 y = sin * this.x + cos * this.y;
51945             this.x = x;
51946             this.y = y;
51947             return this;
51948           },
51949           _rotateAround: function _rotateAround(angle, p) {
51950             var cos = Math.cos(angle),
51951                 sin = Math.sin(angle),
51952                 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
51953                 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
51954             this.x = x;
51955             this.y = y;
51956             return this;
51957           },
51958           _round: function _round() {
51959             this.x = Math.round(this.x);
51960             this.y = Math.round(this.y);
51961             return this;
51962           }
51963         };
51964         /**
51965          * Construct a point from an array if necessary, otherwise if the input
51966          * is already a Point, or an unknown type, return it unchanged
51967          * @param {Array<Number>|Point|*} a any kind of input value
51968          * @return {Point} constructed point, or passed-through value.
51969          * @example
51970          * // this
51971          * var point = Point.convert([0, 1]);
51972          * // is equivalent to
51973          * var point = new Point(0, 1);
51974          */
51975
51976         Point$1.convert = function (a) {
51977           if (a instanceof Point$1) {
51978             return a;
51979           }
51980
51981           if (Array.isArray(a)) {
51982             return new Point$1(a[0], a[1]);
51983           }
51984
51985           return a;
51986         };
51987
51988         var Point = pointGeometry;
51989         var vectortilefeature = VectorTileFeature$1;
51990
51991         function VectorTileFeature$1(pbf, end, extent, keys, values) {
51992           // Public
51993           this.properties = {};
51994           this.extent = extent;
51995           this.type = 0; // Private
51996
51997           this._pbf = pbf;
51998           this._geometry = -1;
51999           this._keys = keys;
52000           this._values = values;
52001           pbf.readFields(readFeature, this, end);
52002         }
52003
52004         function readFeature(tag, feature, pbf) {
52005           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;
52006         }
52007
52008         function readTag(pbf, feature) {
52009           var end = pbf.readVarint() + pbf.pos;
52010
52011           while (pbf.pos < end) {
52012             var key = feature._keys[pbf.readVarint()],
52013                 value = feature._values[pbf.readVarint()];
52014
52015             feature.properties[key] = value;
52016           }
52017         }
52018
52019         VectorTileFeature$1.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
52020
52021         VectorTileFeature$1.prototype.loadGeometry = function () {
52022           var pbf = this._pbf;
52023           pbf.pos = this._geometry;
52024           var end = pbf.readVarint() + pbf.pos,
52025               cmd = 1,
52026               length = 0,
52027               x = 0,
52028               y = 0,
52029               lines = [],
52030               line;
52031
52032           while (pbf.pos < end) {
52033             if (length <= 0) {
52034               var cmdLen = pbf.readVarint();
52035               cmd = cmdLen & 0x7;
52036               length = cmdLen >> 3;
52037             }
52038
52039             length--;
52040
52041             if (cmd === 1 || cmd === 2) {
52042               x += pbf.readSVarint();
52043               y += pbf.readSVarint();
52044
52045               if (cmd === 1) {
52046                 // moveTo
52047                 if (line) lines.push(line);
52048                 line = [];
52049               }
52050
52051               line.push(new Point(x, y));
52052             } else if (cmd === 7) {
52053               // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
52054               if (line) {
52055                 line.push(line[0].clone()); // closePolygon
52056               }
52057             } else {
52058               throw new Error('unknown command ' + cmd);
52059             }
52060           }
52061
52062           if (line) lines.push(line);
52063           return lines;
52064         };
52065
52066         VectorTileFeature$1.prototype.bbox = function () {
52067           var pbf = this._pbf;
52068           pbf.pos = this._geometry;
52069           var end = pbf.readVarint() + pbf.pos,
52070               cmd = 1,
52071               length = 0,
52072               x = 0,
52073               y = 0,
52074               x1 = Infinity,
52075               x2 = -Infinity,
52076               y1 = Infinity,
52077               y2 = -Infinity;
52078
52079           while (pbf.pos < end) {
52080             if (length <= 0) {
52081               var cmdLen = pbf.readVarint();
52082               cmd = cmdLen & 0x7;
52083               length = cmdLen >> 3;
52084             }
52085
52086             length--;
52087
52088             if (cmd === 1 || cmd === 2) {
52089               x += pbf.readSVarint();
52090               y += pbf.readSVarint();
52091               if (x < x1) x1 = x;
52092               if (x > x2) x2 = x;
52093               if (y < y1) y1 = y;
52094               if (y > y2) y2 = y;
52095             } else if (cmd !== 7) {
52096               throw new Error('unknown command ' + cmd);
52097             }
52098           }
52099
52100           return [x1, y1, x2, y2];
52101         };
52102
52103         VectorTileFeature$1.prototype.toGeoJSON = function (x, y, z) {
52104           var size = this.extent * Math.pow(2, z),
52105               x0 = this.extent * x,
52106               y0 = this.extent * y,
52107               coords = this.loadGeometry(),
52108               type = VectorTileFeature$1.types[this.type],
52109               i,
52110               j;
52111
52112           function project(line) {
52113             for (var j = 0; j < line.length; j++) {
52114               var p = line[j],
52115                   y2 = 180 - (p.y + y0) * 360 / size;
52116               line[j] = [(p.x + x0) * 360 / size - 180, 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90];
52117             }
52118           }
52119
52120           switch (this.type) {
52121             case 1:
52122               var points = [];
52123
52124               for (i = 0; i < coords.length; i++) {
52125                 points[i] = coords[i][0];
52126               }
52127
52128               coords = points;
52129               project(coords);
52130               break;
52131
52132             case 2:
52133               for (i = 0; i < coords.length; i++) {
52134                 project(coords[i]);
52135               }
52136
52137               break;
52138
52139             case 3:
52140               coords = classifyRings(coords);
52141
52142               for (i = 0; i < coords.length; i++) {
52143                 for (j = 0; j < coords[i].length; j++) {
52144                   project(coords[i][j]);
52145                 }
52146               }
52147
52148               break;
52149           }
52150
52151           if (coords.length === 1) {
52152             coords = coords[0];
52153           } else {
52154             type = 'Multi' + type;
52155           }
52156
52157           var result = {
52158             type: "Feature",
52159             geometry: {
52160               type: type,
52161               coordinates: coords
52162             },
52163             properties: this.properties
52164           };
52165
52166           if ('id' in this) {
52167             result.id = this.id;
52168           }
52169
52170           return result;
52171         }; // classifies an array of rings into polygons with outer rings and holes
52172
52173
52174         function classifyRings(rings) {
52175           var len = rings.length;
52176           if (len <= 1) return [rings];
52177           var polygons = [],
52178               polygon,
52179               ccw;
52180
52181           for (var i = 0; i < len; i++) {
52182             var area = signedArea(rings[i]);
52183             if (area === 0) continue;
52184             if (ccw === undefined) ccw = area < 0;
52185
52186             if (ccw === area < 0) {
52187               if (polygon) polygons.push(polygon);
52188               polygon = [rings[i]];
52189             } else {
52190               polygon.push(rings[i]);
52191             }
52192           }
52193
52194           if (polygon) polygons.push(polygon);
52195           return polygons;
52196         }
52197
52198         function signedArea(ring) {
52199           var sum = 0;
52200
52201           for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
52202             p1 = ring[i];
52203             p2 = ring[j];
52204             sum += (p2.x - p1.x) * (p1.y + p2.y);
52205           }
52206
52207           return sum;
52208         }
52209
52210         var VectorTileFeature = vectortilefeature;
52211         var vectortilelayer = VectorTileLayer$1;
52212
52213         function VectorTileLayer$1(pbf, end) {
52214           // Public
52215           this.version = 1;
52216           this.name = null;
52217           this.extent = 4096;
52218           this.length = 0; // Private
52219
52220           this._pbf = pbf;
52221           this._keys = [];
52222           this._values = [];
52223           this._features = [];
52224           pbf.readFields(readLayer, this, end);
52225           this.length = this._features.length;
52226         }
52227
52228         function readLayer(tag, layer, pbf) {
52229           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));
52230         }
52231
52232         function readValueMessage(pbf) {
52233           var value = null,
52234               end = pbf.readVarint() + pbf.pos;
52235
52236           while (pbf.pos < end) {
52237             var tag = pbf.readVarint() >> 3;
52238             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;
52239           }
52240
52241           return value;
52242         } // return feature `i` from this layer as a `VectorTileFeature`
52243
52244
52245         VectorTileLayer$1.prototype.feature = function (i) {
52246           if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
52247           this._pbf.pos = this._features[i];
52248
52249           var end = this._pbf.readVarint() + this._pbf.pos;
52250
52251           return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
52252         };
52253
52254         var VectorTileLayer = vectortilelayer;
52255         var vectortile = VectorTile$1;
52256
52257         function VectorTile$1(pbf, end) {
52258           this.layers = pbf.readFields(readTile, {}, end);
52259         }
52260
52261         function readTile(tag, layers, pbf) {
52262           if (tag === 3) {
52263             var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
52264             if (layer.length) layers[layer.name] = layer;
52265           }
52266         }
52267
52268         var VectorTile = vectorTile.VectorTile = vectortile;
52269         vectorTile.VectorTileFeature = vectortilefeature;
52270         vectorTile.VectorTileLayer = vectortilelayer;
52271
52272         var accessToken = 'MLY|4100327730013843|5bb78b81720791946a9a7b956c57b7cf';
52273         var apiUrl = 'https://graph.mapillary.com/';
52274         var baseTileUrl = 'https://tiles.mapillary.com/maps/vtp';
52275         var mapFeatureTileUrl = "".concat(baseTileUrl, "/mly_map_feature_point/2/{z}/{x}/{y}?access_token=").concat(accessToken);
52276         var tileUrl = "".concat(baseTileUrl, "/mly1_public/2/{z}/{x}/{y}?access_token=").concat(accessToken);
52277         var trafficSignTileUrl = "".concat(baseTileUrl, "/mly_map_feature_traffic_sign/2/{z}/{x}/{y}?access_token=").concat(accessToken);
52278         var viewercss = 'mapillary-js/mapillary.css';
52279         var viewerjs = 'mapillary-js/mapillary.js';
52280         var minZoom$1 = 14;
52281         var dispatch$4 = dispatch$8('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'imageChanged');
52282
52283         var _loadViewerPromise$2;
52284
52285         var _mlyActiveImage;
52286
52287         var _mlyCache;
52288
52289         var _mlyFallback = false;
52290
52291         var _mlyHighlightedDetection;
52292
52293         var _mlyShowFeatureDetections = false;
52294         var _mlyShowSignDetections = false;
52295
52296         var _mlyViewer;
52297
52298         var _mlyViewerFilter = ['all']; // Load all data for the specified type from Mapillary vector tiles
52299
52300         function loadTiles$2(which, url, maxZoom, projection) {
52301           var tiler = utilTiler().zoomExtent([minZoom$1, maxZoom]).skipNullIsland(true);
52302           var tiles = tiler.getTiles(projection);
52303           tiles.forEach(function (tile) {
52304             loadTile$1(which, url, tile);
52305           });
52306         } // Load all data for the specified type from one vector tile
52307
52308
52309         function loadTile$1(which, url, tile) {
52310           var cache = _mlyCache.requests;
52311           var tileId = "".concat(tile.id, "-").concat(which);
52312           if (cache.loaded[tileId] || cache.inflight[tileId]) return;
52313           var controller = new AbortController();
52314           cache.inflight[tileId] = controller;
52315           var requestUrl = url.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]).replace('{z}', tile.xyz[2]);
52316           fetch(requestUrl, {
52317             signal: controller.signal
52318           }).then(function (response) {
52319             if (!response.ok) {
52320               throw new Error(response.status + ' ' + response.statusText);
52321             }
52322
52323             cache.loaded[tileId] = true;
52324             delete cache.inflight[tileId];
52325             return response.arrayBuffer();
52326           }).then(function (data) {
52327             if (!data) {
52328               throw new Error('No Data');
52329             }
52330
52331             loadTileDataToCache(data, tile, which);
52332
52333             if (which === 'images') {
52334               dispatch$4.call('loadedImages');
52335             } else if (which === 'signs') {
52336               dispatch$4.call('loadedSigns');
52337             } else if (which === 'points') {
52338               dispatch$4.call('loadedMapFeatures');
52339             }
52340           })["catch"](function () {
52341             cache.loaded[tileId] = true;
52342             delete cache.inflight[tileId];
52343           });
52344         } // Load the data from the vector tile into cache
52345
52346
52347         function loadTileDataToCache(data, tile, which) {
52348           var vectorTile = new VectorTile(new pbf(data));
52349           var features, cache, layer, i, feature, loc, d;
52350
52351           if (vectorTile.layers.hasOwnProperty('image')) {
52352             features = [];
52353             cache = _mlyCache.images;
52354             layer = vectorTile.layers.image;
52355
52356             for (i = 0; i < layer.length; i++) {
52357               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52358               loc = feature.geometry.coordinates;
52359               d = {
52360                 loc: loc,
52361                 captured_at: feature.properties.captured_at,
52362                 ca: feature.properties.compass_angle,
52363                 id: feature.properties.id,
52364                 is_pano: feature.properties.is_pano,
52365                 sequence_id: feature.properties.sequence_id
52366               };
52367               cache.forImageId[d.id] = d;
52368               features.push({
52369                 minX: loc[0],
52370                 minY: loc[1],
52371                 maxX: loc[0],
52372                 maxY: loc[1],
52373                 data: d
52374               });
52375             }
52376
52377             if (cache.rtree) {
52378               cache.rtree.load(features);
52379             }
52380           }
52381
52382           if (vectorTile.layers.hasOwnProperty('sequence')) {
52383             features = [];
52384             cache = _mlyCache.sequences;
52385             layer = vectorTile.layers.sequence;
52386
52387             for (i = 0; i < layer.length; i++) {
52388               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52389
52390               if (cache.lineString[feature.properties.id]) {
52391                 cache.lineString[feature.properties.id].push(feature);
52392               } else {
52393                 cache.lineString[feature.properties.id] = [feature];
52394               }
52395             }
52396           }
52397
52398           if (vectorTile.layers.hasOwnProperty('point')) {
52399             features = [];
52400             cache = _mlyCache[which];
52401             layer = vectorTile.layers.point;
52402
52403             for (i = 0; i < layer.length; i++) {
52404               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52405               loc = feature.geometry.coordinates;
52406               d = {
52407                 loc: loc,
52408                 id: feature.properties.id,
52409                 first_seen_at: feature.properties.first_seen_at,
52410                 last_seen_at: feature.properties.last_seen_at,
52411                 value: feature.properties.value
52412               };
52413               features.push({
52414                 minX: loc[0],
52415                 minY: loc[1],
52416                 maxX: loc[0],
52417                 maxY: loc[1],
52418                 data: d
52419               });
52420             }
52421
52422             if (cache.rtree) {
52423               cache.rtree.load(features);
52424             }
52425           }
52426
52427           if (vectorTile.layers.hasOwnProperty('traffic_sign')) {
52428             features = [];
52429             cache = _mlyCache[which];
52430             layer = vectorTile.layers.traffic_sign;
52431
52432             for (i = 0; i < layer.length; i++) {
52433               feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52434               loc = feature.geometry.coordinates;
52435               d = {
52436                 loc: loc,
52437                 id: feature.properties.id,
52438                 first_seen_at: feature.properties.first_seen_at,
52439                 last_seen_at: feature.properties.last_seen_at,
52440                 value: feature.properties.value
52441               };
52442               features.push({
52443                 minX: loc[0],
52444                 minY: loc[1],
52445                 maxX: loc[0],
52446                 maxY: loc[1],
52447                 data: d
52448               });
52449             }
52450
52451             if (cache.rtree) {
52452               cache.rtree.load(features);
52453             }
52454           }
52455         } // Get data from the API
52456
52457
52458         function loadData(url) {
52459           return fetch(url).then(function (response) {
52460             if (!response.ok) {
52461               throw new Error(response.status + ' ' + response.statusText);
52462             }
52463
52464             return response.json();
52465           }).then(function (result) {
52466             if (!result) {
52467               return [];
52468             }
52469
52470             return result.data || [];
52471           });
52472         } // Partition viewport into higher zoom tiles
52473
52474
52475         function partitionViewport$2(projection) {
52476           var z = geoScaleToZoom(projection.scale());
52477           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
52478
52479           var tiler = utilTiler().zoomExtent([z2, z2]);
52480           return tiler.getTiles(projection).map(function (tile) {
52481             return tile.extent;
52482           });
52483         } // Return no more than `limit` results per partition.
52484
52485
52486         function searchLimited$2(limit, projection, rtree) {
52487           limit = limit || 5;
52488           return partitionViewport$2(projection).reduce(function (result, extent) {
52489             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
52490               return d.data;
52491             });
52492             return found.length ? result.concat(found) : result;
52493           }, []);
52494         }
52495
52496         var serviceMapillary = {
52497           // Initialize Mapillary
52498           init: function init() {
52499             if (!_mlyCache) {
52500               this.reset();
52501             }
52502
52503             this.event = utilRebind(this, dispatch$4, 'on');
52504           },
52505           // Reset cache and state
52506           reset: function reset() {
52507             if (_mlyCache) {
52508               Object.values(_mlyCache.requests.inflight).forEach(function (request) {
52509                 request.abort();
52510               });
52511             }
52512
52513             _mlyCache = {
52514               images: {
52515                 rtree: new RBush(),
52516                 forImageId: {}
52517               },
52518               image_detections: {
52519                 forImageId: {}
52520               },
52521               signs: {
52522                 rtree: new RBush()
52523               },
52524               points: {
52525                 rtree: new RBush()
52526               },
52527               sequences: {
52528                 rtree: new RBush(),
52529                 lineString: {}
52530               },
52531               requests: {
52532                 loaded: {},
52533                 inflight: {}
52534               }
52535             };
52536             _mlyActiveImage = null;
52537           },
52538           // Get visible images
52539           images: function images(projection) {
52540             var limit = 5;
52541             return searchLimited$2(limit, projection, _mlyCache.images.rtree);
52542           },
52543           // Get visible traffic signs
52544           signs: function signs(projection) {
52545             var limit = 5;
52546             return searchLimited$2(limit, projection, _mlyCache.signs.rtree);
52547           },
52548           // Get visible map (point) features
52549           mapFeatures: function mapFeatures(projection) {
52550             var limit = 5;
52551             return searchLimited$2(limit, projection, _mlyCache.points.rtree);
52552           },
52553           // Get cached image by id
52554           cachedImage: function cachedImage(imageId) {
52555             return _mlyCache.images.forImageId[imageId];
52556           },
52557           // Get visible sequences
52558           sequences: function sequences(projection) {
52559             var viewport = projection.clipExtent();
52560             var min = [viewport[0][0], viewport[1][1]];
52561             var max = [viewport[1][0], viewport[0][1]];
52562             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
52563             var sequenceIds = {};
52564             var lineStrings = [];
52565
52566             _mlyCache.images.rtree.search(bbox).forEach(function (d) {
52567               if (d.data.sequence_id) {
52568                 sequenceIds[d.data.sequence_id] = true;
52569               }
52570             });
52571
52572             Object.keys(sequenceIds).forEach(function (sequenceId) {
52573               if (_mlyCache.sequences.lineString[sequenceId]) {
52574                 lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
52575               }
52576             });
52577             return lineStrings;
52578           },
52579           // Load images in the visible area
52580           loadImages: function loadImages(projection) {
52581             loadTiles$2('images', tileUrl, 14, projection);
52582           },
52583           // Load traffic signs in the visible area
52584           loadSigns: function loadSigns(projection) {
52585             loadTiles$2('signs', trafficSignTileUrl, 14, projection);
52586           },
52587           // Load map (point) features in the visible area
52588           loadMapFeatures: function loadMapFeatures(projection) {
52589             loadTiles$2('points', mapFeatureTileUrl, 14, projection);
52590           },
52591           // Return a promise that resolves when the image viewer (Mapillary JS) library has finished loading
52592           ensureViewerLoaded: function ensureViewerLoaded(context) {
52593             if (_loadViewerPromise$2) return _loadViewerPromise$2; // add mly-wrapper
52594
52595             var wrap = context.container().select('.photoviewer').selectAll('.mly-wrapper').data([0]);
52596             wrap.enter().append('div').attr('id', 'ideditor-mly').attr('class', 'photo-wrapper mly-wrapper').classed('hide', true);
52597             var that = this;
52598             _loadViewerPromise$2 = new Promise(function (resolve, reject) {
52599               var loadedCount = 0;
52600
52601               function loaded() {
52602                 loadedCount += 1; // wait until both files are loaded
52603
52604                 if (loadedCount === 2) resolve();
52605               }
52606
52607               var head = select('head'); // load mapillary-viewercss
52608
52609               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 () {
52610                 reject();
52611               }); // load mapillary-viewerjs
52612
52613               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 () {
52614                 reject();
52615               });
52616             })["catch"](function () {
52617               _loadViewerPromise$2 = null;
52618             }).then(function () {
52619               that.initViewer(context);
52620             });
52621             return _loadViewerPromise$2;
52622           },
52623           // Load traffic sign image sprites
52624           loadSignResources: function loadSignResources(context) {
52625             context.ui().svgDefs.addSprites(['mapillary-sprite'], false
52626             /* don't override colors */
52627             );
52628             return this;
52629           },
52630           // Load map (point) feature image sprites
52631           loadObjectResources: function loadObjectResources(context) {
52632             context.ui().svgDefs.addSprites(['mapillary-object-sprite'], false
52633             /* don't override colors */
52634             );
52635             return this;
52636           },
52637           // Remove previous detections in image viewer
52638           resetTags: function resetTags() {
52639             if (_mlyViewer && !_mlyFallback) {
52640               _mlyViewer.getComponent('tag').removeAll();
52641             }
52642           },
52643           // Show map feature detections in image viewer
52644           showFeatureDetections: function showFeatureDetections(value) {
52645             _mlyShowFeatureDetections = value;
52646
52647             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
52648               this.resetTags();
52649             }
52650           },
52651           // Show traffic sign detections in image viewer
52652           showSignDetections: function showSignDetections(value) {
52653             _mlyShowSignDetections = value;
52654
52655             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
52656               this.resetTags();
52657             }
52658           },
52659           // Apply filter to image viewer
52660           filterViewer: function filterViewer(context) {
52661             var showsPano = context.photos().showsPanoramic();
52662             var showsFlat = context.photos().showsFlat();
52663             var fromDate = context.photos().fromDate();
52664             var toDate = context.photos().toDate();
52665             var filter = ['all'];
52666             if (!showsPano) filter.push(['!=', 'cameraType', 'spherical']);
52667             if (!showsFlat && showsPano) filter.push(['==', 'pano', true]);
52668
52669             if (fromDate) {
52670               filter.push(['>=', 'capturedAt', new Date(fromDate).getTime()]);
52671             }
52672
52673             if (toDate) {
52674               filter.push(['>=', 'capturedAt', new Date(toDate).getTime()]);
52675             }
52676
52677             if (_mlyViewer) {
52678               _mlyViewer.setFilter(filter);
52679             }
52680
52681             _mlyViewerFilter = filter;
52682             return filter;
52683           },
52684           // Make the image viewer visible
52685           showViewer: function showViewer(context) {
52686             var wrap = context.container().select('.photoviewer').classed('hide', false);
52687             var isHidden = wrap.selectAll('.photo-wrapper.mly-wrapper.hide').size();
52688
52689             if (isHidden && _mlyViewer) {
52690               wrap.selectAll('.photo-wrapper:not(.mly-wrapper)').classed('hide', true);
52691               wrap.selectAll('.photo-wrapper.mly-wrapper').classed('hide', false);
52692
52693               _mlyViewer.resize();
52694             }
52695
52696             return this;
52697           },
52698           // Hide the image viewer and resets map markers
52699           hideViewer: function hideViewer(context) {
52700             _mlyActiveImage = null;
52701
52702             if (!_mlyFallback && _mlyViewer) {
52703               _mlyViewer.getComponent('sequence').stop();
52704             }
52705
52706             var viewer = context.container().select('.photoviewer');
52707             if (!viewer.empty()) viewer.datum(null);
52708             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
52709             this.updateUrlImage(null);
52710             dispatch$4.call('imageChanged');
52711             dispatch$4.call('loadedMapFeatures');
52712             dispatch$4.call('loadedSigns');
52713             return this.setStyles(context, null);
52714           },
52715           // Update the URL with current image id
52716           updateUrlImage: function updateUrlImage(imageId) {
52717             if (!window.mocha) {
52718               var hash = utilStringQs(window.location.hash);
52719
52720               if (imageId) {
52721                 hash.photo = 'mapillary/' + imageId;
52722               } else {
52723                 delete hash.photo;
52724               }
52725
52726               window.location.replace('#' + utilQsString(hash, true));
52727             }
52728           },
52729           // Highlight the detection in the viewer that is related to the clicked map feature
52730           highlightDetection: function highlightDetection(detection) {
52731             if (detection) {
52732               _mlyHighlightedDetection = detection.id;
52733             }
52734
52735             return this;
52736           },
52737           // Initialize image viewer (Mapillar JS)
52738           initViewer: function initViewer(context) {
52739             var that = this;
52740             if (!window.mapillary) return;
52741             var opts = {
52742               accessToken: accessToken,
52743               component: {
52744                 cover: false,
52745                 keyboard: false,
52746                 tag: true
52747               },
52748               container: 'ideditor-mly'
52749             }; // Disable components requiring WebGL support
52750
52751             if (!mapillary.isSupported() && mapillary.isFallbackSupported()) {
52752               _mlyFallback = true;
52753               opts.component = {
52754                 cover: false,
52755                 direction: false,
52756                 imagePlane: false,
52757                 keyboard: false,
52758                 mouse: false,
52759                 sequence: false,
52760                 tag: false,
52761                 image: true,
52762                 // fallback
52763                 navigation: true // fallback
52764
52765               };
52766             }
52767
52768             _mlyViewer = new mapillary.Viewer(opts);
52769
52770             _mlyViewer.on('image', imageChanged);
52771
52772             _mlyViewer.on('bearing', bearingChanged);
52773
52774             if (_mlyViewerFilter) {
52775               _mlyViewer.setFilter(_mlyViewerFilter);
52776             } // Register viewer resize handler
52777
52778
52779             context.ui().photoviewer.on('resize.mapillary', function () {
52780               if (_mlyViewer) _mlyViewer.resize();
52781             }); // imageChanged: called after the viewer has changed images and is ready.
52782
52783             function imageChanged(node) {
52784               that.resetTags();
52785               var image = node.image;
52786               that.setActiveImage(image);
52787               that.setStyles(context, null);
52788               var loc = [image.originalLngLat.lng, image.originalLngLat.lat];
52789               context.map().centerEase(loc);
52790               that.updateUrlImage(image.id);
52791
52792               if (_mlyShowFeatureDetections || _mlyShowSignDetections) {
52793                 that.updateDetections(image.id, "".concat(apiUrl, "/").concat(image.id, "/detections?access_token=").concat(accessToken, "&fields=id,image,geometry,value"));
52794               }
52795
52796               dispatch$4.call('imageChanged');
52797             } // bearingChanged: called when the bearing changes in the image viewer.
52798
52799
52800             function bearingChanged(e) {
52801               dispatch$4.call('bearingChanged', undefined, e);
52802             }
52803           },
52804           // Move to an image
52805           selectImage: function selectImage(context, imageId) {
52806             if (_mlyViewer && imageId) {
52807               _mlyViewer.moveTo(imageId)["catch"](function (e) {
52808                 console.error('mly3', e); // eslint-disable-line no-console
52809               });
52810             }
52811
52812             return this;
52813           },
52814           // Return the currently displayed image
52815           getActiveImage: function getActiveImage() {
52816             return _mlyActiveImage;
52817           },
52818           // Return a list of detection objects for the given id
52819           getDetections: function getDetections(id) {
52820             return loadData("".concat(apiUrl, "/").concat(id, "/detections?access_token=").concat(accessToken, "&fields=id,value,image"));
52821           },
52822           // Set the currently visible image
52823           setActiveImage: function setActiveImage(image) {
52824             if (image) {
52825               _mlyActiveImage = {
52826                 ca: image.originalCompassAngle,
52827                 id: image.id,
52828                 loc: [image.originalLngLat.lng, image.originalLngLat.lat],
52829                 is_pano: image.cameraType === 'spherical',
52830                 sequence_id: image.sequenceId
52831               };
52832             } else {
52833               _mlyActiveImage = null;
52834             }
52835           },
52836           // Update the currently highlighted sequence and selected bubble.
52837           setStyles: function setStyles(context, hovered) {
52838             var hoveredImageId = hovered && hovered.id;
52839             var hoveredSequenceId = hovered && hovered.sequence_id;
52840             var selectedSequenceId = _mlyActiveImage && _mlyActiveImage.sequence_id;
52841             context.container().selectAll('.layer-mapillary .viewfield-group').classed('highlighted', function (d) {
52842               return d.sequence_id === selectedSequenceId || d.id === hoveredImageId;
52843             }).classed('hovered', function (d) {
52844               return d.id === hoveredImageId;
52845             });
52846             context.container().selectAll('.layer-mapillary .sequence').classed('highlighted', function (d) {
52847               return d.properties.id === hoveredSequenceId;
52848             }).classed('currentView', function (d) {
52849               return d.properties.id === selectedSequenceId;
52850             });
52851             return this;
52852           },
52853           // Get detections for the current image and shows them in the image viewer
52854           updateDetections: function updateDetections(imageId, url) {
52855             if (!_mlyViewer || _mlyFallback) return;
52856             if (!imageId) return;
52857             var cache = _mlyCache.image_detections;
52858
52859             if (cache.forImageId[imageId]) {
52860               showDetections(_mlyCache.image_detections.forImageId[imageId]);
52861             } else {
52862               loadData(url).then(function (detections) {
52863                 detections.forEach(function (detection) {
52864                   if (!cache.forImageId[imageId]) {
52865                     cache.forImageId[imageId] = [];
52866                   }
52867
52868                   cache.forImageId[imageId].push({
52869                     geometry: detection.geometry,
52870                     id: detection.id,
52871                     image_id: imageId,
52872                     value: detection.value
52873                   });
52874                 });
52875                 showDetections(_mlyCache.image_detections.forImageId[imageId] || []);
52876               });
52877             } // Create a tag for each detection and shows it in the image viewer
52878
52879
52880             function showDetections(detections) {
52881               var tagComponent = _mlyViewer.getComponent('tag');
52882
52883               detections.forEach(function (data) {
52884                 var tag = makeTag(data);
52885
52886                 if (tag) {
52887                   tagComponent.add([tag]);
52888                 }
52889               });
52890             } // Create a Mapillary JS tag object
52891
52892
52893             function makeTag(data) {
52894               var valueParts = data.value.split('--');
52895               if (!valueParts.length) return;
52896               var tag;
52897               var text;
52898               var color = 0xffffff;
52899
52900               if (_mlyHighlightedDetection === data.id) {
52901                 color = 0xffff00;
52902                 text = valueParts[1];
52903
52904                 if (text === 'flat' || text === 'discrete' || text === 'sign') {
52905                   text = valueParts[2];
52906                 }
52907
52908                 text = text.replace(/-/g, ' ');
52909                 text = text.charAt(0).toUpperCase() + text.slice(1);
52910                 _mlyHighlightedDetection = null;
52911               }
52912
52913               var decodedGeometry = window.atob(data.geometry);
52914               var uintArray = new Uint8Array(decodedGeometry.length);
52915
52916               for (var i = 0; i < decodedGeometry.length; i++) {
52917                 uintArray[i] = decodedGeometry.charCodeAt(i);
52918               }
52919
52920               var tile = new VectorTile(new pbf(uintArray.buffer));
52921               var layer = tile.layers['mpy-or'];
52922               var geometries = layer.feature(0).loadGeometry();
52923               var polygon = geometries.map(function (ring) {
52924                 return ring.map(function (point) {
52925                   return [point.x / layer.extent, point.y / layer.extent];
52926                 });
52927               });
52928               tag = new mapillary.OutlineTag(data.id, new mapillary.PolygonGeometry(polygon[0]), {
52929                 text: text,
52930                 textColor: color,
52931                 lineColor: color,
52932                 lineWidth: 2,
52933                 fillColor: color,
52934                 fillOpacity: 0.3
52935               });
52936               return tag;
52937             }
52938           },
52939           // Return the current cache
52940           cache: function cache() {
52941             return _mlyCache;
52942           }
52943         };
52944
52945         function validationIssue(attrs) {
52946           this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag')
52947
52948           this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag')
52949
52950           this.severity = attrs.severity; // required - 'warning' or 'error'
52951
52952           this.message = attrs.message; // required - function returning localized string
52953
52954           this.reference = attrs.reference; // optional - function(selection) to render reference information
52955
52956           this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
52957
52958           this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
52959
52960           this.data = attrs.data; // optional - object containing extra data for the fixes
52961
52962           this.dynamicFixes = attrs.dynamicFixes; // optional - function(context) returning fixes
52963
52964           this.hash = attrs.hash; // optional - string to further differentiate the issue
52965
52966           this.id = generateID.apply(this); // generated - see below
52967
52968           this.key = generateKey.apply(this); // generated - see below (call after generating this.id)
52969
52970           this.autoFix = null; // generated - if autofix exists, will be set below
52971           // A unique, deterministic string hash.
52972           // Issues with identical id values are considered identical.
52973
52974           function generateID() {
52975             var parts = [this.type];
52976
52977             if (this.hash) {
52978               // subclasses can pass in their own differentiator
52979               parts.push(this.hash);
52980             }
52981
52982             if (this.subtype) {
52983               parts.push(this.subtype);
52984             } // include the entities this issue is for
52985             // (sort them so the id is deterministic)
52986
52987
52988             if (this.entityIds) {
52989               var entityKeys = this.entityIds.slice().sort();
52990               parts.push.apply(parts, entityKeys);
52991             }
52992
52993             return parts.join(':');
52994           } // An identifier suitable for use as the second argument to d3.selection#data().
52995           // (i.e. this should change whenever the data needs to be refreshed)
52996
52997
52998           function generateKey() {
52999             return this.id + ':' + Date.now().toString(); // include time of creation
53000           }
53001
53002           this.extent = function (resolver) {
53003             if (this.loc) {
53004               return geoExtent(this.loc);
53005             }
53006
53007             if (this.entityIds && this.entityIds.length) {
53008               return this.entityIds.reduce(function (extent, entityId) {
53009                 return extent.extend(resolver.entity(entityId).extent(resolver));
53010               }, geoExtent());
53011             }
53012
53013             return null;
53014           };
53015
53016           this.fixes = function (context) {
53017             var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
53018             var issue = this;
53019
53020             if (issue.severity === 'warning') {
53021               // allow ignoring any issue that's not an error
53022               fixes.push(new validationIssueFix({
53023                 title: _t.html('issues.fix.ignore_issue.title'),
53024                 icon: 'iD-icon-close',
53025                 onClick: function onClick() {
53026                   context.validator().ignoreIssue(this.issue.id);
53027                 }
53028               }));
53029             }
53030
53031             fixes.forEach(function (fix) {
53032               // the id doesn't matter as long as it's unique to this issue/fix
53033               fix.id = fix.title; // add a reference to the issue for use in actions
53034
53035               fix.issue = issue;
53036
53037               if (fix.autoArgs) {
53038                 issue.autoFix = fix;
53039               }
53040             });
53041             return fixes;
53042           };
53043         }
53044         function validationIssueFix(attrs) {
53045           this.title = attrs.title; // Required
53046
53047           this.onClick = attrs.onClick; // Optional - the function to run to apply the fix
53048
53049           this.disabledReason = attrs.disabledReason; // Optional - a string explaining why the fix is unavailable, if any
53050
53051           this.icon = attrs.icon; // Optional - shows 'iD-icon-wrench' if not set
53052
53053           this.entityIds = attrs.entityIds || []; // Optional - used for hover-higlighting.
53054
53055           this.autoArgs = attrs.autoArgs; // Optional - pass [actions, annotation] arglist if this fix can automatically run
53056
53057           this.issue = null; // Generated link - added by validationIssue
53058         }
53059
53060         var buildRuleChecks = function buildRuleChecks() {
53061           return {
53062             equals: function equals(_equals) {
53063               return function (tags) {
53064                 return Object.keys(_equals).every(function (k) {
53065                   return _equals[k] === tags[k];
53066                 });
53067               };
53068             },
53069             notEquals: function notEquals(_notEquals) {
53070               return function (tags) {
53071                 return Object.keys(_notEquals).some(function (k) {
53072                   return _notEquals[k] !== tags[k];
53073                 });
53074               };
53075             },
53076             absence: function absence(_absence) {
53077               return function (tags) {
53078                 return Object.keys(tags).indexOf(_absence) === -1;
53079               };
53080             },
53081             presence: function presence(_presence) {
53082               return function (tags) {
53083                 return Object.keys(tags).indexOf(_presence) > -1;
53084               };
53085             },
53086             greaterThan: function greaterThan(_greaterThan) {
53087               var key = Object.keys(_greaterThan)[0];
53088               var value = _greaterThan[key];
53089               return function (tags) {
53090                 return tags[key] > value;
53091               };
53092             },
53093             greaterThanEqual: function greaterThanEqual(_greaterThanEqual) {
53094               var key = Object.keys(_greaterThanEqual)[0];
53095               var value = _greaterThanEqual[key];
53096               return function (tags) {
53097                 return tags[key] >= value;
53098               };
53099             },
53100             lessThan: function lessThan(_lessThan) {
53101               var key = Object.keys(_lessThan)[0];
53102               var value = _lessThan[key];
53103               return function (tags) {
53104                 return tags[key] < value;
53105               };
53106             },
53107             lessThanEqual: function lessThanEqual(_lessThanEqual) {
53108               var key = Object.keys(_lessThanEqual)[0];
53109               var value = _lessThanEqual[key];
53110               return function (tags) {
53111                 return tags[key] <= value;
53112               };
53113             },
53114             positiveRegex: function positiveRegex(_positiveRegex) {
53115               var tagKey = Object.keys(_positiveRegex)[0];
53116
53117               var expression = _positiveRegex[tagKey].join('|');
53118
53119               var regex = new RegExp(expression);
53120               return function (tags) {
53121                 return regex.test(tags[tagKey]);
53122               };
53123             },
53124             negativeRegex: function negativeRegex(_negativeRegex) {
53125               var tagKey = Object.keys(_negativeRegex)[0];
53126
53127               var expression = _negativeRegex[tagKey].join('|');
53128
53129               var regex = new RegExp(expression);
53130               return function (tags) {
53131                 return !regex.test(tags[tagKey]);
53132               };
53133             }
53134           };
53135         };
53136
53137         var buildLineKeys = function buildLineKeys() {
53138           return {
53139             highway: {
53140               rest_area: true,
53141               services: true
53142             },
53143             railway: {
53144               roundhouse: true,
53145               station: true,
53146               traverser: true,
53147               turntable: true,
53148               wash: true
53149             }
53150           };
53151         };
53152
53153         var serviceMapRules = {
53154           init: function init() {
53155             this._ruleChecks = buildRuleChecks();
53156             this._validationRules = [];
53157             this._areaKeys = osmAreaKeys;
53158             this._lineKeys = buildLineKeys();
53159           },
53160           // list of rules only relevant to tag checks...
53161           filterRuleChecks: function filterRuleChecks(selector) {
53162             var _ruleChecks = this._ruleChecks;
53163             return Object.keys(selector).reduce(function (rules, key) {
53164               if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
53165                 rules.push(_ruleChecks[key](selector[key]));
53166               }
53167
53168               return rules;
53169             }, []);
53170           },
53171           // builds tagMap from mapcss-parse selector object...
53172           buildTagMap: function buildTagMap(selector) {
53173             var getRegexValues = function getRegexValues(regexes) {
53174               return regexes.map(function (regex) {
53175                 return regex.replace(/\$|\^/g, '');
53176               });
53177             };
53178
53179             var tagMap = Object.keys(selector).reduce(function (expectedTags, key) {
53180               var values;
53181               var isRegex = /regex/gi.test(key);
53182               var isEqual = /equals/gi.test(key);
53183
53184               if (isRegex || isEqual) {
53185                 Object.keys(selector[key]).forEach(function (selectorKey) {
53186                   values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
53187
53188                   if (expectedTags.hasOwnProperty(selectorKey)) {
53189                     values = values.concat(expectedTags[selectorKey]);
53190                   }
53191
53192                   expectedTags[selectorKey] = values;
53193                 });
53194               } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
53195                 var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
53196                 values = [selector[key][tagKey]];
53197
53198                 if (expectedTags.hasOwnProperty(tagKey)) {
53199                   values = values.concat(expectedTags[tagKey]);
53200                 }
53201
53202                 expectedTags[tagKey] = values;
53203               }
53204
53205               return expectedTags;
53206             }, {});
53207             return tagMap;
53208           },
53209           // inspired by osmWay#isArea()
53210           inferGeometry: function inferGeometry(tagMap) {
53211             var _lineKeys = this._lineKeys;
53212             var _areaKeys = this._areaKeys;
53213
53214             var keyValueDoesNotImplyArea = function keyValueDoesNotImplyArea(key) {
53215               return utilArrayIntersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
53216             };
53217
53218             var keyValueImpliesLine = function keyValueImpliesLine(key) {
53219               return utilArrayIntersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
53220             };
53221
53222             if (tagMap.hasOwnProperty('area')) {
53223               if (tagMap.area.indexOf('yes') > -1) {
53224                 return 'area';
53225               }
53226
53227               if (tagMap.area.indexOf('no') > -1) {
53228                 return 'line';
53229               }
53230             }
53231
53232             for (var key in tagMap) {
53233               if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
53234                 return 'area';
53235               }
53236
53237               if (key in _lineKeys && keyValueImpliesLine(key)) {
53238                 return 'area';
53239               }
53240             }
53241
53242             return 'line';
53243           },
53244           // adds from mapcss-parse selector check...
53245           addRule: function addRule(selector) {
53246             var rule = {
53247               // checks relevant to mapcss-selector
53248               checks: this.filterRuleChecks(selector),
53249               // true if all conditions for a tag error are true..
53250               matches: function matches(entity) {
53251                 return this.checks.every(function (check) {
53252                   return check(entity.tags);
53253                 });
53254               },
53255               // borrowed from Way#isArea()
53256               inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
53257               geometryMatches: function geometryMatches(entity, graph) {
53258                 if (entity.type === 'node' || entity.type === 'relation') {
53259                   return selector.geometry === entity.type;
53260                 } else if (entity.type === 'way') {
53261                   return this.inferredGeometry === entity.geometry(graph);
53262                 }
53263               },
53264               // when geometries match and tag matches are present, return a warning...
53265               findIssues: function findIssues(entity, graph, issues) {
53266                 if (this.geometryMatches(entity, graph) && this.matches(entity)) {
53267                   var severity = Object.keys(selector).indexOf('error') > -1 ? 'error' : 'warning';
53268                   var _message = selector[severity];
53269                   issues.push(new validationIssue({
53270                     type: 'maprules',
53271                     severity: severity,
53272                     message: function message() {
53273                       return _message;
53274                     },
53275                     entityIds: [entity.id]
53276                   }));
53277                 }
53278               }
53279             };
53280
53281             this._validationRules.push(rule);
53282           },
53283           clearRules: function clearRules() {
53284             this._validationRules = [];
53285           },
53286           // returns validationRules...
53287           validationRules: function validationRules() {
53288             return this._validationRules;
53289           },
53290           // returns ruleChecks
53291           ruleChecks: function ruleChecks() {
53292             return this._ruleChecks;
53293           }
53294         };
53295
53296         var apibase$2 = 'https://nominatim.openstreetmap.org/';
53297         var _inflight$2 = {};
53298
53299         var _nominatimCache;
53300
53301         var serviceNominatim = {
53302           init: function init() {
53303             _inflight$2 = {};
53304             _nominatimCache = new RBush();
53305           },
53306           reset: function reset() {
53307             Object.values(_inflight$2).forEach(function (controller) {
53308               controller.abort();
53309             });
53310             _inflight$2 = {};
53311             _nominatimCache = new RBush();
53312           },
53313           countryCode: function countryCode(location, callback) {
53314             this.reverse(location, function (err, result) {
53315               if (err) {
53316                 return callback(err);
53317               } else if (result.address) {
53318                 return callback(null, result.address.country_code);
53319               } else {
53320                 return callback('Unable to geocode', null);
53321               }
53322             });
53323           },
53324           reverse: function reverse(loc, callback) {
53325             var cached = _nominatimCache.search({
53326               minX: loc[0],
53327               minY: loc[1],
53328               maxX: loc[0],
53329               maxY: loc[1]
53330             });
53331
53332             if (cached.length > 0) {
53333               if (callback) callback(null, cached[0].data);
53334               return;
53335             }
53336
53337             var params = {
53338               zoom: 13,
53339               format: 'json',
53340               addressdetails: 1,
53341               lat: loc[1],
53342               lon: loc[0]
53343             };
53344             var url = apibase$2 + 'reverse?' + utilQsString(params);
53345             if (_inflight$2[url]) return;
53346             var controller = new AbortController();
53347             _inflight$2[url] = controller;
53348             d3_json(url, {
53349               signal: controller.signal
53350             }).then(function (result) {
53351               delete _inflight$2[url];
53352
53353               if (result && result.error) {
53354                 throw new Error(result.error);
53355               }
53356
53357               var extent = geoExtent(loc).padByMeters(200);
53358
53359               _nominatimCache.insert(Object.assign(extent.bbox(), {
53360                 data: result
53361               }));
53362
53363               if (callback) callback(null, result);
53364             })["catch"](function (err) {
53365               delete _inflight$2[url];
53366               if (err.name === 'AbortError') return;
53367               if (callback) callback(err.message);
53368             });
53369           },
53370           search: function search(val, callback) {
53371             var searchVal = encodeURIComponent(val);
53372             var url = apibase$2 + 'search/' + searchVal + '?limit=10&format=json';
53373             if (_inflight$2[url]) return;
53374             var controller = new AbortController();
53375             _inflight$2[url] = controller;
53376             d3_json(url, {
53377               signal: controller.signal
53378             }).then(function (result) {
53379               delete _inflight$2[url];
53380
53381               if (result && result.error) {
53382                 throw new Error(result.error);
53383               }
53384
53385               if (callback) callback(null, result);
53386             })["catch"](function (err) {
53387               delete _inflight$2[url];
53388               if (err.name === 'AbortError') return;
53389               if (callback) callback(err.message);
53390             });
53391           }
53392         };
53393
53394         // for punction see https://stackoverflow.com/a/21224179
53395
53396         function simplify$1(str) {
53397           if (typeof str !== 'string') return '';
53398           return diacritics.remove(str.replace(/&/g, 'and').replace(/İ/ig, 'i') // for BİM, İşbank - #5017
53399           .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());
53400         }
53401
53402         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"]};
53403         var matchGroupsJSON = {
53404         matchGroups: matchGroups$1
53405         };
53406
53407         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$","^церковная( лавка)?$"];
53408         var genericWordsJSON = {
53409         genericWords: genericWords
53410         };
53411
53412         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+)$"}}};
53413         var treesJSON = {
53414         trees: trees$1
53415         };
53416
53417         var matchGroups = matchGroupsJSON.matchGroups;
53418         var trees = treesJSON.trees;
53419         var Matcher = /*#__PURE__*/function () {
53420           //
53421           // `constructor`
53422           // initialize the genericWords regexes
53423           function Matcher() {
53424             var _this = this;
53425
53426             _classCallCheck$1(this, Matcher);
53427
53428             // The `matchIndex` is a specialized structure that allows us to quickly answer
53429             //   _"Given a [key/value tagpair, name, location], what canonical items (brands etc) can match it?"_
53430             //
53431             // The index contains all valid combinations of k/v tagpairs and names
53432             // matchIndex:
53433             // {
53434             //   'k/v': {
53435             //     'primary':         Map (String 'nsimple' -> Set (itemIDs…),   // matches for tags like `name`, `name:xx`, etc.
53436             //     'alternate':       Map (String 'nsimple' -> Set (itemIDs…),   // matches for tags like `alt_name`, `brand`, etc.
53437             //     'excludeNamed':    Map (String 'pattern' -> RegExp),
53438             //     'excludeGeneric':  Map (String 'pattern' -> RegExp)
53439             //   },
53440             // }
53441             //
53442             // {
53443             //   'amenity/bank': {
53444             //     'primary': {
53445             //       'firstbank':              Set ("firstbank-978cca", "firstbank-9794e6", "firstbank-f17495", …),
53446             //       …
53447             //     },
53448             //     'alternate': {
53449             //       '1stbank':                Set ("firstbank-f17495"),
53450             //       …
53451             //     }
53452             //   },
53453             //   'shop/supermarket': {
53454             //     'primary': {
53455             //       'coop':                   Set ("coop-76454b", "coop-ebf2d9", "coop-36e991", …),
53456             //       'coopfood':               Set ("coopfood-a8278b", …),
53457             //       …
53458             //     },
53459             //     'alternate': {
53460             //       'coop':                   Set ("coopfood-a8278b", …),
53461             //       'federatedcooperatives':  Set ("coop-76454b", …),
53462             //       'thecooperative':         Set ("coopfood-a8278b", …),
53463             //       …
53464             //     }
53465             //   }
53466             // }
53467             //
53468             this.matchIndex = undefined; // The `genericWords` structure matches the contents of genericWords.json to instantiated RegExp objects
53469             // Map (String 'pattern' -> RegExp),
53470
53471             this.genericWords = new Map();
53472             (genericWordsJSON.genericWords || []).forEach(function (s) {
53473               return _this.genericWords.set(s, new RegExp(s, 'i'));
53474             }); // The `itemLocation` structure maps itemIDs to locationSetIDs:
53475             // {
53476             //   'firstbank-f17495':  '+[first_bank_western_us.geojson]',
53477             //   'firstbank-978cca':  '+[first_bank_carolinas.geojson]',
53478             //   'coop-76454b':       '+[Q16]',
53479             //   'coopfood-a8278b':   '+[Q23666]',
53480             //   …
53481             // }
53482
53483             this.itemLocation = undefined; // The `locationSets` structure maps locationSetIDs to *resolved* locationSets:
53484             // {
53485             //   '+[first_bank_western_us.geojson]':  GeoJSON {…},
53486             //   '+[first_bank_carolinas.geojson]':   GeoJSON {…},
53487             //   '+[Q16]':                            GeoJSON {…},
53488             //   '+[Q23666]':                         GeoJSON {…},
53489             //   …
53490             // }
53491
53492             this.locationSets = undefined; // The `locationIndex` is an instance of which-polygon spatial index for the locationSets.
53493
53494             this.locationIndex = undefined; // Array of match conflict pairs (currently unused)
53495
53496             this.warnings = [];
53497           } //
53498           // `buildMatchIndex()`
53499           // Call this to prepare the matcher for use
53500           //
53501           // `data` needs to be an Object indexed on a 'tree/key/value' path.
53502           // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
53503           // {
53504           //    'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
53505           //    'brands/amenity/bar':  { properties: {}, items: [ {}, {}, … ] },
53506           //    …
53507           // }
53508           //
53509
53510
53511           _createClass$1(Matcher, [{
53512             key: "buildMatchIndex",
53513             value: function buildMatchIndex(data) {
53514               var that = this;
53515               if (that.matchIndex) return; // it was built already
53516
53517               that.matchIndex = new Map();
53518               Object.keys(data).forEach(function (tkv) {
53519                 var category = data[tkv];
53520                 var parts = tkv.split('/', 3); // tkv = "tree/key/value"
53521
53522                 var t = parts[0];
53523                 var k = parts[1];
53524                 var v = parts[2];
53525                 var thiskv = "".concat(k, "/").concat(v);
53526                 var tree = trees[t];
53527                 var branch = that.matchIndex.get(thiskv);
53528
53529                 if (!branch) {
53530                   branch = {
53531                     primary: new Map(),
53532                     alternate: new Map(),
53533                     excludeGeneric: new Map(),
53534                     excludeNamed: new Map()
53535                   };
53536                   that.matchIndex.set(thiskv, branch);
53537                 } // ADD EXCLUSIONS
53538
53539
53540                 var properties = category.properties || {};
53541                 var exclude = properties.exclude || {};
53542                 (exclude.generic || []).forEach(function (s) {
53543                   return branch.excludeGeneric.set(s, new RegExp(s, 'i'));
53544                 });
53545                 (exclude.named || []).forEach(function (s) {
53546                   return branch.excludeNamed.set(s, new RegExp(s, 'i'));
53547                 });
53548                 var excludeRegexes = [].concat(_toConsumableArray(branch.excludeGeneric.values()), _toConsumableArray(branch.excludeNamed.values())); // ADD ITEMS
53549
53550                 var items = category.items;
53551                 if (!Array.isArray(items) || !items.length) return; // Primary name patterns, match tags to take first
53552                 //  e.g. `name`, `name:ru`
53553
53554                 var primaryName = new RegExp(tree.nameTags.primary, 'i'); // Alternate name patterns, match tags to consider after primary
53555                 //  e.g. `alt_name`, `short_name`, `brand`, `brand:ru`, etc..
53556
53557                 var alternateName = new RegExp(tree.nameTags.alternate, 'i'); // There are a few exceptions to the name matching regexes.
53558                 // Usually a tag suffix contains a language code like `name:en`, `name:ru`
53559                 // but we want to exclude things like `operator:type`, `name:etymology`, etc..
53560
53561                 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`
53562
53563                 var skipGenericKV = skipGenericKVMatches(t, k, v); // We will collect the generic KV pairs anyway (for the purpose of filtering them out of matchTags)
53564
53565                 var genericKV = new Set(["".concat(k, "/yes"), "building/yes"]); // Collect alternate tagpairs for this kv category from matchGroups.
53566                 // We might also pick up a few more generic KVs (like `shop/yes`)
53567
53568                 var matchGroupKV = new Set();
53569                 Object.values(matchGroups).forEach(function (matchGroup) {
53570                   var inGroup = matchGroup.some(function (otherkv) {
53571                     return otherkv === thiskv;
53572                   });
53573                   if (!inGroup) return;
53574                   matchGroup.forEach(function (otherkv) {
53575                     if (otherkv === thiskv) return; // skip self
53576
53577                     matchGroupKV.add(otherkv);
53578                     var otherk = otherkv.split('/', 2)[0]; // we might pick up a `shop/yes`
53579
53580                     genericKV.add("".concat(otherk, "/yes"));
53581                   });
53582                 }); // For each item, insert all [key, value, name] combinations into the match index
53583
53584                 items.forEach(function (item) {
53585                   if (!item.id) return; // Automatically remove redundant `matchTags` - #3417
53586                   // (i.e. This kv is already covered by matchGroups, so it doesn't need to be in `item.matchTags`)
53587
53588                   if (Array.isArray(item.matchTags) && item.matchTags.length) {
53589                     item.matchTags = item.matchTags.filter(function (matchTag) {
53590                       return !matchGroupKV.has(matchTag) && !genericKV.has(matchTag);
53591                     });
53592                     if (!item.matchTags.length) delete item.matchTags;
53593                   } // key/value tagpairs to insert into the match index..
53594
53595
53596                   var kvTags = ["".concat(thiskv)].concat(item.matchTags || []);
53597
53598                   if (!skipGenericKV) {
53599                     kvTags = kvTags.concat(Array.from(genericKV)); // #3454 - match some generic tags
53600                   } // Index all the namelike tag values
53601
53602
53603                   Object.keys(item.tags).forEach(function (osmkey) {
53604                     if (notName.test(osmkey)) return; // osmkey is not a namelike tag, skip
53605
53606                     var osmvalue = item.tags[osmkey];
53607                     if (!osmvalue || excludeRegexes.some(function (regex) {
53608                       return regex.test(osmvalue);
53609                     })) return; // osmvalue missing or excluded
53610
53611                     if (primaryName.test(osmkey)) {
53612                       kvTags.forEach(function (kv) {
53613                         return insertName('primary', kv, simplify$1(osmvalue), item.id);
53614                       });
53615                     } else if (alternateName.test(osmkey)) {
53616                       kvTags.forEach(function (kv) {
53617                         return insertName('alternate', kv, simplify$1(osmvalue), item.id);
53618                       });
53619                     }
53620                   }); // Index `matchNames` after indexing all other names..
53621
53622                   var keepMatchNames = new Set();
53623                   (item.matchNames || []).forEach(function (matchName) {
53624                     // If this matchname isn't already indexed, add it to the alternate index
53625                     var nsimple = simplify$1(matchName);
53626                     kvTags.forEach(function (kv) {
53627                       var branch = that.matchIndex.get(kv);
53628                       var primaryLeaf = branch && branch.primary.get(nsimple);
53629                       var alternateLeaf = branch && branch.alternate.get(nsimple);
53630                       var inPrimary = primaryLeaf && primaryLeaf.has(item.id);
53631                       var inAlternate = alternateLeaf && alternateLeaf.has(item.id);
53632
53633                       if (!inPrimary && !inAlternate) {
53634                         insertName('alternate', kv, nsimple, item.id);
53635                         keepMatchNames.add(matchName);
53636                       }
53637                     });
53638                   }); // Automatically remove redundant `matchNames` - #3417
53639                   // (i.e. This name got indexed some other way, so it doesn't need to be in `item.matchNames`)
53640
53641                   if (keepMatchNames.size) {
53642                     item.matchNames = Array.from(keepMatchNames);
53643                   } else {
53644                     delete item.matchNames;
53645                   }
53646                 }); // each item
53647               }); // each tkv
53648               // Insert this item into the matchIndex
53649
53650               function insertName(which, kv, nsimple, itemID) {
53651                 if (!nsimple) return;
53652                 var branch = that.matchIndex.get(kv);
53653
53654                 if (!branch) {
53655                   branch = {
53656                     primary: new Map(),
53657                     alternate: new Map(),
53658                     excludeGeneric: new Map(),
53659                     excludeNamed: new Map()
53660                   };
53661                   that.matchIndex.set(kv, branch);
53662                 }
53663
53664                 var leaf = branch[which].get(nsimple);
53665
53666                 if (!leaf) {
53667                   leaf = new Set();
53668                   branch[which].set(nsimple, leaf);
53669                 }
53670
53671                 leaf.add(itemID); // insert
53672               } // For certain categories we do not want to match generic KV pairs like `building/yes` or `amenity/yes`
53673
53674
53675               function skipGenericKVMatches(t, k, v) {
53676                 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';
53677               }
53678             } //
53679             // `buildLocationIndex()`
53680             // Call this to prepare a which-polygon location index.
53681             // This *resolves* all the locationSets into GeoJSON, which takes some time.
53682             // You can skip this step if you don't care about matching within a location.
53683             //
53684             // `data` needs to be an Object indexed on a 'tree/key/value' path.
53685             // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
53686             // {
53687             //    'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
53688             //    'brands/amenity/bar':  { properties: {}, items: [ {}, {}, … ] },
53689             //    …
53690             // }
53691             //
53692
53693           }, {
53694             key: "buildLocationIndex",
53695             value: function buildLocationIndex(data, loco) {
53696               var that = this;
53697               if (that.locationIndex) return; // it was built already
53698
53699               that.itemLocation = new Map();
53700               that.locationSets = new Map();
53701               Object.keys(data).forEach(function (tkv) {
53702                 var items = data[tkv].items;
53703                 if (!Array.isArray(items) || !items.length) return;
53704                 items.forEach(function (item) {
53705                   if (that.itemLocation.has(item.id)) return; // we've seen item id already - shouldn't be possible?
53706
53707                   var resolved;
53708
53709                   try {
53710                     resolved = loco.resolveLocationSet(item.locationSet); // resolve a feature for this locationSet
53711                   } catch (err) {
53712                     console.warn("buildLocationIndex: ".concat(err.message)); // couldn't resolve
53713                   }
53714
53715                   if (!resolved || !resolved.id) return;
53716                   that.itemLocation.set(item.id, resolved.id); // link it to the item
53717
53718                   if (that.locationSets.has(resolved.id)) return; // we've seen this locationSet feature before..
53719                   // First time seeing this locationSet feature, make a copy and add to locationSet cache..
53720
53721                   var feature = _cloneDeep(resolved.feature);
53722
53723                   feature.id = resolved.id; // Important: always use the locationSet `id` (`+[Q30]`), not the feature `id` (`Q30`)
53724
53725                   feature.properties.id = resolved.id;
53726
53727                   if (!feature.geometry.coordinates.length || !feature.properties.area) {
53728                     console.warn("buildLocationIndex: locationSet ".concat(resolved.id, " for ").concat(item.id, " resolves to an empty feature:"));
53729                     console.warn(JSON.stringify(feature));
53730                     return;
53731                   }
53732
53733                   that.locationSets.set(resolved.id, feature);
53734                 });
53735               });
53736               that.locationIndex = whichPolygon_1({
53737                 type: 'FeatureCollection',
53738                 features: _toConsumableArray(that.locationSets.values())
53739               });
53740
53741               function _cloneDeep(obj) {
53742                 return JSON.parse(JSON.stringify(obj));
53743               }
53744             } //
53745             // `match()`
53746             // Pass parts and return an Array of matches.
53747             // `k` - key
53748             // `v` - value
53749             // `n` - namelike
53750             // `loc` - optional - [lon,lat] location to search
53751             //
53752             // 1. If the [k,v,n] tuple matches a canonical item…
53753             // Return an Array of match results.
53754             // Each result will include the area in km² that the item is valid.
53755             //
53756             // Order of results:
53757             // Primary ordering will be on the "match" column:
53758             //   "primary" - where the query matches the `name` tag, followed by
53759             //   "alternate" - where the query matches an alternate name tag (e.g. short_name, brand, operator, etc)
53760             // Secondary ordering will be on the "area" column:
53761             //   "area descending" if no location was provided, (worldwide before local)
53762             //   "area ascending" if location was provided (local before worldwide)
53763             //
53764             // [
53765             //   { match: 'primary',   itemID: String,  area: Number,  kv: String,  nsimple: String },
53766             //   { match: 'primary',   itemID: String,  area: Number,  kv: String,  nsimple: String },
53767             //   { match: 'alternate', itemID: String,  area: Number,  kv: String,  nsimple: String },
53768             //   { match: 'alternate', itemID: String,  area: Number,  kv: String,  nsimple: String },
53769             //   …
53770             // ]
53771             //
53772             // -or-
53773             //
53774             // 2. If the [k,v,n] tuple matches an exclude pattern…
53775             // Return an Array with a single exclude result, either
53776             //
53777             // [ { match: 'excludeGeneric', pattern: String,  kv: String } ]  // "generic" e.g. "Food Court"
53778             //   or
53779             // [ { match: 'excludeNamed', pattern: String,  kv: String } ]    // "named", e.g. "Kebabai"
53780             //
53781             // About results
53782             //   "generic" - a generic word that is probably not really a name.
53783             //     For these, iD should warn the user "Hey don't put 'food court' in the name tag".
53784             //   "named" - a real name like "Kebabai" that is just common, but not a brand.
53785             //     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.
53786             //
53787             // -or-
53788             //
53789             // 3. If the [k,v,n] tuple matches nothing of any kind, return `null`
53790             //
53791             //
53792
53793           }, {
53794             key: "match",
53795             value: function match(k, v, n, loc) {
53796               var that = this;
53797
53798               if (!that.matchIndex) {
53799                 throw new Error('match:  matchIndex not built.');
53800               } // If we were supplied a location, and a that.locationIndex has been set up,
53801               // get the locationSets that are valid there so we can filter results.
53802
53803
53804               var matchLocations;
53805
53806               if (Array.isArray(loc) && that.locationIndex) {
53807                 // which-polygon query returns an array of GeoJSON properties, pass true to return all results
53808                 matchLocations = that.locationIndex([loc[0], loc[1], loc[0], loc[1]], true);
53809               }
53810
53811               var nsimple = simplify$1(n);
53812               var seen = new Set();
53813               var results = [];
53814               gatherResults('primary');
53815               gatherResults('alternate');
53816               if (results.length) return results;
53817               gatherResults('exclude');
53818               return results.length ? results : null;
53819
53820               function gatherResults(which) {
53821                 // First try an exact match on k/v
53822                 var kv = "".concat(k, "/").concat(v);
53823                 var didMatch = tryMatch(which, kv);
53824                 if (didMatch) return; // If that didn't work, look in match groups for other pairs considered equivalent to k/v..
53825
53826                 for (var mg in matchGroups) {
53827                   var matchGroup = matchGroups[mg];
53828                   var inGroup = matchGroup.some(function (otherkv) {
53829                     return otherkv === kv;
53830                   });
53831                   if (!inGroup) continue;
53832
53833                   for (var i = 0; i < matchGroup.length; i++) {
53834                     var otherkv = matchGroup[i];
53835                     if (otherkv === kv) continue; // skip self
53836
53837                     didMatch = tryMatch(which, otherkv);
53838                     if (didMatch) return;
53839                   }
53840                 } // If finished 'exclude' pass and still haven't matched anything, try the global `genericWords.json` patterns
53841
53842
53843                 if (which === 'exclude') {
53844                   var regex = _toConsumableArray(that.genericWords.values()).find(function (regex) {
53845                     return regex.test(n);
53846                   });
53847
53848                   if (regex) {
53849                     results.push({
53850                       match: 'excludeGeneric',
53851                       pattern: String(regex)
53852                     }); // note no `branch`, no `kv`
53853
53854                     return;
53855                   }
53856                 }
53857               }
53858
53859               function tryMatch(which, kv) {
53860                 var branch = that.matchIndex.get(kv);
53861                 if (!branch) return;
53862
53863                 if (which === 'exclude') {
53864                   // Test name `n` against named and generic exclude patterns
53865                   var regex = _toConsumableArray(branch.excludeNamed.values()).find(function (regex) {
53866                     return regex.test(n);
53867                   });
53868
53869                   if (regex) {
53870                     results.push({
53871                       match: 'excludeNamed',
53872                       pattern: String(regex),
53873                       kv: kv
53874                     });
53875                     return;
53876                   }
53877
53878                   regex = _toConsumableArray(branch.excludeGeneric.values()).find(function (regex) {
53879                     return regex.test(n);
53880                   });
53881
53882                   if (regex) {
53883                     results.push({
53884                       match: 'excludeGeneric',
53885                       pattern: String(regex),
53886                       kv: kv
53887                     });
53888                     return;
53889                   }
53890
53891                   return;
53892                 }
53893
53894                 var leaf = branch[which].get(nsimple);
53895                 if (!leaf || !leaf.size) return; // If we get here, we matched something..
53896                 // Prepare the results, calculate areas (if location index was set up)
53897
53898                 var hits = Array.from(leaf).map(function (itemID) {
53899                   var area = Infinity;
53900
53901                   if (that.itemLocation && that.locationSets) {
53902                     var location = that.locationSets.get(that.itemLocation.get(itemID));
53903                     area = location && location.properties.area || Infinity;
53904                   }
53905
53906                   return {
53907                     match: which,
53908                     itemID: itemID,
53909                     area: area,
53910                     kv: kv,
53911                     nsimple: nsimple
53912                   };
53913                 });
53914                 var sortFn = byAreaDescending; // Filter the match to include only results valid in the requested `loc`..
53915
53916                 if (matchLocations) {
53917                   hits = hits.filter(isValidLocation);
53918                   sortFn = byAreaAscending;
53919                 }
53920
53921                 if (!hits.length) return; // push results
53922
53923                 hits.sort(sortFn).forEach(function (hit) {
53924                   if (seen.has(hit.itemID)) return;
53925                   seen.add(hit.itemID);
53926                   results.push(hit);
53927                 });
53928                 return true;
53929
53930                 function isValidLocation(hit) {
53931                   if (!that.itemLocation) return true;
53932                   return matchLocations.find(function (props) {
53933                     return props.id === that.itemLocation.get(hit.itemID);
53934                   });
53935                 } // Sort smaller (more local) locations first.
53936
53937
53938                 function byAreaAscending(hitA, hitB) {
53939                   return hitA.area - hitB.area;
53940                 } // Sort larger (more worldwide) locations first.
53941
53942
53943                 function byAreaDescending(hitA, hitB) {
53944                   return hitB.area - hitA.area;
53945                 }
53946               }
53947             } //
53948             // `getWarnings()`
53949             // Return any warnings discovered when buiding the index.
53950             // (currently this does nothing)
53951             //
53952
53953           }, {
53954             key: "getWarnings",
53955             value: function getWarnings() {
53956               return this.warnings;
53957             }
53958           }]);
53959
53960           return Matcher;
53961         }();
53962
53963         /**
53964          * Checks if `value` is the
53965          * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
53966          * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
53967          *
53968          * @static
53969          * @memberOf _
53970          * @since 0.1.0
53971          * @category Lang
53972          * @param {*} value The value to check.
53973          * @returns {boolean} Returns `true` if `value` is an object, else `false`.
53974          * @example
53975          *
53976          * _.isObject({});
53977          * // => true
53978          *
53979          * _.isObject([1, 2, 3]);
53980          * // => true
53981          *
53982          * _.isObject(_.noop);
53983          * // => true
53984          *
53985          * _.isObject(null);
53986          * // => false
53987          */
53988         function isObject$2(value) {
53989           var type = _typeof(value);
53990
53991           return value != null && (type == 'object' || type == 'function');
53992         }
53993
53994         /** Detect free variable `global` from Node.js. */
53995         var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) == 'object' && global && global.Object === Object && global;
53996
53997         /** Detect free variable `self`. */
53998
53999         var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self;
54000         /** Used as a reference to the global object. */
54001
54002         var root = freeGlobal || freeSelf || Function('return this')();
54003
54004         /**
54005          * Gets the timestamp of the number of milliseconds that have elapsed since
54006          * the Unix epoch (1 January 1970 00:00:00 UTC).
54007          *
54008          * @static
54009          * @memberOf _
54010          * @since 2.4.0
54011          * @category Date
54012          * @returns {number} Returns the timestamp.
54013          * @example
54014          *
54015          * _.defer(function(stamp) {
54016          *   console.log(_.now() - stamp);
54017          * }, _.now());
54018          * // => Logs the number of milliseconds it took for the deferred invocation.
54019          */
54020
54021         var now = function now() {
54022           return root.Date.now();
54023         };
54024
54025         /** Used to match a single whitespace character. */
54026         var reWhitespace = /\s/;
54027         /**
54028          * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
54029          * character of `string`.
54030          *
54031          * @private
54032          * @param {string} string The string to inspect.
54033          * @returns {number} Returns the index of the last non-whitespace character.
54034          */
54035
54036         function trimmedEndIndex(string) {
54037           var index = string.length;
54038
54039           while (index-- && reWhitespace.test(string.charAt(index))) {}
54040
54041           return index;
54042         }
54043
54044         /** Used to match leading whitespace. */
54045
54046         var reTrimStart = /^\s+/;
54047         /**
54048          * The base implementation of `_.trim`.
54049          *
54050          * @private
54051          * @param {string} string The string to trim.
54052          * @returns {string} Returns the trimmed string.
54053          */
54054
54055         function baseTrim(string) {
54056           return string ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') : string;
54057         }
54058
54059         /** Built-in value references. */
54060
54061         var _Symbol = root.Symbol;
54062
54063         /** Used for built-in method references. */
54064
54065         var objectProto$1 = Object.prototype;
54066         /** Used to check objects for own properties. */
54067
54068         var hasOwnProperty$2 = objectProto$1.hasOwnProperty;
54069         /**
54070          * Used to resolve the
54071          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
54072          * of values.
54073          */
54074
54075         var nativeObjectToString$1 = objectProto$1.toString;
54076         /** Built-in value references. */
54077
54078         var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
54079         /**
54080          * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
54081          *
54082          * @private
54083          * @param {*} value The value to query.
54084          * @returns {string} Returns the raw `toStringTag`.
54085          */
54086
54087         function getRawTag(value) {
54088           var isOwn = hasOwnProperty$2.call(value, symToStringTag$1),
54089               tag = value[symToStringTag$1];
54090
54091           try {
54092             value[symToStringTag$1] = undefined;
54093             var unmasked = true;
54094           } catch (e) {}
54095
54096           var result = nativeObjectToString$1.call(value);
54097
54098           if (unmasked) {
54099             if (isOwn) {
54100               value[symToStringTag$1] = tag;
54101             } else {
54102               delete value[symToStringTag$1];
54103             }
54104           }
54105
54106           return result;
54107         }
54108
54109         /** Used for built-in method references. */
54110         var objectProto = Object.prototype;
54111         /**
54112          * Used to resolve the
54113          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
54114          * of values.
54115          */
54116
54117         var nativeObjectToString = objectProto.toString;
54118         /**
54119          * Converts `value` to a string using `Object.prototype.toString`.
54120          *
54121          * @private
54122          * @param {*} value The value to convert.
54123          * @returns {string} Returns the converted string.
54124          */
54125
54126         function objectToString(value) {
54127           return nativeObjectToString.call(value);
54128         }
54129
54130         /** `Object#toString` result references. */
54131
54132         var nullTag = '[object Null]',
54133             undefinedTag = '[object Undefined]';
54134         /** Built-in value references. */
54135
54136         var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
54137         /**
54138          * The base implementation of `getTag` without fallbacks for buggy environments.
54139          *
54140          * @private
54141          * @param {*} value The value to query.
54142          * @returns {string} Returns the `toStringTag`.
54143          */
54144
54145         function baseGetTag(value) {
54146           if (value == null) {
54147             return value === undefined ? undefinedTag : nullTag;
54148           }
54149
54150           return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value);
54151         }
54152
54153         /**
54154          * Checks if `value` is object-like. A value is object-like if it's not `null`
54155          * and has a `typeof` result of "object".
54156          *
54157          * @static
54158          * @memberOf _
54159          * @since 4.0.0
54160          * @category Lang
54161          * @param {*} value The value to check.
54162          * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
54163          * @example
54164          *
54165          * _.isObjectLike({});
54166          * // => true
54167          *
54168          * _.isObjectLike([1, 2, 3]);
54169          * // => true
54170          *
54171          * _.isObjectLike(_.noop);
54172          * // => false
54173          *
54174          * _.isObjectLike(null);
54175          * // => false
54176          */
54177         function isObjectLike(value) {
54178           return value != null && _typeof(value) == 'object';
54179         }
54180
54181         /** `Object#toString` result references. */
54182
54183         var symbolTag = '[object Symbol]';
54184         /**
54185          * Checks if `value` is classified as a `Symbol` primitive or object.
54186          *
54187          * @static
54188          * @memberOf _
54189          * @since 4.0.0
54190          * @category Lang
54191          * @param {*} value The value to check.
54192          * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
54193          * @example
54194          *
54195          * _.isSymbol(Symbol.iterator);
54196          * // => true
54197          *
54198          * _.isSymbol('abc');
54199          * // => false
54200          */
54201
54202         function isSymbol(value) {
54203           return _typeof(value) == 'symbol' || isObjectLike(value) && baseGetTag(value) == symbolTag;
54204         }
54205
54206         /** Used as references for various `Number` constants. */
54207
54208         var NAN = 0 / 0;
54209         /** Used to detect bad signed hexadecimal string values. */
54210
54211         var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
54212         /** Used to detect binary string values. */
54213
54214         var reIsBinary = /^0b[01]+$/i;
54215         /** Used to detect octal string values. */
54216
54217         var reIsOctal = /^0o[0-7]+$/i;
54218         /** Built-in method references without a dependency on `root`. */
54219
54220         var freeParseInt = parseInt;
54221         /**
54222          * Converts `value` to a number.
54223          *
54224          * @static
54225          * @memberOf _
54226          * @since 4.0.0
54227          * @category Lang
54228          * @param {*} value The value to process.
54229          * @returns {number} Returns the number.
54230          * @example
54231          *
54232          * _.toNumber(3.2);
54233          * // => 3.2
54234          *
54235          * _.toNumber(Number.MIN_VALUE);
54236          * // => 5e-324
54237          *
54238          * _.toNumber(Infinity);
54239          * // => Infinity
54240          *
54241          * _.toNumber('3.2');
54242          * // => 3.2
54243          */
54244
54245         function toNumber(value) {
54246           if (typeof value == 'number') {
54247             return value;
54248           }
54249
54250           if (isSymbol(value)) {
54251             return NAN;
54252           }
54253
54254           if (isObject$2(value)) {
54255             var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
54256             value = isObject$2(other) ? other + '' : other;
54257           }
54258
54259           if (typeof value != 'string') {
54260             return value === 0 ? value : +value;
54261           }
54262
54263           value = baseTrim(value);
54264           var isBinary = reIsBinary.test(value);
54265           return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
54266         }
54267
54268         /** Error message constants. */
54269
54270         var FUNC_ERROR_TEXT$1 = 'Expected a function';
54271         /* Built-in method references for those with the same name as other `lodash` methods. */
54272
54273         var nativeMax = Math.max,
54274             nativeMin = Math.min;
54275         /**
54276          * Creates a debounced function that delays invoking `func` until after `wait`
54277          * milliseconds have elapsed since the last time the debounced function was
54278          * invoked. The debounced function comes with a `cancel` method to cancel
54279          * delayed `func` invocations and a `flush` method to immediately invoke them.
54280          * Provide `options` to indicate whether `func` should be invoked on the
54281          * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
54282          * with the last arguments provided to the debounced function. Subsequent
54283          * calls to the debounced function return the result of the last `func`
54284          * invocation.
54285          *
54286          * **Note:** If `leading` and `trailing` options are `true`, `func` is
54287          * invoked on the trailing edge of the timeout only if the debounced function
54288          * is invoked more than once during the `wait` timeout.
54289          *
54290          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
54291          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
54292          *
54293          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
54294          * for details over the differences between `_.debounce` and `_.throttle`.
54295          *
54296          * @static
54297          * @memberOf _
54298          * @since 0.1.0
54299          * @category Function
54300          * @param {Function} func The function to debounce.
54301          * @param {number} [wait=0] The number of milliseconds to delay.
54302          * @param {Object} [options={}] The options object.
54303          * @param {boolean} [options.leading=false]
54304          *  Specify invoking on the leading edge of the timeout.
54305          * @param {number} [options.maxWait]
54306          *  The maximum time `func` is allowed to be delayed before it's invoked.
54307          * @param {boolean} [options.trailing=true]
54308          *  Specify invoking on the trailing edge of the timeout.
54309          * @returns {Function} Returns the new debounced function.
54310          * @example
54311          *
54312          * // Avoid costly calculations while the window size is in flux.
54313          * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
54314          *
54315          * // Invoke `sendMail` when clicked, debouncing subsequent calls.
54316          * jQuery(element).on('click', _.debounce(sendMail, 300, {
54317          *   'leading': true,
54318          *   'trailing': false
54319          * }));
54320          *
54321          * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
54322          * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
54323          * var source = new EventSource('/stream');
54324          * jQuery(source).on('message', debounced);
54325          *
54326          * // Cancel the trailing debounced invocation.
54327          * jQuery(window).on('popstate', debounced.cancel);
54328          */
54329
54330         function debounce(func, wait, options) {
54331           var lastArgs,
54332               lastThis,
54333               maxWait,
54334               result,
54335               timerId,
54336               lastCallTime,
54337               lastInvokeTime = 0,
54338               leading = false,
54339               maxing = false,
54340               trailing = true;
54341
54342           if (typeof func != 'function') {
54343             throw new TypeError(FUNC_ERROR_TEXT$1);
54344           }
54345
54346           wait = toNumber(wait) || 0;
54347
54348           if (isObject$2(options)) {
54349             leading = !!options.leading;
54350             maxing = 'maxWait' in options;
54351             maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
54352             trailing = 'trailing' in options ? !!options.trailing : trailing;
54353           }
54354
54355           function invokeFunc(time) {
54356             var args = lastArgs,
54357                 thisArg = lastThis;
54358             lastArgs = lastThis = undefined;
54359             lastInvokeTime = time;
54360             result = func.apply(thisArg, args);
54361             return result;
54362           }
54363
54364           function leadingEdge(time) {
54365             // Reset any `maxWait` timer.
54366             lastInvokeTime = time; // Start the timer for the trailing edge.
54367
54368             timerId = setTimeout(timerExpired, wait); // Invoke the leading edge.
54369
54370             return leading ? invokeFunc(time) : result;
54371           }
54372
54373           function remainingWait(time) {
54374             var timeSinceLastCall = time - lastCallTime,
54375                 timeSinceLastInvoke = time - lastInvokeTime,
54376                 timeWaiting = wait - timeSinceLastCall;
54377             return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
54378           }
54379
54380           function shouldInvoke(time) {
54381             var timeSinceLastCall = time - lastCallTime,
54382                 timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
54383             // trailing edge, the system time has gone backwards and we're treating
54384             // it as the trailing edge, or we've hit the `maxWait` limit.
54385
54386             return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
54387           }
54388
54389           function timerExpired() {
54390             var time = now();
54391
54392             if (shouldInvoke(time)) {
54393               return trailingEdge(time);
54394             } // Restart the timer.
54395
54396
54397             timerId = setTimeout(timerExpired, remainingWait(time));
54398           }
54399
54400           function trailingEdge(time) {
54401             timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
54402             // debounced at least once.
54403
54404             if (trailing && lastArgs) {
54405               return invokeFunc(time);
54406             }
54407
54408             lastArgs = lastThis = undefined;
54409             return result;
54410           }
54411
54412           function cancel() {
54413             if (timerId !== undefined) {
54414               clearTimeout(timerId);
54415             }
54416
54417             lastInvokeTime = 0;
54418             lastArgs = lastCallTime = lastThis = timerId = undefined;
54419           }
54420
54421           function flush() {
54422             return timerId === undefined ? result : trailingEdge(now());
54423           }
54424
54425           function debounced() {
54426             var time = now(),
54427                 isInvoking = shouldInvoke(time);
54428             lastArgs = arguments;
54429             lastThis = this;
54430             lastCallTime = time;
54431
54432             if (isInvoking) {
54433               if (timerId === undefined) {
54434                 return leadingEdge(lastCallTime);
54435               }
54436
54437               if (maxing) {
54438                 // Handle invocations in a tight loop.
54439                 clearTimeout(timerId);
54440                 timerId = setTimeout(timerExpired, wait);
54441                 return invokeFunc(lastCallTime);
54442               }
54443             }
54444
54445             if (timerId === undefined) {
54446               timerId = setTimeout(timerExpired, wait);
54447             }
54448
54449             return result;
54450           }
54451
54452           debounced.cancel = cancel;
54453           debounced.flush = flush;
54454           return debounced;
54455         }
54456
54457         /*
54458             iD.coreDifference represents the difference between two graphs.
54459             It knows how to calculate the set of entities that were
54460             created, modified, or deleted, and also contains the logic
54461             for recursively extending a difference to the complete set
54462             of entities that will require a redraw, taking into account
54463             child and parent relationships.
54464          */
54465
54466         function coreDifference(base, head) {
54467           var _changes = {};
54468           var _didChange = {}; // 'addition', 'deletion', 'geometry', 'properties'
54469
54470           var _diff = {};
54471
54472           function checkEntityID(id) {
54473             var h = head.entities[id];
54474             var b = base.entities[id];
54475             if (h === b) return;
54476             if (_changes[id]) return;
54477
54478             if (!h && b) {
54479               _changes[id] = {
54480                 base: b,
54481                 head: h
54482               };
54483               _didChange.deletion = true;
54484               return;
54485             }
54486
54487             if (h && !b) {
54488               _changes[id] = {
54489                 base: b,
54490                 head: h
54491               };
54492               _didChange.addition = true;
54493               return;
54494             }
54495
54496             if (h && b) {
54497               if (h.members && b.members && !fastDeepEqual(h.members, b.members)) {
54498                 _changes[id] = {
54499                   base: b,
54500                   head: h
54501                 };
54502                 _didChange.geometry = true;
54503                 _didChange.properties = true;
54504                 return;
54505               }
54506
54507               if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
54508                 _changes[id] = {
54509                   base: b,
54510                   head: h
54511                 };
54512                 _didChange.geometry = true;
54513               }
54514
54515               if (h.nodes && b.nodes && !fastDeepEqual(h.nodes, b.nodes)) {
54516                 _changes[id] = {
54517                   base: b,
54518                   head: h
54519                 };
54520                 _didChange.geometry = true;
54521               }
54522
54523               if (h.tags && b.tags && !fastDeepEqual(h.tags, b.tags)) {
54524                 _changes[id] = {
54525                   base: b,
54526                   head: h
54527                 };
54528                 _didChange.properties = true;
54529               }
54530             }
54531           }
54532
54533           function load() {
54534             // HOT CODE: there can be many thousands of downloaded entities, so looping
54535             // through them all can become a performance bottleneck. Optimize by
54536             // resolving duplicates and using a basic `for` loop
54537             var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
54538
54539             for (var i = 0; i < ids.length; i++) {
54540               checkEntityID(ids[i]);
54541             }
54542           }
54543
54544           load();
54545
54546           _diff.length = function length() {
54547             return Object.keys(_changes).length;
54548           };
54549
54550           _diff.changes = function changes() {
54551             return _changes;
54552           };
54553
54554           _diff.didChange = _didChange; // pass true to include affected relation members
54555
54556           _diff.extantIDs = function extantIDs(includeRelMembers) {
54557             var result = new Set();
54558             Object.keys(_changes).forEach(function (id) {
54559               if (_changes[id].head) {
54560                 result.add(id);
54561               }
54562
54563               var h = _changes[id].head;
54564               var b = _changes[id].base;
54565               var entity = h || b;
54566
54567               if (includeRelMembers && entity.type === 'relation') {
54568                 var mh = h ? h.members.map(function (m) {
54569                   return m.id;
54570                 }) : [];
54571                 var mb = b ? b.members.map(function (m) {
54572                   return m.id;
54573                 }) : [];
54574                 utilArrayUnion(mh, mb).forEach(function (memberID) {
54575                   if (head.hasEntity(memberID)) {
54576                     result.add(memberID);
54577                   }
54578                 });
54579               }
54580             });
54581             return Array.from(result);
54582           };
54583
54584           _diff.modified = function modified() {
54585             var result = [];
54586             Object.values(_changes).forEach(function (change) {
54587               if (change.base && change.head) {
54588                 result.push(change.head);
54589               }
54590             });
54591             return result;
54592           };
54593
54594           _diff.created = function created() {
54595             var result = [];
54596             Object.values(_changes).forEach(function (change) {
54597               if (!change.base && change.head) {
54598                 result.push(change.head);
54599               }
54600             });
54601             return result;
54602           };
54603
54604           _diff.deleted = function deleted() {
54605             var result = [];
54606             Object.values(_changes).forEach(function (change) {
54607               if (change.base && !change.head) {
54608                 result.push(change.base);
54609               }
54610             });
54611             return result;
54612           };
54613
54614           _diff.summary = function summary() {
54615             var relevant = {};
54616             var keys = Object.keys(_changes);
54617
54618             for (var i = 0; i < keys.length; i++) {
54619               var change = _changes[keys[i]];
54620
54621               if (change.head && change.head.geometry(head) !== 'vertex') {
54622                 addEntity(change.head, head, change.base ? 'modified' : 'created');
54623               } else if (change.base && change.base.geometry(base) !== 'vertex') {
54624                 addEntity(change.base, base, 'deleted');
54625               } else if (change.base && change.head) {
54626                 // modified vertex
54627                 var moved = !fastDeepEqual(change.base.loc, change.head.loc);
54628                 var retagged = !fastDeepEqual(change.base.tags, change.head.tags);
54629
54630                 if (moved) {
54631                   addParents(change.head);
54632                 }
54633
54634                 if (retagged || moved && change.head.hasInterestingTags()) {
54635                   addEntity(change.head, head, 'modified');
54636                 }
54637               } else if (change.head && change.head.hasInterestingTags()) {
54638                 // created vertex
54639                 addEntity(change.head, head, 'created');
54640               } else if (change.base && change.base.hasInterestingTags()) {
54641                 // deleted vertex
54642                 addEntity(change.base, base, 'deleted');
54643               }
54644             }
54645
54646             return Object.values(relevant);
54647
54648             function addEntity(entity, graph, changeType) {
54649               relevant[entity.id] = {
54650                 entity: entity,
54651                 graph: graph,
54652                 changeType: changeType
54653               };
54654             }
54655
54656             function addParents(entity) {
54657               var parents = head.parentWays(entity);
54658
54659               for (var j = parents.length - 1; j >= 0; j--) {
54660                 var parent = parents[j];
54661
54662                 if (!(parent.id in relevant)) {
54663                   addEntity(parent, head, 'modified');
54664                 }
54665               }
54666             }
54667           }; // returns complete set of entities that require a redraw
54668           //  (optionally within given `extent`)
54669
54670
54671           _diff.complete = function complete(extent) {
54672             var result = {};
54673             var id, change;
54674
54675             for (id in _changes) {
54676               change = _changes[id];
54677               var h = change.head;
54678               var b = change.base;
54679               var entity = h || b;
54680               var i;
54681
54682               if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) {
54683                 continue;
54684               }
54685
54686               result[id] = h;
54687
54688               if (entity.type === 'way') {
54689                 var nh = h ? h.nodes : [];
54690                 var nb = b ? b.nodes : [];
54691                 var diff;
54692                 diff = utilArrayDifference(nh, nb);
54693
54694                 for (i = 0; i < diff.length; i++) {
54695                   result[diff[i]] = head.hasEntity(diff[i]);
54696                 }
54697
54698                 diff = utilArrayDifference(nb, nh);
54699
54700                 for (i = 0; i < diff.length; i++) {
54701                   result[diff[i]] = head.hasEntity(diff[i]);
54702                 }
54703               }
54704
54705               if (entity.type === 'relation' && entity.isMultipolygon()) {
54706                 var mh = h ? h.members.map(function (m) {
54707                   return m.id;
54708                 }) : [];
54709                 var mb = b ? b.members.map(function (m) {
54710                   return m.id;
54711                 }) : [];
54712                 var ids = utilArrayUnion(mh, mb);
54713
54714                 for (i = 0; i < ids.length; i++) {
54715                   var member = head.hasEntity(ids[i]);
54716                   if (!member) continue; // not downloaded
54717
54718                   if (extent && !member.intersects(extent, head)) continue; // not visible
54719
54720                   result[ids[i]] = member;
54721                 }
54722               }
54723
54724               addParents(head.parentWays(entity), result);
54725               addParents(head.parentRelations(entity), result);
54726             }
54727
54728             return result;
54729
54730             function addParents(parents, result) {
54731               for (var i = 0; i < parents.length; i++) {
54732                 var parent = parents[i];
54733                 if (parent.id in result) continue;
54734                 result[parent.id] = parent;
54735                 addParents(head.parentRelations(parent), result);
54736               }
54737             }
54738           };
54739
54740           return _diff;
54741         }
54742
54743         function coreTree(head) {
54744           // tree for entities
54745           var _rtree = new RBush();
54746
54747           var _bboxes = {}; // maintain a separate tree for granular way segments
54748
54749           var _segmentsRTree = new RBush();
54750
54751           var _segmentsBBoxes = {};
54752           var _segmentsByWayId = {};
54753           var tree = {};
54754
54755           function entityBBox(entity) {
54756             var bbox = entity.extent(head).bbox();
54757             bbox.id = entity.id;
54758             _bboxes[entity.id] = bbox;
54759             return bbox;
54760           }
54761
54762           function segmentBBox(segment) {
54763             var extent = segment.extent(head); // extent can be null if the node entities aren't in the graph for some reason
54764
54765             if (!extent) return null;
54766             var bbox = extent.bbox();
54767             bbox.segment = segment;
54768             _segmentsBBoxes[segment.id] = bbox;
54769             return bbox;
54770           }
54771
54772           function removeEntity(entity) {
54773             _rtree.remove(_bboxes[entity.id]);
54774
54775             delete _bboxes[entity.id];
54776
54777             if (_segmentsByWayId[entity.id]) {
54778               _segmentsByWayId[entity.id].forEach(function (segment) {
54779                 _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
54780
54781                 delete _segmentsBBoxes[segment.id];
54782               });
54783
54784               delete _segmentsByWayId[entity.id];
54785             }
54786           }
54787
54788           function loadEntities(entities) {
54789             _rtree.load(entities.map(entityBBox));
54790
54791             var segments = [];
54792             entities.forEach(function (entity) {
54793               if (entity.segments) {
54794                 var entitySegments = entity.segments(head); // cache these to make them easy to remove later
54795
54796                 _segmentsByWayId[entity.id] = entitySegments;
54797                 segments = segments.concat(entitySegments);
54798               }
54799             });
54800             if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
54801           }
54802
54803           function updateParents(entity, insertions, memo) {
54804             head.parentWays(entity).forEach(function (way) {
54805               if (_bboxes[way.id]) {
54806                 removeEntity(way);
54807                 insertions[way.id] = way;
54808               }
54809
54810               updateParents(way, insertions, memo);
54811             });
54812             head.parentRelations(entity).forEach(function (relation) {
54813               if (memo[entity.id]) return;
54814               memo[entity.id] = true;
54815
54816               if (_bboxes[relation.id]) {
54817                 removeEntity(relation);
54818                 insertions[relation.id] = relation;
54819               }
54820
54821               updateParents(relation, insertions, memo);
54822             });
54823           }
54824
54825           tree.rebase = function (entities, force) {
54826             var insertions = {};
54827
54828             for (var i = 0; i < entities.length; i++) {
54829               var entity = entities[i];
54830               if (!entity.visible) continue;
54831
54832               if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
54833                 if (!force) {
54834                   continue;
54835                 } else if (_bboxes[entity.id]) {
54836                   removeEntity(entity);
54837                 }
54838               }
54839
54840               insertions[entity.id] = entity;
54841               updateParents(entity, insertions, {});
54842             }
54843
54844             loadEntities(Object.values(insertions));
54845             return tree;
54846           };
54847
54848           function updateToGraph(graph) {
54849             if (graph === head) return;
54850             var diff = coreDifference(head, graph);
54851             head = graph;
54852             var changed = diff.didChange;
54853             if (!changed.addition && !changed.deletion && !changed.geometry) return;
54854             var insertions = {};
54855
54856             if (changed.deletion) {
54857               diff.deleted().forEach(function (entity) {
54858                 removeEntity(entity);
54859               });
54860             }
54861
54862             if (changed.geometry) {
54863               diff.modified().forEach(function (entity) {
54864                 removeEntity(entity);
54865                 insertions[entity.id] = entity;
54866                 updateParents(entity, insertions, {});
54867               });
54868             }
54869
54870             if (changed.addition) {
54871               diff.created().forEach(function (entity) {
54872                 insertions[entity.id] = entity;
54873               });
54874             }
54875
54876             loadEntities(Object.values(insertions));
54877           } // returns an array of entities with bounding boxes overlapping `extent` for the given `graph`
54878
54879
54880           tree.intersects = function (extent, graph) {
54881             updateToGraph(graph);
54882             return _rtree.search(extent.bbox()).map(function (bbox) {
54883               return graph.entity(bbox.id);
54884             });
54885           }; // returns an array of segment objects with bounding boxes overlapping `extent` for the given `graph`
54886
54887
54888           tree.waySegments = function (extent, graph) {
54889             updateToGraph(graph);
54890             return _segmentsRTree.search(extent.bbox()).map(function (bbox) {
54891               return bbox.segment;
54892             });
54893           };
54894
54895           return tree;
54896         }
54897
54898         function svgIcon(name, svgklass, useklass) {
54899           return function drawIcon(selection) {
54900             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);
54901           };
54902         }
54903
54904         function uiModal(selection, blocking) {
54905           var _this = this;
54906
54907           var keybinding = utilKeybinding('modal');
54908           var previous = selection.select('div.modal');
54909           var animate = previous.empty();
54910           previous.transition().duration(200).style('opacity', 0).remove();
54911           var shaded = selection.append('div').attr('class', 'shaded').style('opacity', 0);
54912
54913           shaded.close = function () {
54914             shaded.transition().duration(200).style('opacity', 0).remove();
54915             modal.transition().duration(200).style('top', '0px');
54916             select(document).call(keybinding.unbind);
54917           };
54918
54919           var modal = shaded.append('div').attr('class', 'modal fillL');
54920           modal.append('input').attr('class', 'keytrap keytrap-first').on('focus.keytrap', moveFocusToLast);
54921
54922           if (!blocking) {
54923             shaded.on('click.remove-modal', function (d3_event) {
54924               if (d3_event.target === _this) {
54925                 shaded.close();
54926               }
54927             });
54928             modal.append('button').attr('class', 'close').on('click', shaded.close).call(svgIcon('#iD-icon-close'));
54929             keybinding.on('⌫', shaded.close).on('⎋', shaded.close);
54930             select(document).call(keybinding);
54931           }
54932
54933           modal.append('div').attr('class', 'content');
54934           modal.append('input').attr('class', 'keytrap keytrap-last').on('focus.keytrap', moveFocusToFirst);
54935
54936           if (animate) {
54937             shaded.transition().style('opacity', 1);
54938           } else {
54939             shaded.style('opacity', 1);
54940           }
54941
54942           return shaded;
54943
54944           function moveFocusToFirst() {
54945             var node = modal // there are additional rules about what's focusable, but this suits our purposes
54946             .select('a, button, input:not(.keytrap), select, textarea').node();
54947
54948             if (node) {
54949               node.focus();
54950             } else {
54951               select(this).node().blur();
54952             }
54953           }
54954
54955           function moveFocusToLast() {
54956             var nodes = modal.selectAll('a, button, input:not(.keytrap), select, textarea').nodes();
54957
54958             if (nodes.length) {
54959               nodes[nodes.length - 1].focus();
54960             } else {
54961               select(this).node().blur();
54962             }
54963           }
54964         }
54965
54966         function uiLoading(context) {
54967           var _modalSelection = select(null);
54968
54969           var _message = '';
54970           var _blocking = false;
54971
54972           var loading = function loading(selection) {
54973             _modalSelection = uiModal(selection, _blocking);
54974
54975             var loadertext = _modalSelection.select('.content').classed('loading-modal', true).append('div').attr('class', 'modal-section fillL');
54976
54977             loadertext.append('img').attr('class', 'loader').attr('src', context.imagePath('loader-white.gif'));
54978             loadertext.append('h3').html(_message);
54979
54980             _modalSelection.select('button.close').attr('class', 'hide');
54981
54982             return loading;
54983           };
54984
54985           loading.message = function (val) {
54986             if (!arguments.length) return _message;
54987             _message = val;
54988             return loading;
54989           };
54990
54991           loading.blocking = function (val) {
54992             if (!arguments.length) return _blocking;
54993             _blocking = val;
54994             return loading;
54995           };
54996
54997           loading.close = function () {
54998             _modalSelection.remove();
54999           };
55000
55001           loading.isShown = function () {
55002             return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
55003           };
55004
55005           return loading;
55006         }
55007
55008         function coreHistory(context) {
55009           var dispatch = dispatch$8('reset', 'change', 'merge', 'restore', 'undone', 'redone', 'storage_error');
55010
55011           var _lock = utilSessionMutex('lock'); // restorable if iD not open in another window/tab and a saved history exists in localStorage
55012
55013
55014           var _hasUnresolvedRestorableChanges = _lock.lock() && !!corePreferences(getKey('saved_history'));
55015
55016           var duration = 150;
55017           var _imageryUsed = [];
55018           var _photoOverlaysUsed = [];
55019           var _checkpoints = {};
55020
55021           var _pausedGraph;
55022
55023           var _stack;
55024
55025           var _index;
55026
55027           var _tree; // internal _act, accepts list of actions and eased time
55028
55029
55030           function _act(actions, t) {
55031             actions = Array.prototype.slice.call(actions);
55032             var annotation;
55033
55034             if (typeof actions[actions.length - 1] !== 'function') {
55035               annotation = actions.pop();
55036             }
55037
55038             var graph = _stack[_index].graph;
55039
55040             for (var i = 0; i < actions.length; i++) {
55041               graph = actions[i](graph, t);
55042             }
55043
55044             return {
55045               graph: graph,
55046               annotation: annotation,
55047               imageryUsed: _imageryUsed,
55048               photoOverlaysUsed: _photoOverlaysUsed,
55049               transform: context.projection.transform(),
55050               selectedIDs: context.selectedIDs()
55051             };
55052           } // internal _perform with eased time
55053
55054
55055           function _perform(args, t) {
55056             var previous = _stack[_index].graph;
55057             _stack = _stack.slice(0, _index + 1);
55058
55059             var actionResult = _act(args, t);
55060
55061             _stack.push(actionResult);
55062
55063             _index++;
55064             return change(previous);
55065           } // internal _replace with eased time
55066
55067
55068           function _replace(args, t) {
55069             var previous = _stack[_index].graph; // assert(_index == _stack.length - 1)
55070
55071             var actionResult = _act(args, t);
55072
55073             _stack[_index] = actionResult;
55074             return change(previous);
55075           } // internal _overwrite with eased time
55076
55077
55078           function _overwrite(args, t) {
55079             var previous = _stack[_index].graph;
55080
55081             if (_index > 0) {
55082               _index--;
55083
55084               _stack.pop();
55085             }
55086
55087             _stack = _stack.slice(0, _index + 1);
55088
55089             var actionResult = _act(args, t);
55090
55091             _stack.push(actionResult);
55092
55093             _index++;
55094             return change(previous);
55095           } // determine difference and dispatch a change event
55096
55097
55098           function change(previous) {
55099             var difference = coreDifference(previous, history.graph());
55100
55101             if (!_pausedGraph) {
55102               dispatch.call('change', this, difference);
55103             }
55104
55105             return difference;
55106           } // iD uses namespaced keys so multiple installations do not conflict
55107
55108
55109           function getKey(n) {
55110             return 'iD_' + window.location.origin + '_' + n;
55111           }
55112
55113           var history = {
55114             graph: function graph() {
55115               return _stack[_index].graph;
55116             },
55117             tree: function tree() {
55118               return _tree;
55119             },
55120             base: function base() {
55121               return _stack[0].graph;
55122             },
55123             merge: function merge(entities
55124             /*, extent*/
55125             ) {
55126               var stack = _stack.map(function (state) {
55127                 return state.graph;
55128               });
55129
55130               _stack[0].graph.rebase(entities, stack, false);
55131
55132               _tree.rebase(entities, false);
55133
55134               dispatch.call('merge', this, entities);
55135             },
55136             perform: function perform() {
55137               // complete any transition already in progress
55138               select(document).interrupt('history.perform');
55139               var transitionable = false;
55140               var action0 = arguments[0];
55141
55142               if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== 'function') {
55143                 transitionable = !!action0.transitionable;
55144               }
55145
55146               if (transitionable) {
55147                 var origArguments = arguments;
55148                 select(document).transition('history.perform').duration(duration).ease(linear$1).tween('history.tween', function () {
55149                   return function (t) {
55150                     if (t < 1) _overwrite([action0], t);
55151                   };
55152                 }).on('start', function () {
55153                   _perform([action0], 0);
55154                 }).on('end interrupt', function () {
55155                   _overwrite(origArguments, 1);
55156                 });
55157               } else {
55158                 return _perform(arguments);
55159               }
55160             },
55161             replace: function replace() {
55162               select(document).interrupt('history.perform');
55163               return _replace(arguments, 1);
55164             },
55165             // Same as calling pop and then perform
55166             overwrite: function overwrite() {
55167               select(document).interrupt('history.perform');
55168               return _overwrite(arguments, 1);
55169             },
55170             pop: function pop(n) {
55171               select(document).interrupt('history.perform');
55172               var previous = _stack[_index].graph;
55173
55174               if (isNaN(+n) || +n < 0) {
55175                 n = 1;
55176               }
55177
55178               while (n-- > 0 && _index > 0) {
55179                 _index--;
55180
55181                 _stack.pop();
55182               }
55183
55184               return change(previous);
55185             },
55186             // Back to the previous annotated state or _index = 0.
55187             undo: function undo() {
55188               select(document).interrupt('history.perform');
55189               var previousStack = _stack[_index];
55190               var previous = previousStack.graph;
55191
55192               while (_index > 0) {
55193                 _index--;
55194                 if (_stack[_index].annotation) break;
55195               }
55196
55197               dispatch.call('undone', this, _stack[_index], previousStack);
55198               return change(previous);
55199             },
55200             // Forward to the next annotated state.
55201             redo: function redo() {
55202               select(document).interrupt('history.perform');
55203               var previousStack = _stack[_index];
55204               var previous = previousStack.graph;
55205               var tryIndex = _index;
55206
55207               while (tryIndex < _stack.length - 1) {
55208                 tryIndex++;
55209
55210                 if (_stack[tryIndex].annotation) {
55211                   _index = tryIndex;
55212                   dispatch.call('redone', this, _stack[_index], previousStack);
55213                   break;
55214                 }
55215               }
55216
55217               return change(previous);
55218             },
55219             pauseChangeDispatch: function pauseChangeDispatch() {
55220               if (!_pausedGraph) {
55221                 _pausedGraph = _stack[_index].graph;
55222               }
55223             },
55224             resumeChangeDispatch: function resumeChangeDispatch() {
55225               if (_pausedGraph) {
55226                 var previous = _pausedGraph;
55227                 _pausedGraph = null;
55228                 return change(previous);
55229               }
55230             },
55231             undoAnnotation: function undoAnnotation() {
55232               var i = _index;
55233
55234               while (i >= 0) {
55235                 if (_stack[i].annotation) return _stack[i].annotation;
55236                 i--;
55237               }
55238             },
55239             redoAnnotation: function redoAnnotation() {
55240               var i = _index + 1;
55241
55242               while (i <= _stack.length - 1) {
55243                 if (_stack[i].annotation) return _stack[i].annotation;
55244                 i++;
55245               }
55246             },
55247             // Returns the entities from the active graph with bounding boxes
55248             // overlapping the given `extent`.
55249             intersects: function intersects(extent) {
55250               return _tree.intersects(extent, _stack[_index].graph);
55251             },
55252             difference: function difference() {
55253               var base = _stack[0].graph;
55254               var head = _stack[_index].graph;
55255               return coreDifference(base, head);
55256             },
55257             changes: function changes(action) {
55258               var base = _stack[0].graph;
55259               var head = _stack[_index].graph;
55260
55261               if (action) {
55262                 head = action(head);
55263               }
55264
55265               var difference = coreDifference(base, head);
55266               return {
55267                 modified: difference.modified(),
55268                 created: difference.created(),
55269                 deleted: difference.deleted()
55270               };
55271             },
55272             hasChanges: function hasChanges() {
55273               return this.difference().length() > 0;
55274             },
55275             imageryUsed: function imageryUsed(sources) {
55276               if (sources) {
55277                 _imageryUsed = sources;
55278                 return history;
55279               } else {
55280                 var s = new Set();
55281
55282                 _stack.slice(1, _index + 1).forEach(function (state) {
55283                   state.imageryUsed.forEach(function (source) {
55284                     if (source !== 'Custom') {
55285                       s.add(source);
55286                     }
55287                   });
55288                 });
55289
55290                 return Array.from(s);
55291               }
55292             },
55293             photoOverlaysUsed: function photoOverlaysUsed(sources) {
55294               if (sources) {
55295                 _photoOverlaysUsed = sources;
55296                 return history;
55297               } else {
55298                 var s = new Set();
55299
55300                 _stack.slice(1, _index + 1).forEach(function (state) {
55301                   if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
55302                     state.photoOverlaysUsed.forEach(function (photoOverlay) {
55303                       s.add(photoOverlay);
55304                     });
55305                   }
55306                 });
55307
55308                 return Array.from(s);
55309               }
55310             },
55311             // save the current history state
55312             checkpoint: function checkpoint(key) {
55313               _checkpoints[key] = {
55314                 stack: _stack,
55315                 index: _index
55316               };
55317               return history;
55318             },
55319             // restore history state to a given checkpoint or reset completely
55320             reset: function reset(key) {
55321               if (key !== undefined && _checkpoints.hasOwnProperty(key)) {
55322                 _stack = _checkpoints[key].stack;
55323                 _index = _checkpoints[key].index;
55324               } else {
55325                 _stack = [{
55326                   graph: coreGraph()
55327                 }];
55328                 _index = 0;
55329                 _tree = coreTree(_stack[0].graph);
55330                 _checkpoints = {};
55331               }
55332
55333               dispatch.call('reset');
55334               dispatch.call('change');
55335               return history;
55336             },
55337             // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
55338             //
55339             // To use it:
55340             //  1. Start the walkthrough.
55341             //  2. Get to a "free editing" tutorial step
55342             //  3. Make your edits to the walkthrough map
55343             //  4. In your browser dev console run:
55344             //        `id.history().toIntroGraph()`
55345             //  5. This outputs stringified JSON to the browser console
55346             //  6. Copy it to `data/intro_graph.json` and prettify it in your code editor
55347             toIntroGraph: function toIntroGraph() {
55348               var nextID = {
55349                 n: 0,
55350                 r: 0,
55351                 w: 0
55352               };
55353               var permIDs = {};
55354               var graph = this.graph();
55355               var baseEntities = {}; // clone base entities..
55356
55357               Object.values(graph.base().entities).forEach(function (entity) {
55358                 var copy = copyIntroEntity(entity);
55359                 baseEntities[copy.id] = copy;
55360               }); // replace base entities with head entities..
55361
55362               Object.keys(graph.entities).forEach(function (id) {
55363                 var entity = graph.entities[id];
55364
55365                 if (entity) {
55366                   var copy = copyIntroEntity(entity);
55367                   baseEntities[copy.id] = copy;
55368                 } else {
55369                   delete baseEntities[id];
55370                 }
55371               }); // swap temporary for permanent ids..
55372
55373               Object.values(baseEntities).forEach(function (entity) {
55374                 if (Array.isArray(entity.nodes)) {
55375                   entity.nodes = entity.nodes.map(function (node) {
55376                     return permIDs[node] || node;
55377                   });
55378                 }
55379
55380                 if (Array.isArray(entity.members)) {
55381                   entity.members = entity.members.map(function (member) {
55382                     member.id = permIDs[member.id] || member.id;
55383                     return member;
55384                   });
55385                 }
55386               });
55387               return JSON.stringify({
55388                 dataIntroGraph: baseEntities
55389               });
55390
55391               function copyIntroEntity(source) {
55392                 var copy = utilObjectOmit(source, ['type', 'user', 'v', 'version', 'visible']); // Note: the copy is no longer an osmEntity, so it might not have `tags`
55393
55394                 if (copy.tags && !Object.keys(copy.tags)) {
55395                   delete copy.tags;
55396                 }
55397
55398                 if (Array.isArray(copy.loc)) {
55399                   copy.loc[0] = +copy.loc[0].toFixed(6);
55400                   copy.loc[1] = +copy.loc[1].toFixed(6);
55401                 }
55402
55403                 var match = source.id.match(/([nrw])-\d*/); // temporary id
55404
55405                 if (match !== null) {
55406                   var nrw = match[1];
55407                   var permID;
55408
55409                   do {
55410                     permID = nrw + ++nextID[nrw];
55411                   } while (baseEntities.hasOwnProperty(permID));
55412
55413                   copy.id = permIDs[source.id] = permID;
55414                 }
55415
55416                 return copy;
55417               }
55418             },
55419             toJSON: function toJSON() {
55420               if (!this.hasChanges()) return;
55421               var allEntities = {};
55422               var baseEntities = {};
55423               var base = _stack[0];
55424
55425               var s = _stack.map(function (i) {
55426                 var modified = [];
55427                 var deleted = [];
55428                 Object.keys(i.graph.entities).forEach(function (id) {
55429                   var entity = i.graph.entities[id];
55430
55431                   if (entity) {
55432                     var key = osmEntity.key(entity);
55433                     allEntities[key] = entity;
55434                     modified.push(key);
55435                   } else {
55436                     deleted.push(id);
55437                   } // make sure that the originals of changed or deleted entities get merged
55438                   // into the base of the _stack after restoring the data from JSON.
55439
55440
55441                   if (id in base.graph.entities) {
55442                     baseEntities[id] = base.graph.entities[id];
55443                   }
55444
55445                   if (entity && entity.nodes) {
55446                     // get originals of pre-existing child nodes
55447                     entity.nodes.forEach(function (nodeID) {
55448                       if (nodeID in base.graph.entities) {
55449                         baseEntities[nodeID] = base.graph.entities[nodeID];
55450                       }
55451                     });
55452                   } // get originals of parent entities too
55453
55454
55455                   var baseParents = base.graph._parentWays[id];
55456
55457                   if (baseParents) {
55458                     baseParents.forEach(function (parentID) {
55459                       if (parentID in base.graph.entities) {
55460                         baseEntities[parentID] = base.graph.entities[parentID];
55461                       }
55462                     });
55463                   }
55464                 });
55465                 var x = {};
55466                 if (modified.length) x.modified = modified;
55467                 if (deleted.length) x.deleted = deleted;
55468                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
55469                 if (i.photoOverlaysUsed) x.photoOverlaysUsed = i.photoOverlaysUsed;
55470                 if (i.annotation) x.annotation = i.annotation;
55471                 if (i.transform) x.transform = i.transform;
55472                 if (i.selectedIDs) x.selectedIDs = i.selectedIDs;
55473                 return x;
55474               });
55475
55476               return JSON.stringify({
55477                 version: 3,
55478                 entities: Object.values(allEntities),
55479                 baseEntities: Object.values(baseEntities),
55480                 stack: s,
55481                 nextIDs: osmEntity.id.next,
55482                 index: _index,
55483                 // note the time the changes were saved
55484                 timestamp: new Date().getTime()
55485               });
55486             },
55487             fromJSON: function fromJSON(json, loadChildNodes) {
55488               var h = JSON.parse(json);
55489               var loadComplete = true;
55490               osmEntity.id.next = h.nextIDs;
55491               _index = h.index;
55492
55493               if (h.version === 2 || h.version === 3) {
55494                 var allEntities = {};
55495                 h.entities.forEach(function (entity) {
55496                   allEntities[osmEntity.key(entity)] = osmEntity(entity);
55497                 });
55498
55499                 if (h.version === 3) {
55500                   // This merges originals for changed entities into the base of
55501                   // the _stack even if the current _stack doesn't have them (for
55502                   // example when iD has been restarted in a different region)
55503                   var baseEntities = h.baseEntities.map(function (d) {
55504                     return osmEntity(d);
55505                   });
55506
55507                   var stack = _stack.map(function (state) {
55508                     return state.graph;
55509                   });
55510
55511                   _stack[0].graph.rebase(baseEntities, stack, true);
55512
55513                   _tree.rebase(baseEntities, true); // When we restore a modified way, we also need to fetch any missing
55514                   // childnodes that would normally have been downloaded with it.. #2142
55515
55516
55517                   if (loadChildNodes) {
55518                     var osm = context.connection();
55519                     var baseWays = baseEntities.filter(function (e) {
55520                       return e.type === 'way';
55521                     });
55522                     var nodeIDs = baseWays.reduce(function (acc, way) {
55523                       return utilArrayUnion(acc, way.nodes);
55524                     }, []);
55525                     var missing = nodeIDs.filter(function (n) {
55526                       return !_stack[0].graph.hasEntity(n);
55527                     });
55528
55529                     if (missing.length && osm) {
55530                       loadComplete = false;
55531                       context.map().redrawEnable(false);
55532                       var loading = uiLoading(context).blocking(true);
55533                       context.container().call(loading);
55534
55535                       var childNodesLoaded = function childNodesLoaded(err, result) {
55536                         if (!err) {
55537                           var visibleGroups = utilArrayGroupBy(result.data, 'visible');
55538                           var visibles = visibleGroups["true"] || []; // alive nodes
55539
55540                           var invisibles = visibleGroups["false"] || []; // deleted nodes
55541
55542                           if (visibles.length) {
55543                             var visibleIDs = visibles.map(function (entity) {
55544                               return entity.id;
55545                             });
55546
55547                             var stack = _stack.map(function (state) {
55548                               return state.graph;
55549                             });
55550
55551                             missing = utilArrayDifference(missing, visibleIDs);
55552
55553                             _stack[0].graph.rebase(visibles, stack, true);
55554
55555                             _tree.rebase(visibles, true);
55556                           } // fetch older versions of nodes that were deleted..
55557
55558
55559                           invisibles.forEach(function (entity) {
55560                             osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
55561                           });
55562                         }
55563
55564                         if (err || !missing.length) {
55565                           loading.close();
55566                           context.map().redrawEnable(true);
55567                           dispatch.call('change');
55568                           dispatch.call('restore', this);
55569                         }
55570                       };
55571
55572                       osm.loadMultiple(missing, childNodesLoaded);
55573                     }
55574                   }
55575                 }
55576
55577                 _stack = h.stack.map(function (d) {
55578                   var entities = {},
55579                       entity;
55580
55581                   if (d.modified) {
55582                     d.modified.forEach(function (key) {
55583                       entity = allEntities[key];
55584                       entities[entity.id] = entity;
55585                     });
55586                   }
55587
55588                   if (d.deleted) {
55589                     d.deleted.forEach(function (id) {
55590                       entities[id] = undefined;
55591                     });
55592                   }
55593
55594                   return {
55595                     graph: coreGraph(_stack[0].graph).load(entities),
55596                     annotation: d.annotation,
55597                     imageryUsed: d.imageryUsed,
55598                     photoOverlaysUsed: d.photoOverlaysUsed,
55599                     transform: d.transform,
55600                     selectedIDs: d.selectedIDs
55601                   };
55602                 });
55603               } else {
55604                 // original version
55605                 _stack = h.stack.map(function (d) {
55606                   var entities = {};
55607
55608                   for (var i in d.entities) {
55609                     var entity = d.entities[i];
55610                     entities[i] = entity === 'undefined' ? undefined : osmEntity(entity);
55611                   }
55612
55613                   d.graph = coreGraph(_stack[0].graph).load(entities);
55614                   return d;
55615                 });
55616               }
55617
55618               var transform = _stack[_index].transform;
55619
55620               if (transform) {
55621                 context.map().transformEase(transform, 0); // 0 = immediate, no easing
55622               }
55623
55624               if (loadComplete) {
55625                 dispatch.call('change');
55626                 dispatch.call('restore', this);
55627               }
55628
55629               return history;
55630             },
55631             lock: function lock() {
55632               return _lock.lock();
55633             },
55634             unlock: function unlock() {
55635               _lock.unlock();
55636             },
55637             save: function save() {
55638               if (_lock.locked() && // don't overwrite existing, unresolved changes
55639               !_hasUnresolvedRestorableChanges) {
55640                 var success = corePreferences(getKey('saved_history'), history.toJSON() || null);
55641                 if (!success) dispatch.call('storage_error');
55642               }
55643
55644               return history;
55645             },
55646             // delete the history version saved in localStorage
55647             clearSaved: function clearSaved() {
55648               context.debouncedSave.cancel();
55649
55650               if (_lock.locked()) {
55651                 _hasUnresolvedRestorableChanges = false;
55652                 corePreferences(getKey('saved_history'), null); // clear the changeset metadata associated with the saved history
55653
55654                 corePreferences('comment', null);
55655                 corePreferences('hashtags', null);
55656                 corePreferences('source', null);
55657               }
55658
55659               return history;
55660             },
55661             savedHistoryJSON: function savedHistoryJSON() {
55662               return corePreferences(getKey('saved_history'));
55663             },
55664             hasRestorableChanges: function hasRestorableChanges() {
55665               return _hasUnresolvedRestorableChanges;
55666             },
55667             // load history from a version stored in localStorage
55668             restore: function restore() {
55669               if (_lock.locked()) {
55670                 _hasUnresolvedRestorableChanges = false;
55671                 var json = this.savedHistoryJSON();
55672                 if (json) history.fromJSON(json, true);
55673               }
55674             },
55675             _getKey: getKey
55676           };
55677           history.reset();
55678           return utilRebind(history, dispatch, 'on');
55679         }
55680
55681         /**
55682          * Look for roads that can be connected to other roads with a short extension
55683          */
55684
55685         function validationAlmostJunction(context) {
55686           var type = 'almost_junction';
55687           var EXTEND_TH_METERS = 5;
55688           var WELD_TH_METERS = 0.75; // Comes from considering bounding case of parallel ways
55689
55690           var CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS; // Comes from considering bounding case of perpendicular ways
55691
55692           var SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
55693
55694           function isHighway(entity) {
55695             return entity.type === 'way' && osmRoutableHighwayTagValues[entity.tags.highway];
55696           }
55697
55698           function isTaggedAsNotContinuing(node) {
55699             return node.tags.noexit === 'yes' || node.tags.amenity === 'parking_entrance' || node.tags.entrance && node.tags.entrance !== 'no';
55700           }
55701
55702           var validation = function checkAlmostJunction(entity, graph) {
55703             if (!isHighway(entity)) return [];
55704             if (entity.isDegenerate()) return [];
55705             var tree = context.history().tree();
55706             var extendableNodeInfos = findConnectableEndNodesByExtension(entity);
55707             var issues = [];
55708             extendableNodeInfos.forEach(function (extendableNodeInfo) {
55709               issues.push(new validationIssue({
55710                 type: type,
55711                 subtype: 'highway-highway',
55712                 severity: 'warning',
55713                 message: function message(context) {
55714                   var entity1 = context.hasEntity(this.entityIds[0]);
55715
55716                   if (this.entityIds[0] === this.entityIds[2]) {
55717                     return entity1 ? _t.html('issues.almost_junction.self.message', {
55718                       feature: utilDisplayLabel(entity1, context.graph())
55719                     }) : '';
55720                   } else {
55721                     var entity2 = context.hasEntity(this.entityIds[2]);
55722                     return entity1 && entity2 ? _t.html('issues.almost_junction.message', {
55723                       feature: utilDisplayLabel(entity1, context.graph()),
55724                       feature2: utilDisplayLabel(entity2, context.graph())
55725                     }) : '';
55726                   }
55727                 },
55728                 reference: showReference,
55729                 entityIds: [entity.id, extendableNodeInfo.node.id, extendableNodeInfo.wid],
55730                 loc: extendableNodeInfo.node.loc,
55731                 hash: JSON.stringify(extendableNodeInfo.node.loc),
55732                 data: {
55733                   midId: extendableNodeInfo.mid.id,
55734                   edge: extendableNodeInfo.edge,
55735                   cross_loc: extendableNodeInfo.cross_loc
55736                 },
55737                 dynamicFixes: makeFixes
55738               }));
55739             });
55740             return issues;
55741
55742             function makeFixes(context) {
55743               var fixes = [new validationIssueFix({
55744                 icon: 'iD-icon-abutment',
55745                 title: _t.html('issues.fix.connect_features.title'),
55746                 onClick: function onClick(context) {
55747                   var annotation = _t('issues.fix.connect_almost_junction.annotation');
55748
55749                   var _this$issue$entityIds = _slicedToArray(this.issue.entityIds, 3),
55750                       endNodeId = _this$issue$entityIds[1],
55751                       crossWayId = _this$issue$entityIds[2];
55752
55753                   var midNode = context.entity(this.issue.data.midId);
55754                   var endNode = context.entity(endNodeId);
55755                   var crossWay = context.entity(crossWayId); // When endpoints are close, just join if resulting small change in angle (#7201)
55756
55757                   var nearEndNodes = findNearbyEndNodes(endNode, crossWay);
55758
55759                   if (nearEndNodes.length > 0) {
55760                     var collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
55761
55762                     if (collinear) {
55763                       context.perform(actionMergeNodes([collinear.id, endNode.id], collinear.loc), annotation);
55764                       return;
55765                     }
55766                   }
55767
55768                   var targetEdge = this.issue.data.edge;
55769                   var crossLoc = this.issue.data.cross_loc;
55770                   var edgeNodes = [context.entity(targetEdge[0]), context.entity(targetEdge[1])];
55771                   var closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc); // already a point nearby, just connect to that
55772
55773                   if (closestNodeInfo.distance < WELD_TH_METERS) {
55774                     context.perform(actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc), annotation); // else add the end node to the edge way
55775                   } else {
55776                     context.perform(actionAddMidpoint({
55777                       loc: crossLoc,
55778                       edge: targetEdge
55779                     }, endNode), annotation);
55780                   }
55781                 }
55782               })];
55783               var node = context.hasEntity(this.entityIds[1]);
55784
55785               if (node && !node.hasInterestingTags()) {
55786                 // node has no descriptive tags, suggest noexit fix
55787                 fixes.push(new validationIssueFix({
55788                   icon: 'maki-barrier',
55789                   title: _t.html('issues.fix.tag_as_disconnected.title'),
55790                   onClick: function onClick(context) {
55791                     var nodeID = this.issue.entityIds[1];
55792                     var tags = Object.assign({}, context.entity(nodeID).tags);
55793                     tags.noexit = 'yes';
55794                     context.perform(actionChangeTags(nodeID, tags), _t('issues.fix.tag_as_disconnected.annotation'));
55795                   }
55796                 }));
55797               }
55798
55799               return fixes;
55800             }
55801
55802             function showReference(selection) {
55803               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.almost_junction.highway-highway.reference'));
55804             }
55805
55806             function isExtendableCandidate(node, way) {
55807               // can not accurately test vertices on tiles not downloaded from osm - #5938
55808               var osm = services.osm;
55809
55810               if (osm && !osm.isDataLoaded(node.loc)) {
55811                 return false;
55812               }
55813
55814               if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
55815                 return false;
55816               }
55817
55818               var occurrences = 0;
55819
55820               for (var index in way.nodes) {
55821                 if (way.nodes[index] === node.id) {
55822                   occurrences += 1;
55823
55824                   if (occurrences > 1) {
55825                     return false;
55826                   }
55827                 }
55828               }
55829
55830               return true;
55831             }
55832
55833             function findConnectableEndNodesByExtension(way) {
55834               var results = [];
55835               if (way.isClosed()) return results;
55836               var testNodes;
55837               var indices = [0, way.nodes.length - 1];
55838               indices.forEach(function (nodeIndex) {
55839                 var nodeID = way.nodes[nodeIndex];
55840                 var node = graph.entity(nodeID);
55841                 if (!isExtendableCandidate(node, way)) return;
55842                 var connectionInfo = canConnectByExtend(way, nodeIndex);
55843                 if (!connectionInfo) return;
55844                 testNodes = graph.childNodes(way).slice(); // shallow copy
55845
55846                 testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc); // don't flag issue if connecting the ways would cause self-intersection
55847
55848                 if (geoHasSelfIntersections(testNodes, nodeID)) return;
55849                 results.push(connectionInfo);
55850               });
55851               return results;
55852             }
55853
55854             function findNearbyEndNodes(node, way) {
55855               return [way.nodes[0], way.nodes[way.nodes.length - 1]].map(function (d) {
55856                 return graph.entity(d);
55857               }).filter(function (d) {
55858                 // Node cannot be near to itself, but other endnode of same way could be
55859                 return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
55860               });
55861             }
55862
55863             function findSmallJoinAngle(midNode, tipNode, endNodes) {
55864               // Both nodes could be close, so want to join whichever is closest to collinear
55865               var joinTo;
55866               var minAngle = Infinity; // Checks midNode -> tipNode -> endNode for collinearity
55867
55868               endNodes.forEach(function (endNode) {
55869                 var a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
55870                 var a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
55871                 var diff = Math.max(a1, a2) - Math.min(a1, a2);
55872
55873                 if (diff < minAngle) {
55874                   joinTo = endNode;
55875                   minAngle = diff;
55876                 }
55877               });
55878               /* Threshold set by considering right angle triangle
55879               based on node joining threshold and extension distance */
55880
55881               if (minAngle <= SIG_ANGLE_TH) return joinTo;
55882               return null;
55883             }
55884
55885             function hasTag(tags, key) {
55886               return tags[key] !== undefined && tags[key] !== 'no';
55887             }
55888
55889             function canConnectWays(way, way2) {
55890               // allow self-connections
55891               if (way.id === way2.id) return true; // if one is bridge or tunnel, both must be bridge or tunnel
55892
55893               if ((hasTag(way.tags, 'bridge') || hasTag(way2.tags, 'bridge')) && !(hasTag(way.tags, 'bridge') && hasTag(way2.tags, 'bridge'))) return false;
55894               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
55895
55896               var layer1 = way.tags.layer || '0',
55897                   layer2 = way2.tags.layer || '0';
55898               if (layer1 !== layer2) return false;
55899               var level1 = way.tags.level || '0',
55900                   level2 = way2.tags.level || '0';
55901               if (level1 !== level2) return false;
55902               return true;
55903             }
55904
55905             function canConnectByExtend(way, endNodeIdx) {
55906               var tipNid = way.nodes[endNodeIdx]; // the 'tip' node for extension point
55907
55908               var midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2]; // the other node of the edge
55909
55910               var tipNode = graph.entity(tipNid);
55911               var midNode = graph.entity(midNid);
55912               var lon = tipNode.loc[0];
55913               var lat = tipNode.loc[1];
55914               var lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
55915               var lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
55916               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
55917
55918               var edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
55919               var t = EXTEND_TH_METERS / edgeLen + 1.0;
55920               var extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t); // then, check if the extension part [tipNode.loc -> extTipLoc] intersects any other ways
55921
55922               var segmentInfos = tree.waySegments(queryExtent, graph);
55923
55924               for (var i = 0; i < segmentInfos.length; i++) {
55925                 var segmentInfo = segmentInfos[i];
55926                 var way2 = graph.entity(segmentInfo.wayId);
55927                 if (!isHighway(way2)) continue;
55928                 if (!canConnectWays(way, way2)) continue;
55929                 var nAid = segmentInfo.nodes[0],
55930                     nBid = segmentInfo.nodes[1];
55931                 if (nAid === tipNid || nBid === tipNid) continue;
55932                 var nA = graph.entity(nAid),
55933                     nB = graph.entity(nBid);
55934                 var crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
55935
55936                 if (crossLoc) {
55937                   return {
55938                     mid: midNode,
55939                     node: tipNode,
55940                     wid: way2.id,
55941                     edge: [nA.id, nB.id],
55942                     cross_loc: crossLoc
55943                   };
55944                 }
55945               }
55946
55947               return null;
55948             }
55949           };
55950
55951           validation.type = type;
55952           return validation;
55953         }
55954
55955         function validationCloseNodes(context) {
55956           var type = 'close_nodes';
55957           var pointThresholdMeters = 0.2;
55958
55959           var validation = function validation(entity, graph) {
55960             if (entity.type === 'node') {
55961               return getIssuesForNode(entity);
55962             } else if (entity.type === 'way') {
55963               return getIssuesForWay(entity);
55964             }
55965
55966             return [];
55967
55968             function getIssuesForNode(node) {
55969               var parentWays = graph.parentWays(node);
55970
55971               if (parentWays.length) {
55972                 return getIssuesForVertex(node, parentWays);
55973               } else {
55974                 return getIssuesForDetachedPoint(node);
55975               }
55976             }
55977
55978             function wayTypeFor(way) {
55979               if (way.tags.boundary && way.tags.boundary !== 'no') return 'boundary';
55980               if (way.tags.indoor && way.tags.indoor !== 'no') return 'indoor';
55981               if (way.tags.building && way.tags.building !== 'no' || way.tags['building:part'] && way.tags['building:part'] !== 'no') return 'building';
55982               if (osmPathHighwayTagValues[way.tags.highway]) return 'path';
55983               var parentRelations = graph.parentRelations(way);
55984
55985               for (var i in parentRelations) {
55986                 var relation = parentRelations[i];
55987                 if (relation.tags.type === 'boundary') return 'boundary';
55988
55989                 if (relation.isMultipolygon()) {
55990                   if (relation.tags.indoor && relation.tags.indoor !== 'no') return 'indoor';
55991                   if (relation.tags.building && relation.tags.building !== 'no' || relation.tags['building:part'] && relation.tags['building:part'] !== 'no') return 'building';
55992                 }
55993               }
55994
55995               return 'other';
55996             }
55997
55998             function shouldCheckWay(way) {
55999               // don't flag issues where merging would create degenerate ways
56000               if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
56001               var bbox = way.extent(graph).bbox();
56002               var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]); // don't flag close nodes in very small ways
56003
56004               if (hypotenuseMeters < 1.5) return false;
56005               return true;
56006             }
56007
56008             function getIssuesForWay(way) {
56009               if (!shouldCheckWay(way)) return [];
56010               var issues = [],
56011                   nodes = graph.childNodes(way);
56012
56013               for (var i = 0; i < nodes.length - 1; i++) {
56014                 var node1 = nodes[i];
56015                 var node2 = nodes[i + 1];
56016                 var issue = getWayIssueIfAny(node1, node2, way);
56017                 if (issue) issues.push(issue);
56018               }
56019
56020               return issues;
56021             }
56022
56023             function getIssuesForVertex(node, parentWays) {
56024               var issues = [];
56025
56026               function checkForCloseness(node1, node2, way) {
56027                 var issue = getWayIssueIfAny(node1, node2, way);
56028                 if (issue) issues.push(issue);
56029               }
56030
56031               for (var i = 0; i < parentWays.length; i++) {
56032                 var parentWay = parentWays[i];
56033                 if (!shouldCheckWay(parentWay)) continue;
56034                 var lastIndex = parentWay.nodes.length - 1;
56035
56036                 for (var j = 0; j < parentWay.nodes.length; j++) {
56037                   if (j !== 0) {
56038                     if (parentWay.nodes[j - 1] === node.id) {
56039                       checkForCloseness(node, graph.entity(parentWay.nodes[j]), parentWay);
56040                     }
56041                   }
56042
56043                   if (j !== lastIndex) {
56044                     if (parentWay.nodes[j + 1] === node.id) {
56045                       checkForCloseness(graph.entity(parentWay.nodes[j]), node, parentWay);
56046                     }
56047                   }
56048                 }
56049               }
56050
56051               return issues;
56052             }
56053
56054             function thresholdMetersForWay(way) {
56055               if (!shouldCheckWay(way)) return 0;
56056               var wayType = wayTypeFor(way); // don't flag boundaries since they might be highly detailed and can't be easily verified
56057
56058               if (wayType === 'boundary') return 0; // expect some features to be mapped with higher levels of detail
56059
56060               if (wayType === 'indoor') return 0.01;
56061               if (wayType === 'building') return 0.05;
56062               if (wayType === 'path') return 0.1;
56063               return 0.2;
56064             }
56065
56066             function getIssuesForDetachedPoint(node) {
56067               var issues = [];
56068               var lon = node.loc[0];
56069               var lat = node.loc[1];
56070               var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
56071               var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
56072               var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]);
56073               var intersected = context.history().tree().intersects(queryExtent, graph);
56074
56075               for (var j = 0; j < intersected.length; j++) {
56076                 var nearby = intersected[j];
56077                 if (nearby.id === node.id) continue;
56078                 if (nearby.type !== 'node' || nearby.geometry(graph) !== 'point') continue;
56079
56080                 if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
56081                   // allow very close points if tags indicate the z-axis might vary
56082                   var zAxisKeys = {
56083                     layer: true,
56084                     level: true,
56085                     'addr:housenumber': true,
56086                     'addr:unit': true
56087                   };
56088                   var zAxisDifferentiates = false;
56089
56090                   for (var key in zAxisKeys) {
56091                     var nodeValue = node.tags[key] || '0';
56092                     var nearbyValue = nearby.tags[key] || '0';
56093
56094                     if (nodeValue !== nearbyValue) {
56095                       zAxisDifferentiates = true;
56096                       break;
56097                     }
56098                   }
56099
56100                   if (zAxisDifferentiates) continue;
56101                   issues.push(new validationIssue({
56102                     type: type,
56103                     subtype: 'detached',
56104                     severity: 'warning',
56105                     message: function message(context) {
56106                       var entity = context.hasEntity(this.entityIds[0]),
56107                           entity2 = context.hasEntity(this.entityIds[1]);
56108                       return entity && entity2 ? _t.html('issues.close_nodes.detached.message', {
56109                         feature: utilDisplayLabel(entity, context.graph()),
56110                         feature2: utilDisplayLabel(entity2, context.graph())
56111                       }) : '';
56112                     },
56113                     reference: showReference,
56114                     entityIds: [node.id, nearby.id],
56115                     dynamicFixes: function dynamicFixes() {
56116                       return [new validationIssueFix({
56117                         icon: 'iD-operation-disconnect',
56118                         title: _t.html('issues.fix.move_points_apart.title')
56119                       }), new validationIssueFix({
56120                         icon: 'iD-icon-layers',
56121                         title: _t.html('issues.fix.use_different_layers_or_levels.title')
56122                       })];
56123                     }
56124                   }));
56125                 }
56126               }
56127
56128               return issues;
56129
56130               function showReference(selection) {
56131                 var referenceText = _t('issues.close_nodes.detached.reference');
56132                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
56133               }
56134             }
56135
56136             function getWayIssueIfAny(node1, node2, way) {
56137               if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
56138                 return null;
56139               }
56140
56141               if (node1.loc !== node2.loc) {
56142                 var parentWays1 = graph.parentWays(node1);
56143                 var parentWays2 = new Set(graph.parentWays(node2));
56144                 var sharedWays = parentWays1.filter(function (parentWay) {
56145                   return parentWays2.has(parentWay);
56146                 });
56147                 var thresholds = sharedWays.map(function (parentWay) {
56148                   return thresholdMetersForWay(parentWay);
56149                 });
56150                 var threshold = Math.min.apply(Math, _toConsumableArray(thresholds));
56151                 var distance = geoSphericalDistance(node1.loc, node2.loc);
56152                 if (distance > threshold) return null;
56153               }
56154
56155               return new validationIssue({
56156                 type: type,
56157                 subtype: 'vertices',
56158                 severity: 'warning',
56159                 message: function message(context) {
56160                   var entity = context.hasEntity(this.entityIds[0]);
56161                   return entity ? _t.html('issues.close_nodes.message', {
56162                     way: utilDisplayLabel(entity, context.graph())
56163                   }) : '';
56164                 },
56165                 reference: showReference,
56166                 entityIds: [way.id, node1.id, node2.id],
56167                 loc: node1.loc,
56168                 dynamicFixes: function dynamicFixes() {
56169                   return [new validationIssueFix({
56170                     icon: 'iD-icon-plus',
56171                     title: _t.html('issues.fix.merge_points.title'),
56172                     onClick: function onClick(context) {
56173                       var entityIds = this.issue.entityIds;
56174                       var action = actionMergeNodes([entityIds[1], entityIds[2]]);
56175                       context.perform(action, _t('issues.fix.merge_close_vertices.annotation'));
56176                     }
56177                   }), new validationIssueFix({
56178                     icon: 'iD-operation-disconnect',
56179                     title: _t.html('issues.fix.move_points_apart.title')
56180                   })];
56181                 }
56182               });
56183
56184               function showReference(selection) {
56185                 var referenceText = _t('issues.close_nodes.reference');
56186                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
56187               }
56188             }
56189           };
56190
56191           validation.type = type;
56192           return validation;
56193         }
56194
56195         function validationCrossingWays(context) {
56196           var type = 'crossing_ways'; // returns the way or its parent relation, whichever has a useful feature type
56197
56198           function getFeatureWithFeatureTypeTagsForWay(way, graph) {
56199             if (getFeatureType(way, graph) === null) {
56200               // if the way doesn't match a feature type, check its parent relations
56201               var parentRels = graph.parentRelations(way);
56202
56203               for (var i = 0; i < parentRels.length; i++) {
56204                 var rel = parentRels[i];
56205
56206                 if (getFeatureType(rel, graph) !== null) {
56207                   return rel;
56208                 }
56209               }
56210             }
56211
56212             return way;
56213           }
56214
56215           function hasTag(tags, key) {
56216             return tags[key] !== undefined && tags[key] !== 'no';
56217           }
56218
56219           function taggedAsIndoor(tags) {
56220             return hasTag(tags, 'indoor') || hasTag(tags, 'level') || tags.highway === 'corridor';
56221           }
56222
56223           function allowsBridge(featureType) {
56224             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
56225           }
56226
56227           function allowsTunnel(featureType) {
56228             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
56229           } // discard
56230
56231
56232           var ignoredBuildings = {
56233             demolished: true,
56234             dismantled: true,
56235             proposed: true,
56236             razed: true
56237           };
56238
56239           function getFeatureType(entity, graph) {
56240             var geometry = entity.geometry(graph);
56241             if (geometry !== 'line' && geometry !== 'area') return null;
56242             var tags = entity.tags;
56243             if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
56244             if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway'; // don't check railway or waterway areas
56245
56246             if (geometry !== 'line') return null;
56247             if (hasTag(tags, 'railway') && osmRailwayTrackTagValues[tags.railway]) return 'railway';
56248             if (hasTag(tags, 'waterway') && osmFlowingWaterwayTagValues[tags.waterway]) return 'waterway';
56249             return null;
56250           }
56251
56252           function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
56253             // assume 0 by default
56254             var level1 = tags1.level || '0';
56255             var level2 = tags2.level || '0';
56256
56257             if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
56258               // assume features don't interact if they're indoor on different levels
56259               return true;
56260             } // assume 0 by default; don't use way.layer() since we account for structures here
56261
56262
56263             var layer1 = tags1.layer || '0';
56264             var layer2 = tags2.layer || '0';
56265
56266             if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
56267               if (hasTag(tags1, 'bridge') && !hasTag(tags2, 'bridge')) return true;
56268               if (!hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge')) return true; // crossing bridges must use different layers
56269
56270               if (hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge') && layer1 !== layer2) return true;
56271             } else if (allowsBridge(featureType1) && hasTag(tags1, 'bridge')) return true;else if (allowsBridge(featureType2) && hasTag(tags2, 'bridge')) return true;
56272
56273             if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
56274               if (hasTag(tags1, 'tunnel') && !hasTag(tags2, 'tunnel')) return true;
56275               if (!hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel')) return true; // crossing tunnels must use different layers
56276
56277               if (hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel') && layer1 !== layer2) return true;
56278             } 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
56279
56280
56281             if (featureType1 === 'waterway' && featureType2 === 'highway' && tags2.man_made === 'pier') return true;
56282             if (featureType2 === 'waterway' && featureType1 === 'highway' && tags1.man_made === 'pier') return true;
56283
56284             if (featureType1 === 'building' || featureType2 === 'building') {
56285               // for building crossings, different layers are enough
56286               if (layer1 !== layer2) return true;
56287             }
56288
56289             return false;
56290           } // highway values for which we shouldn't recommend connecting to waterways
56291
56292
56293           var highwaysDisallowingFords = {
56294             motorway: true,
56295             motorway_link: true,
56296             trunk: true,
56297             trunk_link: true,
56298             primary: true,
56299             primary_link: true,
56300             secondary: true,
56301             secondary_link: true
56302           };
56303           var nonCrossingHighways = {
56304             track: true
56305           };
56306
56307           function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
56308             var featureType1 = getFeatureType(entity1, graph);
56309             var featureType2 = getFeatureType(entity2, graph);
56310             var geometry1 = entity1.geometry(graph);
56311             var geometry2 = entity2.geometry(graph);
56312             var bothLines = geometry1 === 'line' && geometry2 === 'line';
56313
56314             if (featureType1 === featureType2) {
56315               if (featureType1 === 'highway') {
56316                 var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
56317                 var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
56318
56319                 if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
56320                   // one feature is a path but not both
56321                   var roadFeature = entity1IsPath ? entity2 : entity1;
56322
56323                   if (nonCrossingHighways[roadFeature.tags.highway]) {
56324                     // don't mark path connections with certain roads as crossings
56325                     return {};
56326                   }
56327
56328                   var pathFeature = entity1IsPath ? entity1 : entity2;
56329
56330                   if (['marked', 'unmarked'].indexOf(pathFeature.tags.crossing) !== -1) {
56331                     // if the path is a crossing, match the crossing type
56332                     return bothLines ? {
56333                       highway: 'crossing',
56334                       crossing: pathFeature.tags.crossing
56335                     } : {};
56336                   } // don't add a `crossing` subtag to ambiguous crossings
56337
56338
56339                   return bothLines ? {
56340                     highway: 'crossing'
56341                   } : {};
56342                 }
56343
56344                 return {};
56345               }
56346
56347               if (featureType1 === 'waterway') return {};
56348               if (featureType1 === 'railway') return {};
56349             } else {
56350               var featureTypes = [featureType1, featureType2];
56351
56352               if (featureTypes.indexOf('highway') !== -1) {
56353                 if (featureTypes.indexOf('railway') !== -1) {
56354                   if (!bothLines) return {};
56355                   var isTram = entity1.tags.railway === 'tram' || entity2.tags.railway === 'tram';
56356
56357                   if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
56358                     // path-tram connections use this tag
56359                     if (isTram) return {
56360                       railway: 'tram_crossing'
56361                     }; // other path-rail connections use this tag
56362
56363                     return {
56364                       railway: 'crossing'
56365                     };
56366                   } else {
56367                     // path-tram connections use this tag
56368                     if (isTram) return {
56369                       railway: 'tram_level_crossing'
56370                     }; // other road-rail connections use this tag
56371
56372                     return {
56373                       railway: 'level_crossing'
56374                     };
56375                   }
56376                 }
56377
56378                 if (featureTypes.indexOf('waterway') !== -1) {
56379                   // do not allow fords on structures
56380                   if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return null;
56381                   if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return null;
56382
56383                   if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
56384                     // do not allow fords on major highways
56385                     return null;
56386                   }
56387
56388                   return bothLines ? {
56389                     ford: 'yes'
56390                   } : {};
56391                 }
56392               }
56393             }
56394
56395             return null;
56396           }
56397
56398           function findCrossingsByWay(way1, graph, tree) {
56399             var edgeCrossInfos = [];
56400             if (way1.type !== 'way') return edgeCrossInfos;
56401             var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
56402             var way1FeatureType = getFeatureType(taggedFeature1, graph);
56403             if (way1FeatureType === null) return edgeCrossInfos;
56404             var checkedSingleCrossingWays = {}; // declare vars ahead of time to reduce garbage collection
56405
56406             var i, j;
56407             var extent;
56408             var n1, n2, nA, nB, nAId, nBId;
56409             var segment1, segment2;
56410             var oneOnly;
56411             var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
56412             var way1Nodes = graph.childNodes(way1);
56413             var comparedWays = {};
56414
56415             for (i = 0; i < way1Nodes.length - 1; i++) {
56416               n1 = way1Nodes[i];
56417               n2 = way1Nodes[i + 1];
56418               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
56419               // of overlapping ways
56420
56421               segmentInfos = tree.waySegments(extent, graph);
56422
56423               for (j = 0; j < segmentInfos.length; j++) {
56424                 segment2Info = segmentInfos[j]; // don't check for self-intersection in this validation
56425
56426                 if (segment2Info.wayId === way1.id) continue; // skip if this way was already checked and only one issue is needed
56427
56428                 if (checkedSingleCrossingWays[segment2Info.wayId]) continue; // mark this way as checked even if there are no crossings
56429
56430                 comparedWays[segment2Info.wayId] = true;
56431                 way2 = graph.hasEntity(segment2Info.wayId);
56432                 if (!way2) continue;
56433                 taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph); // only check crossing highway, waterway, building, and railway
56434
56435                 way2FeatureType = getFeatureType(taggedFeature2, graph);
56436
56437                 if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
56438                   continue;
56439                 } // create only one issue for building crossings
56440
56441
56442                 oneOnly = way1FeatureType === 'building' || way2FeatureType === 'building';
56443                 nAId = segment2Info.nodes[0];
56444                 nBId = segment2Info.nodes[1];
56445
56446                 if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
56447                   // n1 or n2 is a connection node; skip
56448                   continue;
56449                 }
56450
56451                 nA = graph.hasEntity(nAId);
56452                 if (!nA) continue;
56453                 nB = graph.hasEntity(nBId);
56454                 if (!nB) continue;
56455                 segment1 = [n1.loc, n2.loc];
56456                 segment2 = [nA.loc, nB.loc];
56457                 var point = geoLineIntersection(segment1, segment2);
56458
56459                 if (point) {
56460                   edgeCrossInfos.push({
56461                     wayInfos: [{
56462                       way: way1,
56463                       featureType: way1FeatureType,
56464                       edge: [n1.id, n2.id]
56465                     }, {
56466                       way: way2,
56467                       featureType: way2FeatureType,
56468                       edge: [nA.id, nB.id]
56469                     }],
56470                     crossPoint: point
56471                   });
56472
56473                   if (oneOnly) {
56474                     checkedSingleCrossingWays[way2.id] = true;
56475                     break;
56476                   }
56477                 }
56478               }
56479             }
56480
56481             return edgeCrossInfos;
56482           }
56483
56484           function waysToCheck(entity, graph) {
56485             var featureType = getFeatureType(entity, graph);
56486             if (!featureType) return [];
56487
56488             if (entity.type === 'way') {
56489               return [entity];
56490             } else if (entity.type === 'relation') {
56491               return entity.members.reduce(function (array, member) {
56492                 if (member.type === 'way' && ( // only look at geometry ways
56493                 !member.role || member.role === 'outer' || member.role === 'inner')) {
56494                   var entity = graph.hasEntity(member.id); // don't add duplicates
56495
56496                   if (entity && array.indexOf(entity) === -1) {
56497                     array.push(entity);
56498                   }
56499                 }
56500
56501                 return array;
56502               }, []);
56503             }
56504
56505             return [];
56506           }
56507
56508           var validation = function checkCrossingWays(entity, graph) {
56509             var tree = context.history().tree();
56510             var ways = waysToCheck(entity, graph);
56511             var issues = []; // declare these here to reduce garbage collection
56512
56513             var wayIndex, crossingIndex, crossings;
56514
56515             for (wayIndex in ways) {
56516               crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
56517
56518               for (crossingIndex in crossings) {
56519                 issues.push(createIssue(crossings[crossingIndex], graph));
56520               }
56521             }
56522
56523             return issues;
56524           };
56525
56526           function createIssue(crossing, graph) {
56527             // use the entities with the tags that define the feature type
56528             crossing.wayInfos.sort(function (way1Info, way2Info) {
56529               var type1 = way1Info.featureType;
56530               var type2 = way2Info.featureType;
56531
56532               if (type1 === type2) {
56533                 return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
56534               } else if (type1 === 'waterway') {
56535                 return true;
56536               } else if (type2 === 'waterway') {
56537                 return false;
56538               }
56539
56540               return type1 < type2;
56541             });
56542             var entities = crossing.wayInfos.map(function (wayInfo) {
56543               return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
56544             });
56545             var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
56546             var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
56547             var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
56548             var featureType1 = crossing.wayInfos[0].featureType;
56549             var featureType2 = crossing.wayInfos[1].featureType;
56550             var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
56551             var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, 'tunnel') && allowsTunnel(featureType2) && hasTag(entities[1].tags, 'tunnel');
56552             var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, 'bridge') && allowsBridge(featureType2) && hasTag(entities[1].tags, 'bridge');
56553             var subtype = [featureType1, featureType2].sort().join('-');
56554             var crossingTypeID = subtype;
56555
56556             if (isCrossingIndoors) {
56557               crossingTypeID = 'indoor-indoor';
56558             } else if (isCrossingTunnels) {
56559               crossingTypeID = 'tunnel-tunnel';
56560             } else if (isCrossingBridges) {
56561               crossingTypeID = 'bridge-bridge';
56562             }
56563
56564             if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
56565               crossingTypeID += '_connectable';
56566             } // Differentiate based on the loc rounded to 4 digits, since two ways can cross multiple times.
56567
56568
56569             var uniqueID = '' + crossing.crossPoint[0].toFixed(4) + ',' + crossing.crossPoint[1].toFixed(4);
56570             return new validationIssue({
56571               type: type,
56572               subtype: subtype,
56573               severity: 'warning',
56574               message: function message(context) {
56575                 var graph = context.graph();
56576                 var entity1 = graph.hasEntity(this.entityIds[0]),
56577                     entity2 = graph.hasEntity(this.entityIds[1]);
56578                 return entity1 && entity2 ? _t.html('issues.crossing_ways.message', {
56579                   feature: utilDisplayLabel(entity1, graph),
56580                   feature2: utilDisplayLabel(entity2, graph)
56581                 }) : '';
56582               },
56583               reference: showReference,
56584               entityIds: entities.map(function (entity) {
56585                 return entity.id;
56586               }),
56587               data: {
56588                 edges: edges,
56589                 featureTypes: featureTypes,
56590                 connectionTags: connectionTags
56591               },
56592               hash: uniqueID,
56593               loc: crossing.crossPoint,
56594               dynamicFixes: function dynamicFixes(context) {
56595                 var mode = context.mode();
56596                 if (!mode || mode.id !== 'select' || mode.selectedIDs().length !== 1) return [];
56597                 var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
56598                 var selectedFeatureType = this.data.featureTypes[selectedIndex];
56599                 var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
56600                 var fixes = [];
56601
56602                 if (connectionTags) {
56603                   fixes.push(makeConnectWaysFix(this.data.connectionTags));
56604                 }
56605
56606                 if (isCrossingIndoors) {
56607                   fixes.push(new validationIssueFix({
56608                     icon: 'iD-icon-layers',
56609                     title: _t.html('issues.fix.use_different_levels.title')
56610                   }));
56611                 } else if (isCrossingTunnels || isCrossingBridges || featureType1 === 'building' || featureType2 === 'building') {
56612                   fixes.push(makeChangeLayerFix('higher'));
56613                   fixes.push(makeChangeLayerFix('lower')); // can only add bridge/tunnel if both features are lines
56614                 } else if (context.graph().geometry(this.entityIds[0]) === 'line' && context.graph().geometry(this.entityIds[1]) === 'line') {
56615                   // don't recommend adding bridges to waterways since they're uncommon
56616                   if (allowsBridge(selectedFeatureType) && selectedFeatureType !== 'waterway') {
56617                     fixes.push(makeAddBridgeOrTunnelFix('add_a_bridge', 'temaki-bridge', 'bridge'));
56618                   } // don't recommend adding tunnels under waterways since they're uncommon
56619
56620
56621                   var skipTunnelFix = otherFeatureType === 'waterway' && selectedFeatureType !== 'waterway';
56622
56623                   if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
56624                     fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
56625                   }
56626                 } // repositioning the features is always an option
56627
56628
56629                 fixes.push(new validationIssueFix({
56630                   icon: 'iD-operation-move',
56631                   title: _t.html('issues.fix.reposition_features.title')
56632                 }));
56633                 return fixes;
56634               }
56635             });
56636
56637             function showReference(selection) {
56638               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.crossing_ways.' + crossingTypeID + '.reference'));
56639             }
56640           }
56641
56642           function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
56643             return new validationIssueFix({
56644               icon: iconName,
56645               title: _t.html('issues.fix.' + fixTitleID + '.title'),
56646               onClick: function onClick(context) {
56647                 var mode = context.mode();
56648                 if (!mode || mode.id !== 'select') return;
56649                 var selectedIDs = mode.selectedIDs();
56650                 if (selectedIDs.length !== 1) return;
56651                 var selectedWayID = selectedIDs[0];
56652                 if (!context.hasEntity(selectedWayID)) return;
56653                 var resultWayIDs = [selectedWayID];
56654                 var edge, crossedEdge, crossedWayID;
56655
56656                 if (this.issue.entityIds[0] === selectedWayID) {
56657                   edge = this.issue.data.edges[0];
56658                   crossedEdge = this.issue.data.edges[1];
56659                   crossedWayID = this.issue.entityIds[1];
56660                 } else {
56661                   edge = this.issue.data.edges[1];
56662                   crossedEdge = this.issue.data.edges[0];
56663                   crossedWayID = this.issue.entityIds[0];
56664                 }
56665
56666                 var crossingLoc = this.issue.loc;
56667                 var projection = context.projection;
56668
56669                 var action = function actionAddStructure(graph) {
56670                   var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
56671                   var crossedWay = graph.hasEntity(crossedWayID); // use the explicit width of the crossed feature as the structure length, if available
56672
56673                   var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
56674
56675                   if (!structLengthMeters) {
56676                     // if no explicit width is set, approximate the width based on the tags
56677                     structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
56678                   }
56679
56680                   if (structLengthMeters) {
56681                     if (getFeatureType(crossedWay, graph) === 'railway') {
56682                       // bridges over railways are generally much longer than the rail bed itself, compensate
56683                       structLengthMeters *= 2;
56684                     }
56685                   } else {
56686                     // should ideally never land here since all rail/water/road tags should have an implied width
56687                     structLengthMeters = 8;
56688                   }
56689
56690                   var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection) + Math.PI;
56691                   var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection) + Math.PI;
56692                   var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
56693                   if (crossingAngle > Math.PI) crossingAngle -= Math.PI; // lengthen the structure to account for the angle of the crossing
56694
56695                   structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2; // add padding since the structure must extend past the edges of the crossed feature
56696
56697                   structLengthMeters += 4; // clamp the length to a reasonable range
56698
56699                   structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
56700
56701                   function geomToProj(geoPoint) {
56702                     return [geoLonToMeters(geoPoint[0], geoPoint[1]), geoLatToMeters(geoPoint[1])];
56703                   }
56704
56705                   function projToGeom(projPoint) {
56706                     var lat = geoMetersToLat(projPoint[1]);
56707                     return [geoMetersToLon(projPoint[0], lat), lat];
56708                   }
56709
56710                   var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
56711                   var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
56712                   var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
56713                   var projectedCrossingLoc = geomToProj(crossingLoc);
56714                   var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
56715
56716                   function locSphericalDistanceFromCrossingLoc(angle, distanceMeters) {
56717                     var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
56718                     return projToGeom([projectedCrossingLoc[0] + Math.cos(angle) * lengthSphericalMeters, projectedCrossingLoc[1] + Math.sin(angle) * lengthSphericalMeters]);
56719                   }
56720
56721                   var endpointLocGetter1 = function endpointLocGetter1(lengthMeters) {
56722                     return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
56723                   };
56724
56725                   var endpointLocGetter2 = function endpointLocGetter2(lengthMeters) {
56726                     return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
56727                   }; // avoid creating very short edges from splitting too close to another node
56728
56729
56730                   var minEdgeLengthMeters = 0.55; // decide where to bound the structure along the way, splitting as necessary
56731
56732                   function determineEndpoint(edge, endNode, locGetter) {
56733                     var newNode;
56734                     var idealLengthMeters = structLengthMeters / 2; // distance between the crossing location and the end of the edge,
56735                     // the maximum length of this side of the structure
56736
56737                     var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
56738
56739                     if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
56740                       // the edge is long enough to insert a new node
56741                       // the loc that would result in the full expected length
56742                       var idealNodeLoc = locGetter(idealLengthMeters);
56743                       newNode = osmNode();
56744                       graph = actionAddMidpoint({
56745                         loc: idealNodeLoc,
56746                         edge: edge
56747                       }, newNode)(graph);
56748                     } else {
56749                       var edgeCount = 0;
56750                       endNode.parentIntersectionWays(graph).forEach(function (way) {
56751                         way.nodes.forEach(function (nodeID) {
56752                           if (nodeID === endNode.id) {
56753                             if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
56754                               edgeCount += 1;
56755                             } else {
56756                               edgeCount += 2;
56757                             }
56758                           }
56759                         });
56760                       });
56761
56762                       if (edgeCount >= 3) {
56763                         // the end node is a junction, try to leave a segment
56764                         // between it and the structure - #7202
56765                         var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
56766
56767                         if (insetLength > minEdgeLengthMeters) {
56768                           var insetNodeLoc = locGetter(insetLength);
56769                           newNode = osmNode();
56770                           graph = actionAddMidpoint({
56771                             loc: insetNodeLoc,
56772                             edge: edge
56773                           }, newNode)(graph);
56774                         }
56775                       }
56776                     } // if the edge is too short to subdivide as desired, then
56777                     // just bound the structure at the existing end node
56778
56779
56780                     if (!newNode) newNode = endNode;
56781                     var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs); // only split selected or created ways
56782                     // do the split
56783
56784                     graph = splitAction(graph);
56785
56786                     if (splitAction.getCreatedWayIDs().length) {
56787                       resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
56788                     }
56789
56790                     return newNode;
56791                   }
56792
56793                   var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
56794                   var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
56795                   var structureWay = resultWayIDs.map(function (id) {
56796                     return graph.entity(id);
56797                   }).find(function (way) {
56798                     return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
56799                   });
56800                   var tags = Object.assign({}, structureWay.tags); // copy tags
56801
56802                   if (bridgeOrTunnel === 'bridge') {
56803                     tags.bridge = 'yes';
56804                     tags.layer = '1';
56805                   } else {
56806                     var tunnelValue = 'yes';
56807
56808                     if (getFeatureType(structureWay, graph) === 'waterway') {
56809                       // use `tunnel=culvert` for waterways by default
56810                       tunnelValue = 'culvert';
56811                     }
56812
56813                     tags.tunnel = tunnelValue;
56814                     tags.layer = '-1';
56815                   } // apply the structure tags to the way
56816
56817
56818                   graph = actionChangeTags(structureWay.id, tags)(graph);
56819                   return graph;
56820                 };
56821
56822                 context.perform(action, _t('issues.fix.' + fixTitleID + '.annotation'));
56823                 context.enter(modeSelect(context, resultWayIDs));
56824               }
56825             });
56826           }
56827
56828           function makeConnectWaysFix(connectionTags) {
56829             var fixTitleID = 'connect_features';
56830
56831             if (connectionTags.ford) {
56832               fixTitleID = 'connect_using_ford';
56833             }
56834
56835             return new validationIssueFix({
56836               icon: 'iD-icon-crossing',
56837               title: _t.html('issues.fix.' + fixTitleID + '.title'),
56838               onClick: function onClick(context) {
56839                 var loc = this.issue.loc;
56840                 var connectionTags = this.issue.data.connectionTags;
56841                 var edges = this.issue.data.edges;
56842                 context.perform(function actionConnectCrossingWays(graph) {
56843                   // create the new node for the points
56844                   var node = osmNode({
56845                     loc: loc,
56846                     tags: connectionTags
56847                   });
56848                   graph = graph.replace(node);
56849                   var nodesToMerge = [node.id];
56850                   var mergeThresholdInMeters = 0.75;
56851                   edges.forEach(function (edge) {
56852                     var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
56853                     var nearby = geoSphericalClosestNode(edgeNodes, loc); // if there is already a suitable node nearby, use that
56854                     // use the node if node has no interesting tags or if it is a crossing node #8326
56855
56856                     if ((!nearby.node.hasInterestingTags() || nearby.node.isCrossing()) && nearby.distance < mergeThresholdInMeters) {
56857                       nodesToMerge.push(nearby.node.id); // else add the new node to the way
56858                     } else {
56859                       graph = actionAddMidpoint({
56860                         loc: loc,
56861                         edge: edge
56862                       }, node)(graph);
56863                     }
56864                   });
56865
56866                   if (nodesToMerge.length > 1) {
56867                     // if we're using nearby nodes, merge them with the new node
56868                     graph = actionMergeNodes(nodesToMerge, loc)(graph);
56869                   }
56870
56871                   return graph;
56872                 }, _t('issues.fix.connect_crossing_features.annotation'));
56873               }
56874             });
56875           }
56876
56877           function makeChangeLayerFix(higherOrLower) {
56878             return new validationIssueFix({
56879               icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'),
56880               title: _t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'),
56881               onClick: function onClick(context) {
56882                 var mode = context.mode();
56883                 if (!mode || mode.id !== 'select') return;
56884                 var selectedIDs = mode.selectedIDs();
56885                 if (selectedIDs.length !== 1) return;
56886                 var selectedID = selectedIDs[0];
56887                 if (!this.issue.entityIds.some(function (entityId) {
56888                   return entityId === selectedID;
56889                 })) return;
56890                 var entity = context.hasEntity(selectedID);
56891                 if (!entity) return;
56892                 var tags = Object.assign({}, entity.tags); // shallow copy
56893
56894                 var layer = tags.layer && Number(tags.layer);
56895
56896                 if (layer && !isNaN(layer)) {
56897                   if (higherOrLower === 'higher') {
56898                     layer += 1;
56899                   } else {
56900                     layer -= 1;
56901                   }
56902                 } else {
56903                   if (higherOrLower === 'higher') {
56904                     layer = 1;
56905                   } else {
56906                     layer = -1;
56907                   }
56908                 }
56909
56910                 tags.layer = layer.toString();
56911                 context.perform(actionChangeTags(entity.id, tags), _t('operations.change_tags.annotation'));
56912               }
56913             });
56914           }
56915
56916           validation.type = type;
56917           return validation;
56918         }
56919
56920         function behaviorDrawWay(context, wayID, mode, startGraph) {
56921           var keybinding = utilKeybinding('drawWay');
56922           var dispatch = dispatch$8('rejectedSelfIntersection');
56923           var behavior = behaviorDraw(context); // Must be set by `drawWay.nodeIndex` before each install of this behavior.
56924
56925           var _nodeIndex;
56926
56927           var _origWay;
56928
56929           var _wayGeometry;
56930
56931           var _headNodeID;
56932
56933           var _annotation;
56934
56935           var _pointerHasMoved = false; // The osmNode to be placed.
56936           // This is temporary and just follows the mouse cursor until an "add" event occurs.
56937
56938           var _drawNode;
56939
56940           var _didResolveTempEdit = false;
56941
56942           function createDrawNode(loc) {
56943             // don't make the draw node until we actually need it
56944             _drawNode = osmNode({
56945               loc: loc
56946             });
56947             context.pauseChangeDispatch();
56948             context.replace(function actionAddDrawNode(graph) {
56949               // add the draw node to the graph and insert it into the way
56950               var way = graph.entity(wayID);
56951               return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
56952             }, _annotation);
56953             context.resumeChangeDispatch();
56954             setActiveElements();
56955           }
56956
56957           function removeDrawNode() {
56958             context.pauseChangeDispatch();
56959             context.replace(function actionDeleteDrawNode(graph) {
56960               var way = graph.entity(wayID);
56961               return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
56962             }, _annotation);
56963             _drawNode = undefined;
56964             context.resumeChangeDispatch();
56965           }
56966
56967           function keydown(d3_event) {
56968             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56969               if (context.surface().classed('nope')) {
56970                 context.surface().classed('nope-suppressed', true);
56971               }
56972
56973               context.surface().classed('nope', false).classed('nope-disabled', true);
56974             }
56975           }
56976
56977           function keyup(d3_event) {
56978             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56979               if (context.surface().classed('nope-suppressed')) {
56980                 context.surface().classed('nope', true);
56981               }
56982
56983               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
56984             }
56985           }
56986
56987           function allowsVertex(d) {
56988             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
56989           } // related code
56990           // - `mode/drag_node.js`     `doMove()`
56991           // - `behavior/draw.js`      `click()`
56992           // - `behavior/draw_way.js`  `move()`
56993
56994
56995           function move(d3_event, datum) {
56996             var loc = context.map().mouseCoordinates();
56997             if (!_drawNode) createDrawNode(loc);
56998             context.surface().classed('nope-disabled', d3_event.altKey);
56999             var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
57000             var targetNodes = datum && datum.properties && datum.properties.nodes;
57001
57002             if (targetLoc) {
57003               // snap to node/vertex - a point target with `.loc`
57004               loc = targetLoc;
57005             } else if (targetNodes) {
57006               // snap to way - a line target with `.nodes`
57007               var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
57008
57009               if (choice) {
57010                 loc = choice.loc;
57011               }
57012             }
57013
57014             context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
57015             _drawNode = context.entity(_drawNode.id);
57016             checkGeometry(true
57017             /* includeDrawNode */
57018             );
57019           } // Check whether this edit causes the geometry to break.
57020           // If so, class the surface with a nope cursor.
57021           // `includeDrawNode` - Only check the relevant line segments if finishing drawing
57022
57023
57024           function checkGeometry(includeDrawNode) {
57025             var nopeDisabled = context.surface().classed('nope-disabled');
57026             var isInvalid = isInvalidGeometry(includeDrawNode);
57027
57028             if (nopeDisabled) {
57029               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
57030             } else {
57031               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
57032             }
57033           }
57034
57035           function isInvalidGeometry(includeDrawNode) {
57036             var testNode = _drawNode; // we only need to test the single way we're drawing
57037
57038             var parentWay = context.graph().entity(wayID);
57039             var nodes = context.graph().childNodes(parentWay).slice(); // shallow copy
57040
57041             if (includeDrawNode) {
57042               if (parentWay.isClosed()) {
57043                 // don't test the last segment for closed ways - #4655
57044                 // (still test the first segment)
57045                 nodes.pop();
57046               }
57047             } else {
57048               // discount the draw node
57049               if (parentWay.isClosed()) {
57050                 if (nodes.length < 3) return false;
57051                 if (_drawNode) nodes.splice(-2, 1);
57052                 testNode = nodes[nodes.length - 2];
57053               } else {
57054                 // there's nothing we need to test if we ignore the draw node on open ways
57055                 return false;
57056               }
57057             }
57058
57059             return testNode && geoHasSelfIntersections(nodes, testNode.id);
57060           }
57061
57062           function undone() {
57063             // undoing removed the temp edit
57064             _didResolveTempEdit = true;
57065             context.pauseChangeDispatch();
57066             var nextMode;
57067
57068             if (context.graph() === startGraph) {
57069               // We've undone back to the initial state before we started drawing.
57070               // Just exit the draw mode without undoing whatever we did before
57071               // we entered the draw mode.
57072               nextMode = modeSelect(context, [wayID]);
57073             } else {
57074               // The `undo` only removed the temporary edit, so here we have to
57075               // manually undo to actually remove the last node we added. We can't
57076               // use the `undo` function since the initial "add" graph doesn't have
57077               // an annotation and so cannot be undone to.
57078               context.pop(1); // continue drawing
57079
57080               nextMode = mode;
57081             } // clear the redo stack by adding and removing a blank edit
57082
57083
57084             context.perform(actionNoop());
57085             context.pop(1);
57086             context.resumeChangeDispatch();
57087             context.enter(nextMode);
57088           }
57089
57090           function setActiveElements() {
57091             if (!_drawNode) return;
57092             context.surface().selectAll('.' + _drawNode.id).classed('active', true);
57093           }
57094
57095           function resetToStartGraph() {
57096             while (context.graph() !== startGraph) {
57097               context.pop();
57098             }
57099           }
57100
57101           var drawWay = function drawWay(surface) {
57102             _drawNode = undefined;
57103             _didResolveTempEdit = false;
57104             _origWay = context.entity(wayID);
57105
57106             if (typeof _nodeIndex === 'number') {
57107               _headNodeID = _origWay.nodes[_nodeIndex];
57108             } else if (_origWay.isClosed()) {
57109               _headNodeID = _origWay.nodes[_origWay.nodes.length - 2];
57110             } else {
57111               _headNodeID = _origWay.nodes[_origWay.nodes.length - 1];
57112             }
57113
57114             _wayGeometry = _origWay.geometry(context.graph());
57115             _annotation = _t((_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? 'operations.start.annotation.' : 'operations.continue.annotation.') + _wayGeometry);
57116             _pointerHasMoved = false; // Push an annotated state for undo to return back to.
57117             // We must make sure to replace or remove it later.
57118
57119             context.pauseChangeDispatch();
57120             context.perform(actionNoop(), _annotation);
57121             context.resumeChangeDispatch();
57122             behavior.hover().initialNodeID(_headNodeID);
57123             behavior.on('move', function () {
57124               _pointerHasMoved = true;
57125               move.apply(this, arguments);
57126             }).on('down', function () {
57127               move.apply(this, arguments);
57128             }).on('downcancel', function () {
57129               if (_drawNode) removeDrawNode();
57130             }).on('click', drawWay.add).on('clickWay', drawWay.addWay).on('clickNode', drawWay.addNode).on('undo', context.undo).on('cancel', drawWay.cancel).on('finish', drawWay.finish);
57131             select(window).on('keydown.drawWay', keydown).on('keyup.drawWay', keyup);
57132             context.map().dblclickZoomEnable(false).on('drawn.draw', setActiveElements);
57133             setActiveElements();
57134             surface.call(behavior);
57135             context.history().on('undone.draw', undone);
57136           };
57137
57138           drawWay.off = function (surface) {
57139             if (!_didResolveTempEdit) {
57140               // Drawing was interrupted unexpectedly.
57141               // This can happen if the user changes modes,
57142               // clicks geolocate button, a hashchange event occurs, etc.
57143               context.pauseChangeDispatch();
57144               resetToStartGraph();
57145               context.resumeChangeDispatch();
57146             }
57147
57148             _drawNode = undefined;
57149             _nodeIndex = undefined;
57150             context.map().on('drawn.draw', null);
57151             surface.call(behavior.off).selectAll('.active').classed('active', false);
57152             surface.classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false);
57153             select(window).on('keydown.drawWay', null).on('keyup.drawWay', null);
57154             context.history().on('undone.draw', null);
57155           };
57156
57157           function attemptAdd(d, loc, doAdd) {
57158             if (_drawNode) {
57159               // move the node to the final loc in case move wasn't called
57160               // consistently (e.g. on touch devices)
57161               context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
57162               _drawNode = context.entity(_drawNode.id);
57163             } else {
57164               createDrawNode(loc);
57165             }
57166
57167             checkGeometry(true
57168             /* includeDrawNode */
57169             );
57170
57171             if (d && d.properties && d.properties.nope || context.surface().classed('nope')) {
57172               if (!_pointerHasMoved) {
57173                 // prevent the temporary draw node from appearing on touch devices
57174                 removeDrawNode();
57175               }
57176
57177               dispatch.call('rejectedSelfIntersection', this);
57178               return; // can't click here
57179             }
57180
57181             context.pauseChangeDispatch();
57182             doAdd(); // we just replaced the temporary edit with the real one
57183
57184             _didResolveTempEdit = true;
57185             context.resumeChangeDispatch();
57186             context.enter(mode);
57187           } // Accept the current position of the drawing node
57188
57189
57190           drawWay.add = function (loc, d) {
57191             attemptAdd(d, loc, function () {// don't need to do anything extra
57192             });
57193           }; // Connect the way to an existing way
57194
57195
57196           drawWay.addWay = function (loc, edge, d) {
57197             attemptAdd(d, loc, function () {
57198               context.replace(actionAddMidpoint({
57199                 loc: loc,
57200                 edge: edge
57201               }, _drawNode), _annotation);
57202             });
57203           }; // Connect the way to an existing node
57204
57205
57206           drawWay.addNode = function (node, d) {
57207             // finish drawing if the mapper targets the prior node
57208             if (node.id === _headNodeID || // or the first node when drawing an area
57209             _origWay.isClosed() && node.id === _origWay.first()) {
57210               drawWay.finish();
57211               return;
57212             }
57213
57214             attemptAdd(d, node.loc, function () {
57215               context.replace(function actionReplaceDrawNode(graph) {
57216                 // remove the temporary draw node and insert the existing node
57217                 // at the same index
57218                 graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
57219                 return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
57220               }, _annotation);
57221             });
57222           };
57223           /**
57224            * @param {(typeof osmWay)[]} ways
57225            * @returns {"line" | "area" | "generic"}
57226            */
57227
57228
57229           function getFeatureType(ways) {
57230             if (ways.every(function (way) {
57231               return way.isClosed();
57232             })) return 'area';
57233             if (ways.every(function (way) {
57234               return !way.isClosed();
57235             })) return 'line';
57236             return 'generic';
57237           }
57238           /** see PR #8671 */
57239
57240
57241           function followMode() {
57242             if (_didResolveTempEdit) return;
57243
57244             try {
57245               // get the last 2 added nodes.
57246               // check if they are both part of only oneway (the same one)
57247               // check if the ways that they're part of are the same way
57248               // find index of the last two nodes, to determine the direction to travel around the existing way
57249               // add the next node to the way we are drawing
57250               // if we're drawing an area, the first node = last node.
57251               var isDrawingArea = _origWay.nodes[0] === _origWay.nodes.slice(-1)[0];
57252
57253               var _origWay$nodes$slice = _origWay.nodes.slice(isDrawingArea ? -3 : -2),
57254                   _origWay$nodes$slice2 = _slicedToArray(_origWay$nodes$slice, 2),
57255                   secondLastNodeId = _origWay$nodes$slice2[0],
57256                   lastNodeId = _origWay$nodes$slice2[1]; // Unlike startGraph, the full history graph may contain unsaved vertices to follow.
57257               // https://github.com/openstreetmap/iD/issues/8749
57258
57259
57260               var historyGraph = context.history().graph();
57261
57262               if (!lastNodeId || !secondLastNodeId || !historyGraph.hasEntity(lastNodeId) || !historyGraph.hasEntity(secondLastNodeId)) {
57263                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.follow.error.needs_more_initial_nodes'))();
57264                 return;
57265               } // If the way has looped over itself, follow some other way.
57266
57267
57268               var lastNodesParents = historyGraph.parentWays(historyGraph.entity(lastNodeId)).filter(function (w) {
57269                 return w.id !== wayID;
57270               });
57271               var secondLastNodesParents = historyGraph.parentWays(historyGraph.entity(secondLastNodeId)).filter(function (w) {
57272                 return w.id !== wayID;
57273               });
57274               var featureType = getFeatureType(lastNodesParents);
57275
57276               if (lastNodesParents.length !== 1 || secondLastNodesParents.length === 0) {
57277                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t("operations.follow.error.intersection_of_multiple_ways.".concat(featureType)))();
57278                 return;
57279               } // Check if the last node's parent is also the parent of the second last node.
57280               // The last node must only have one parent, but the second last node can have
57281               // multiple parents.
57282
57283
57284               if (!secondLastNodesParents.some(function (n) {
57285                 return n.id === lastNodesParents[0].id;
57286               })) {
57287                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t("operations.follow.error.intersection_of_different_ways.".concat(featureType)))();
57288                 return;
57289               }
57290
57291               var way = lastNodesParents[0];
57292               var indexOfLast = way.nodes.indexOf(lastNodeId);
57293               var indexOfSecondLast = way.nodes.indexOf(secondLastNodeId); // for a closed way, the first/last node is the same so it appears twice in the array,
57294               // but indexOf always finds the first occurrence. This is only an issue when following a way
57295               // in descending order
57296
57297               var isDescendingPastZero = indexOfLast === way.nodes.length - 2 && indexOfSecondLast === 0;
57298               var nextNodeIndex = indexOfLast + (indexOfLast > indexOfSecondLast && !isDescendingPastZero ? 1 : -1); // if we're following a closed way and we pass the first/last node, the  next index will be -1
57299
57300               if (nextNodeIndex === -1) nextNodeIndex = indexOfSecondLast === 1 ? way.nodes.length - 2 : 1;
57301               var nextNode = historyGraph.entity(way.nodes[nextNodeIndex]);
57302               drawWay.addNode(nextNode, {
57303                 geometry: {
57304                   type: 'Point',
57305                   coordinates: nextNode.loc
57306                 },
57307                 id: nextNode.id,
57308                 properties: {
57309                   target: true,
57310                   entity: nextNode
57311                 }
57312               });
57313             } catch (ex) {
57314               context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.follow.error.unknown'))();
57315             }
57316           }
57317
57318           keybinding.on(_t('operations.follow.key'), followMode);
57319           select(document).call(keybinding); // Finish the draw operation, removing the temporary edit.
57320           // If the way has enough nodes to be valid, it's selected.
57321           // Otherwise, delete everything and return to browse mode.
57322
57323           drawWay.finish = function () {
57324             checkGeometry(false
57325             /* includeDrawNode */
57326             );
57327
57328             if (context.surface().classed('nope')) {
57329               dispatch.call('rejectedSelfIntersection', this);
57330               return; // can't click here
57331             }
57332
57333             context.pauseChangeDispatch(); // remove the temporary edit
57334
57335             context.pop(1);
57336             _didResolveTempEdit = true;
57337             context.resumeChangeDispatch();
57338             var way = context.hasEntity(wayID);
57339
57340             if (!way || way.isDegenerate()) {
57341               drawWay.cancel();
57342               return;
57343             }
57344
57345             window.setTimeout(function () {
57346               context.map().dblclickZoomEnable(true);
57347             }, 1000);
57348             var isNewFeature = !mode.isContinuing;
57349             context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
57350           }; // Cancel the draw operation, delete everything, and return to browse mode.
57351
57352
57353           drawWay.cancel = function () {
57354             context.pauseChangeDispatch();
57355             resetToStartGraph();
57356             context.resumeChangeDispatch();
57357             window.setTimeout(function () {
57358               context.map().dblclickZoomEnable(true);
57359             }, 1000);
57360             context.surface().classed('nope', false).classed('nope-disabled', false).classed('nope-suppressed', false);
57361             context.enter(modeBrowse(context));
57362           };
57363
57364           drawWay.nodeIndex = function (val) {
57365             if (!arguments.length) return _nodeIndex;
57366             _nodeIndex = val;
57367             return drawWay;
57368           };
57369
57370           drawWay.activeID = function () {
57371             if (!arguments.length) return _drawNode && _drawNode.id; // no assign
57372
57373             return drawWay;
57374           };
57375
57376           return utilRebind(drawWay, dispatch, 'on');
57377         }
57378
57379         function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
57380           var mode = {
57381             button: button,
57382             id: 'draw-line'
57383           };
57384           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawLine', function () {
57385             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.lines'))();
57386           });
57387           mode.wayID = wayID;
57388           mode.isContinuing = continuing;
57389
57390           mode.enter = function () {
57391             behavior.nodeIndex(affix === 'prefix' ? 0 : undefined);
57392             context.install(behavior);
57393           };
57394
57395           mode.exit = function () {
57396             context.uninstall(behavior);
57397           };
57398
57399           mode.selectedIDs = function () {
57400             return [wayID];
57401           };
57402
57403           mode.activeID = function () {
57404             return behavior && behavior.activeID() || [];
57405           };
57406
57407           return mode;
57408         }
57409
57410         function validationDisconnectedWay() {
57411           var type = 'disconnected_way';
57412
57413           function isTaggedAsHighway(entity) {
57414             return osmRoutableHighwayTagValues[entity.tags.highway];
57415           }
57416
57417           var validation = function checkDisconnectedWay(entity, graph) {
57418             var routingIslandWays = routingIslandForEntity(entity);
57419             if (!routingIslandWays) return [];
57420             return [new validationIssue({
57421               type: type,
57422               subtype: 'highway',
57423               severity: 'warning',
57424               message: function message(context) {
57425                 var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]);
57426                 var label = entity && utilDisplayLabel(entity, context.graph());
57427                 return _t.html('issues.disconnected_way.routable.message', {
57428                   count: this.entityIds.length,
57429                   highway: label
57430                 });
57431               },
57432               reference: showReference,
57433               entityIds: Array.from(routingIslandWays).map(function (way) {
57434                 return way.id;
57435               }),
57436               dynamicFixes: makeFixes
57437             })];
57438
57439             function makeFixes(context) {
57440               var fixes = [];
57441               var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
57442
57443               if (singleEntity) {
57444                 if (singleEntity.type === 'way' && !singleEntity.isClosed()) {
57445                   var textDirection = _mainLocalizer.textDirection();
57446                   var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), 'start');
57447                   if (startFix) fixes.push(startFix);
57448                   var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), 'end');
57449                   if (endFix) fixes.push(endFix);
57450                 }
57451
57452                 if (!fixes.length) {
57453                   fixes.push(new validationIssueFix({
57454                     title: _t.html('issues.fix.connect_feature.title')
57455                   }));
57456                 }
57457
57458                 fixes.push(new validationIssueFix({
57459                   icon: 'iD-operation-delete',
57460                   title: _t.html('issues.fix.delete_feature.title'),
57461                   entityIds: [singleEntity.id],
57462                   onClick: function onClick(context) {
57463                     var id = this.issue.entityIds[0];
57464                     var operation = operationDelete(context, [id]);
57465
57466                     if (!operation.disabled()) {
57467                       operation();
57468                     }
57469                   }
57470                 }));
57471               } else {
57472                 fixes.push(new validationIssueFix({
57473                   title: _t.html('issues.fix.connect_features.title')
57474                 }));
57475               }
57476
57477               return fixes;
57478             }
57479
57480             function showReference(selection) {
57481               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.disconnected_way.routable.reference'));
57482             }
57483
57484             function routingIslandForEntity(entity) {
57485               var routingIsland = new Set(); // the interconnected routable features
57486
57487               var waysToCheck = []; // the queue of remaining routable ways to traverse
57488
57489               function queueParentWays(node) {
57490                 graph.parentWays(node).forEach(function (parentWay) {
57491                   if (!routingIsland.has(parentWay) && // only check each feature once
57492                   isRoutableWay(parentWay, false)) {
57493                     // only check routable features
57494                     routingIsland.add(parentWay);
57495                     waysToCheck.push(parentWay);
57496                   }
57497                 });
57498               }
57499
57500               if (entity.type === 'way' && isRoutableWay(entity, true)) {
57501                 routingIsland.add(entity);
57502                 waysToCheck.push(entity);
57503               } else if (entity.type === 'node' && isRoutableNode(entity)) {
57504                 routingIsland.add(entity);
57505                 queueParentWays(entity);
57506               } else {
57507                 // this feature isn't routable, cannot be a routing island
57508                 return null;
57509               }
57510
57511               while (waysToCheck.length) {
57512                 var wayToCheck = waysToCheck.pop();
57513                 var childNodes = graph.childNodes(wayToCheck);
57514
57515                 for (var i in childNodes) {
57516                   var vertex = childNodes[i];
57517
57518                   if (isConnectedVertex(vertex)) {
57519                     // found a link to the wider network, not a routing island
57520                     return null;
57521                   }
57522
57523                   if (isRoutableNode(vertex)) {
57524                     routingIsland.add(vertex);
57525                   }
57526
57527                   queueParentWays(vertex);
57528                 }
57529               } // no network link found, this is a routing island, return its members
57530
57531
57532               return routingIsland;
57533             }
57534
57535             function isConnectedVertex(vertex) {
57536               // assume ways overlapping unloaded tiles are connected to the wider road network  - #5938
57537               var osm = services.osm;
57538               if (osm && !osm.isDataLoaded(vertex.loc)) return true; // entrances are considered connected
57539
57540               if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return true;
57541               if (vertex.tags.amenity === 'parking_entrance') return true;
57542               return false;
57543             }
57544
57545             function isRoutableNode(node) {
57546               // treat elevators as distinct features in the highway network
57547               if (node.tags.highway === 'elevator') return true;
57548               return false;
57549             }
57550
57551             function isRoutableWay(way, ignoreInnerWays) {
57552               if (isTaggedAsHighway(way) || way.tags.route === 'ferry') return true;
57553               return graph.parentRelations(way).some(function (parentRelation) {
57554                 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true;
57555                 if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== 'inner')) return true;
57556                 return false;
57557               });
57558             }
57559
57560             function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
57561               var vertex = graph.hasEntity(vertexID);
57562               if (!vertex || vertex.tags.noexit === 'yes') return null;
57563               var useLeftContinue = whichEnd === 'start' && textDirection === 'ltr' || whichEnd === 'end' && textDirection === 'rtl';
57564               return new validationIssueFix({
57565                 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
57566                 title: _t.html('issues.fix.continue_from_' + whichEnd + '.title'),
57567                 entityIds: [vertexID],
57568                 onClick: function onClick(context) {
57569                   var wayId = this.issue.entityIds[0];
57570                   var way = context.hasEntity(wayId);
57571                   var vertexId = this.entityIds[0];
57572                   var vertex = context.hasEntity(vertexId);
57573                   if (!way || !vertex) return; // make sure the vertex is actually visible and editable
57574
57575                   var map = context.map();
57576
57577                   if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
57578                     map.zoomToEase(vertex);
57579                   }
57580
57581                   context.enter(modeDrawLine(context, wayId, context.graph(), 'line', way.affix(vertexId), true));
57582                 }
57583               });
57584             }
57585           };
57586
57587           validation.type = type;
57588           return validation;
57589         }
57590
57591         function validationFormatting() {
57592           var type = 'invalid_format';
57593
57594           var validation = function validation(entity) {
57595             var issues = [];
57596
57597             function isValidEmail(email) {
57598               // Emails in OSM are going to be official so they should be pretty simple
57599               // Using negated lists to better support all possible unicode characters (#6494)
57600               var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i; // An empty value is also acceptable
57601
57602               return !email || valid_email.test(email);
57603             }
57604             /*
57605             function isSchemePresent(url) {
57606                 var valid_scheme = /^https?:\/\//i;
57607                 return (!url || valid_scheme.test(url));
57608             }
57609             */
57610
57611
57612             function showReferenceEmail(selection) {
57613               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.invalid_format.email.reference'));
57614             }
57615             /*
57616             function showReferenceWebsite(selection) {
57617                 selection.selectAll('.issue-reference')
57618                     .data([0])
57619                     .enter()
57620                     .append('div')
57621                     .attr('class', 'issue-reference')
57622                     .html(t.html('issues.invalid_format.website.reference'));
57623             }
57624              if (entity.tags.website) {
57625                 // Multiple websites are possible
57626                 // If ever we support ES6, arrow functions make this nicer
57627                 var websites = entity.tags.website
57628                     .split(';')
57629                     .map(function(s) { return s.trim(); })
57630                     .filter(function(x) { return !isSchemePresent(x); });
57631                  if (websites.length) {
57632                     issues.push(new validationIssue({
57633                         type: type,
57634                         subtype: 'website',
57635                         severity: 'warning',
57636                         message: function(context) {
57637                             var entity = context.hasEntity(this.entityIds[0]);
57638                             return entity ? t.html('issues.invalid_format.website.message' + this.data,
57639                                 { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : '';
57640                         },
57641                         reference: showReferenceWebsite,
57642                         entityIds: [entity.id],
57643                         hash: websites.join(),
57644                         data: (websites.length > 1) ? '_multi' : ''
57645                     }));
57646                 }
57647             }
57648             */
57649
57650
57651             if (entity.tags.email) {
57652               // Multiple emails are possible
57653               var emails = entity.tags.email.split(';').map(function (s) {
57654                 return s.trim();
57655               }).filter(function (x) {
57656                 return !isValidEmail(x);
57657               });
57658
57659               if (emails.length) {
57660                 issues.push(new validationIssue({
57661                   type: type,
57662                   subtype: 'email',
57663                   severity: 'warning',
57664                   message: function message(context) {
57665                     var entity = context.hasEntity(this.entityIds[0]);
57666                     return entity ? _t.html('issues.invalid_format.email.message' + this.data, {
57667                       feature: utilDisplayLabel(entity, context.graph()),
57668                       email: emails.join(', ')
57669                     }) : '';
57670                   },
57671                   reference: showReferenceEmail,
57672                   entityIds: [entity.id],
57673                   hash: emails.join(),
57674                   data: emails.length > 1 ? '_multi' : ''
57675                 }));
57676               }
57677             }
57678
57679             return issues;
57680           };
57681
57682           validation.type = type;
57683           return validation;
57684         }
57685
57686         function validationHelpRequest(context) {
57687           var type = 'help_request';
57688
57689           var validation = function checkFixmeTag(entity) {
57690             if (!entity.tags.fixme) return []; // don't flag fixmes on features added by the user
57691
57692             if (entity.version === undefined) return [];
57693
57694             if (entity.v !== undefined) {
57695               var baseEntity = context.history().base().hasEntity(entity.id); // don't flag fixmes added by the user on existing features
57696
57697               if (!baseEntity || !baseEntity.tags.fixme) return [];
57698             }
57699
57700             return [new validationIssue({
57701               type: type,
57702               subtype: 'fixme_tag',
57703               severity: 'warning',
57704               message: function message(context) {
57705                 var entity = context.hasEntity(this.entityIds[0]);
57706                 return entity ? _t.html('issues.fixme_tag.message', {
57707                   feature: utilDisplayLabel(entity, context.graph(), true
57708                   /* verbose */
57709                   )
57710                 }) : '';
57711               },
57712               dynamicFixes: function dynamicFixes() {
57713                 return [new validationIssueFix({
57714                   title: _t.html('issues.fix.address_the_concern.title')
57715                 })];
57716               },
57717               reference: showReference,
57718               entityIds: [entity.id]
57719             })];
57720
57721             function showReference(selection) {
57722               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.fixme_tag.reference'));
57723             }
57724           };
57725
57726           validation.type = type;
57727           return validation;
57728         }
57729
57730         function validationImpossibleOneway() {
57731           var type = 'impossible_oneway';
57732
57733           var validation = function checkImpossibleOneway(entity, graph) {
57734             if (entity.type !== 'way' || entity.geometry(graph) !== 'line') return [];
57735             if (entity.isClosed()) return [];
57736             if (!typeForWay(entity)) return [];
57737             if (!isOneway(entity)) return [];
57738             var firstIssues = issuesForNode(entity, entity.first());
57739             var lastIssues = issuesForNode(entity, entity.last());
57740             return firstIssues.concat(lastIssues);
57741
57742             function typeForWay(way) {
57743               if (way.geometry(graph) !== 'line') return null;
57744               if (osmRoutableHighwayTagValues[way.tags.highway]) return 'highway';
57745               if (osmFlowingWaterwayTagValues[way.tags.waterway]) return 'waterway';
57746               return null;
57747             }
57748
57749             function isOneway(way) {
57750               if (way.tags.oneway === 'yes') return true;
57751               if (way.tags.oneway) return false;
57752
57753               for (var key in way.tags) {
57754                 if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
57755                   return true;
57756                 }
57757               }
57758
57759               return false;
57760             }
57761
57762             function nodeOccursMoreThanOnce(way, nodeID) {
57763               var occurrences = 0;
57764
57765               for (var index in way.nodes) {
57766                 if (way.nodes[index] === nodeID) {
57767                   occurrences += 1;
57768                   if (occurrences > 1) return true;
57769                 }
57770               }
57771
57772               return false;
57773             }
57774
57775             function isConnectedViaOtherTypes(way, node) {
57776               var wayType = typeForWay(way);
57777
57778               if (wayType === 'highway') {
57779                 // entrances are considered connected
57780                 if (node.tags.entrance && node.tags.entrance !== 'no') return true;
57781                 if (node.tags.amenity === 'parking_entrance') return true;
57782               } else if (wayType === 'waterway') {
57783                 if (node.id === way.first()) {
57784                   // multiple waterways may start at the same spring
57785                   if (node.tags.natural === 'spring') return true;
57786                 } else {
57787                   // multiple waterways may end at the same drain
57788                   if (node.tags.manhole === 'drain') return true;
57789                 }
57790               }
57791
57792               return graph.parentWays(node).some(function (parentWay) {
57793                 if (parentWay.id === way.id) return false;
57794
57795                 if (wayType === 'highway') {
57796                   // allow connections to highway areas
57797                   if (parentWay.geometry(graph) === 'area' && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true; // count connections to ferry routes as connected
57798
57799                   if (parentWay.tags.route === 'ferry') return true;
57800                   return graph.parentRelations(parentWay).some(function (parentRelation) {
57801                     if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true; // allow connections to highway multipolygons
57802
57803                     return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
57804                   });
57805                 } else if (wayType === 'waterway') {
57806                   // multiple waterways may start or end at a water body at the same node
57807                   if (parentWay.tags.natural === 'water' || parentWay.tags.natural === 'coastline') return true;
57808                 }
57809
57810                 return false;
57811               });
57812             }
57813
57814             function issuesForNode(way, nodeID) {
57815               var isFirst = nodeID === way.first();
57816               var wayType = typeForWay(way); // ignore if this way is self-connected at this node
57817
57818               if (nodeOccursMoreThanOnce(way, nodeID)) return [];
57819               var osm = services.osm;
57820               if (!osm) return [];
57821               var node = graph.hasEntity(nodeID); // ignore if this node or its tile are unloaded
57822
57823               if (!node || !osm.isDataLoaded(node.loc)) return [];
57824               if (isConnectedViaOtherTypes(way, node)) return [];
57825               var attachedWaysOfSameType = graph.parentWays(node).filter(function (parentWay) {
57826                 if (parentWay.id === way.id) return false;
57827                 return typeForWay(parentWay) === wayType;
57828               }); // assume it's okay for waterways to start or end disconnected for now
57829
57830               if (wayType === 'waterway' && attachedWaysOfSameType.length === 0) return [];
57831               var attachedOneways = attachedWaysOfSameType.filter(function (attachedWay) {
57832                 return isOneway(attachedWay);
57833               }); // ignore if the way is connected to some non-oneway features
57834
57835               if (attachedOneways.length < attachedWaysOfSameType.length) return [];
57836
57837               if (attachedOneways.length) {
57838                 var connectedEndpointsOkay = attachedOneways.some(function (attachedOneway) {
57839                   if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
57840                   if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
57841                   return false;
57842                 });
57843                 if (connectedEndpointsOkay) return [];
57844               }
57845
57846               var placement = isFirst ? 'start' : 'end',
57847                   messageID = wayType + '.',
57848                   referenceID = wayType + '.';
57849
57850               if (wayType === 'waterway') {
57851                 messageID += 'connected.' + placement;
57852                 referenceID += 'connected';
57853               } else {
57854                 messageID += placement;
57855                 referenceID += placement;
57856               }
57857
57858               return [new validationIssue({
57859                 type: type,
57860                 subtype: wayType,
57861                 severity: 'warning',
57862                 message: function message(context) {
57863                   var entity = context.hasEntity(this.entityIds[0]);
57864                   return entity ? _t.html('issues.impossible_oneway.' + messageID + '.message', {
57865                     feature: utilDisplayLabel(entity, context.graph())
57866                   }) : '';
57867                 },
57868                 reference: getReference(referenceID),
57869                 entityIds: [way.id, node.id],
57870                 dynamicFixes: function dynamicFixes() {
57871                   var fixes = [];
57872
57873                   if (attachedOneways.length) {
57874                     fixes.push(new validationIssueFix({
57875                       icon: 'iD-operation-reverse',
57876                       title: _t.html('issues.fix.reverse_feature.title'),
57877                       entityIds: [way.id],
57878                       onClick: function onClick(context) {
57879                         var id = this.issue.entityIds[0];
57880                         context.perform(actionReverse(id), _t('operations.reverse.annotation.line', {
57881                           n: 1
57882                         }));
57883                       }
57884                     }));
57885                   }
57886
57887                   if (node.tags.noexit !== 'yes') {
57888                     var textDirection = _mainLocalizer.textDirection();
57889                     var useLeftContinue = isFirst && textDirection === 'ltr' || !isFirst && textDirection === 'rtl';
57890                     fixes.push(new validationIssueFix({
57891                       icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
57892                       title: _t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'),
57893                       onClick: function onClick(context) {
57894                         var entityID = this.issue.entityIds[0];
57895                         var vertexID = this.issue.entityIds[1];
57896                         var way = context.entity(entityID);
57897                         var vertex = context.entity(vertexID);
57898                         continueDrawing(way, vertex, context);
57899                       }
57900                     }));
57901                   }
57902
57903                   return fixes;
57904                 },
57905                 loc: node.loc
57906               })];
57907
57908               function getReference(referenceID) {
57909                 return function showReference(selection) {
57910                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.impossible_oneway.' + referenceID + '.reference'));
57911                 };
57912               }
57913             }
57914           };
57915
57916           function continueDrawing(way, vertex, context) {
57917             // make sure the vertex is actually visible and editable
57918             var map = context.map();
57919
57920             if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
57921               map.zoomToEase(vertex);
57922             }
57923
57924             context.enter(modeDrawLine(context, way.id, context.graph(), 'line', way.affix(vertex.id), true));
57925           }
57926
57927           validation.type = type;
57928           return validation;
57929         }
57930
57931         function validationIncompatibleSource() {
57932           var type = 'incompatible_source';
57933           var incompatibleRules = [{
57934             id: 'amap',
57935             regex: /(amap|autonavi|mapabc|高德)/i
57936           }, {
57937             id: 'baidu',
57938             regex: /(baidu|mapbar|百度)/i
57939           }, {
57940             id: 'google',
57941             regex: /google/i,
57942             exceptRegex: /((books|drive)\.google|google\s?(books|drive|plus))/i
57943           }];
57944
57945           var validation = function checkIncompatibleSource(entity) {
57946             var entitySources = entity.tags && entity.tags.source && entity.tags.source.split(';');
57947             if (!entitySources) return [];
57948             var entityID = entity.id;
57949             return entitySources.map(function (source) {
57950               var matchRule = incompatibleRules.find(function (rule) {
57951                 if (!rule.regex.test(source)) return false;
57952                 if (rule.exceptRegex && rule.exceptRegex.test(source)) return false;
57953                 return true;
57954               });
57955               if (!matchRule) return null;
57956               return new validationIssue({
57957                 type: type,
57958                 severity: 'warning',
57959                 message: function message(context) {
57960                   var entity = context.hasEntity(entityID);
57961                   return entity ? _t.html('issues.incompatible_source.feature.message', {
57962                     feature: utilDisplayLabel(entity, context.graph(), true
57963                     /* verbose */
57964                     ),
57965                     value: source
57966                   }) : '';
57967                 },
57968                 reference: getReference(matchRule.id),
57969                 entityIds: [entityID],
57970                 hash: source,
57971                 dynamicFixes: function dynamicFixes() {
57972                   return [new validationIssueFix({
57973                     title: _t.html('issues.fix.remove_proprietary_data.title')
57974                   })];
57975                 }
57976               });
57977             }).filter(Boolean);
57978
57979             function getReference(id) {
57980               return function showReference(selection) {
57981                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html("issues.incompatible_source.reference.".concat(id)));
57982               };
57983             }
57984           };
57985
57986           validation.type = type;
57987           return validation;
57988         }
57989
57990         function validationMaprules() {
57991           var type = 'maprules';
57992
57993           var validation = function checkMaprules(entity, graph) {
57994             if (!services.maprules) return [];
57995             var rules = services.maprules.validationRules();
57996             var issues = [];
57997
57998             for (var i = 0; i < rules.length; i++) {
57999               var rule = rules[i];
58000               rule.findIssues(entity, graph, issues);
58001             }
58002
58003             return issues;
58004           };
58005
58006           validation.type = type;
58007           return validation;
58008         }
58009
58010         function validationMismatchedGeometry() {
58011           var type = 'mismatched_geometry';
58012
58013           function tagSuggestingLineIsArea(entity) {
58014             if (entity.type !== 'way' || entity.isClosed()) return null;
58015             var tagSuggestingArea = entity.tagSuggestingArea();
58016
58017             if (!tagSuggestingArea) {
58018               return null;
58019             }
58020
58021             var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, 'line');
58022             var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, 'area');
58023
58024             if (asLine && asArea && asLine === asArea) {
58025               // these tags also allow lines and making this an area wouldn't matter
58026               return null;
58027             }
58028
58029             return tagSuggestingArea;
58030           }
58031
58032           function makeConnectEndpointsFixOnClick(way, graph) {
58033             // must have at least three nodes to close this automatically
58034             if (way.nodes.length < 3) return null;
58035             var nodes = graph.childNodes(way),
58036                 testNodes;
58037             var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc); // if the distance is very small, attempt to merge the endpoints
58038
58039             if (firstToLastDistanceMeters < 0.75) {
58040               testNodes = nodes.slice(); // shallow copy
58041
58042               testNodes.pop();
58043               testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
58044
58045               if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
58046                 return function (context) {
58047                   var way = context.entity(this.issue.entityIds[0]);
58048                   context.perform(actionMergeNodes([way.nodes[0], way.nodes[way.nodes.length - 1]], nodes[0].loc), _t('issues.fix.connect_endpoints.annotation'));
58049                 };
58050               }
58051             } // if the points were not merged, attempt to close the way
58052
58053
58054             testNodes = nodes.slice(); // shallow copy
58055
58056             testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
58057
58058             if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
58059               return function (context) {
58060                 var wayId = this.issue.entityIds[0];
58061                 var way = context.entity(wayId);
58062                 var nodeId = way.nodes[0];
58063                 var index = way.nodes.length;
58064                 context.perform(actionAddVertex(wayId, nodeId, index), _t('issues.fix.connect_endpoints.annotation'));
58065               };
58066             }
58067           }
58068
58069           function lineTaggedAsAreaIssue(entity) {
58070             var tagSuggestingArea = tagSuggestingLineIsArea(entity);
58071             if (!tagSuggestingArea) return null;
58072             return new validationIssue({
58073               type: type,
58074               subtype: 'area_as_line',
58075               severity: 'warning',
58076               message: function message(context) {
58077                 var entity = context.hasEntity(this.entityIds[0]);
58078                 return entity ? _t.html('issues.tag_suggests_area.message', {
58079                   feature: utilDisplayLabel(entity, 'area', true
58080                   /* verbose */
58081                   ),
58082                   tag: utilTagText({
58083                     tags: tagSuggestingArea
58084                   })
58085                 }) : '';
58086               },
58087               reference: showReference,
58088               entityIds: [entity.id],
58089               hash: JSON.stringify(tagSuggestingArea),
58090               dynamicFixes: function dynamicFixes(context) {
58091                 var fixes = [];
58092                 var entity = context.entity(this.entityIds[0]);
58093                 var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph());
58094                 fixes.push(new validationIssueFix({
58095                   title: _t.html('issues.fix.connect_endpoints.title'),
58096                   onClick: connectEndsOnClick
58097                 }));
58098                 fixes.push(new validationIssueFix({
58099                   icon: 'iD-operation-delete',
58100                   title: _t.html('issues.fix.remove_tag.title'),
58101                   onClick: function onClick(context) {
58102                     var entityId = this.issue.entityIds[0];
58103                     var entity = context.entity(entityId);
58104                     var tags = Object.assign({}, entity.tags); // shallow copy
58105
58106                     for (var key in tagSuggestingArea) {
58107                       delete tags[key];
58108                     }
58109
58110                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_tag.annotation'));
58111                   }
58112                 }));
58113                 return fixes;
58114               }
58115             });
58116
58117             function showReference(selection) {
58118               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.tag_suggests_area.reference'));
58119             }
58120           }
58121
58122           function vertexPointIssue(entity, graph) {
58123             // we only care about nodes
58124             if (entity.type !== 'node') return null; // ignore tagless points
58125
58126             if (Object.keys(entity.tags).length === 0) return null; // address lines are special so just ignore them
58127
58128             if (entity.isOnAddressLine(graph)) return null;
58129             var geometry = entity.geometry(graph);
58130             var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
58131
58132             if (geometry === 'point' && !allowedGeometries.point && allowedGeometries.vertex) {
58133               return new validationIssue({
58134                 type: type,
58135                 subtype: 'vertex_as_point',
58136                 severity: 'warning',
58137                 message: function message(context) {
58138                   var entity = context.hasEntity(this.entityIds[0]);
58139                   return entity ? _t.html('issues.vertex_as_point.message', {
58140                     feature: utilDisplayLabel(entity, 'vertex', true
58141                     /* verbose */
58142                     )
58143                   }) : '';
58144                 },
58145                 reference: function showReference(selection) {
58146                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.vertex_as_point.reference'));
58147                 },
58148                 entityIds: [entity.id]
58149               });
58150             } else if (geometry === 'vertex' && !allowedGeometries.vertex && allowedGeometries.point) {
58151               return new validationIssue({
58152                 type: type,
58153                 subtype: 'point_as_vertex',
58154                 severity: 'warning',
58155                 message: function message(context) {
58156                   var entity = context.hasEntity(this.entityIds[0]);
58157                   return entity ? _t.html('issues.point_as_vertex.message', {
58158                     feature: utilDisplayLabel(entity, 'point', true
58159                     /* verbose */
58160                     )
58161                   }) : '';
58162                 },
58163                 reference: function showReference(selection) {
58164                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.point_as_vertex.reference'));
58165                 },
58166                 entityIds: [entity.id],
58167                 dynamicFixes: extractPointDynamicFixes
58168               });
58169             }
58170
58171             return null;
58172           }
58173
58174           function otherMismatchIssue(entity, graph) {
58175             // ignore boring features
58176             if (!entity.hasInterestingTags()) return null;
58177             if (entity.type !== 'node' && entity.type !== 'way') return null; // address lines are special so just ignore them
58178
58179             if (entity.type === 'node' && entity.isOnAddressLine(graph)) return null;
58180             var sourceGeom = entity.geometry(graph);
58181             var targetGeoms = entity.type === 'way' ? ['point', 'vertex'] : ['line', 'area'];
58182             if (sourceGeom === 'area') targetGeoms.unshift('line');
58183             var asSource = _mainPresetIndex.match(entity, graph);
58184             var targetGeom = targetGeoms.find(function (nodeGeom) {
58185               var asTarget = _mainPresetIndex.matchTags(entity.tags, nodeGeom);
58186               if (!asSource || !asTarget || asSource === asTarget || // sometimes there are two presets with the same tags for different geometries
58187               fastDeepEqual(asSource.tags, asTarget.tags)) return false;
58188               if (asTarget.isFallback()) return false;
58189               var primaryKey = Object.keys(asTarget.tags)[0]; // special case: buildings-as-points are discouraged by iD, but common in OSM, so ignore them
58190
58191               if (primaryKey === 'building') return false;
58192               if (asTarget.tags[primaryKey] === '*') return false;
58193               return asSource.isFallback() || asSource.tags[primaryKey] === '*';
58194             });
58195             if (!targetGeom) return null;
58196             var subtype = targetGeom + '_as_' + sourceGeom;
58197             if (targetGeom === 'vertex') targetGeom = 'point';
58198             if (sourceGeom === 'vertex') sourceGeom = 'point';
58199             var referenceId = targetGeom + '_as_' + sourceGeom;
58200             var dynamicFixes;
58201
58202             if (targetGeom === 'point') {
58203               dynamicFixes = extractPointDynamicFixes;
58204             } else if (sourceGeom === 'area' && targetGeom === 'line') {
58205               dynamicFixes = lineToAreaDynamicFixes;
58206             }
58207
58208             return new validationIssue({
58209               type: type,
58210               subtype: subtype,
58211               severity: 'warning',
58212               message: function message(context) {
58213                 var entity = context.hasEntity(this.entityIds[0]);
58214                 return entity ? _t.html('issues.' + referenceId + '.message', {
58215                   feature: utilDisplayLabel(entity, targetGeom, true
58216                   /* verbose */
58217                   )
58218                 }) : '';
58219               },
58220               reference: function showReference(selection) {
58221                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.mismatched_geometry.reference'));
58222               },
58223               entityIds: [entity.id],
58224               dynamicFixes: dynamicFixes
58225             });
58226           }
58227
58228           function lineToAreaDynamicFixes(context) {
58229             var convertOnClick;
58230             var entityId = this.entityIds[0];
58231             var entity = context.entity(entityId);
58232             var tags = Object.assign({}, entity.tags); // shallow copy
58233
58234             delete tags.area;
58235
58236             if (!osmTagSuggestingArea(tags)) {
58237               // if removing the area tag would make this a line, offer that as a quick fix
58238               convertOnClick = function convertOnClick(context) {
58239                 var entityId = this.issue.entityIds[0];
58240                 var entity = context.entity(entityId);
58241                 var tags = Object.assign({}, entity.tags); // shallow copy
58242
58243                 if (tags.area) {
58244                   delete tags.area;
58245                 }
58246
58247                 context.perform(actionChangeTags(entityId, tags), _t('issues.fix.convert_to_line.annotation'));
58248               };
58249             }
58250
58251             return [new validationIssueFix({
58252               icon: 'iD-icon-line',
58253               title: _t.html('issues.fix.convert_to_line.title'),
58254               onClick: convertOnClick
58255             })];
58256           }
58257
58258           function extractPointDynamicFixes(context) {
58259             var entityId = this.entityIds[0];
58260             var extractOnClick = null;
58261
58262             if (!context.hasHiddenConnections(entityId)) {
58263               extractOnClick = function extractOnClick(context) {
58264                 var entityId = this.issue.entityIds[0];
58265                 var action = actionExtract(entityId, context.projection);
58266                 context.perform(action, _t('operations.extract.annotation', {
58267                   n: 1
58268                 })); // re-enter mode to trigger updates
58269
58270                 context.enter(modeSelect(context, [action.getExtractedNodeID()]));
58271               };
58272             }
58273
58274             return [new validationIssueFix({
58275               icon: 'iD-operation-extract',
58276               title: _t.html('issues.fix.extract_point.title'),
58277               onClick: extractOnClick
58278             })];
58279           }
58280
58281           function unclosedMultipolygonPartIssues(entity, graph) {
58282             if (entity.type !== 'relation' || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
58283             !entity.isComplete(graph)) return [];
58284             var sequences = osmJoinWays(entity.members, graph);
58285             var issues = [];
58286
58287             for (var i in sequences) {
58288               var sequence = sequences[i];
58289               if (!sequence.nodes) continue;
58290               var firstNode = sequence.nodes[0];
58291               var lastNode = sequence.nodes[sequence.nodes.length - 1]; // part is closed if the first and last nodes are the same
58292
58293               if (firstNode === lastNode) continue;
58294               var issue = new validationIssue({
58295                 type: type,
58296                 subtype: 'unclosed_multipolygon_part',
58297                 severity: 'warning',
58298                 message: function message(context) {
58299                   var entity = context.hasEntity(this.entityIds[0]);
58300                   return entity ? _t.html('issues.unclosed_multipolygon_part.message', {
58301                     feature: utilDisplayLabel(entity, context.graph(), true
58302                     /* verbose */
58303                     )
58304                   }) : '';
58305                 },
58306                 reference: showReference,
58307                 loc: sequence.nodes[0].loc,
58308                 entityIds: [entity.id],
58309                 hash: sequence.map(function (way) {
58310                   return way.id;
58311                 }).join()
58312               });
58313               issues.push(issue);
58314             }
58315
58316             return issues;
58317
58318             function showReference(selection) {
58319               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unclosed_multipolygon_part.reference'));
58320             }
58321           }
58322
58323           var validation = function checkMismatchedGeometry(entity, graph) {
58324             var vertexPoint = vertexPointIssue(entity, graph);
58325             if (vertexPoint) return [vertexPoint];
58326             var lineAsArea = lineTaggedAsAreaIssue(entity);
58327             if (lineAsArea) return [lineAsArea];
58328             var mismatch = otherMismatchIssue(entity, graph);
58329             if (mismatch) return [mismatch];
58330             return unclosedMultipolygonPartIssues(entity, graph);
58331           };
58332
58333           validation.type = type;
58334           return validation;
58335         }
58336
58337         function validationMissingRole() {
58338           var type = 'missing_role';
58339
58340           var validation = function checkMissingRole(entity, graph) {
58341             var issues = [];
58342
58343             if (entity.type === 'way') {
58344               graph.parentRelations(entity).forEach(function (relation) {
58345                 if (!relation.isMultipolygon()) return;
58346                 var member = relation.memberById(entity.id);
58347
58348                 if (member && isMissingRole(member)) {
58349                   issues.push(makeIssue(entity, relation, member));
58350                 }
58351               });
58352             } else if (entity.type === 'relation' && entity.isMultipolygon()) {
58353               entity.indexedMembers().forEach(function (member) {
58354                 var way = graph.hasEntity(member.id);
58355
58356                 if (way && isMissingRole(member)) {
58357                   issues.push(makeIssue(way, entity, member));
58358                 }
58359               });
58360             }
58361
58362             return issues;
58363           };
58364
58365           function isMissingRole(member) {
58366             return !member.role || !member.role.trim().length;
58367           }
58368
58369           function makeIssue(way, relation, member) {
58370             return new validationIssue({
58371               type: type,
58372               severity: 'warning',
58373               message: function message(context) {
58374                 var member = context.hasEntity(this.entityIds[1]),
58375                     relation = context.hasEntity(this.entityIds[0]);
58376                 return member && relation ? _t.html('issues.missing_role.message', {
58377                   member: utilDisplayLabel(member, context.graph()),
58378                   relation: utilDisplayLabel(relation, context.graph())
58379                 }) : '';
58380               },
58381               reference: showReference,
58382               entityIds: [relation.id, way.id],
58383               data: {
58384                 member: member
58385               },
58386               hash: member.index.toString(),
58387               dynamicFixes: function dynamicFixes() {
58388                 return [makeAddRoleFix('inner'), makeAddRoleFix('outer'), new validationIssueFix({
58389                   icon: 'iD-operation-delete',
58390                   title: _t.html('issues.fix.remove_from_relation.title'),
58391                   onClick: function onClick(context) {
58392                     context.perform(actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), _t('operations.delete_member.annotation', {
58393                       n: 1
58394                     }));
58395                   }
58396                 })];
58397               }
58398             });
58399
58400             function showReference(selection) {
58401               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.missing_role.multipolygon.reference'));
58402             }
58403           }
58404
58405           function makeAddRoleFix(role) {
58406             return new validationIssueFix({
58407               title: _t.html('issues.fix.set_as_' + role + '.title'),
58408               onClick: function onClick(context) {
58409                 var oldMember = this.issue.data.member;
58410                 var member = {
58411                   id: this.issue.entityIds[1],
58412                   type: oldMember.type,
58413                   role: role
58414                 };
58415                 context.perform(actionChangeMember(this.issue.entityIds[0], member, oldMember.index), _t('operations.change_role.annotation', {
58416                   n: 1
58417                 }));
58418               }
58419             });
58420           }
58421
58422           validation.type = type;
58423           return validation;
58424         }
58425
58426         function validationMissingTag(context) {
58427           var type = 'missing_tag';
58428
58429           function hasDescriptiveTags(entity, graph) {
58430             var onlyAttributeKeys = ['description', 'name', 'note', 'start_date'];
58431             var entityDescriptiveKeys = Object.keys(entity.tags).filter(function (k) {
58432               if (k === 'area' || !osmIsInterestingTag(k)) return false;
58433               return !onlyAttributeKeys.some(function (attributeKey) {
58434                 return k === attributeKey || k.indexOf(attributeKey + ':') === 0;
58435               });
58436             });
58437
58438             if (entity.type === 'relation' && entityDescriptiveKeys.length === 1 && entity.tags.type === 'multipolygon') {
58439               // this relation's only interesting tag just says its a multipolygon,
58440               // which is not descriptive enough
58441               // It's okay for a simple multipolygon to have no descriptive tags
58442               // if its outer way has them (old model, see `outdated_tags.js`)
58443               return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
58444             }
58445
58446             return entityDescriptiveKeys.length > 0;
58447           }
58448
58449           function isUnknownRoad(entity) {
58450             return entity.type === 'way' && entity.tags.highway === 'road';
58451           }
58452
58453           function isUntypedRelation(entity) {
58454             return entity.type === 'relation' && !entity.tags.type;
58455           }
58456
58457           var validation = function checkMissingTag(entity, graph) {
58458             var subtype;
58459             var osm = context.connection();
58460             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
58461
58462             if (!isUnloadedNode && // allow untagged nodes that are part of ways
58463             entity.geometry(graph) !== 'vertex' && // allow untagged entities that are part of relations
58464             !entity.hasParentRelations(graph)) {
58465               if (Object.keys(entity.tags).length === 0) {
58466                 subtype = 'any';
58467               } else if (!hasDescriptiveTags(entity, graph)) {
58468                 subtype = 'descriptive';
58469               } else if (isUntypedRelation(entity)) {
58470                 subtype = 'relation_type';
58471               }
58472             } // flag an unknown road even if it's a member of a relation
58473
58474
58475             if (!subtype && isUnknownRoad(entity)) {
58476               subtype = 'highway_classification';
58477             }
58478
58479             if (!subtype) return [];
58480             var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
58481             var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag'; // can always delete if the user created it in the first place..
58482
58483             var canDelete = entity.version === undefined || entity.v !== undefined;
58484             var severity = canDelete && subtype !== 'highway_classification' ? 'error' : 'warning';
58485             return [new validationIssue({
58486               type: type,
58487               subtype: subtype,
58488               severity: severity,
58489               message: function message(context) {
58490                 var entity = context.hasEntity(this.entityIds[0]);
58491                 return entity ? _t.html('issues.' + messageID + '.message', {
58492                   feature: utilDisplayLabel(entity, context.graph())
58493                 }) : '';
58494               },
58495               reference: showReference,
58496               entityIds: [entity.id],
58497               dynamicFixes: function dynamicFixes(context) {
58498                 var fixes = [];
58499                 var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';
58500                 fixes.push(new validationIssueFix({
58501                   icon: 'iD-icon-search',
58502                   title: _t.html('issues.fix.' + selectFixType + '.title'),
58503                   onClick: function onClick(context) {
58504                     context.ui().sidebar.showPresetList();
58505                   }
58506                 }));
58507                 var deleteOnClick;
58508                 var id = this.entityIds[0];
58509                 var operation = operationDelete(context, [id]);
58510                 var disabledReasonID = operation.disabled();
58511
58512                 if (!disabledReasonID) {
58513                   deleteOnClick = function deleteOnClick(context) {
58514                     var id = this.issue.entityIds[0];
58515                     var operation = operationDelete(context, [id]);
58516
58517                     if (!operation.disabled()) {
58518                       operation();
58519                     }
58520                   };
58521                 }
58522
58523                 fixes.push(new validationIssueFix({
58524                   icon: 'iD-operation-delete',
58525                   title: _t.html('issues.fix.delete_feature.title'),
58526                   disabledReason: disabledReasonID ? _t('operations.delete.' + disabledReasonID + '.single') : undefined,
58527                   onClick: deleteOnClick
58528                 }));
58529                 return fixes;
58530               }
58531             })];
58532
58533             function showReference(selection) {
58534               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.' + referenceID + '.reference'));
58535             }
58536           };
58537
58538           validation.type = type;
58539           return validation;
58540         }
58541
58542         function validationOutdatedTags() {
58543           var type = 'outdated_tags';
58544           var _waitingForDeprecated = true;
58545
58546           var _dataDeprecated; // fetch deprecated tags
58547
58548
58549           _mainFileFetcher.get('deprecated').then(function (d) {
58550             return _dataDeprecated = d;
58551           })["catch"](function () {
58552             /* ignore */
58553           })["finally"](function () {
58554             return _waitingForDeprecated = false;
58555           });
58556
58557           function oldTagIssues(entity, graph) {
58558             var oldTags = Object.assign({}, entity.tags); // shallow copy
58559
58560             var preset = _mainPresetIndex.match(entity, graph);
58561             var subtype = 'deprecated_tags';
58562             if (!preset) return [];
58563             if (!entity.hasInterestingTags()) return []; // Upgrade preset, if a replacement is available..
58564
58565             if (preset.replacement) {
58566               var newPreset = _mainPresetIndex.item(preset.replacement);
58567               graph = actionChangePreset(entity.id, preset, newPreset, true
58568               /* skip field defaults */
58569               )(graph);
58570               entity = graph.entity(entity.id);
58571               preset = newPreset;
58572             } // Upgrade deprecated tags..
58573
58574
58575             if (_dataDeprecated) {
58576               var deprecatedTags = entity.deprecatedTags(_dataDeprecated);
58577
58578               if (deprecatedTags.length) {
58579                 deprecatedTags.forEach(function (tag) {
58580                   graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
58581                 });
58582                 entity = graph.entity(entity.id);
58583               }
58584             } // Add missing addTags from the detected preset
58585
58586
58587             var newTags = Object.assign({}, entity.tags); // shallow copy
58588
58589             if (preset.tags !== preset.addTags) {
58590               Object.keys(preset.addTags).forEach(function (k) {
58591                 if (!newTags[k]) {
58592                   if (preset.addTags[k] === '*') {
58593                     newTags[k] = 'yes';
58594                   } else {
58595                     newTags[k] = preset.addTags[k];
58596                   }
58597                 }
58598               });
58599             } // Attempt to match a canonical record in the name-suggestion-index.
58600
58601
58602             var nsi = services.nsi;
58603             var waitingForNsi = false;
58604             var nsiResult;
58605
58606             if (nsi) {
58607               waitingForNsi = nsi.status() === 'loading';
58608
58609               if (!waitingForNsi) {
58610                 var loc = entity.extent(graph).center();
58611                 nsiResult = nsi.upgradeTags(newTags, loc);
58612
58613                 if (nsiResult) {
58614                   newTags = nsiResult.newTags;
58615                   subtype = 'noncanonical_brand';
58616                 }
58617               }
58618             }
58619
58620             var issues = [];
58621             issues.provisional = _waitingForDeprecated || waitingForNsi; // determine diff
58622
58623             var tagDiff = utilTagDiff(oldTags, newTags);
58624             if (!tagDiff.length) return issues;
58625             var isOnlyAddingTags = tagDiff.every(function (d) {
58626               return d.type === '+';
58627             });
58628             var prefix = '';
58629
58630             if (nsiResult) {
58631               prefix = 'noncanonical_brand.';
58632             } else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
58633               subtype = 'incomplete_tags';
58634               prefix = 'incomplete.';
58635             } // don't allow autofixing brand tags
58636
58637
58638             var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, _t('issues.fix.upgrade_tags.annotation')] : null;
58639             issues.push(new validationIssue({
58640               type: type,
58641               subtype: subtype,
58642               severity: 'warning',
58643               message: showMessage,
58644               reference: showReference,
58645               entityIds: [entity.id],
58646               hash: utilHashcode(JSON.stringify(tagDiff)),
58647               dynamicFixes: function dynamicFixes() {
58648                 var fixes = [new validationIssueFix({
58649                   autoArgs: autoArgs,
58650                   title: _t.html('issues.fix.upgrade_tags.title'),
58651                   onClick: function onClick(context) {
58652                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
58653                   }
58654                 })];
58655                 var item = nsiResult && nsiResult.matched;
58656
58657                 if (item) {
58658                   fixes.push(new validationIssueFix({
58659                     title: _t.html('issues.fix.tag_as_not.title', {
58660                       name: item.displayName
58661                     }),
58662                     onClick: function onClick(context) {
58663                       context.perform(addNotTag, _t('issues.fix.tag_as_not.annotation'));
58664                     }
58665                   }));
58666                 }
58667
58668                 return fixes;
58669               }
58670             }));
58671             return issues;
58672
58673             function doUpgrade(graph) {
58674               var currEntity = graph.hasEntity(entity.id);
58675               if (!currEntity) return graph;
58676               var newTags = Object.assign({}, currEntity.tags); // shallow copy
58677
58678               tagDiff.forEach(function (diff) {
58679                 if (diff.type === '-') {
58680                   delete newTags[diff.key];
58681                 } else if (diff.type === '+') {
58682                   newTags[diff.key] = diff.newVal;
58683                 }
58684               });
58685               return actionChangeTags(currEntity.id, newTags)(graph);
58686             }
58687
58688             function addNotTag(graph) {
58689               var currEntity = graph.hasEntity(entity.id);
58690               if (!currEntity) return graph;
58691               var item = nsiResult && nsiResult.matched;
58692               if (!item) return graph;
58693               var newTags = Object.assign({}, currEntity.tags); // shallow copy
58694
58695               var wd = item.mainTag; // e.g. `brand:wikidata`
58696
58697               var notwd = "not:".concat(wd); // e.g. `not:brand:wikidata`
58698
58699               var qid = item.tags[wd];
58700               newTags[notwd] = qid;
58701
58702               if (newTags[wd] === qid) {
58703                 // if `brand:wikidata` was set to that qid
58704                 var wp = item.mainTag.replace('wikidata', 'wikipedia');
58705                 delete newTags[wd]; // remove `brand:wikidata`
58706
58707                 delete newTags[wp]; // remove `brand:wikipedia`
58708               }
58709
58710               return actionChangeTags(currEntity.id, newTags)(graph);
58711             }
58712
58713             function showMessage(context) {
58714               var currEntity = context.hasEntity(entity.id);
58715               if (!currEntity) return '';
58716               var messageID = "issues.outdated_tags.".concat(prefix, "message");
58717
58718               if (subtype === 'noncanonical_brand' && isOnlyAddingTags) {
58719                 messageID += '_incomplete';
58720               }
58721
58722               return _t.html(messageID, {
58723                 feature: utilDisplayLabel(currEntity, context.graph(), true
58724                 /* verbose */
58725                 )
58726               });
58727             }
58728
58729             function showReference(selection) {
58730               var enter = selection.selectAll('.issue-reference').data([0]).enter();
58731               enter.append('div').attr('class', 'issue-reference').html(_t.html("issues.outdated_tags.".concat(prefix, "reference")));
58732               enter.append('strong').html(_t.html('issues.suggested'));
58733               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) {
58734                 var klass = d.type === '+' ? 'add' : 'remove';
58735                 return "tagDiff-cell tagDiff-cell-".concat(klass);
58736               }).html(function (d) {
58737                 return d.display;
58738               });
58739             }
58740           }
58741
58742           function oldMultipolygonIssues(entity, graph) {
58743             var multipolygon, outerWay;
58744
58745             if (entity.type === 'relation') {
58746               outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
58747               multipolygon = entity;
58748             } else if (entity.type === 'way') {
58749               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
58750               outerWay = entity;
58751             } else {
58752               return [];
58753             }
58754
58755             if (!multipolygon || !outerWay) return [];
58756             return [new validationIssue({
58757               type: type,
58758               subtype: 'old_multipolygon',
58759               severity: 'warning',
58760               message: showMessage,
58761               reference: showReference,
58762               entityIds: [outerWay.id, multipolygon.id],
58763               dynamicFixes: function dynamicFixes() {
58764                 return [new validationIssueFix({
58765                   autoArgs: [doUpgrade, _t('issues.fix.move_tags.annotation')],
58766                   title: _t.html('issues.fix.move_tags.title'),
58767                   onClick: function onClick(context) {
58768                     context.perform(doUpgrade, _t('issues.fix.move_tags.annotation'));
58769                   }
58770                 })];
58771               }
58772             })];
58773
58774             function doUpgrade(graph) {
58775               var currMultipolygon = graph.hasEntity(multipolygon.id);
58776               var currOuterWay = graph.hasEntity(outerWay.id);
58777               if (!currMultipolygon || !currOuterWay) return graph;
58778               currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
58779               graph = graph.replace(currMultipolygon);
58780               return actionChangeTags(currOuterWay.id, {})(graph);
58781             }
58782
58783             function showMessage(context) {
58784               var currMultipolygon = context.hasEntity(multipolygon.id);
58785               if (!currMultipolygon) return '';
58786               return _t.html('issues.old_multipolygon.message', {
58787                 multipolygon: utilDisplayLabel(currMultipolygon, context.graph(), true
58788                 /* verbose */
58789                 )
58790               });
58791             }
58792
58793             function showReference(selection) {
58794               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.old_multipolygon.reference'));
58795             }
58796           }
58797
58798           var validation = function checkOutdatedTags(entity, graph) {
58799             var issues = oldMultipolygonIssues(entity, graph);
58800             if (!issues.length) issues = oldTagIssues(entity, graph);
58801             return issues;
58802           };
58803
58804           validation.type = type;
58805           return validation;
58806         }
58807
58808         function validationPrivateData() {
58809           var type = 'private_data'; // assume that some buildings are private
58810
58811           var privateBuildingValues = {
58812             detached: true,
58813             farm: true,
58814             house: true,
58815             houseboat: true,
58816             residential: true,
58817             semidetached_house: true,
58818             static_caravan: true
58819           }; // but they might be public if they have one of these other tags
58820
58821           var publicKeys = {
58822             amenity: true,
58823             craft: true,
58824             historic: true,
58825             leisure: true,
58826             office: true,
58827             shop: true,
58828             tourism: true
58829           }; // these tags may contain personally identifying info
58830
58831           var personalTags = {
58832             'contact:email': true,
58833             'contact:fax': true,
58834             'contact:phone': true,
58835             email: true,
58836             fax: true,
58837             phone: true
58838           };
58839
58840           var validation = function checkPrivateData(entity) {
58841             var tags = entity.tags;
58842             if (!tags.building || !privateBuildingValues[tags.building]) return [];
58843             var keepTags = {};
58844
58845             for (var k in tags) {
58846               if (publicKeys[k]) return []; // probably a public feature
58847
58848               if (!personalTags[k]) {
58849                 keepTags[k] = tags[k];
58850               }
58851             }
58852
58853             var tagDiff = utilTagDiff(tags, keepTags);
58854             if (!tagDiff.length) return [];
58855             var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
58856             return [new validationIssue({
58857               type: type,
58858               severity: 'warning',
58859               message: showMessage,
58860               reference: showReference,
58861               entityIds: [entity.id],
58862               dynamicFixes: function dynamicFixes() {
58863                 return [new validationIssueFix({
58864                   icon: 'iD-operation-delete',
58865                   title: _t.html('issues.fix.' + fixID + '.title'),
58866                   onClick: function onClick(context) {
58867                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
58868                   }
58869                 })];
58870               }
58871             })];
58872
58873             function doUpgrade(graph) {
58874               var currEntity = graph.hasEntity(entity.id);
58875               if (!currEntity) return graph;
58876               var newTags = Object.assign({}, currEntity.tags); // shallow copy
58877
58878               tagDiff.forEach(function (diff) {
58879                 if (diff.type === '-') {
58880                   delete newTags[diff.key];
58881                 } else if (diff.type === '+') {
58882                   newTags[diff.key] = diff.newVal;
58883                 }
58884               });
58885               return actionChangeTags(currEntity.id, newTags)(graph);
58886             }
58887
58888             function showMessage(context) {
58889               var currEntity = context.hasEntity(this.entityIds[0]);
58890               if (!currEntity) return '';
58891               return _t.html('issues.private_data.contact.message', {
58892                 feature: utilDisplayLabel(currEntity, context.graph())
58893               });
58894             }
58895
58896             function showReference(selection) {
58897               var enter = selection.selectAll('.issue-reference').data([0]).enter();
58898               enter.append('div').attr('class', 'issue-reference').html(_t.html('issues.private_data.reference'));
58899               enter.append('strong').html(_t.html('issues.suggested'));
58900               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) {
58901                 var klass = d.type === '+' ? 'add' : 'remove';
58902                 return 'tagDiff-cell tagDiff-cell-' + klass;
58903               }).html(function (d) {
58904                 return d.display;
58905               });
58906             }
58907           };
58908
58909           validation.type = type;
58910           return validation;
58911         }
58912
58913         function validationSuspiciousName() {
58914           var type = 'suspicious_name';
58915           var keysToTestForGenericValues = ['aerialway', 'aeroway', 'amenity', 'building', 'craft', 'highway', 'leisure', 'railway', 'man_made', 'office', 'shop', 'tourism', 'waterway'];
58916           var _waitingForNsi = false; // Attempt to match a generic record in the name-suggestion-index.
58917
58918           function isGenericMatchInNsi(tags) {
58919             var nsi = services.nsi;
58920
58921             if (nsi) {
58922               _waitingForNsi = nsi.status() === 'loading';
58923
58924               if (!_waitingForNsi) {
58925                 return nsi.isGenericName(tags);
58926               }
58927             }
58928
58929             return false;
58930           } // Test if the name is just the key or tag value (e.g. "park")
58931
58932
58933           function nameMatchesRawTag(lowercaseName, tags) {
58934             for (var i = 0; i < keysToTestForGenericValues.length; i++) {
58935               var key = keysToTestForGenericValues[i];
58936               var val = tags[key];
58937
58938               if (val) {
58939                 val = val.toLowerCase();
58940
58941                 if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, ' ') === lowercaseName || val.replace(/\_/g, ' ') === lowercaseName) {
58942                   return true;
58943                 }
58944               }
58945             }
58946
58947             return false;
58948           }
58949
58950           function isGenericName(name, tags) {
58951             name = name.toLowerCase();
58952             return nameMatchesRawTag(name, tags) || isGenericMatchInNsi(tags);
58953           }
58954
58955           function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
58956             return new validationIssue({
58957               type: type,
58958               subtype: 'generic_name',
58959               severity: 'warning',
58960               message: function message(context) {
58961                 var entity = context.hasEntity(this.entityIds[0]);
58962                 if (!entity) return '';
58963                 var preset = _mainPresetIndex.match(entity, context.graph());
58964                 var langName = langCode && _mainLocalizer.languageName(langCode);
58965                 return _t.html('issues.generic_name.message' + (langName ? '_language' : ''), {
58966                   feature: preset.name(),
58967                   name: genericName,
58968                   language: langName
58969                 });
58970               },
58971               reference: showReference,
58972               entityIds: [entityId],
58973               hash: "".concat(nameKey, "=").concat(genericName),
58974               dynamicFixes: function dynamicFixes() {
58975                 return [new validationIssueFix({
58976                   icon: 'iD-operation-delete',
58977                   title: _t.html('issues.fix.remove_the_name.title'),
58978                   onClick: function onClick(context) {
58979                     var entityId = this.issue.entityIds[0];
58980                     var entity = context.entity(entityId);
58981                     var tags = Object.assign({}, entity.tags); // shallow copy
58982
58983                     delete tags[nameKey];
58984                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_generic_name.annotation'));
58985                   }
58986                 })];
58987               }
58988             });
58989
58990             function showReference(selection) {
58991               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
58992             }
58993           }
58994
58995           function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
58996             return new validationIssue({
58997               type: type,
58998               subtype: 'not_name',
58999               severity: 'warning',
59000               message: function message(context) {
59001                 var entity = context.hasEntity(this.entityIds[0]);
59002                 if (!entity) return '';
59003                 var preset = _mainPresetIndex.match(entity, context.graph());
59004                 var langName = langCode && _mainLocalizer.languageName(langCode);
59005                 return _t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), {
59006                   feature: preset.name(),
59007                   name: incorrectName,
59008                   language: langName
59009                 });
59010               },
59011               reference: showReference,
59012               entityIds: [entityId],
59013               hash: "".concat(nameKey, "=").concat(incorrectName),
59014               dynamicFixes: function dynamicFixes() {
59015                 return [new validationIssueFix({
59016                   icon: 'iD-operation-delete',
59017                   title: _t.html('issues.fix.remove_the_name.title'),
59018                   onClick: function onClick(context) {
59019                     var entityId = this.issue.entityIds[0];
59020                     var entity = context.entity(entityId);
59021                     var tags = Object.assign({}, entity.tags); // shallow copy
59022
59023                     delete tags[nameKey];
59024                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_mistaken_name.annotation'));
59025                   }
59026                 })];
59027               }
59028             });
59029
59030             function showReference(selection) {
59031               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
59032             }
59033           }
59034
59035           var validation = function checkGenericName(entity) {
59036             var tags = entity.tags; // a generic name is allowed if it's a known brand or entity
59037
59038             var hasWikidata = !!tags.wikidata || !!tags['brand:wikidata'] || !!tags['operator:wikidata'];
59039             if (hasWikidata) return [];
59040             var issues = [];
59041             var notNames = (tags['not:name'] || '').split(';');
59042
59043             for (var key in tags) {
59044               var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
59045               if (!m) continue;
59046               var langCode = m.length >= 2 ? m[1] : null;
59047               var value = tags[key];
59048
59049               if (notNames.length) {
59050                 for (var i in notNames) {
59051                   var notName = notNames[i];
59052
59053                   if (notName && value === notName) {
59054                     issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
59055                     continue;
59056                   }
59057                 }
59058               }
59059
59060               if (isGenericName(value, tags)) {
59061                 issues.provisional = _waitingForNsi; // retry later if we are waiting on NSI to finish loading
59062
59063                 issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
59064               }
59065             }
59066
59067             return issues;
59068           };
59069
59070           validation.type = type;
59071           return validation;
59072         }
59073
59074         function validationUnsquareWay(context) {
59075           var type = 'unsquare_way';
59076           var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
59077           // use looser epsilon for detection to reduce warnings of buildings that are essentially square already
59078
59079           var epsilon = 0.05;
59080           var nodeThreshold = 10;
59081
59082           function isBuilding(entity, graph) {
59083             if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
59084             return entity.tags.building && entity.tags.building !== 'no';
59085           }
59086
59087           var validation = function checkUnsquareWay(entity, graph) {
59088             if (!isBuilding(entity, graph)) return []; // don't flag ways marked as physically unsquare
59089
59090             if (entity.tags.nonsquare === 'yes') return [];
59091             var isClosed = entity.isClosed();
59092             if (!isClosed) return []; // this building has bigger problems
59093             // don't flag ways with lots of nodes since they are likely detail-mapped
59094
59095             var nodes = graph.childNodes(entity).slice(); // shallow copy
59096
59097             if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
59098             // ignore if not all nodes are fully downloaded
59099
59100             var osm = services.osm;
59101             if (!osm || nodes.some(function (node) {
59102               return !osm.isDataLoaded(node.loc);
59103             })) return []; // don't flag connected ways to avoid unresolvable unsquare loops
59104
59105             var hasConnectedSquarableWays = nodes.some(function (node) {
59106               return graph.parentWays(node).some(function (way) {
59107                 if (way.id === entity.id) return false;
59108                 if (isBuilding(way, graph)) return true;
59109                 return graph.parentRelations(way).some(function (parentRelation) {
59110                   return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== 'no';
59111                 });
59112               });
59113             });
59114             if (hasConnectedSquarableWays) return []; // user-configurable square threshold
59115
59116             var storedDegreeThreshold = corePreferences('validate-square-degrees');
59117             var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
59118             var points = nodes.map(function (node) {
59119               return context.projection(node.loc);
59120             });
59121             if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
59122             var autoArgs; // don't allow autosquaring features linked to wikidata
59123
59124             if (!entity.tags.wikidata) {
59125               // use same degree threshold as for detection
59126               var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
59127               autoAction.transitionable = false; // when autofixing, do it instantly
59128
59129               autoArgs = [autoAction, _t('operations.orthogonalize.annotation.feature', {
59130                 n: 1
59131               })];
59132             }
59133
59134             return [new validationIssue({
59135               type: type,
59136               subtype: 'building',
59137               severity: 'warning',
59138               message: function message(context) {
59139                 var entity = context.hasEntity(this.entityIds[0]);
59140                 return entity ? _t.html('issues.unsquare_way.message', {
59141                   feature: utilDisplayLabel(entity, context.graph())
59142                 }) : '';
59143               },
59144               reference: showReference,
59145               entityIds: [entity.id],
59146               hash: degreeThreshold,
59147               dynamicFixes: function dynamicFixes() {
59148                 return [new validationIssueFix({
59149                   icon: 'iD-operation-orthogonalize',
59150                   title: _t.html('issues.fix.square_feature.title'),
59151                   autoArgs: autoArgs,
59152                   onClick: function onClick(context, completionHandler) {
59153                     var entityId = this.issue.entityIds[0]; // use same degree threshold as for detection
59154
59155                     context.perform(actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold), _t('operations.orthogonalize.annotation.feature', {
59156                       n: 1
59157                     })); // run after the squaring transition (currently 150ms)
59158
59159                     window.setTimeout(function () {
59160                       completionHandler();
59161                     }, 175);
59162                   }
59163                 })
59164                 /*
59165                 new validationIssueFix({
59166                     title: t.html('issues.fix.tag_as_unsquare.title'),
59167                     onClick: function(context) {
59168                         var entityId = this.issue.entityIds[0];
59169                         var entity = context.entity(entityId);
59170                         var tags = Object.assign({}, entity.tags);  // shallow copy
59171                         tags.nonsquare = 'yes';
59172                         context.perform(
59173                             actionChangeTags(entityId, tags),
59174                             t('issues.fix.tag_as_unsquare.annotation')
59175                         );
59176                     }
59177                 })
59178                 */
59179                 ];
59180               }
59181             })];
59182
59183             function showReference(selection) {
59184               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unsquare_way.buildings.reference'));
59185             }
59186           };
59187
59188           validation.type = type;
59189           return validation;
59190         }
59191
59192         var Validations = /*#__PURE__*/Object.freeze({
59193                 __proto__: null,
59194                 validationAlmostJunction: validationAlmostJunction,
59195                 validationCloseNodes: validationCloseNodes,
59196                 validationCrossingWays: validationCrossingWays,
59197                 validationDisconnectedWay: validationDisconnectedWay,
59198                 validationFormatting: validationFormatting,
59199                 validationHelpRequest: validationHelpRequest,
59200                 validationImpossibleOneway: validationImpossibleOneway,
59201                 validationIncompatibleSource: validationIncompatibleSource,
59202                 validationMaprules: validationMaprules,
59203                 validationMismatchedGeometry: validationMismatchedGeometry,
59204                 validationMissingRole: validationMissingRole,
59205                 validationMissingTag: validationMissingTag,
59206                 validationOutdatedTags: validationOutdatedTags,
59207                 validationPrivateData: validationPrivateData,
59208                 validationSuspiciousName: validationSuspiciousName,
59209                 validationUnsquareWay: validationUnsquareWay
59210         });
59211
59212         function coreValidator(context) {
59213           var _this = this;
59214
59215           var dispatch = dispatch$8('validated', 'focusedIssue');
59216           var validator = utilRebind({}, dispatch, 'on');
59217           var _rules = {};
59218           var _disabledRules = {};
59219
59220           var _ignoredIssueIDs = new Set();
59221
59222           var _resolvedIssueIDs = new Set();
59223
59224           var _baseCache = validationCache('base'); // issues before any user edits
59225
59226
59227           var _headCache = validationCache('head'); // issues after all user edits
59228
59229
59230           var _completeDiff = {}; // complete diff base -> head of what the user changed
59231
59232           var _headIsCurrent = false;
59233
59234           var _deferredRIC = new Set(); // Set( RequestIdleCallback handles )
59235
59236
59237           var _deferredST = new Set(); // Set( SetTimeout handles )
59238
59239
59240           var _headPromise; // Promise fulfilled when validation is performed up to headGraph snapshot
59241
59242
59243           var RETRY = 5000; // wait 5sec before revalidating provisional entities
59244           // Allow validation severity to be overridden by url queryparams...
59245           // See: https://github.com/openstreetmap/iD/pull/8243
59246           //
59247           // Each param should contain a urlencoded comma separated list of
59248           // `type/subtype` rules.  `*` may be used as a wildcard..
59249           // Examples:
59250           //  `validationError=disconnected_way/*`
59251           //  `validationError=disconnected_way/highway`
59252           //  `validationError=crossing_ways/bridge*`
59253           //  `validationError=crossing_ways/bridge*,crossing_ways/tunnel*`
59254
59255           var _errorOverrides = parseHashParam(context.initialHashParams.validationError);
59256
59257           var _warningOverrides = parseHashParam(context.initialHashParams.validationWarning);
59258
59259           var _disableOverrides = parseHashParam(context.initialHashParams.validationDisable); // `parseHashParam()`   (private)
59260           // Checks hash parameters for severity overrides
59261           // Arguments
59262           //   `param` - a url hash parameter (`validationError`, `validationWarning`, or `validationDisable`)
59263           // Returns
59264           //   Array of Objects like { type: RegExp, subtype: RegExp }
59265           //
59266
59267
59268           function parseHashParam(param) {
59269             var result = [];
59270             var rules = (param || '').split(',');
59271             rules.forEach(function (rule) {
59272               rule = rule.trim();
59273               var parts = rule.split('/', 2); // "type/subtype"
59274
59275               var type = parts[0];
59276               var subtype = parts[1] || '*';
59277               if (!type || !subtype) return;
59278               result.push({
59279                 type: makeRegExp(type),
59280                 subtype: makeRegExp(subtype)
59281               });
59282             });
59283             return result;
59284
59285             function makeRegExp(str) {
59286               var escaped = str.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&') // escape all reserved chars except for the '*'
59287               .replace(/\*/g, '.*'); // treat a '*' like '.*'
59288
59289               return new RegExp('^' + escaped + '$');
59290             }
59291           } // `init()`
59292           // Initialize the validator, called once on iD startup
59293           //
59294
59295
59296           validator.init = function () {
59297             Object.values(Validations).forEach(function (validation) {
59298               if (typeof validation !== 'function') return;
59299               var fn = validation(context);
59300               var key = fn.type;
59301               _rules[key] = fn;
59302             });
59303             var disabledRules = corePreferences('validate-disabledRules');
59304
59305             if (disabledRules) {
59306               disabledRules.split(',').forEach(function (k) {
59307                 return _disabledRules[k] = true;
59308               });
59309             }
59310           }; // `reset()`   (private)
59311           // Cancels deferred work and resets all caches
59312           //
59313           // Arguments
59314           //   `resetIgnored` - `true` to clear the list of user-ignored issues
59315           //
59316
59317
59318           function reset(resetIgnored) {
59319             // cancel deferred work
59320             _deferredRIC.forEach(window.cancelIdleCallback);
59321
59322             _deferredRIC.clear();
59323
59324             _deferredST.forEach(window.clearTimeout);
59325
59326             _deferredST.clear(); // empty queues and resolve any pending promise
59327
59328
59329             _baseCache.queue = [];
59330             _headCache.queue = [];
59331             processQueue(_headCache);
59332             processQueue(_baseCache); // clear caches
59333
59334             if (resetIgnored) _ignoredIssueIDs.clear();
59335
59336             _resolvedIssueIDs.clear();
59337
59338             _baseCache = validationCache('base');
59339             _headCache = validationCache('head');
59340             _completeDiff = {};
59341             _headIsCurrent = false;
59342           } // `reset()`
59343           // clear caches, called whenever iD resets after a save or switches sources
59344           // (clears out the _ignoredIssueIDs set also)
59345           //
59346
59347
59348           validator.reset = function () {
59349             reset(true);
59350           }; // `resetIgnoredIssues()`
59351           // clears out the _ignoredIssueIDs Set
59352           //
59353
59354
59355           validator.resetIgnoredIssues = function () {
59356             _ignoredIssueIDs.clear();
59357
59358             dispatch.call('validated'); // redraw UI
59359           }; // `revalidateUnsquare()`
59360           // Called whenever the user changes the unsquare threshold
59361           // It reruns just the "unsquare_way" validation on all buildings.
59362           //
59363
59364
59365           validator.revalidateUnsquare = function () {
59366             revalidateUnsquare(_headCache);
59367             revalidateUnsquare(_baseCache);
59368             dispatch.call('validated');
59369           };
59370
59371           function revalidateUnsquare(cache) {
59372             var checkUnsquareWay = _rules.unsquare_way;
59373             if (!cache.graph || typeof checkUnsquareWay !== 'function') return; // uncache existing
59374
59375             cache.uncacheIssuesOfType('unsquare_way');
59376             var buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), cache.graph) // everywhere
59377             .filter(function (entity) {
59378               return entity.type === 'way' && entity.tags.building && entity.tags.building !== 'no';
59379             }); // rerun for all buildings
59380
59381             buildings.forEach(function (entity) {
59382               var detected = checkUnsquareWay(entity, cache.graph);
59383               if (!detected.length) return;
59384               cache.cacheIssues(detected);
59385             });
59386           } // `getIssues()`
59387           // Gets all issues that match the given options
59388           // This is called by many other places
59389           //
59390           // Arguments
59391           //   `options` Object like:
59392           //   {
59393           //     what: 'all',                  // 'all' or 'edited'
59394           //     where: 'all',                 // 'all' or 'visible'
59395           //     includeIgnored: false,        // true, false, or 'only'
59396           //     includeDisabledRules: false   // true, false, or 'only'
59397           //   }
59398           //
59399           // Returns
59400           //   An Array containing the issues
59401           //
59402
59403
59404           validator.getIssues = function (options) {
59405             var opts = Object.assign({
59406               what: 'all',
59407               where: 'all',
59408               includeIgnored: false,
59409               includeDisabledRules: false
59410             }, options);
59411             var view = context.map().extent();
59412             var seen = new Set();
59413             var results = []; // collect head issues - present in the user edits
59414
59415             if (_headCache.graph && _headCache.graph !== _baseCache.graph) {
59416               Object.values(_headCache.issuesByIssueID).forEach(function (issue) {
59417                 // In the head cache, only count features that the user is responsible for - #8632
59418                 // For example, a user can undo some work and an issue will still present in the
59419                 // head graph, but we don't want to credit the user for causing that issue.
59420                 var userModified = (issue.entityIds || []).some(function (id) {
59421                   return _completeDiff.hasOwnProperty(id);
59422                 });
59423                 if (opts.what === 'edited' && !userModified) return; // present in head but user didn't touch it
59424
59425                 if (!filter(issue)) return;
59426                 seen.add(issue.id);
59427                 results.push(issue);
59428               });
59429             } // collect base issues - present before user edits
59430
59431
59432             if (opts.what === 'all') {
59433               Object.values(_baseCache.issuesByIssueID).forEach(function (issue) {
59434                 if (!filter(issue)) return;
59435                 seen.add(issue.id);
59436                 results.push(issue);
59437               });
59438             }
59439
59440             return results; // Filter the issue set to include only what the calling code wants to see.
59441             // Note that we use `context.graph()`/`context.hasEntity()` here, not `cache.graph`,
59442             // because that is the graph that the calling code will be using.
59443
59444             function filter(issue) {
59445               if (!issue) return false;
59446               if (seen.has(issue.id)) return false;
59447               if (_resolvedIssueIDs.has(issue.id)) return false;
59448               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
59449               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
59450               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs.has(issue.id)) return false;
59451               if (!opts.includeIgnored && _ignoredIssueIDs.has(issue.id)) return false; // This issue may involve an entity that doesn't exist in context.graph()
59452               // This can happen because validation is async and rendering the issue lists is async.
59453
59454               if ((issue.entityIds || []).some(function (id) {
59455                 return !context.hasEntity(id);
59456               })) return false;
59457
59458               if (opts.where === 'visible') {
59459                 var extent = issue.extent(context.graph());
59460                 if (!view.intersects(extent)) return false;
59461               }
59462
59463               return true;
59464             }
59465           }; // `getResolvedIssues()`
59466           // Gets the issues that have been fixed by the user.
59467           //
59468           // Resolved issues are tracked in the `_resolvedIssueIDs` Set,
59469           // and they should all be issues that exist in the _baseCache.
59470           //
59471           // Returns
59472           //   An Array containing the issues
59473           //
59474
59475
59476           validator.getResolvedIssues = function () {
59477             return Array.from(_resolvedIssueIDs).map(function (issueID) {
59478               return _baseCache.issuesByIssueID[issueID];
59479             }).filter(Boolean);
59480           }; // `focusIssue()`
59481           // Adjusts the map to focus on the given issue.
59482           // (requires the issue to have a reasonable extent defined)
59483           //
59484           // Arguments
59485           //   `issue` - the issue to focus on
59486           //
59487
59488
59489           validator.focusIssue = function (issue) {
59490             // Note that we use `context.graph()`/`context.hasEntity()` here, not `cache.graph`,
59491             // because that is the graph that the calling code will be using.
59492             var graph = context.graph();
59493             var selectID;
59494             var focusCenter; // Try to focus the map at the center of the issue..
59495
59496             var issueExtent = issue.extent(graph);
59497
59498             if (issueExtent) {
59499               focusCenter = issueExtent.center();
59500             } // Try to select the first entity in the issue..
59501
59502
59503             if (issue.entityIds && issue.entityIds.length) {
59504               selectID = issue.entityIds[0]; // If a relation, focus on one of its members instead.
59505               // Otherwise we might be focusing on a part of map where the relation is not visible.
59506
59507               if (selectID && selectID.charAt(0) === 'r') {
59508                 // relation
59509                 var ids = utilEntityAndDeepMemberIDs([selectID], graph);
59510                 var nodeID = ids.find(function (id) {
59511                   return id.charAt(0) === 'n' && graph.hasEntity(id);
59512                 });
59513
59514                 if (!nodeID) {
59515                   // relation has no downloaded nodes to focus on
59516                   var wayID = ids.find(function (id) {
59517                     return id.charAt(0) === 'w' && graph.hasEntity(id);
59518                   });
59519
59520                   if (wayID) {
59521                     nodeID = graph.entity(wayID).first(); // focus on the first node of this way
59522                   }
59523                 }
59524
59525                 if (nodeID) {
59526                   focusCenter = graph.entity(nodeID).loc;
59527                 }
59528               }
59529             }
59530
59531             if (focusCenter) {
59532               // Adjust the view
59533               var setZoom = Math.max(context.map().zoom(), 19);
59534               context.map().unobscuredCenterZoomEase(focusCenter, setZoom);
59535             }
59536
59537             if (selectID) {
59538               // Enter select mode
59539               window.setTimeout(function () {
59540                 context.enter(modeSelect(context, [selectID]));
59541                 dispatch.call('focusedIssue', _this, issue);
59542               }, 250); // after ease
59543             }
59544           }; // `getIssuesBySeverity()`
59545           // Gets the issues then groups them by error/warning
59546           // (This just calls getIssues, then puts issues in groups)
59547           //
59548           // Arguments
59549           //   `options` - (see `getIssues`)
59550           // Returns
59551           //   Object result like:
59552           //   {
59553           //     error:    Array of errors,
59554           //     warning:  Array of warnings
59555           //   }
59556           //
59557
59558
59559           validator.getIssuesBySeverity = function (options) {
59560             var groups = utilArrayGroupBy(validator.getIssues(options), 'severity');
59561             groups.error = groups.error || [];
59562             groups.warning = groups.warning || [];
59563             return groups;
59564           }; // `getEntityIssues()`
59565           // Gets the issues that the given entity IDs have in common, matching the given options
59566           // (This just calls getIssues, then filters for the given entity IDs)
59567           // The issues are sorted for relevance
59568           //
59569           // Arguments
59570           //   `entityIDs` - Array or Set of entityIDs to get issues for
59571           //   `options` - (see `getIssues`)
59572           // Returns
59573           //   An Array containing the issues
59574           //
59575
59576
59577           validator.getSharedEntityIssues = function (entityIDs, options) {
59578             var orderedIssueTypes = [// Show some issue types in a particular order:
59579             'missing_tag', 'missing_role', // - missing data first
59580             'outdated_tags', 'mismatched_geometry', // - identity issues
59581             'crossing_ways', 'almost_junction', // - geometry issues where fixing them might solve connectivity issues
59582             'disconnected_way', 'impossible_oneway' // - finally connectivity issues
59583             ];
59584             var allIssues = validator.getIssues(options);
59585             var forEntityIDs = new Set(entityIDs);
59586             return allIssues.filter(function (issue) {
59587               return (issue.entityIds || []).some(function (entityID) {
59588                 return forEntityIDs.has(entityID);
59589               });
59590             }).sort(function (issue1, issue2) {
59591               if (issue1.type === issue2.type) {
59592                 // issues of the same type, sort deterministically
59593                 return issue1.id < issue2.id ? -1 : 1;
59594               }
59595
59596               var index1 = orderedIssueTypes.indexOf(issue1.type);
59597               var index2 = orderedIssueTypes.indexOf(issue2.type);
59598
59599               if (index1 !== -1 && index2 !== -1) {
59600                 // both issue types have explicit sort orders
59601                 return index1 - index2;
59602               } else if (index1 === -1 && index2 === -1) {
59603                 // neither issue type has an explicit sort order, sort by type
59604                 return issue1.type < issue2.type ? -1 : 1;
59605               } else {
59606                 // order explicit types before everything else
59607                 return index1 !== -1 ? -1 : 1;
59608               }
59609             });
59610           }; // `getEntityIssues()`
59611           // Get an array of detected issues for the given entityID.
59612           // (This just calls getSharedEntityIssues for a single entity)
59613           //
59614           // Arguments
59615           //   `entityID` - the entity ID to get the issues for
59616           //   `options` - (see `getIssues`)
59617           // Returns
59618           //   An Array containing the issues
59619           //
59620
59621
59622           validator.getEntityIssues = function (entityID, options) {
59623             return validator.getSharedEntityIssues([entityID], options);
59624           }; // `getRuleKeys()`
59625           //
59626           // Returns
59627           //   An Array containing the rule keys
59628           //
59629
59630
59631           validator.getRuleKeys = function () {
59632             return Object.keys(_rules);
59633           }; // `isRuleEnabled()`
59634           //
59635           // Arguments
59636           //   `key` - the rule to check (e.g. 'crossing_ways')
59637           // Returns
59638           //   `true`/`false`
59639           //
59640
59641
59642           validator.isRuleEnabled = function (key) {
59643             return !_disabledRules[key];
59644           }; // `toggleRule()`
59645           // Toggles a single validation rule,
59646           // then reruns the validation so that the user sees something happen in the UI
59647           //
59648           // Arguments
59649           //   `key` - the rule to toggle (e.g. 'crossing_ways')
59650           //
59651
59652
59653           validator.toggleRule = function (key) {
59654             if (_disabledRules[key]) {
59655               delete _disabledRules[key];
59656             } else {
59657               _disabledRules[key] = true;
59658             }
59659
59660             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
59661             validator.validate();
59662           }; // `disableRules()`
59663           // Disables given validation rules,
59664           // then reruns the validation so that the user sees something happen in the UI
59665           //
59666           // Arguments
59667           //   `keys` - Array or Set containing rule keys to disable
59668           //
59669
59670
59671           validator.disableRules = function (keys) {
59672             _disabledRules = {};
59673             keys.forEach(function (k) {
59674               return _disabledRules[k] = true;
59675             });
59676             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
59677             validator.validate();
59678           }; // `ignoreIssue()`
59679           // Don't show the given issue in lists
59680           //
59681           // Arguments
59682           //   `issueID` - the issueID
59683           //
59684
59685
59686           validator.ignoreIssue = function (issueID) {
59687             _ignoredIssueIDs.add(issueID);
59688           }; // `validate()`
59689           // Validates anything that has changed in the head graph since the last time it was run.
59690           // (head graph contains user's edits)
59691           //
59692           // Returns
59693           //   A Promise fulfilled when the validation has completed and then dispatches a `validated` event.
59694           //   This may take time but happen in the background during browser idle time.
59695           //
59696
59697
59698           validator.validate = function () {
59699             // Make sure the caches have graphs assigned to them.
59700             // (we don't do this in `reset` because context is still resetting things and `history.base()` is unstable then)
59701             var baseGraph = context.history().base();
59702             if (!_headCache.graph) _headCache.graph = baseGraph;
59703             if (!_baseCache.graph) _baseCache.graph = baseGraph;
59704             var prevGraph = _headCache.graph;
59705             var currGraph = context.graph();
59706
59707             if (currGraph === prevGraph) {
59708               // _headCache.graph is current - we are caught up
59709               _headIsCurrent = true;
59710               dispatch.call('validated');
59711               return Promise.resolve();
59712             }
59713
59714             if (_headPromise) {
59715               // Validation already in process, but we aren't caught up to current
59716               _headIsCurrent = false; // We will need to catch up after the validation promise fulfills
59717
59718               return _headPromise;
59719             } // If we get here, its time to start validating stuff.
59720
59721
59722             _headCache.graph = currGraph; // take snapshot
59723
59724             _completeDiff = context.history().difference().complete();
59725             var incrementalDiff = coreDifference(prevGraph, currGraph);
59726             var entityIDs = Object.keys(incrementalDiff.complete());
59727             entityIDs = _headCache.withAllRelatedEntities(entityIDs); // expand set
59728
59729             if (!entityIDs.size) {
59730               dispatch.call('validated');
59731               return Promise.resolve();
59732             }
59733
59734             _headPromise = validateEntitiesAsync(entityIDs, _headCache).then(function () {
59735               return updateResolvedIssues(entityIDs);
59736             }).then(function () {
59737               return dispatch.call('validated');
59738             })["catch"](function () {
59739               /* ignore */
59740             }).then(function () {
59741               _headPromise = null;
59742
59743               if (!_headIsCurrent) {
59744                 validator.validate(); // run it again to catch up to current graph
59745               }
59746             });
59747             return _headPromise;
59748           }; // register event handlers:
59749           // WHEN TO RUN VALIDATION:
59750           // When history changes:
59751
59752
59753           context.history().on('restore.validator', validator.validate) // on restore saved history
59754           .on('undone.validator', validator.validate) // on undo
59755           .on('redone.validator', validator.validate) // on redo
59756           .on('reset.validator', function () {
59757             // on history reset - happens after save, or enter/exit walkthrough
59758             reset(false); // cached issues aren't valid any longer if the history has been reset
59759
59760             validator.validate();
59761           }); // but not on 'change' (e.g. while drawing)
59762           // When user changes editing modes (to catch recent changes e.g. drawing)
59763
59764           context.on('exit.validator', validator.validate); // When merging fetched data, validate base graph:
59765
59766           context.history().on('merge.validator', function (entities) {
59767             if (!entities) return; // Make sure the caches have graphs assigned to them.
59768             // (we don't do this in `reset` because context is still resetting things and `history.base()` is unstable then)
59769
59770             var baseGraph = context.history().base();
59771             if (!_headCache.graph) _headCache.graph = baseGraph;
59772             if (!_baseCache.graph) _baseCache.graph = baseGraph;
59773             var entityIDs = entities.map(function (entity) {
59774               return entity.id;
59775             });
59776             entityIDs = _baseCache.withAllRelatedEntities(entityIDs); // expand set
59777
59778             validateEntitiesAsync(entityIDs, _baseCache);
59779           }); // `validateEntity()`   (private)
59780           // Runs all validation rules on a single entity.
59781           // Some things to note:
59782           //  - Graph is passed in from whenever the validation was started.  Validators shouldn't use
59783           //   `context.graph()` because this all happens async, and the graph might have changed
59784           //   (for example, nodes getting deleted before the validation can run)
59785           //  - Validator functions may still be waiting on something and return a "provisional" result.
59786           //    In this situation, we will schedule to revalidate the entity sometime later.
59787           //
59788           // Arguments
59789           //   `entity` - The entity
59790           //   `graph` - graph containing the entity
59791           //
59792           // Returns
59793           //   Object result like:
59794           //   {
59795           //     issues:       Array of detected issues
59796           //     provisional:  `true` if provisional result, `false` if final result
59797           //   }
59798           //
59799
59800           function validateEntity(entity, graph) {
59801             var result = {
59802               issues: [],
59803               provisional: false
59804             };
59805             Object.keys(_rules).forEach(runValidation); // run all rules
59806
59807             return result; // runs validation and appends resulting issues
59808
59809             function runValidation(key) {
59810               var fn = _rules[key];
59811
59812               if (typeof fn !== 'function') {
59813                 console.error('no such validation rule = ' + key); // eslint-disable-line no-console
59814
59815                 return;
59816               }
59817
59818               var detected = fn(entity, graph);
59819
59820               if (detected.provisional) {
59821                 // this validation should be run again later
59822                 result.provisional = true;
59823               }
59824
59825               detected = detected.filter(applySeverityOverrides);
59826               result.issues = result.issues.concat(detected); // If there are any override rules that match the issue type/subtype,
59827               // adjust severity (or disable it) and keep/discard as quickly as possible.
59828
59829               function applySeverityOverrides(issue) {
59830                 var type = issue.type;
59831                 var subtype = issue.subtype || '';
59832                 var i;
59833
59834                 for (i = 0; i < _errorOverrides.length; i++) {
59835                   if (_errorOverrides[i].type.test(type) && _errorOverrides[i].subtype.test(subtype)) {
59836                     issue.severity = 'error';
59837                     return true;
59838                   }
59839                 }
59840
59841                 for (i = 0; i < _warningOverrides.length; i++) {
59842                   if (_warningOverrides[i].type.test(type) && _warningOverrides[i].subtype.test(subtype)) {
59843                     issue.severity = 'warning';
59844                     return true;
59845                   }
59846                 }
59847
59848                 for (i = 0; i < _disableOverrides.length; i++) {
59849                   if (_disableOverrides[i].type.test(type) && _disableOverrides[i].subtype.test(subtype)) {
59850                     return false;
59851                   }
59852                 }
59853
59854                 return true;
59855               }
59856             }
59857           } // `updateResolvedIssues()`   (private)
59858           // Determine if any issues were resolved for the given entities.
59859           // This is called by `validate()` after validation of the head graph
59860           //
59861           // Give the user credit for fixing an issue if:
59862           // - the issue is in the base cache
59863           // - the issue is not in the head cache
59864           // - the user did something to one of the entities involved in the issue
59865           //
59866           // Arguments
59867           //   `entityIDs` - Array or Set containing entity IDs.
59868           //
59869
59870
59871           function updateResolvedIssues(entityIDs) {
59872             entityIDs.forEach(function (entityID) {
59873               var baseIssues = _baseCache.issuesByEntityID[entityID];
59874               if (!baseIssues) return;
59875               baseIssues.forEach(function (issueID) {
59876                 // Check if the user did something to one of the entities involved in this issue.
59877                 // (This issue could involve multiple entities, e.g. disconnected routable features)
59878                 var issue = _baseCache.issuesByIssueID[issueID];
59879                 var userModified = (issue.entityIds || []).some(function (id) {
59880                   return _completeDiff.hasOwnProperty(id);
59881                 });
59882
59883                 if (userModified && !_headCache.issuesByIssueID[issueID]) {
59884                   // issue seems fixed
59885                   _resolvedIssueIDs.add(issueID);
59886                 } else {
59887                   // issue still not resolved
59888                   _resolvedIssueIDs["delete"](issueID); // (did undo, or possibly fixed and then re-caused the issue)
59889
59890                 }
59891               });
59892             });
59893           } // `validateEntitiesAsync()`   (private)
59894           // Schedule validation for many entities.
59895           //
59896           // Arguments
59897           //   `entityIDs` - Array or Set containing entityIDs.
59898           //   `graph` - the graph to validate that contains those entities
59899           //   `cache` - the cache to store results in (_headCache or _baseCache)
59900           //
59901           // Returns
59902           //   A Promise fulfilled when the validation has completed.
59903           //   This may take time but happen in the background during browser idle time.
59904           //
59905
59906
59907           function validateEntitiesAsync(entityIDs, cache) {
59908             // Enqueue the work
59909             var jobs = Array.from(entityIDs).map(function (entityID) {
59910               if (cache.queuedEntityIDs.has(entityID)) return null; // queued already
59911
59912               cache.queuedEntityIDs.add(entityID); // Clear caches for existing issues related to this entity
59913
59914               cache.uncacheEntityID(entityID);
59915               return function () {
59916                 cache.queuedEntityIDs["delete"](entityID);
59917                 var graph = cache.graph;
59918                 if (!graph) return; // was reset?
59919
59920                 var entity = graph.hasEntity(entityID); // Sanity check: don't validate deleted entities
59921
59922                 if (!entity) return; // detect new issues and update caches
59923
59924                 var result = validateEntity(entity, graph);
59925
59926                 if (result.provisional) {
59927                   // provisional result
59928                   cache.provisionalEntityIDs.add(entityID); // we'll need to revalidate this entity again later
59929                 }
59930
59931                 cache.cacheIssues(result.issues); // update cache
59932               };
59933             }).filter(Boolean); // Perform the work in chunks.
59934             // Because this will happen during idle callbacks, we want to choose a chunk size
59935             // that won't make the browser stutter too badly.
59936
59937             cache.queue = cache.queue.concat(utilArrayChunk(jobs, 100)); // Perform the work
59938
59939             if (cache.queuePromise) return cache.queuePromise;
59940             cache.queuePromise = processQueue(cache).then(function () {
59941               return revalidateProvisionalEntities(cache);
59942             })["catch"](function () {
59943               /* ignore */
59944             })["finally"](function () {
59945               return cache.queuePromise = null;
59946             });
59947             return cache.queuePromise;
59948           } // `revalidateProvisionalEntities()`   (private)
59949           // Sometimes a validator will return a "provisional" result.
59950           // In this situation, we'll need to revalidate the entity later.
59951           // This function waits a delay, then places them back into the validation queue.
59952           //
59953           // Arguments
59954           //   `cache` - The cache (_headCache or _baseCache)
59955           //
59956
59957
59958           function revalidateProvisionalEntities(cache) {
59959             if (!cache.provisionalEntityIDs.size) return; // nothing to do
59960
59961             var handle = window.setTimeout(function () {
59962               _deferredST["delete"](handle);
59963
59964               if (!cache.provisionalEntityIDs.size) return; // nothing to do
59965
59966               validateEntitiesAsync(Array.from(cache.provisionalEntityIDs), cache);
59967             }, RETRY);
59968
59969             _deferredST.add(handle);
59970           } // `processQueue(queue)`   (private)
59971           // Process the next chunk of deferred validation work
59972           //
59973           // Arguments
59974           //   `cache` - The cache (_headCache or _baseCache)
59975           //
59976           // Returns
59977           //   A Promise fulfilled when the validation has completed.
59978           //   This may take time but happen in the background during browser idle time.
59979           //
59980
59981
59982           function processQueue(cache) {
59983             // console.log(`${cache.which} queue length ${cache.queue.length}`);
59984             if (!cache.queue.length) return Promise.resolve(); // we're done
59985
59986             var chunk = cache.queue.pop();
59987             return new Promise(function (resolvePromise) {
59988               var handle = window.requestIdleCallback(function () {
59989                 _deferredRIC["delete"](handle); // const t0 = performance.now();
59990
59991
59992                 chunk.forEach(function (job) {
59993                   return job();
59994                 }); // const t1 = performance.now();
59995                 // console.log('chunk processed in ' + (t1 - t0) + ' ms');
59996
59997                 resolvePromise();
59998               });
59999
60000               _deferredRIC.add(handle);
60001             }).then(function () {
60002               // dispatch an event sometimes to redraw various UI things
60003               if (cache.queue.length % 25 === 0) dispatch.call('validated');
60004             }).then(function () {
60005               return processQueue(cache);
60006             });
60007           }
60008
60009           return validator;
60010         } // `validationCache()`   (private)
60011         // Creates a cache to store validation state
60012         // We create 2 of these:
60013         //   `_baseCache` for validation on the base graph (unedited)
60014         //   `_headCache` for validation on the head graph (user edits applied)
60015         //
60016         // Arguments
60017         //   `which` - just a String 'base' or 'head' to keep track of it
60018         //
60019
60020         function validationCache(which) {
60021           var cache = {
60022             which: which,
60023             graph: null,
60024             queue: [],
60025             queuePromise: null,
60026             queuedEntityIDs: new Set(),
60027             provisionalEntityIDs: new Set(),
60028             issuesByIssueID: {},
60029             // issue.id -> issue
60030             issuesByEntityID: {} // entity.id -> Set(issue.id)
60031
60032           };
60033
60034           cache.cacheIssue = function (issue) {
60035             (issue.entityIds || []).forEach(function (entityID) {
60036               if (!cache.issuesByEntityID[entityID]) {
60037                 cache.issuesByEntityID[entityID] = new Set();
60038               }
60039
60040               cache.issuesByEntityID[entityID].add(issue.id);
60041             });
60042             cache.issuesByIssueID[issue.id] = issue;
60043           };
60044
60045           cache.uncacheIssue = function (issue) {
60046             (issue.entityIds || []).forEach(function (entityID) {
60047               if (cache.issuesByEntityID[entityID]) {
60048                 cache.issuesByEntityID[entityID]["delete"](issue.id);
60049               }
60050             });
60051             delete cache.issuesByIssueID[issue.id];
60052           };
60053
60054           cache.cacheIssues = function (issues) {
60055             issues.forEach(cache.cacheIssue);
60056           };
60057
60058           cache.uncacheIssues = function (issues) {
60059             issues.forEach(cache.uncacheIssue);
60060           };
60061
60062           cache.uncacheIssuesOfType = function (type) {
60063             var issuesOfType = Object.values(cache.issuesByIssueID).filter(function (issue) {
60064               return issue.type === type;
60065             });
60066             cache.uncacheIssues(issuesOfType);
60067           }; // Remove a single entity and all its related issues from the caches
60068
60069
60070           cache.uncacheEntityID = function (entityID) {
60071             var entityIssueIDs = cache.issuesByEntityID[entityID];
60072
60073             if (entityIssueIDs) {
60074               entityIssueIDs.forEach(function (issueID) {
60075                 var issue = cache.issuesByIssueID[issueID];
60076
60077                 if (issue) {
60078                   cache.uncacheIssue(issue);
60079                 } else {
60080                   // shouldn't happen, clean up
60081                   delete cache.issuesByIssueID[issueID];
60082                 }
60083               });
60084             }
60085
60086             delete cache.issuesByEntityID[entityID];
60087             cache.provisionalEntityIDs["delete"](entityID);
60088           }; // Return the expandeded set of entityIDs related to issues for the given entityIDs
60089           //
60090           // Arguments
60091           //   `entityIDs` - Array or Set containing entityIDs.
60092           //
60093
60094
60095           cache.withAllRelatedEntities = function (entityIDs) {
60096             var result = new Set();
60097             (entityIDs || []).forEach(function (entityID) {
60098               result.add(entityID); // include self
60099
60100               var entityIssueIDs = cache.issuesByEntityID[entityID];
60101
60102               if (entityIssueIDs) {
60103                 entityIssueIDs.forEach(function (issueID) {
60104                   var issue = cache.issuesByIssueID[issueID];
60105
60106                   if (issue) {
60107                     (issue.entityIds || []).forEach(function (relatedID) {
60108                       return result.add(relatedID);
60109                     });
60110                   } else {
60111                     // shouldn't happen, clean up
60112                     delete cache.issuesByIssueID[issueID];
60113                   }
60114                 });
60115               }
60116             });
60117             return result;
60118           };
60119
60120           return cache;
60121         }
60122
60123         function coreUploader(context) {
60124           var dispatch = dispatch$8( // Start and end events are dispatched exactly once each per legitimate outside call to `save`
60125           'saveStarted', // dispatched as soon as a call to `save` has been deemed legitimate
60126           'saveEnded', // dispatched after the result event has been dispatched
60127           'willAttemptUpload', // dispatched before the actual upload call occurs, if it will
60128           'progressChanged', // Each save results in one of these outcomes:
60129           'resultNoChanges', // upload wasn't attempted since there were no edits
60130           'resultErrors', // upload failed due to errors
60131           'resultConflicts', // upload failed due to data conflicts
60132           'resultSuccess' // upload completed without errors
60133           );
60134           var _isSaving = false;
60135           var _conflicts = [];
60136           var _errors = [];
60137
60138           var _origChanges;
60139
60140           var _discardTags = {};
60141           _mainFileFetcher.get('discarded').then(function (d) {
60142             _discardTags = d;
60143           })["catch"](function () {
60144             /* ignore */
60145           });
60146           var uploader = utilRebind({}, dispatch, 'on');
60147
60148           uploader.isSaving = function () {
60149             return _isSaving;
60150           };
60151
60152           uploader.save = function (changeset, tryAgain, checkConflicts) {
60153             // Guard against accidentally entering save code twice - #4641
60154             if (_isSaving && !tryAgain) {
60155               return;
60156             }
60157
60158             var osm = context.connection();
60159             if (!osm) return; // If user somehow got logged out mid-save, try to reauthenticate..
60160             // This can happen if they were logged in from before, but the tokens are no longer valid.
60161
60162             if (!osm.authenticated()) {
60163               osm.authenticate(function (err) {
60164                 if (!err) {
60165                   uploader.save(changeset, tryAgain, checkConflicts); // continue where we left off..
60166                 }
60167               });
60168               return;
60169             }
60170
60171             if (!_isSaving) {
60172               _isSaving = true;
60173               dispatch.call('saveStarted', this);
60174             }
60175
60176             var history = context.history();
60177             _conflicts = [];
60178             _errors = []; // Store original changes, in case user wants to download them as an .osc file
60179
60180             _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags)); // First time, `history.perform` a no-op action.
60181             // Any conflict resolutions will be done as `history.replace`
60182             // Remember to pop this later if needed
60183
60184             if (!tryAgain) {
60185               history.perform(actionNoop());
60186             } // Attempt a fast upload.. If there are conflicts, re-enter with `checkConflicts = true`
60187
60188
60189             if (!checkConflicts) {
60190               upload(changeset); // Do the full (slow) conflict check..
60191             } else {
60192               performFullConflictCheck(changeset);
60193             }
60194           };
60195
60196           function performFullConflictCheck(changeset) {
60197             var osm = context.connection();
60198             if (!osm) return;
60199             var history = context.history();
60200             var localGraph = context.graph();
60201             var remoteGraph = coreGraph(history.base(), true);
60202             var summary = history.difference().summary();
60203             var _toCheck = [];
60204
60205             for (var i = 0; i < summary.length; i++) {
60206               var item = summary[i];
60207
60208               if (item.changeType === 'modified') {
60209                 _toCheck.push(item.entity.id);
60210               }
60211             }
60212
60213             var _toLoad = withChildNodes(_toCheck, localGraph);
60214
60215             var _loaded = {};
60216             var _toLoadCount = 0;
60217             var _toLoadTotal = _toLoad.length;
60218
60219             if (_toCheck.length) {
60220               dispatch.call('progressChanged', this, _toLoadCount, _toLoadTotal);
60221
60222               _toLoad.forEach(function (id) {
60223                 _loaded[id] = false;
60224               });
60225
60226               osm.loadMultiple(_toLoad, loaded);
60227             } else {
60228               upload(changeset);
60229             }
60230
60231             return;
60232
60233             function withChildNodes(ids, graph) {
60234               var s = new Set(ids);
60235               ids.forEach(function (id) {
60236                 var entity = graph.entity(id);
60237                 if (entity.type !== 'way') return;
60238                 graph.childNodes(entity).forEach(function (child) {
60239                   if (child.version !== undefined) {
60240                     s.add(child.id);
60241                   }
60242                 });
60243               });
60244               return Array.from(s);
60245             } // Reload modified entities into an alternate graph and check for conflicts..
60246
60247
60248             function loaded(err, result) {
60249               if (_errors.length) return;
60250
60251               if (err) {
60252                 _errors.push({
60253                   msg: err.message || err.responseText,
60254                   details: [_t('save.status_code', {
60255                     code: err.status
60256                   })]
60257                 });
60258
60259                 didResultInErrors();
60260               } else {
60261                 var loadMore = [];
60262                 result.data.forEach(function (entity) {
60263                   remoteGraph.replace(entity);
60264                   _loaded[entity.id] = true;
60265                   _toLoad = _toLoad.filter(function (val) {
60266                     return val !== entity.id;
60267                   });
60268                   if (!entity.visible) return; // Because loadMultiple doesn't download /full like loadEntity,
60269                   // need to also load children that aren't already being checked..
60270
60271                   var i, id;
60272
60273                   if (entity.type === 'way') {
60274                     for (i = 0; i < entity.nodes.length; i++) {
60275                       id = entity.nodes[i];
60276
60277                       if (_loaded[id] === undefined) {
60278                         _loaded[id] = false;
60279                         loadMore.push(id);
60280                       }
60281                     }
60282                   } else if (entity.type === 'relation' && entity.isMultipolygon()) {
60283                     for (i = 0; i < entity.members.length; i++) {
60284                       id = entity.members[i].id;
60285
60286                       if (_loaded[id] === undefined) {
60287                         _loaded[id] = false;
60288                         loadMore.push(id);
60289                       }
60290                     }
60291                   }
60292                 });
60293                 _toLoadCount += result.data.length;
60294                 _toLoadTotal += loadMore.length;
60295                 dispatch.call('progressChanged', this, _toLoadCount, _toLoadTotal);
60296
60297                 if (loadMore.length) {
60298                   _toLoad.push.apply(_toLoad, loadMore);
60299
60300                   osm.loadMultiple(loadMore, loaded);
60301                 }
60302
60303                 if (!_toLoad.length) {
60304                   detectConflicts();
60305                   upload(changeset);
60306                 }
60307               }
60308             }
60309
60310             function detectConflicts() {
60311               function choice(id, text, _action) {
60312                 return {
60313                   id: id,
60314                   text: text,
60315                   action: function action() {
60316                     history.replace(_action);
60317                   }
60318                 };
60319               }
60320
60321               function formatUser(d) {
60322                 return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
60323               }
60324
60325               function entityName(entity) {
60326                 return utilDisplayName(entity) || utilDisplayType(entity.id) + ' ' + entity.id;
60327               }
60328
60329               function sameVersions(local, remote) {
60330                 if (local.version !== remote.version) return false;
60331
60332                 if (local.type === 'way') {
60333                   var children = utilArrayUnion(local.nodes, remote.nodes);
60334
60335                   for (var i = 0; i < children.length; i++) {
60336                     var a = localGraph.hasEntity(children[i]);
60337                     var b = remoteGraph.hasEntity(children[i]);
60338                     if (a && b && a.version !== b.version) return false;
60339                   }
60340                 }
60341
60342                 return true;
60343               }
60344
60345               _toCheck.forEach(function (id) {
60346                 var local = localGraph.entity(id);
60347                 var remote = remoteGraph.entity(id);
60348                 if (sameVersions(local, remote)) return;
60349                 var merge = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags, formatUser);
60350                 history.replace(merge);
60351                 var mergeConflicts = merge.conflicts();
60352                 if (!mergeConflicts.length) return; // merged safely
60353
60354                 var forceLocal = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_local');
60355                 var forceRemote = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_remote');
60356                 var keepMine = _t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore'));
60357                 var keepTheirs = _t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
60358
60359                 _conflicts.push({
60360                   id: id,
60361                   name: entityName(local),
60362                   details: mergeConflicts,
60363                   chosen: 1,
60364                   choices: [choice(id, keepMine, forceLocal), choice(id, keepTheirs, forceRemote)]
60365                 });
60366               });
60367             }
60368           }
60369
60370           function upload(changeset) {
60371             var osm = context.connection();
60372
60373             if (!osm) {
60374               _errors.push({
60375                 msg: 'No OSM Service'
60376               });
60377             }
60378
60379             if (_conflicts.length) {
60380               didResultInConflicts(changeset);
60381             } else if (_errors.length) {
60382               didResultInErrors();
60383             } else {
60384               var history = context.history();
60385               var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
60386
60387               if (changes.modified.length || changes.created.length || changes.deleted.length) {
60388                 dispatch.call('willAttemptUpload', this);
60389                 osm.putChangeset(changeset, changes, uploadCallback);
60390               } else {
60391                 // changes were insignificant or reverted by user
60392                 didResultInNoChanges();
60393               }
60394             }
60395           }
60396
60397           function uploadCallback(err, changeset) {
60398             if (err) {
60399               if (err.status === 409) {
60400                 // 409 Conflict
60401                 uploader.save(changeset, true, true); // tryAgain = true, checkConflicts = true
60402               } else {
60403                 _errors.push({
60404                   msg: err.message || err.responseText,
60405                   details: [_t('save.status_code', {
60406                     code: err.status
60407                   })]
60408                 });
60409
60410                 didResultInErrors();
60411               }
60412             } else {
60413               didResultInSuccess(changeset);
60414             }
60415           }
60416
60417           function didResultInNoChanges() {
60418             dispatch.call('resultNoChanges', this);
60419             endSave();
60420             context.flush(); // reset iD
60421           }
60422
60423           function didResultInErrors() {
60424             context.history().pop();
60425             dispatch.call('resultErrors', this, _errors);
60426             endSave();
60427           }
60428
60429           function didResultInConflicts(changeset) {
60430             _conflicts.sort(function (a, b) {
60431               return b.id.localeCompare(a.id);
60432             });
60433
60434             dispatch.call('resultConflicts', this, changeset, _conflicts, _origChanges);
60435             endSave();
60436           }
60437
60438           function didResultInSuccess(changeset) {
60439             // delete the edit stack cached to local storage
60440             context.history().clearSaved();
60441             dispatch.call('resultSuccess', this, changeset); // Add delay to allow for postgres replication #1646 #2678
60442
60443             window.setTimeout(function () {
60444               endSave();
60445               context.flush(); // reset iD
60446             }, 2500);
60447           }
60448
60449           function endSave() {
60450             _isSaving = false;
60451             dispatch.call('saveEnded', this);
60452           }
60453
60454           uploader.cancelConflictResolution = function () {
60455             context.history().pop();
60456           };
60457
60458           uploader.processResolvedConflicts = function (changeset) {
60459             var history = context.history();
60460
60461             for (var i = 0; i < _conflicts.length; i++) {
60462               if (_conflicts[i].chosen === 1) {
60463                 // user chose "use theirs"
60464                 var entity = context.hasEntity(_conflicts[i].id);
60465
60466                 if (entity && entity.type === 'way') {
60467                   var children = utilArrayUniq(entity.nodes);
60468
60469                   for (var j = 0; j < children.length; j++) {
60470                     history.replace(actionRevert(children[j]));
60471                   }
60472                 }
60473
60474                 history.replace(actionRevert(_conflicts[i].id));
60475               }
60476             }
60477
60478             uploader.save(changeset, true, false); // tryAgain = true, checkConflicts = false
60479           };
60480
60481           uploader.reset = function () {};
60482
60483           return uploader;
60484         }
60485
60486         var $$3 = _export;
60487         var fails = fails$N;
60488         var expm1 = mathExpm1;
60489
60490         var abs = Math.abs;
60491         var exp = Math.exp;
60492         var E = Math.E;
60493
60494         var FORCED = fails(function () {
60495           // eslint-disable-next-line es/no-math-sinh -- required for testing
60496           return Math.sinh(-2e-17) != -2e-17;
60497         });
60498
60499         // `Math.sinh` method
60500         // https://tc39.es/ecma262/#sec-math.sinh
60501         // V8 near Chromium 38 has a problem with very small numbers
60502         $$3({ target: 'Math', stat: true, forced: FORCED }, {
60503           sinh: function sinh(x) {
60504             return abs(x = +x) < 1 ? (expm1(x) - expm1(-x)) / 2 : (exp(x - 1) - exp(-x - 1)) * (E / 2);
60505           }
60506         });
60507
60508         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
60509
60510         window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function () {
60511           isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
60512         });
60513
60514         function localeDateString(s) {
60515           if (!s) return null;
60516           var options = {
60517             day: 'numeric',
60518             month: 'short',
60519             year: 'numeric'
60520           };
60521           var d = new Date(s);
60522           if (isNaN(d.getTime())) return null;
60523           return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
60524         }
60525
60526         function vintageRange(vintage) {
60527           var s;
60528
60529           if (vintage.start || vintage.end) {
60530             s = vintage.start || '?';
60531
60532             if (vintage.start !== vintage.end) {
60533               s += ' - ' + (vintage.end || '?');
60534             }
60535           }
60536
60537           return s;
60538         }
60539
60540         function rendererBackgroundSource(data) {
60541           var source = Object.assign({}, data); // shallow copy
60542
60543           var _offset = [0, 0];
60544           var _name = source.name;
60545           var _description = source.description;
60546
60547           var _best = !!source.best;
60548
60549           var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
60550
60551           source.tileSize = data.tileSize || 256;
60552           source.zoomExtent = data.zoomExtent || [0, 22];
60553           source.overzoom = data.overzoom !== false;
60554
60555           source.offset = function (val) {
60556             if (!arguments.length) return _offset;
60557             _offset = val;
60558             return source;
60559           };
60560
60561           source.nudge = function (val, zoomlevel) {
60562             _offset[0] += val[0] / Math.pow(2, zoomlevel);
60563             _offset[1] += val[1] / Math.pow(2, zoomlevel);
60564             return source;
60565           };
60566
60567           source.name = function () {
60568             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
60569             return _t('imagery.' + id_safe + '.name', {
60570               "default": _name
60571             });
60572           };
60573
60574           source.label = function () {
60575             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
60576             return _t.html('imagery.' + id_safe + '.name', {
60577               "default": _name
60578             });
60579           };
60580
60581           source.description = function () {
60582             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
60583             return _t.html('imagery.' + id_safe + '.description', {
60584               "default": _description
60585             });
60586           };
60587
60588           source.best = function () {
60589             return _best;
60590           };
60591
60592           source.area = function () {
60593             if (!data.polygon) return Number.MAX_VALUE; // worldwide
60594
60595             var area = d3_geoArea({
60596               type: 'MultiPolygon',
60597               coordinates: [data.polygon]
60598             });
60599             return isNaN(area) ? 0 : area;
60600           };
60601
60602           source.imageryUsed = function () {
60603             return _name || source.id;
60604           };
60605
60606           source.template = function (val) {
60607             if (!arguments.length) return _template;
60608
60609             if (source.id === 'custom' || source.id === 'Bing') {
60610               _template = val;
60611             }
60612
60613             return source;
60614           };
60615
60616           source.url = function (coord) {
60617             var result = _template;
60618             if (result === '') return result; // source 'none'
60619             // Guess a type based on the tokens present in the template
60620             // (This is for 'custom' source, where we don't know)
60621
60622             if (!source.type) {
60623               if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(_template)) {
60624                 source.type = 'wms';
60625                 source.projection = 'EPSG:3857'; // guess
60626               } else if (/\{(x|y)\}/.test(_template)) {
60627                 source.type = 'tms';
60628               } else if (/\{u\}/.test(_template)) {
60629                 source.type = 'bing';
60630               }
60631             }
60632
60633             if (source.type === 'wms') {
60634               var tileToProjectedCoords = function tileToProjectedCoords(x, y, z) {
60635                 //polyfill for IE11, PhantomJS
60636                 var sinh = Math.sinh || function (x) {
60637                   var y = Math.exp(x);
60638                   return (y - 1 / y) / 2;
60639                 };
60640
60641                 var zoomSize = Math.pow(2, z);
60642                 var lon = x / zoomSize * Math.PI * 2 - Math.PI;
60643                 var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
60644
60645                 switch (source.projection) {
60646                   case 'EPSG:4326':
60647                     return {
60648                       x: lon * 180 / Math.PI,
60649                       y: lat * 180 / Math.PI
60650                     };
60651
60652                   default:
60653                     // EPSG:3857 and synonyms
60654                     var mercCoords = mercatorRaw(lon, lat);
60655                     return {
60656                       x: 20037508.34 / Math.PI * mercCoords[0],
60657                       y: 20037508.34 / Math.PI * mercCoords[1]
60658                     };
60659                 }
60660               };
60661
60662               var tileSize = source.tileSize;
60663               var projection = source.projection;
60664               var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
60665               var maxXminY = tileToProjectedCoords(coord[0] + 1, coord[1] + 1, coord[2]);
60666               result = result.replace(/\{(\w+)\}/g, function (token, key) {
60667                 switch (key) {
60668                   case 'width':
60669                   case 'height':
60670                     return tileSize;
60671
60672                   case 'proj':
60673                     return projection;
60674
60675                   case 'wkid':
60676                     return projection.replace(/^EPSG:/, '');
60677
60678                   case 'bbox':
60679                     // WMS 1.3 flips x/y for some coordinate systems including EPSG:4326 - #7557
60680                     if (projection === 'EPSG:4326' && // The CRS parameter implies version 1.3 (prior versions use SRS)
60681                     /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
60682                       return maxXminY.y + ',' + minXmaxY.x + ',' + minXmaxY.y + ',' + maxXminY.x;
60683                     } else {
60684                       return minXmaxY.x + ',' + maxXminY.y + ',' + maxXminY.x + ',' + minXmaxY.y;
60685                     }
60686
60687                   case 'w':
60688                     return minXmaxY.x;
60689
60690                   case 's':
60691                     return maxXminY.y;
60692
60693                   case 'n':
60694                     return maxXminY.x;
60695
60696                   case 'e':
60697                     return minXmaxY.y;
60698
60699                   default:
60700                     return token;
60701                 }
60702               });
60703             } else if (source.type === 'tms') {
60704               result = result.replace('{x}', coord[0]).replace('{y}', coord[1]) // TMS-flipped y coordinate
60705               .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1).replace(/\{z(oom)?\}/, coord[2]) // only fetch retina tiles for retina screens
60706               .replace(/\{@2x\}|\{r\}/, isRetina ? '@2x' : '');
60707             } else if (source.type === 'bing') {
60708               result = result.replace('{u}', function () {
60709                 var u = '';
60710
60711                 for (var zoom = coord[2]; zoom > 0; zoom--) {
60712                   var b = 0;
60713                   var mask = 1 << zoom - 1;
60714                   if ((coord[0] & mask) !== 0) b++;
60715                   if ((coord[1] & mask) !== 0) b += 2;
60716                   u += b.toString();
60717                 }
60718
60719                 return u;
60720               });
60721             } // these apply to any type..
60722
60723
60724             result = result.replace(/\{switch:([^}]+)\}/, function (s, r) {
60725               var subdomains = r.split(',');
60726               return subdomains[(coord[0] + coord[1]) % subdomains.length];
60727             });
60728             return result;
60729           };
60730
60731           source.validZoom = function (z) {
60732             return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
60733           };
60734
60735           source.isLocatorOverlay = function () {
60736             return source.id === 'mapbox_locator_overlay';
60737           };
60738           /* hides a source from the list, but leaves it available for use */
60739
60740
60741           source.isHidden = function () {
60742             return source.id === 'DigitalGlobe-Premium-vintage' || source.id === 'DigitalGlobe-Standard-vintage';
60743           };
60744
60745           source.copyrightNotices = function () {};
60746
60747           source.getMetadata = function (center, tileCoord, callback) {
60748             var vintage = {
60749               start: localeDateString(source.startDate),
60750               end: localeDateString(source.endDate)
60751             };
60752             vintage.range = vintageRange(vintage);
60753             var metadata = {
60754               vintage: vintage
60755             };
60756             callback(null, metadata);
60757           };
60758
60759           return source;
60760         }
60761
60762         rendererBackgroundSource.Bing = function (data, dispatch) {
60763           // https://docs.microsoft.com/en-us/bingmaps/rest-services/imagery/get-imagery-metadata
60764           // https://docs.microsoft.com/en-us/bingmaps/rest-services/directly-accessing-the-bing-maps-tiles
60765           //fallback url template
60766           data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&n=z';
60767           var bing = rendererBackgroundSource(data); //var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc
60768
60769           var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD
60770
60771           /*
60772           missing tile image strictness param (n=)
60773           •   n=f -> (Fail) returns a 404
60774           •   n=z -> (Empty) returns a 200 with 0 bytes (no content)
60775           •   n=t -> (Transparent) returns a 200 with a transparent (png) tile
60776           */
60777
60778           var strictParam = 'n';
60779           var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&uriScheme=https&key=' + key;
60780           var cache = {};
60781           var inflight = {};
60782           var providers = [];
60783           d3_json(url).then(function (json) {
60784             var imageryResource = json.resourceSets[0].resources[0]; //retrieve and prepare up to date imagery template
60785
60786             var template = imageryResource.imageUrl; //https://ecn.{subdomain}.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=10339
60787
60788             var subDomains = imageryResource.imageUrlSubdomains; //["t0, t1, t2, t3"]
60789
60790             var subDomainNumbers = subDomains.map(function (subDomain) {
60791               return subDomain.substring(1);
60792             }).join(',');
60793             template = template.replace('{subdomain}', "t{switch:".concat(subDomainNumbers, "}")).replace('{quadkey}', '{u}');
60794
60795             if (!new URLSearchParams(template).has(strictParam)) {
60796               template += "&".concat(strictParam, "=z");
60797             }
60798
60799             bing.template(template);
60800             providers = imageryResource.imageryProviders.map(function (provider) {
60801               return {
60802                 attribution: provider.attribution,
60803                 areas: provider.coverageAreas.map(function (area) {
60804                   return {
60805                     zoom: [area.zoomMin, area.zoomMax],
60806                     extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
60807                   };
60808                 })
60809               };
60810             });
60811             dispatch.call('change');
60812           })["catch"](function () {
60813             /* ignore */
60814           });
60815
60816           bing.copyrightNotices = function (zoom, extent) {
60817             zoom = Math.min(zoom, 21);
60818             return providers.filter(function (provider) {
60819               return provider.areas.some(function (area) {
60820                 return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
60821               });
60822             }).map(function (provider) {
60823               return provider.attribution;
60824             }).join(', ');
60825           };
60826
60827           bing.getMetadata = function (center, tileCoord, callback) {
60828             var tileID = tileCoord.slice(0, 3).join('/');
60829             var zoom = Math.min(tileCoord[2], 21);
60830             var centerPoint = center[1] + ',' + center[0]; // lat,lng
60831
60832             var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + '?zl=' + zoom + '&key=' + key;
60833             if (inflight[tileID]) return;
60834
60835             if (!cache[tileID]) {
60836               cache[tileID] = {};
60837             }
60838
60839             if (cache[tileID] && cache[tileID].metadata) {
60840               return callback(null, cache[tileID].metadata);
60841             }
60842
60843             inflight[tileID] = true;
60844             d3_json(url).then(function (result) {
60845               delete inflight[tileID];
60846
60847               if (!result) {
60848                 throw new Error('Unknown Error');
60849               }
60850
60851               var vintage = {
60852                 start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
60853                 end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
60854               };
60855               vintage.range = vintageRange(vintage);
60856               var metadata = {
60857                 vintage: vintage
60858               };
60859               cache[tileID].metadata = metadata;
60860               if (callback) callback(null, metadata);
60861             })["catch"](function (err) {
60862               delete inflight[tileID];
60863               if (callback) callback(err.message);
60864             });
60865           };
60866
60867           bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
60868           return bing;
60869         };
60870
60871         rendererBackgroundSource.Esri = function (data) {
60872           // in addition to using the tilemap at zoom level 20, overzoom real tiles - #4327 (deprecated technique, but it works)
60873           if (data.template.match(/blankTile/) === null) {
60874             data.template = data.template + '?blankTile=false';
60875           }
60876
60877           var esri = rendererBackgroundSource(data);
60878           var cache = {};
60879           var inflight = {};
60880
60881           var _prevCenter; // use a tilemap service to set maximum zoom for esri tiles dynamically
60882           // https://developers.arcgis.com/documentation/tiled-elevation-service/
60883
60884
60885           esri.fetchTilemap = function (center) {
60886             // skip if we have already fetched a tilemap within 5km
60887             if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
60888             _prevCenter = center; // tiles are available globally to zoom level 19, afterward they may or may not be present
60889
60890             var z = 20; // first generate a random url using the template
60891
60892             var dummyUrl = esri.url([1, 2, 3]); // calculate url z/y/x from the lat/long of the center of the map
60893
60894             var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
60895             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
60896
60897             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
60898
60899             d3_json(tilemapUrl).then(function (tilemap) {
60900               if (!tilemap) {
60901                 throw new Error('Unknown Error');
60902               }
60903
60904               var hasTiles = true;
60905
60906               for (var i = 0; i < tilemap.data.length; i++) {
60907                 // 0 means an individual tile in the grid doesn't exist
60908                 if (!tilemap.data[i]) {
60909                   hasTiles = false;
60910                   break;
60911                 }
60912               } // if any tiles are missing at level 20 we restrict maxZoom to 19
60913
60914
60915               esri.zoomExtent[1] = hasTiles ? 22 : 19;
60916             })["catch"](function () {
60917               /* ignore */
60918             });
60919           };
60920
60921           esri.getMetadata = function (center, tileCoord, callback) {
60922             var tileID = tileCoord.slice(0, 3).join('/');
60923             var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
60924             var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
60925
60926             var unknown = _t('info_panels.background.unknown');
60927             var metadataLayer;
60928             var vintage = {};
60929             var metadata = {};
60930             if (inflight[tileID]) return;
60931
60932             switch (true) {
60933               case zoom >= 20 && esri.id === 'EsriWorldImageryClarity':
60934                 metadataLayer = 4;
60935                 break;
60936
60937               case zoom >= 19:
60938                 metadataLayer = 3;
60939                 break;
60940
60941               case zoom >= 17:
60942                 metadataLayer = 2;
60943                 break;
60944
60945               case zoom >= 13:
60946                 metadataLayer = 0;
60947                 break;
60948
60949               default:
60950                 metadataLayer = 99;
60951             }
60952
60953             var url; // build up query using the layer appropriate to the current zoom
60954
60955             if (esri.id === 'EsriWorldImagery') {
60956               url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
60957             } else if (esri.id === 'EsriWorldImageryClarity') {
60958               url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
60959             }
60960
60961             url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
60962
60963             if (!cache[tileID]) {
60964               cache[tileID] = {};
60965             }
60966
60967             if (cache[tileID] && cache[tileID].metadata) {
60968               return callback(null, cache[tileID].metadata);
60969             } // accurate metadata is only available >= 13
60970
60971
60972             if (metadataLayer === 99) {
60973               vintage = {
60974                 start: null,
60975                 end: null,
60976                 range: null
60977               };
60978               metadata = {
60979                 vintage: null,
60980                 source: unknown,
60981                 description: unknown,
60982                 resolution: unknown,
60983                 accuracy: unknown
60984               };
60985               callback(null, metadata);
60986             } else {
60987               inflight[tileID] = true;
60988               d3_json(url).then(function (result) {
60989                 delete inflight[tileID];
60990
60991                 if (!result) {
60992                   throw new Error('Unknown Error');
60993                 } else if (result.features && result.features.length < 1) {
60994                   throw new Error('No Results');
60995                 } else if (result.error && result.error.message) {
60996                   throw new Error(result.error.message);
60997                 } // pass through the discrete capture date from metadata
60998
60999
61000                 var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
61001                 vintage = {
61002                   start: captureDate,
61003                   end: captureDate,
61004                   range: captureDate
61005                 };
61006                 metadata = {
61007                   vintage: vintage,
61008                   source: clean(result.features[0].attributes.NICE_NAME),
61009                   description: clean(result.features[0].attributes.NICE_DESC),
61010                   resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
61011                   accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
61012                 }; // append units - meters
61013
61014                 if (isFinite(metadata.resolution)) {
61015                   metadata.resolution += ' m';
61016                 }
61017
61018                 if (isFinite(metadata.accuracy)) {
61019                   metadata.accuracy += ' m';
61020                 }
61021
61022                 cache[tileID].metadata = metadata;
61023                 if (callback) callback(null, metadata);
61024               })["catch"](function (err) {
61025                 delete inflight[tileID];
61026                 if (callback) callback(err.message);
61027               });
61028             }
61029
61030             function clean(val) {
61031               return String(val).trim() || unknown;
61032             }
61033           };
61034
61035           return esri;
61036         };
61037
61038         rendererBackgroundSource.None = function () {
61039           var source = rendererBackgroundSource({
61040             id: 'none',
61041             template: ''
61042           });
61043
61044           source.name = function () {
61045             return _t('background.none');
61046           };
61047
61048           source.label = function () {
61049             return _t.html('background.none');
61050           };
61051
61052           source.imageryUsed = function () {
61053             return null;
61054           };
61055
61056           source.area = function () {
61057             return -1; // sources in background pane are sorted by area
61058           };
61059
61060           return source;
61061         };
61062
61063         rendererBackgroundSource.Custom = function (template) {
61064           var source = rendererBackgroundSource({
61065             id: 'custom',
61066             template: template
61067           });
61068
61069           source.name = function () {
61070             return _t('background.custom');
61071           };
61072
61073           source.label = function () {
61074             return _t.html('background.custom');
61075           };
61076
61077           source.imageryUsed = function () {
61078             // sanitize personal connection tokens - #6801
61079             var cleaned = source.template(); // from query string parameters
61080
61081             if (cleaned.indexOf('?') !== -1) {
61082               var parts = cleaned.split('?', 2);
61083               var qs = utilStringQs(parts[1]);
61084               ['access_token', 'connectId', 'token'].forEach(function (param) {
61085                 if (qs[param]) {
61086                   qs[param] = '{apikey}';
61087                 }
61088               });
61089               cleaned = parts[0] + '?' + utilQsString(qs, true); // true = soft encode
61090             } // from wms/wmts api path parameters
61091
61092
61093             cleaned = cleaned.replace(/token\/(\w+)/, 'token/{apikey}');
61094             return 'Custom (' + cleaned + ' )';
61095           };
61096
61097           source.area = function () {
61098             return -2; // sources in background pane are sorted by area
61099           };
61100
61101           return source;
61102         };
61103
61104         function rendererTileLayer(context) {
61105           var transformProp = utilPrefixCSSProperty('Transform');
61106           var tiler = utilTiler();
61107           var _tileSize = 256;
61108
61109           var _projection;
61110
61111           var _cache = {};
61112
61113           var _tileOrigin;
61114
61115           var _zoom;
61116
61117           var _source;
61118
61119           function tileSizeAtZoom(d, z) {
61120             var EPSILON = 0.002; // close seams
61121
61122             return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
61123           }
61124
61125           function atZoom(t, distance) {
61126             var power = Math.pow(2, distance);
61127             return [Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance];
61128           }
61129
61130           function lookUp(d) {
61131             for (var up = -1; up > -d[2]; up--) {
61132               var tile = atZoom(d, up);
61133
61134               if (_cache[_source.url(tile)] !== false) {
61135                 return tile;
61136               }
61137             }
61138           }
61139
61140           function uniqueBy(a, n) {
61141             var o = [];
61142             var seen = {};
61143
61144             for (var i = 0; i < a.length; i++) {
61145               if (seen[a[i][n]] === undefined) {
61146                 o.push(a[i]);
61147                 seen[a[i][n]] = true;
61148               }
61149             }
61150
61151             return o;
61152           }
61153
61154           function addSource(d) {
61155             d.push(_source.url(d));
61156             return d;
61157           } // Update tiles based on current state of `projection`.
61158
61159
61160           function background(selection) {
61161             _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
61162             var pixelOffset;
61163
61164             if (_source) {
61165               pixelOffset = [_source.offset()[0] * Math.pow(2, _zoom), _source.offset()[1] * Math.pow(2, _zoom)];
61166             } else {
61167               pixelOffset = [0, 0];
61168             }
61169
61170             var translate = [_projection.translate()[0] + pixelOffset[0], _projection.translate()[1] + pixelOffset[1]];
61171             tiler.scale(_projection.scale() * 2 * Math.PI).translate(translate);
61172             _tileOrigin = [_projection.scale() * Math.PI - translate[0], _projection.scale() * Math.PI - translate[1]];
61173             render(selection);
61174           } // Derive the tiles onscreen, remove those offscreen and position them.
61175           // Important that this part not depend on `_projection` because it's
61176           // rentered when tiles load/error (see #644).
61177
61178
61179           function render(selection) {
61180             if (!_source) return;
61181             var requests = [];
61182             var showDebug = context.getDebug('tile') && !_source.overlay;
61183
61184             if (_source.validZoom(_zoom)) {
61185               tiler.skipNullIsland(!!_source.overlay);
61186               tiler().forEach(function (d) {
61187                 addSource(d);
61188                 if (d[3] === '') return;
61189                 if (typeof d[3] !== 'string') return; // Workaround for #2295
61190
61191                 requests.push(d);
61192
61193                 if (_cache[d[3]] === false && lookUp(d)) {
61194                   requests.push(addSource(lookUp(d)));
61195                 }
61196               });
61197               requests = uniqueBy(requests, 3).filter(function (r) {
61198                 // don't re-request tiles which have failed in the past
61199                 return _cache[r[3]] !== false;
61200               });
61201             }
61202
61203             function load(d3_event, d) {
61204               _cache[d[3]] = true;
61205               select(this).on('error', null).on('load', null).classed('tile-loaded', true);
61206               render(selection);
61207             }
61208
61209             function error(d3_event, d) {
61210               _cache[d[3]] = false;
61211               select(this).on('error', null).on('load', null).remove();
61212               render(selection);
61213             }
61214
61215             function imageTransform(d) {
61216               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
61217
61218               var scale = tileSizeAtZoom(d, _zoom);
61219               return 'translate(' + (d[0] * ts - _tileOrigin[0]) + 'px,' + (d[1] * ts - _tileOrigin[1]) + 'px) ' + 'scale(' + scale + ',' + scale + ')';
61220             }
61221
61222             function tileCenter(d) {
61223               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
61224
61225               return [d[0] * ts - _tileOrigin[0] + ts / 2, d[1] * ts - _tileOrigin[1] + ts / 2];
61226             }
61227
61228             function debugTransform(d) {
61229               var coord = tileCenter(d);
61230               return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
61231             } // Pick a representative tile near the center of the viewport
61232             // (This is useful for sampling the imagery vintage)
61233
61234
61235             var dims = tiler.size();
61236             var mapCenter = [dims[0] / 2, dims[1] / 2];
61237             var minDist = Math.max(dims[0], dims[1]);
61238             var nearCenter;
61239             requests.forEach(function (d) {
61240               var c = tileCenter(d);
61241               var dist = geoVecLength(c, mapCenter);
61242
61243               if (dist < minDist) {
61244                 minDist = dist;
61245                 nearCenter = d;
61246               }
61247             });
61248             var image = selection.selectAll('img').data(requests, function (d) {
61249               return d[3];
61250             });
61251             image.exit().style(transformProp, imageTransform).classed('tile-removing', true).classed('tile-center', false).each(function () {
61252               var tile = select(this);
61253               window.setTimeout(function () {
61254                 if (tile.classed('tile-removing')) {
61255                   tile.remove();
61256                 }
61257               }, 300);
61258             });
61259             image.enter().append('img').attr('class', 'tile').attr('draggable', 'false').style('width', _tileSize + 'px').style('height', _tileSize + 'px').attr('src', function (d) {
61260               return d[3];
61261             }).on('error', error).on('load', load).merge(image).style(transformProp, imageTransform).classed('tile-debug', showDebug).classed('tile-removing', false).classed('tile-center', function (d) {
61262               return d === nearCenter;
61263             });
61264             var debug = selection.selectAll('.tile-label-debug').data(showDebug ? requests : [], function (d) {
61265               return d[3];
61266             });
61267             debug.exit().remove();
61268
61269             if (showDebug) {
61270               var debugEnter = debug.enter().append('div').attr('class', 'tile-label-debug');
61271               debugEnter.append('div').attr('class', 'tile-label-debug-coord');
61272               debugEnter.append('div').attr('class', 'tile-label-debug-vintage');
61273               debug = debug.merge(debugEnter);
61274               debug.style(transformProp, debugTransform);
61275               debug.selectAll('.tile-label-debug-coord').html(function (d) {
61276                 return d[2] + ' / ' + d[0] + ' / ' + d[1];
61277               });
61278               debug.selectAll('.tile-label-debug-vintage').each(function (d) {
61279                 var span = select(this);
61280                 var center = context.projection.invert(tileCenter(d));
61281
61282                 _source.getMetadata(center, d, function (err, result) {
61283                   span.html(result && result.vintage && result.vintage.range || _t('info_panels.background.vintage') + ': ' + _t('info_panels.background.unknown'));
61284                 });
61285               });
61286             }
61287           }
61288
61289           background.projection = function (val) {
61290             if (!arguments.length) return _projection;
61291             _projection = val;
61292             return background;
61293           };
61294
61295           background.dimensions = function (val) {
61296             if (!arguments.length) return tiler.size();
61297             tiler.size(val);
61298             return background;
61299           };
61300
61301           background.source = function (val) {
61302             if (!arguments.length) return _source;
61303             _source = val;
61304             _tileSize = _source.tileSize;
61305             _cache = {};
61306             tiler.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
61307             return background;
61308           };
61309
61310           return background;
61311         }
61312
61313         var _imageryIndex = null;
61314         function rendererBackground(context) {
61315           var dispatch = dispatch$8('change');
61316           var detected = utilDetect();
61317           var baseLayer = rendererTileLayer(context).projection(context.projection);
61318           var _isValid = true;
61319           var _overlayLayers = [];
61320           var _brightness = 1;
61321           var _contrast = 1;
61322           var _saturation = 1;
61323           var _sharpness = 1;
61324
61325           function ensureImageryIndex() {
61326             return _mainFileFetcher.get('imagery').then(function (sources) {
61327               if (_imageryIndex) return _imageryIndex;
61328               _imageryIndex = {
61329                 imagery: sources,
61330                 features: {}
61331               }; // use which-polygon to support efficient index and querying for imagery
61332
61333               var features = sources.map(function (source) {
61334                 if (!source.polygon) return null; // workaround for editor-layer-index weirdness..
61335                 // Add an extra array nest to each element in `source.polygon`
61336                 // so the rings are not treated as a bunch of holes:
61337                 // what we have: [ [[outer],[hole],[hole]] ]
61338                 // what we want: [ [[outer]],[[outer]],[[outer]] ]
61339
61340                 var rings = source.polygon.map(function (ring) {
61341                   return [ring];
61342                 });
61343                 var feature = {
61344                   type: 'Feature',
61345                   properties: {
61346                     id: source.id
61347                   },
61348                   geometry: {
61349                     type: 'MultiPolygon',
61350                     coordinates: rings
61351                   }
61352                 };
61353                 _imageryIndex.features[source.id] = feature;
61354                 return feature;
61355               }).filter(Boolean);
61356               _imageryIndex.query = whichPolygon_1({
61357                 type: 'FeatureCollection',
61358                 features: features
61359               }); // Instantiate `rendererBackgroundSource` objects for each source
61360
61361               _imageryIndex.backgrounds = sources.map(function (source) {
61362                 if (source.type === 'bing') {
61363                   return rendererBackgroundSource.Bing(source, dispatch);
61364                 } else if (/^EsriWorldImagery/.test(source.id)) {
61365                   return rendererBackgroundSource.Esri(source);
61366                 } else {
61367                   return rendererBackgroundSource(source);
61368                 }
61369               }); // Add 'None'
61370
61371               _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None()); // Add 'Custom'
61372
61373
61374               var template = corePreferences('background-custom-template') || '';
61375               var custom = rendererBackgroundSource.Custom(template);
61376
61377               _imageryIndex.backgrounds.unshift(custom);
61378
61379               return _imageryIndex;
61380             });
61381           }
61382
61383           function background(selection) {
61384             var currSource = baseLayer.source(); // If we are displaying an Esri basemap at high zoom,
61385             // check its tilemap to see how high the zoom can go
61386
61387             if (context.map().zoom() > 18) {
61388               if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
61389                 var center = context.map().center();
61390                 currSource.fetchTilemap(center);
61391               }
61392             } // Is the imagery valid here? - #4827
61393
61394
61395             var sources = background.sources(context.map().extent());
61396             var wasValid = _isValid;
61397             _isValid = !!sources.filter(function (d) {
61398               return d === currSource;
61399             }).length;
61400
61401             if (wasValid !== _isValid) {
61402               // change in valid status
61403               background.updateImagery();
61404             }
61405
61406             var baseFilter = '';
61407
61408             if (detected.cssfilters) {
61409               if (_brightness !== 1) {
61410                 baseFilter += " brightness(".concat(_brightness, ")");
61411               }
61412
61413               if (_contrast !== 1) {
61414                 baseFilter += " contrast(".concat(_contrast, ")");
61415               }
61416
61417               if (_saturation !== 1) {
61418                 baseFilter += " saturate(".concat(_saturation, ")");
61419               }
61420
61421               if (_sharpness < 1) {
61422                 // gaussian blur
61423                 var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
61424                 baseFilter += " blur(".concat(blur, "px)");
61425               }
61426             }
61427
61428             var base = selection.selectAll('.layer-background').data([0]);
61429             base = base.enter().insert('div', '.layer-data').attr('class', 'layer layer-background').merge(base);
61430
61431             if (detected.cssfilters) {
61432               base.style('filter', baseFilter || null);
61433             } else {
61434               base.style('opacity', _brightness);
61435             }
61436
61437             var imagery = base.selectAll('.layer-imagery').data([0]);
61438             imagery.enter().append('div').attr('class', 'layer layer-imagery').merge(imagery).call(baseLayer);
61439             var maskFilter = '';
61440             var mixBlendMode = '';
61441
61442             if (detected.cssfilters && _sharpness > 1) {
61443               // apply unsharp mask
61444               mixBlendMode = 'overlay';
61445               maskFilter = 'saturate(0) blur(3px) invert(1)';
61446               var contrast = _sharpness - 1;
61447               maskFilter += " contrast(".concat(contrast, ")");
61448               var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
61449               maskFilter += " brightness(".concat(brightness, ")");
61450             }
61451
61452             var mask = base.selectAll('.layer-unsharp-mask').data(detected.cssfilters && _sharpness > 1 ? [0] : []);
61453             mask.exit().remove();
61454             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);
61455             var overlays = selection.selectAll('.layer-overlay').data(_overlayLayers, function (d) {
61456               return d.source().name();
61457             });
61458             overlays.exit().remove();
61459             overlays.enter().insert('div', '.layer-data').attr('class', 'layer layer-overlay').merge(overlays).each(function (layer, i, nodes) {
61460               return select(nodes[i]).call(layer);
61461             });
61462           }
61463
61464           background.updateImagery = function () {
61465             var currSource = baseLayer.source();
61466             if (context.inIntro() || !currSource) return;
61467
61468             var o = _overlayLayers.filter(function (d) {
61469               return !d.source().isLocatorOverlay() && !d.source().isHidden();
61470             }).map(function (d) {
61471               return d.source().id;
61472             }).join(',');
61473
61474             var meters = geoOffsetToMeters(currSource.offset());
61475             var EPSILON = 0.01;
61476             var x = +meters[0].toFixed(2);
61477             var y = +meters[1].toFixed(2);
61478             var hash = utilStringQs(window.location.hash);
61479             var id = currSource.id;
61480
61481             if (id === 'custom') {
61482               id = "custom:".concat(currSource.template());
61483             }
61484
61485             if (id) {
61486               hash.background = id;
61487             } else {
61488               delete hash.background;
61489             }
61490
61491             if (o) {
61492               hash.overlays = o;
61493             } else {
61494               delete hash.overlays;
61495             }
61496
61497             if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
61498               hash.offset = "".concat(x, ",").concat(y);
61499             } else {
61500               delete hash.offset;
61501             }
61502
61503             if (!window.mocha) {
61504               window.location.replace('#' + utilQsString(hash, true));
61505             }
61506
61507             var imageryUsed = [];
61508             var photoOverlaysUsed = [];
61509             var currUsed = currSource.imageryUsed();
61510
61511             if (currUsed && _isValid) {
61512               imageryUsed.push(currUsed);
61513             }
61514
61515             _overlayLayers.filter(function (d) {
61516               return !d.source().isLocatorOverlay() && !d.source().isHidden();
61517             }).forEach(function (d) {
61518               return imageryUsed.push(d.source().imageryUsed());
61519             });
61520
61521             var dataLayer = context.layers().layer('data');
61522
61523             if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
61524               imageryUsed.push(dataLayer.getSrc());
61525             }
61526
61527             var photoOverlayLayers = {
61528               streetside: 'Bing Streetside',
61529               mapillary: 'Mapillary Images',
61530               'mapillary-map-features': 'Mapillary Map Features',
61531               'mapillary-signs': 'Mapillary Signs',
61532               openstreetcam: 'OpenStreetCam Images'
61533             };
61534
61535             for (var layerID in photoOverlayLayers) {
61536               var layer = context.layers().layer(layerID);
61537
61538               if (layer && layer.enabled()) {
61539                 photoOverlaysUsed.push(layerID);
61540                 imageryUsed.push(photoOverlayLayers[layerID]);
61541               }
61542             }
61543
61544             context.history().imageryUsed(imageryUsed);
61545             context.history().photoOverlaysUsed(photoOverlaysUsed);
61546           };
61547
61548           var _checkedBlocklists;
61549
61550           background.sources = function (extent, zoom, includeCurrent) {
61551             if (!_imageryIndex) return []; // called before init()?
61552
61553             var visible = {};
61554             (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach(function (d) {
61555               return visible[d.id] = true;
61556             });
61557             var currSource = baseLayer.source();
61558             var osm = context.connection();
61559             var blocklists = osm && osm.imageryBlocklists();
61560
61561             if (blocklists && blocklists !== _checkedBlocklists) {
61562               _imageryIndex.backgrounds.forEach(function (source) {
61563                 source.isBlocked = blocklists.some(function (blocklist) {
61564                   return blocklist.test(source.template());
61565                 });
61566               });
61567
61568               _checkedBlocklists = blocklists;
61569             }
61570
61571             return _imageryIndex.backgrounds.filter(function (source) {
61572               if (includeCurrent && currSource === source) return true; // optionally always include the current imagery
61573
61574               if (source.isBlocked) return false; // even bundled sources may be blocked - #7905
61575
61576               if (!source.polygon) return true; // always include imagery with worldwide coverage
61577
61578               if (zoom && zoom < 6) return false; // optionally exclude local imagery at low zooms
61579
61580               return visible[source.id]; // include imagery visible in given extent
61581             });
61582           };
61583
61584           background.dimensions = function (val) {
61585             if (!val) return;
61586             baseLayer.dimensions(val);
61587
61588             _overlayLayers.forEach(function (layer) {
61589               return layer.dimensions(val);
61590             });
61591           };
61592
61593           background.baseLayerSource = function (d) {
61594             if (!arguments.length) return baseLayer.source(); // test source against OSM imagery blocklists..
61595
61596             var osm = context.connection();
61597             if (!osm) return background;
61598             var blocklists = osm.imageryBlocklists();
61599             var template = d.template();
61600             var fail = false;
61601             var tested = 0;
61602             var regex;
61603
61604             for (var i = 0; i < blocklists.length; i++) {
61605               regex = blocklists[i];
61606               fail = regex.test(template);
61607               tested++;
61608               if (fail) break;
61609             } // ensure at least one test was run.
61610
61611
61612             if (!tested) {
61613               regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
61614               fail = regex.test(template);
61615             }
61616
61617             baseLayer.source(!fail ? d : background.findSource('none'));
61618             dispatch.call('change');
61619             background.updateImagery();
61620             return background;
61621           };
61622
61623           background.findSource = function (id) {
61624             if (!id || !_imageryIndex) return null; // called before init()?
61625
61626             return _imageryIndex.backgrounds.find(function (d) {
61627               return d.id && d.id === id;
61628             });
61629           };
61630
61631           background.bing = function () {
61632             background.baseLayerSource(background.findSource('Bing'));
61633           };
61634
61635           background.showsLayer = function (d) {
61636             var currSource = baseLayer.source();
61637             if (!d || !currSource) return false;
61638             return d.id === currSource.id || _overlayLayers.some(function (layer) {
61639               return d.id === layer.source().id;
61640             });
61641           };
61642
61643           background.overlayLayerSources = function () {
61644             return _overlayLayers.map(function (layer) {
61645               return layer.source();
61646             });
61647           };
61648
61649           background.toggleOverlayLayer = function (d) {
61650             var layer;
61651
61652             for (var i = 0; i < _overlayLayers.length; i++) {
61653               layer = _overlayLayers[i];
61654
61655               if (layer.source() === d) {
61656                 _overlayLayers.splice(i, 1);
61657
61658                 dispatch.call('change');
61659                 background.updateImagery();
61660                 return;
61661               }
61662             }
61663
61664             layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(baseLayer.dimensions());
61665
61666             _overlayLayers.push(layer);
61667
61668             dispatch.call('change');
61669             background.updateImagery();
61670           };
61671
61672           background.nudge = function (d, zoom) {
61673             var currSource = baseLayer.source();
61674
61675             if (currSource) {
61676               currSource.nudge(d, zoom);
61677               dispatch.call('change');
61678               background.updateImagery();
61679             }
61680
61681             return background;
61682           };
61683
61684           background.offset = function (d) {
61685             var currSource = baseLayer.source();
61686
61687             if (!arguments.length) {
61688               return currSource && currSource.offset() || [0, 0];
61689             }
61690
61691             if (currSource) {
61692               currSource.offset(d);
61693               dispatch.call('change');
61694               background.updateImagery();
61695             }
61696
61697             return background;
61698           };
61699
61700           background.brightness = function (d) {
61701             if (!arguments.length) return _brightness;
61702             _brightness = d;
61703             if (context.mode()) dispatch.call('change');
61704             return background;
61705           };
61706
61707           background.contrast = function (d) {
61708             if (!arguments.length) return _contrast;
61709             _contrast = d;
61710             if (context.mode()) dispatch.call('change');
61711             return background;
61712           };
61713
61714           background.saturation = function (d) {
61715             if (!arguments.length) return _saturation;
61716             _saturation = d;
61717             if (context.mode()) dispatch.call('change');
61718             return background;
61719           };
61720
61721           background.sharpness = function (d) {
61722             if (!arguments.length) return _sharpness;
61723             _sharpness = d;
61724             if (context.mode()) dispatch.call('change');
61725             return background;
61726           };
61727
61728           var _loadPromise;
61729
61730           background.ensureLoaded = function () {
61731             if (_loadPromise) return _loadPromise;
61732
61733             function parseMapParams(qmap) {
61734               if (!qmap) return false;
61735               var params = qmap.split('/').map(Number);
61736               if (params.length < 3 || params.some(isNaN)) return false;
61737               return geoExtent([params[2], params[1]]); // lon,lat
61738             }
61739
61740             var hash = utilStringQs(window.location.hash);
61741             var requested = hash.background || hash.layer;
61742             var extent = parseMapParams(hash.map);
61743             return _loadPromise = ensureImageryIndex().then(function (imageryIndex) {
61744               var first = imageryIndex.backgrounds.length && imageryIndex.backgrounds[0];
61745               var best;
61746
61747               if (!requested && extent) {
61748                 best = background.sources(extent).find(function (s) {
61749                   return s.best();
61750                 });
61751               } // Decide which background layer to display
61752
61753
61754               if (requested && requested.indexOf('custom:') === 0) {
61755                 var template = requested.replace(/^custom:/, '');
61756                 var custom = background.findSource('custom');
61757                 background.baseLayerSource(custom.template(template));
61758                 corePreferences('background-custom-template', template);
61759               } else {
61760                 background.baseLayerSource(background.findSource(requested) || best || background.findSource(corePreferences('background-last-used')) || background.findSource('Bing') || first || background.findSource('none'));
61761               }
61762
61763               var locator = imageryIndex.backgrounds.find(function (d) {
61764                 return d.overlay && d["default"];
61765               });
61766
61767               if (locator) {
61768                 background.toggleOverlayLayer(locator);
61769               }
61770
61771               var overlays = (hash.overlays || '').split(',');
61772               overlays.forEach(function (overlay) {
61773                 overlay = background.findSource(overlay);
61774
61775                 if (overlay) {
61776                   background.toggleOverlayLayer(overlay);
61777                 }
61778               });
61779
61780               if (hash.gpx) {
61781                 var gpx = context.layers().layer('data');
61782
61783                 if (gpx) {
61784                   gpx.url(hash.gpx, '.gpx');
61785                 }
61786               }
61787
61788               if (hash.offset) {
61789                 var offset = hash.offset.replace(/;/g, ',').split(',').map(function (n) {
61790                   return !isNaN(n) && n;
61791                 });
61792
61793                 if (offset.length === 2) {
61794                   background.offset(geoMetersToOffset(offset));
61795                 }
61796               }
61797             })["catch"](function () {
61798               /* ignore */
61799             });
61800           };
61801
61802           return utilRebind(background, dispatch, 'on');
61803         }
61804
61805         function rendererFeatures(context) {
61806           var dispatch = dispatch$8('change', 'redraw');
61807           var features = utilRebind({}, dispatch, 'on');
61808
61809           var _deferred = new Set();
61810
61811           var traffic_roads = {
61812             'motorway': true,
61813             'motorway_link': true,
61814             'trunk': true,
61815             'trunk_link': true,
61816             'primary': true,
61817             'primary_link': true,
61818             'secondary': true,
61819             'secondary_link': true,
61820             'tertiary': true,
61821             'tertiary_link': true,
61822             'residential': true,
61823             'unclassified': true,
61824             'living_street': true
61825           };
61826           var service_roads = {
61827             'service': true,
61828             'road': true,
61829             'track': true
61830           };
61831           var paths = {
61832             'path': true,
61833             'footway': true,
61834             'cycleway': true,
61835             'bridleway': true,
61836             'steps': true,
61837             'pedestrian': true
61838           };
61839           var past_futures = {
61840             'proposed': true,
61841             'construction': true,
61842             'abandoned': true,
61843             'dismantled': true,
61844             'disused': true,
61845             'razed': true,
61846             'demolished': true,
61847             'obliterated': true
61848           };
61849           var _cullFactor = 1;
61850           var _cache = {};
61851           var _rules = {};
61852           var _stats = {};
61853           var _keys = [];
61854           var _hidden = [];
61855           var _forceVisible = {};
61856
61857           function update() {
61858             if (!window.mocha) {
61859               var hash = utilStringQs(window.location.hash);
61860               var disabled = features.disabled();
61861
61862               if (disabled.length) {
61863                 hash.disable_features = disabled.join(',');
61864               } else {
61865                 delete hash.disable_features;
61866               }
61867
61868               window.location.replace('#' + utilQsString(hash, true));
61869               corePreferences('disabled-features', disabled.join(','));
61870             }
61871
61872             _hidden = features.hidden();
61873             dispatch.call('change');
61874             dispatch.call('redraw');
61875           }
61876
61877           function defineRule(k, filter, max) {
61878             var isEnabled = true;
61879
61880             _keys.push(k);
61881
61882             _rules[k] = {
61883               filter: filter,
61884               enabled: isEnabled,
61885               // whether the user wants it enabled..
61886               count: 0,
61887               currentMax: max || Infinity,
61888               defaultMax: max || Infinity,
61889               enable: function enable() {
61890                 this.enabled = true;
61891                 this.currentMax = this.defaultMax;
61892               },
61893               disable: function disable() {
61894                 this.enabled = false;
61895                 this.currentMax = 0;
61896               },
61897               hidden: function hidden() {
61898                 return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
61899               },
61900               autoHidden: function autoHidden() {
61901                 return this.hidden() && this.currentMax > 0;
61902               }
61903             };
61904           }
61905
61906           defineRule('points', function isPoint(tags, geometry) {
61907             return geometry === 'point';
61908           }, 200);
61909           defineRule('traffic_roads', function isTrafficRoad(tags) {
61910             return traffic_roads[tags.highway];
61911           });
61912           defineRule('service_roads', function isServiceRoad(tags) {
61913             return service_roads[tags.highway];
61914           });
61915           defineRule('paths', function isPath(tags) {
61916             return paths[tags.highway];
61917           });
61918           defineRule('buildings', function isBuilding(tags) {
61919             return !!tags.building && tags.building !== 'no' || tags.parking === 'multi-storey' || tags.parking === 'sheds' || tags.parking === 'carports' || tags.parking === 'garage_boxes';
61920           }, 250);
61921           defineRule('building_parts', function isBuildingPart(tags) {
61922             return tags['building:part'];
61923           });
61924           defineRule('indoor', function isIndoor(tags) {
61925             return tags.indoor;
61926           });
61927           defineRule('landuse', function isLanduse(tags, geometry) {
61928             return geometry === 'area' && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
61929           });
61930           defineRule('boundaries', function isBoundary(tags) {
61931             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);
61932           });
61933           defineRule('water', function isWater(tags) {
61934             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';
61935           });
61936           defineRule('rail', function isRail(tags) {
61937             return (!!tags.railway || tags.landuse === 'railway') && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
61938           });
61939           defineRule('pistes', function isPiste(tags) {
61940             return tags['piste:type'];
61941           });
61942           defineRule('aerialways', function isPiste(tags) {
61943             return tags.aerialway && tags.aerialway !== 'yes' && tags.aerialway !== 'station';
61944           });
61945           defineRule('power', function isPower(tags) {
61946             return !!tags.power;
61947           }); // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
61948
61949           defineRule('past_future', function isPastFuture(tags) {
61950             if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
61951               return false;
61952             }
61953
61954             var strings = Object.keys(tags);
61955
61956             for (var i = 0; i < strings.length; i++) {
61957               var s = strings[i];
61958
61959               if (past_futures[s] || past_futures[tags[s]]) {
61960                 return true;
61961               }
61962             }
61963
61964             return false;
61965           }); // Lines or areas that don't match another feature filter.
61966           // IMPORTANT: The 'others' feature must be the last one defined,
61967           //   so that code in getMatches can skip this test if `hasMatch = true`
61968
61969           defineRule('others', function isOther(tags, geometry) {
61970             return geometry === 'line' || geometry === 'area';
61971           });
61972
61973           features.features = function () {
61974             return _rules;
61975           };
61976
61977           features.keys = function () {
61978             return _keys;
61979           };
61980
61981           features.enabled = function (k) {
61982             if (!arguments.length) {
61983               return _keys.filter(function (k) {
61984                 return _rules[k].enabled;
61985               });
61986             }
61987
61988             return _rules[k] && _rules[k].enabled;
61989           };
61990
61991           features.disabled = function (k) {
61992             if (!arguments.length) {
61993               return _keys.filter(function (k) {
61994                 return !_rules[k].enabled;
61995               });
61996             }
61997
61998             return _rules[k] && !_rules[k].enabled;
61999           };
62000
62001           features.hidden = function (k) {
62002             if (!arguments.length) {
62003               return _keys.filter(function (k) {
62004                 return _rules[k].hidden();
62005               });
62006             }
62007
62008             return _rules[k] && _rules[k].hidden();
62009           };
62010
62011           features.autoHidden = function (k) {
62012             if (!arguments.length) {
62013               return _keys.filter(function (k) {
62014                 return _rules[k].autoHidden();
62015               });
62016             }
62017
62018             return _rules[k] && _rules[k].autoHidden();
62019           };
62020
62021           features.enable = function (k) {
62022             if (_rules[k] && !_rules[k].enabled) {
62023               _rules[k].enable();
62024
62025               update();
62026             }
62027           };
62028
62029           features.enableAll = function () {
62030             var didEnable = false;
62031
62032             for (var k in _rules) {
62033               if (!_rules[k].enabled) {
62034                 didEnable = true;
62035
62036                 _rules[k].enable();
62037               }
62038             }
62039
62040             if (didEnable) update();
62041           };
62042
62043           features.disable = function (k) {
62044             if (_rules[k] && _rules[k].enabled) {
62045               _rules[k].disable();
62046
62047               update();
62048             }
62049           };
62050
62051           features.disableAll = function () {
62052             var didDisable = false;
62053
62054             for (var k in _rules) {
62055               if (_rules[k].enabled) {
62056                 didDisable = true;
62057
62058                 _rules[k].disable();
62059               }
62060             }
62061
62062             if (didDisable) update();
62063           };
62064
62065           features.toggle = function (k) {
62066             if (_rules[k]) {
62067               (function (f) {
62068                 return f.enabled ? f.disable() : f.enable();
62069               })(_rules[k]);
62070
62071               update();
62072             }
62073           };
62074
62075           features.resetStats = function () {
62076             for (var i = 0; i < _keys.length; i++) {
62077               _rules[_keys[i]].count = 0;
62078             }
62079
62080             dispatch.call('change');
62081           };
62082
62083           features.gatherStats = function (d, resolver, dimensions) {
62084             var needsRedraw = false;
62085             var types = utilArrayGroupBy(d, 'type');
62086             var entities = [].concat(types.relation || [], types.way || [], types.node || []);
62087             var currHidden, geometry, matches, i, j;
62088
62089             for (i = 0; i < _keys.length; i++) {
62090               _rules[_keys[i]].count = 0;
62091             } // adjust the threshold for point/building culling based on viewport size..
62092             // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
62093
62094
62095             _cullFactor = dimensions[0] * dimensions[1] / 1000000;
62096
62097             for (i = 0; i < entities.length; i++) {
62098               geometry = entities[i].geometry(resolver);
62099               matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
62100
62101               for (j = 0; j < matches.length; j++) {
62102                 _rules[matches[j]].count++;
62103               }
62104             }
62105
62106             currHidden = features.hidden();
62107
62108             if (currHidden !== _hidden) {
62109               _hidden = currHidden;
62110               needsRedraw = true;
62111               dispatch.call('change');
62112             }
62113
62114             return needsRedraw;
62115           };
62116
62117           features.stats = function () {
62118             for (var i = 0; i < _keys.length; i++) {
62119               _stats[_keys[i]] = _rules[_keys[i]].count;
62120             }
62121
62122             return _stats;
62123           };
62124
62125           features.clear = function (d) {
62126             for (var i = 0; i < d.length; i++) {
62127               features.clearEntity(d[i]);
62128             }
62129           };
62130
62131           features.clearEntity = function (entity) {
62132             delete _cache[osmEntity.key(entity)];
62133           };
62134
62135           features.reset = function () {
62136             Array.from(_deferred).forEach(function (handle) {
62137               window.cancelIdleCallback(handle);
62138
62139               _deferred["delete"](handle);
62140             });
62141             _cache = {};
62142           }; // only certain relations are worth checking
62143
62144
62145           function relationShouldBeChecked(relation) {
62146             // multipolygon features have `area` geometry and aren't checked here
62147             return relation.tags.type === 'boundary';
62148           }
62149
62150           features.getMatches = function (entity, resolver, geometry) {
62151             if (geometry === 'vertex' || geometry === 'relation' && !relationShouldBeChecked(entity)) return {};
62152             var ent = osmEntity.key(entity);
62153
62154             if (!_cache[ent]) {
62155               _cache[ent] = {};
62156             }
62157
62158             if (!_cache[ent].matches) {
62159               var matches = {};
62160               var hasMatch = false;
62161
62162               for (var i = 0; i < _keys.length; i++) {
62163                 if (_keys[i] === 'others') {
62164                   if (hasMatch) continue; // If an entity...
62165                   //   1. is a way that hasn't matched other 'interesting' feature rules,
62166
62167                   if (entity.type === 'way') {
62168                     var parents = features.getParents(entity, resolver, geometry); //   2a. belongs only to a single multipolygon relation
62169
62170                     if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
62171                     parents.length > 0 && parents.every(function (parent) {
62172                       return parent.tags.type === 'boundary';
62173                     })) {
62174                       // ...then match whatever feature rules the parent relation has matched.
62175                       // see #2548, #2887
62176                       //
62177                       // IMPORTANT:
62178                       // For this to work, getMatches must be called on relations before ways.
62179                       //
62180                       var pkey = osmEntity.key(parents[0]);
62181
62182                       if (_cache[pkey] && _cache[pkey].matches) {
62183                         matches = Object.assign({}, _cache[pkey].matches); // shallow copy
62184
62185                         continue;
62186                       }
62187                     }
62188                   }
62189                 }
62190
62191                 if (_rules[_keys[i]].filter(entity.tags, geometry)) {
62192                   matches[_keys[i]] = hasMatch = true;
62193                 }
62194               }
62195
62196               _cache[ent].matches = matches;
62197             }
62198
62199             return _cache[ent].matches;
62200           };
62201
62202           features.getParents = function (entity, resolver, geometry) {
62203             if (geometry === 'point') return [];
62204             var ent = osmEntity.key(entity);
62205
62206             if (!_cache[ent]) {
62207               _cache[ent] = {};
62208             }
62209
62210             if (!_cache[ent].parents) {
62211               var parents = [];
62212
62213               if (geometry === 'vertex') {
62214                 parents = resolver.parentWays(entity);
62215               } else {
62216                 // 'line', 'area', 'relation'
62217                 parents = resolver.parentRelations(entity);
62218               }
62219
62220               _cache[ent].parents = parents;
62221             }
62222
62223             return _cache[ent].parents;
62224           };
62225
62226           features.isHiddenPreset = function (preset, geometry) {
62227             if (!_hidden.length) return false;
62228             if (!preset.tags) return false;
62229             var test = preset.setTags({}, geometry);
62230
62231             for (var key in _rules) {
62232               if (_rules[key].filter(test, geometry)) {
62233                 if (_hidden.indexOf(key) !== -1) {
62234                   return key;
62235                 }
62236
62237                 return false;
62238               }
62239             }
62240
62241             return false;
62242           };
62243
62244           features.isHiddenFeature = function (entity, resolver, geometry) {
62245             if (!_hidden.length) return false;
62246             if (!entity.version) return false;
62247             if (_forceVisible[entity.id]) return false;
62248             var matches = Object.keys(features.getMatches(entity, resolver, geometry));
62249             return matches.length && matches.every(function (k) {
62250               return features.hidden(k);
62251             });
62252           };
62253
62254           features.isHiddenChild = function (entity, resolver, geometry) {
62255             if (!_hidden.length) return false;
62256             if (!entity.version || geometry === 'point') return false;
62257             if (_forceVisible[entity.id]) return false;
62258             var parents = features.getParents(entity, resolver, geometry);
62259             if (!parents.length) return false;
62260
62261             for (var i = 0; i < parents.length; i++) {
62262               if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
62263                 return false;
62264               }
62265             }
62266
62267             return true;
62268           };
62269
62270           features.hasHiddenConnections = function (entity, resolver) {
62271             if (!_hidden.length) return false;
62272             var childNodes, connections;
62273
62274             if (entity.type === 'midpoint') {
62275               childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
62276               connections = [];
62277             } else {
62278               childNodes = entity.nodes ? resolver.childNodes(entity) : [];
62279               connections = features.getParents(entity, resolver, entity.geometry(resolver));
62280             } // gather ways connected to child nodes..
62281
62282
62283             connections = childNodes.reduce(function (result, e) {
62284               return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
62285             }, connections);
62286             return connections.some(function (e) {
62287               return features.isHidden(e, resolver, e.geometry(resolver));
62288             });
62289           };
62290
62291           features.isHidden = function (entity, resolver, geometry) {
62292             if (!_hidden.length) return false;
62293             if (!entity.version) return false;
62294             var fn = geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature;
62295             return fn(entity, resolver, geometry);
62296           };
62297
62298           features.filter = function (d, resolver) {
62299             if (!_hidden.length) return d;
62300             var result = [];
62301
62302             for (var i = 0; i < d.length; i++) {
62303               var entity = d[i];
62304
62305               if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
62306                 result.push(entity);
62307               }
62308             }
62309
62310             return result;
62311           };
62312
62313           features.forceVisible = function (entityIDs) {
62314             if (!arguments.length) return Object.keys(_forceVisible);
62315             _forceVisible = {};
62316
62317             for (var i = 0; i < entityIDs.length; i++) {
62318               _forceVisible[entityIDs[i]] = true;
62319               var entity = context.hasEntity(entityIDs[i]);
62320
62321               if (entity && entity.type === 'relation') {
62322                 // also show relation members (one level deep)
62323                 for (var j in entity.members) {
62324                   _forceVisible[entity.members[j].id] = true;
62325                 }
62326               }
62327             }
62328
62329             return features;
62330           };
62331
62332           features.init = function () {
62333             var storage = corePreferences('disabled-features');
62334
62335             if (storage) {
62336               var storageDisabled = storage.replace(/;/g, ',').split(',');
62337               storageDisabled.forEach(features.disable);
62338             }
62339
62340             var hash = utilStringQs(window.location.hash);
62341
62342             if (hash.disable_features) {
62343               var hashDisabled = hash.disable_features.replace(/;/g, ',').split(',');
62344               hashDisabled.forEach(features.disable);
62345             }
62346           }; // warm up the feature matching cache upon merging fetched data
62347
62348
62349           context.history().on('merge.features', function (newEntities) {
62350             if (!newEntities) return;
62351             var handle = window.requestIdleCallback(function () {
62352               var graph = context.graph();
62353               var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways
62354
62355               var entities = [].concat(types.relation || [], types.way || [], types.node || []);
62356
62357               for (var i = 0; i < entities.length; i++) {
62358                 var geometry = entities[i].geometry(graph);
62359                 features.getMatches(entities[i], graph, geometry);
62360               }
62361             });
62362
62363             _deferred.add(handle);
62364           });
62365           return features;
62366         }
62367
62368         /** Error message constants. */
62369
62370         var FUNC_ERROR_TEXT = 'Expected a function';
62371         /**
62372          * Creates a throttled function that only invokes `func` at most once per
62373          * every `wait` milliseconds. The throttled function comes with a `cancel`
62374          * method to cancel delayed `func` invocations and a `flush` method to
62375          * immediately invoke them. Provide `options` to indicate whether `func`
62376          * should be invoked on the leading and/or trailing edge of the `wait`
62377          * timeout. The `func` is invoked with the last arguments provided to the
62378          * throttled function. Subsequent calls to the throttled function return the
62379          * result of the last `func` invocation.
62380          *
62381          * **Note:** If `leading` and `trailing` options are `true`, `func` is
62382          * invoked on the trailing edge of the timeout only if the throttled function
62383          * is invoked more than once during the `wait` timeout.
62384          *
62385          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
62386          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
62387          *
62388          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
62389          * for details over the differences between `_.throttle` and `_.debounce`.
62390          *
62391          * @static
62392          * @memberOf _
62393          * @since 0.1.0
62394          * @category Function
62395          * @param {Function} func The function to throttle.
62396          * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
62397          * @param {Object} [options={}] The options object.
62398          * @param {boolean} [options.leading=true]
62399          *  Specify invoking on the leading edge of the timeout.
62400          * @param {boolean} [options.trailing=true]
62401          *  Specify invoking on the trailing edge of the timeout.
62402          * @returns {Function} Returns the new throttled function.
62403          * @example
62404          *
62405          * // Avoid excessively updating the position while scrolling.
62406          * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
62407          *
62408          * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
62409          * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
62410          * jQuery(element).on('click', throttled);
62411          *
62412          * // Cancel the trailing throttled invocation.
62413          * jQuery(window).on('popstate', throttled.cancel);
62414          */
62415
62416         function throttle(func, wait, options) {
62417           var leading = true,
62418               trailing = true;
62419
62420           if (typeof func != 'function') {
62421             throw new TypeError(FUNC_ERROR_TEXT);
62422           }
62423
62424           if (isObject$2(options)) {
62425             leading = 'leading' in options ? !!options.leading : leading;
62426             trailing = 'trailing' in options ? !!options.trailing : trailing;
62427           }
62428
62429           return debounce(func, wait, {
62430             'leading': leading,
62431             'maxWait': wait,
62432             'trailing': trailing
62433           });
62434         }
62435
62436         //
62437         // - the activeID - nope
62438         // - 1 away (adjacent) to the activeID - yes (vertices will be merged)
62439         // - 2 away from the activeID - nope (would create a self intersecting segment)
62440         // - all others on a linear way - yes
62441         // - all others on a closed way - nope (would create a self intersecting polygon)
62442         //
62443         // returns
62444         // 0 = active vertex - no touch/connect
62445         // 1 = passive vertex - yes touch/connect
62446         // 2 = adjacent vertex - yes but pay attention segmenting a line here
62447         //
62448
62449         function svgPassiveVertex(node, graph, activeID) {
62450           if (!activeID) return 1;
62451           if (activeID === node.id) return 0;
62452           var parents = graph.parentWays(node);
62453           var i, j, nodes, isClosed, ix1, ix2, ix3, ix4, max;
62454
62455           for (i = 0; i < parents.length; i++) {
62456             nodes = parents[i].nodes;
62457             isClosed = parents[i].isClosed();
62458
62459             for (j = 0; j < nodes.length; j++) {
62460               // find this vertex, look nearby
62461               if (nodes[j] === node.id) {
62462                 ix1 = j - 2;
62463                 ix2 = j - 1;
62464                 ix3 = j + 1;
62465                 ix4 = j + 2;
62466
62467                 if (isClosed) {
62468                   // wraparound if needed
62469                   max = nodes.length - 1;
62470                   if (ix1 < 0) ix1 = max + ix1;
62471                   if (ix2 < 0) ix2 = max + ix2;
62472                   if (ix3 > max) ix3 = ix3 - max;
62473                   if (ix4 > max) ix4 = ix4 - max;
62474                 }
62475
62476                 if (nodes[ix1] === activeID) return 0; // no - prevent self intersect
62477                 else if (nodes[ix2] === activeID) return 2; // ok - adjacent
62478                   else if (nodes[ix3] === activeID) return 2; // ok - adjacent
62479                     else if (nodes[ix4] === activeID) return 0; // no - prevent self intersect
62480                       else if (isClosed && nodes.indexOf(activeID) !== -1) return 0; // no - prevent self intersect
62481               }
62482             }
62483           }
62484
62485           return 1; // ok
62486         }
62487         function svgMarkerSegments(projection, graph, dt, shouldReverse, bothDirections) {
62488           return function (entity) {
62489             var i = 0;
62490             var offset = dt;
62491             var segments = [];
62492             var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream;
62493             var coordinates = graph.childNodes(entity).map(function (n) {
62494               return n.loc;
62495             });
62496             var a, b;
62497
62498             if (shouldReverse(entity)) {
62499               coordinates.reverse();
62500             }
62501
62502             d3_geoStream({
62503               type: 'LineString',
62504               coordinates: coordinates
62505             }, projection.stream(clip({
62506               lineStart: function lineStart() {},
62507               lineEnd: function lineEnd() {
62508                 a = null;
62509               },
62510               point: function point(x, y) {
62511                 b = [x, y];
62512
62513                 if (a) {
62514                   var span = geoVecLength(a, b) - offset;
62515
62516                   if (span >= 0) {
62517                     var heading = geoVecAngle(a, b);
62518                     var dx = dt * Math.cos(heading);
62519                     var dy = dt * Math.sin(heading);
62520                     var p = [a[0] + offset * Math.cos(heading), a[1] + offset * Math.sin(heading)]; // gather coordinates
62521
62522                     var coord = [a, p];
62523
62524                     for (span -= dt; span >= 0; span -= dt) {
62525                       p = geoVecAdd(p, [dx, dy]);
62526                       coord.push(p);
62527                     }
62528
62529                     coord.push(b); // generate svg paths
62530
62531                     var segment = '';
62532                     var j;
62533
62534                     for (j = 0; j < coord.length; j++) {
62535                       segment += (j === 0 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
62536                     }
62537
62538                     segments.push({
62539                       id: entity.id,
62540                       index: i++,
62541                       d: segment
62542                     });
62543
62544                     if (bothDirections(entity)) {
62545                       segment = '';
62546
62547                       for (j = coord.length - 1; j >= 0; j--) {
62548                         segment += (j === coord.length - 1 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
62549                       }
62550
62551                       segments.push({
62552                         id: entity.id,
62553                         index: i++,
62554                         d: segment
62555                       });
62556                     }
62557                   }
62558
62559                   offset = -span;
62560                 }
62561
62562                 a = b;
62563               }
62564             })));
62565             return segments;
62566           };
62567         }
62568         function svgPath(projection, graph, isArea) {
62569           // Explanation of magic numbers:
62570           // "padding" here allows space for strokes to extend beyond the viewport,
62571           // so that the stroke isn't drawn along the edge of the viewport when
62572           // the shape is clipped.
62573           //
62574           // When drawing lines, pad viewport by 5px.
62575           // When drawing areas, pad viewport by 65px in each direction to allow
62576           // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
62577           var cache = {};
62578           var padding = isArea ? 65 : 5;
62579           var viewport = projection.clipExtent();
62580           var paddedExtent = [[viewport[0][0] - padding, viewport[0][1] - padding], [viewport[1][0] + padding, viewport[1][1] + padding]];
62581           var clip = d3_geoIdentity().clipExtent(paddedExtent).stream;
62582           var project = projection.stream;
62583           var path = d3_geoPath().projection({
62584             stream: function stream(output) {
62585               return project(clip(output));
62586             }
62587           });
62588
62589           var svgpath = function svgpath(entity) {
62590             if (entity.id in cache) {
62591               return cache[entity.id];
62592             } else {
62593               return cache[entity.id] = path(entity.asGeoJSON(graph));
62594             }
62595           };
62596
62597           svgpath.geojson = function (d) {
62598             if (d.__featurehash__ !== undefined) {
62599               if (d.__featurehash__ in cache) {
62600                 return cache[d.__featurehash__];
62601               } else {
62602                 return cache[d.__featurehash__] = path(d);
62603               }
62604             } else {
62605               return path(d);
62606             }
62607           };
62608
62609           return svgpath;
62610         }
62611         function svgPointTransform(projection) {
62612           var svgpoint = function svgpoint(entity) {
62613             // http://jsperf.com/short-array-join
62614             var pt = projection(entity.loc);
62615             return 'translate(' + pt[0] + ',' + pt[1] + ')';
62616           };
62617
62618           svgpoint.geojson = function (d) {
62619             return svgpoint(d.properties.entity);
62620           };
62621
62622           return svgpoint;
62623         }
62624         function svgRelationMemberTags(graph) {
62625           return function (entity) {
62626             var tags = entity.tags;
62627             var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
62628             graph.parentRelations(entity).forEach(function (relation) {
62629               var type = relation.tags.type;
62630
62631               if (type === 'multipolygon' && shouldCopyMultipolygonTags || type === 'boundary') {
62632                 tags = Object.assign({}, relation.tags, tags);
62633               }
62634             });
62635             return tags;
62636           };
62637         }
62638         function svgSegmentWay(way, graph, activeID) {
62639           // When there is no activeID, we can memoize this expensive computation
62640           if (activeID === undefined) {
62641             return graph["transient"](way, 'waySegments', getWaySegments);
62642           } else {
62643             return getWaySegments();
62644           }
62645
62646           function getWaySegments() {
62647             var isActiveWay = way.nodes.indexOf(activeID) !== -1;
62648             var features = {
62649               passive: [],
62650               active: []
62651             };
62652             var start = {};
62653             var end = {};
62654             var node, type;
62655
62656             for (var i = 0; i < way.nodes.length; i++) {
62657               node = graph.entity(way.nodes[i]);
62658               type = svgPassiveVertex(node, graph, activeID);
62659               end = {
62660                 node: node,
62661                 type: type
62662               };
62663
62664               if (start.type !== undefined) {
62665                 if (start.node.id === activeID || end.node.id === activeID) ; else if (isActiveWay && (start.type === 2 || end.type === 2)) {
62666                   // one adjacent vertex
62667                   pushActive(start, end, i);
62668                 } else if (start.type === 0 && end.type === 0) {
62669                   // both active vertices
62670                   pushActive(start, end, i);
62671                 } else {
62672                   pushPassive(start, end, i);
62673                 }
62674               }
62675
62676               start = end;
62677             }
62678
62679             return features;
62680
62681             function pushActive(start, end, index) {
62682               features.active.push({
62683                 type: 'Feature',
62684                 id: way.id + '-' + index + '-nope',
62685                 properties: {
62686                   nope: true,
62687                   target: true,
62688                   entity: way,
62689                   nodes: [start.node, end.node],
62690                   index: index
62691                 },
62692                 geometry: {
62693                   type: 'LineString',
62694                   coordinates: [start.node.loc, end.node.loc]
62695                 }
62696               });
62697             }
62698
62699             function pushPassive(start, end, index) {
62700               features.passive.push({
62701                 type: 'Feature',
62702                 id: way.id + '-' + index,
62703                 properties: {
62704                   target: true,
62705                   entity: way,
62706                   nodes: [start.node, end.node],
62707                   index: index
62708                 },
62709                 geometry: {
62710                   type: 'LineString',
62711                   coordinates: [start.node.loc, end.node.loc]
62712                 }
62713               });
62714             }
62715           }
62716         }
62717
62718         function svgTagClasses() {
62719           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'];
62720           var statuses = [// nonexistent, might be built
62721           'proposed', 'planned', // under maintentance or between groundbreaking and opening
62722           'construction', // existent but not functional
62723           'disused', // dilapidated to nonexistent
62724           'abandoned', // nonexistent, still may appear in imagery
62725           'dismantled', 'razed', 'demolished', 'obliterated', // existent occasionally, e.g. stormwater drainage basin
62726           'intermittent'];
62727           var secondaries = ['oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier', 'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport', 'public_transport', 'location', 'parking', 'golf', 'type', 'leisure', 'man_made', 'indoor'];
62728
62729           var _tags = function _tags(entity) {
62730             return entity.tags;
62731           };
62732
62733           var tagClasses = function tagClasses(selection) {
62734             selection.each(function tagClassesEach(entity) {
62735               var value = this.className;
62736
62737               if (value.baseVal !== undefined) {
62738                 value = value.baseVal;
62739               }
62740
62741               var t = _tags(entity);
62742
62743               var computed = tagClasses.getClassesString(t, value);
62744
62745               if (computed !== value) {
62746                 select(this).attr('class', computed);
62747               }
62748             });
62749           };
62750
62751           tagClasses.getClassesString = function (t, value) {
62752             var primary, status;
62753             var i, j, k, v; // in some situations we want to render perimeter strokes a certain way
62754
62755             var overrideGeometry;
62756
62757             if (/\bstroke\b/.test(value)) {
62758               if (!!t.barrier && t.barrier !== 'no') {
62759                 overrideGeometry = 'line';
62760               }
62761             } // preserve base classes (nothing with `tag-`)
62762
62763
62764             var classes = value.trim().split(/\s+/).filter(function (klass) {
62765               return klass.length && !/^tag-/.test(klass);
62766             }).map(function (klass) {
62767               // special overrides for some perimeter strokes
62768               return klass === 'line' || klass === 'area' ? overrideGeometry || klass : klass;
62769             }); // pick at most one primary classification tag..
62770
62771             for (i = 0; i < primaries.length; i++) {
62772               k = primaries[i];
62773               v = t[k];
62774               if (!v || v === 'no') continue;
62775
62776               if (k === 'piste:type') {
62777                 // avoid a ':' in the class name
62778                 k = 'piste';
62779               } else if (k === 'building:part') {
62780                 // avoid a ':' in the class name
62781                 k = 'building_part';
62782               }
62783
62784               primary = k;
62785
62786               if (statuses.indexOf(v) !== -1) {
62787                 // e.g. `railway=abandoned`
62788                 status = v;
62789                 classes.push('tag-' + k);
62790               } else {
62791                 classes.push('tag-' + k);
62792                 classes.push('tag-' + k + '-' + v);
62793               }
62794
62795               break;
62796             }
62797
62798             if (!primary) {
62799               for (i = 0; i < statuses.length; i++) {
62800                 for (j = 0; j < primaries.length; j++) {
62801                   k = statuses[i] + ':' + primaries[j]; // e.g. `demolished:building=yes`
62802
62803                   v = t[k];
62804                   if (!v || v === 'no') continue;
62805                   status = statuses[i];
62806                   break;
62807                 }
62808               }
62809             } // add at most one status tag, only if relates to primary tag..
62810
62811
62812             if (!status) {
62813               for (i = 0; i < statuses.length; i++) {
62814                 k = statuses[i];
62815                 v = t[k];
62816                 if (!v || v === 'no') continue;
62817
62818                 if (v === 'yes') {
62819                   // e.g. `railway=rail + abandoned=yes`
62820                   status = k;
62821                 } else if (primary && primary === v) {
62822                   // e.g. `railway=rail + abandoned=railway`
62823                   status = k;
62824                 } else if (!primary && primaries.indexOf(v) !== -1) {
62825                   // e.g. `abandoned=railway`
62826                   status = k;
62827                   primary = v;
62828                   classes.push('tag-' + v);
62829                 } // else ignore e.g.  `highway=path + abandoned=railway`
62830
62831
62832                 if (status) break;
62833               }
62834             }
62835
62836             if (status) {
62837               classes.push('tag-status');
62838               classes.push('tag-status-' + status);
62839             } // add any secondary tags
62840
62841
62842             for (i = 0; i < secondaries.length; i++) {
62843               k = secondaries[i];
62844               v = t[k];
62845               if (!v || v === 'no' || k === primary) continue;
62846               classes.push('tag-' + k);
62847               classes.push('tag-' + k + '-' + v);
62848             } // For highways, look for surface tagging..
62849
62850
62851             if (primary === 'highway' && !osmPathHighwayTagValues[t.highway] || primary === 'aeroway') {
62852               var surface = t.highway === 'track' ? 'unpaved' : 'paved';
62853
62854               for (k in t) {
62855                 v = t[k];
62856
62857                 if (k in osmPavedTags) {
62858                   surface = osmPavedTags[k][v] ? 'paved' : 'unpaved';
62859                 }
62860
62861                 if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
62862                   surface = 'semipaved';
62863                 }
62864               }
62865
62866               classes.push('tag-' + surface);
62867             } // If this is a wikidata-tagged item, add a class for that..
62868
62869
62870             var qid = t.wikidata || t['flag:wikidata'] || t['brand:wikidata'] || t['network:wikidata'] || t['operator:wikidata'];
62871
62872             if (qid) {
62873               classes.push('tag-wikidata');
62874             }
62875
62876             return classes.join(' ').trim();
62877           };
62878
62879           tagClasses.tags = function (val) {
62880             if (!arguments.length) return _tags;
62881             _tags = val;
62882             return tagClasses;
62883           };
62884
62885           return tagClasses;
62886         }
62887
62888         // Patterns only work in Firefox when set directly on element.
62889         // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
62890         var patterns = {
62891           // tag - pattern name
62892           // -or-
62893           // tag - value - pattern name
62894           // -or-
62895           // tag - value - rules (optional tag-values, pattern name)
62896           // (matches earlier rules first, so fallback should be last entry)
62897           amenity: {
62898             grave_yard: 'cemetery',
62899             fountain: 'water_standing'
62900           },
62901           landuse: {
62902             cemetery: [{
62903               religion: 'christian',
62904               pattern: 'cemetery_christian'
62905             }, {
62906               religion: 'buddhist',
62907               pattern: 'cemetery_buddhist'
62908             }, {
62909               religion: 'muslim',
62910               pattern: 'cemetery_muslim'
62911             }, {
62912               religion: 'jewish',
62913               pattern: 'cemetery_jewish'
62914             }, {
62915               pattern: 'cemetery'
62916             }],
62917             construction: 'construction',
62918             farmland: 'farmland',
62919             farmyard: 'farmyard',
62920             forest: [{
62921               leaf_type: 'broadleaved',
62922               pattern: 'forest_broadleaved'
62923             }, {
62924               leaf_type: 'needleleaved',
62925               pattern: 'forest_needleleaved'
62926             }, {
62927               leaf_type: 'leafless',
62928               pattern: 'forest_leafless'
62929             }, {
62930               pattern: 'forest'
62931             } // same as 'leaf_type:mixed'
62932             ],
62933             grave_yard: 'cemetery',
62934             grass: [{
62935               golf: 'green',
62936               pattern: 'golf_green'
62937             }, {
62938               pattern: 'grass'
62939             }],
62940             landfill: 'landfill',
62941             meadow: 'meadow',
62942             military: 'construction',
62943             orchard: 'orchard',
62944             quarry: 'quarry',
62945             vineyard: 'vineyard'
62946           },
62947           natural: {
62948             beach: 'beach',
62949             grassland: 'grass',
62950             sand: 'beach',
62951             scrub: 'scrub',
62952             water: [{
62953               water: 'pond',
62954               pattern: 'pond'
62955             }, {
62956               water: 'reservoir',
62957               pattern: 'water_standing'
62958             }, {
62959               pattern: 'waves'
62960             }],
62961             wetland: [{
62962               wetland: 'marsh',
62963               pattern: 'wetland_marsh'
62964             }, {
62965               wetland: 'swamp',
62966               pattern: 'wetland_swamp'
62967             }, {
62968               wetland: 'bog',
62969               pattern: 'wetland_bog'
62970             }, {
62971               wetland: 'reedbed',
62972               pattern: 'wetland_reedbed'
62973             }, {
62974               pattern: 'wetland'
62975             }],
62976             wood: [{
62977               leaf_type: 'broadleaved',
62978               pattern: 'forest_broadleaved'
62979             }, {
62980               leaf_type: 'needleleaved',
62981               pattern: 'forest_needleleaved'
62982             }, {
62983               leaf_type: 'leafless',
62984               pattern: 'forest_leafless'
62985             }, {
62986               pattern: 'forest'
62987             } // same as 'leaf_type:mixed'
62988             ]
62989           },
62990           traffic_calming: {
62991             island: [{
62992               surface: 'grass',
62993               pattern: 'grass'
62994             }],
62995             chicane: [{
62996               surface: 'grass',
62997               pattern: 'grass'
62998             }],
62999             choker: [{
63000               surface: 'grass',
63001               pattern: 'grass'
63002             }]
63003           }
63004         };
63005         function svgTagPattern(tags) {
63006           // Skip pattern filling if this is a building (buildings don't get patterns applied)
63007           if (tags.building && tags.building !== 'no') {
63008             return null;
63009           }
63010
63011           for (var tag in patterns) {
63012             var entityValue = tags[tag];
63013             if (!entityValue) continue;
63014
63015             if (typeof patterns[tag] === 'string') {
63016               // extra short syntax (just tag) - pattern name
63017               return 'pattern-' + patterns[tag];
63018             } else {
63019               var values = patterns[tag];
63020
63021               for (var value in values) {
63022                 if (entityValue !== value) continue;
63023                 var rules = values[value];
63024
63025                 if (typeof rules === 'string') {
63026                   // short syntax - pattern name
63027                   return 'pattern-' + rules;
63028                 } // long syntax - rule array
63029
63030
63031                 for (var ruleKey in rules) {
63032                   var rule = rules[ruleKey];
63033                   var pass = true;
63034
63035                   for (var criterion in rule) {
63036                     if (criterion !== 'pattern') {
63037                       // reserved for pattern name
63038                       // The only rule is a required tag-value pair
63039                       var v = tags[criterion];
63040
63041                       if (!v || v !== rule[criterion]) {
63042                         pass = false;
63043                         break;
63044                       }
63045                     }
63046                   }
63047
63048                   if (pass) {
63049                     return 'pattern-' + rule.pattern;
63050                   }
63051                 }
63052               }
63053             }
63054           }
63055
63056           return null;
63057         }
63058
63059         function svgAreas(projection, context) {
63060           function getPatternStyle(tags) {
63061             var imageID = svgTagPattern(tags);
63062
63063             if (imageID) {
63064               return 'url("#ideditor-' + imageID + '")';
63065             }
63066
63067             return '';
63068           }
63069
63070           function drawTargets(selection, graph, entities, filter) {
63071             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
63072             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
63073             var getPath = svgPath(projection).geojson;
63074             var activeID = context.activeID();
63075             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
63076
63077             var data = {
63078               targets: [],
63079               nopes: []
63080             };
63081             entities.forEach(function (way) {
63082               var features = svgSegmentWay(way, graph, activeID);
63083               data.targets.push.apply(data.targets, features.passive);
63084               data.nopes.push.apply(data.nopes, features.active);
63085             }); // Targets allow hover and vertex snapping
63086
63087             var targetData = data.targets.filter(getPath);
63088             var targets = selection.selectAll('.area.target-allowed').filter(function (d) {
63089               return filter(d.properties.entity);
63090             }).data(targetData, function key(d) {
63091               return d.id;
63092             }); // exit
63093
63094             targets.exit().remove();
63095
63096             var segmentWasEdited = function segmentWasEdited(d) {
63097               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
63098
63099               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
63100                 return false;
63101               }
63102
63103               return d.properties.nodes.some(function (n) {
63104                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
63105               });
63106             }; // enter/update
63107
63108
63109             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
63110               return 'way area target target-allowed ' + targetClass + d.id;
63111             }).classed('segment-edited', segmentWasEdited); // NOPE
63112
63113             var nopeData = data.nopes.filter(getPath);
63114             var nopes = selection.selectAll('.area.target-nope').filter(function (d) {
63115               return filter(d.properties.entity);
63116             }).data(nopeData, function key(d) {
63117               return d.id;
63118             }); // exit
63119
63120             nopes.exit().remove(); // enter/update
63121
63122             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
63123               return 'way area target target-nope ' + nopeClass + d.id;
63124             }).classed('segment-edited', segmentWasEdited);
63125           }
63126
63127           function drawAreas(selection, graph, entities, filter) {
63128             var path = svgPath(projection, graph, true);
63129             var areas = {};
63130             var multipolygon;
63131             var base = context.history().base();
63132
63133             for (var i = 0; i < entities.length; i++) {
63134               var entity = entities[i];
63135               if (entity.geometry(graph) !== 'area') continue;
63136               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
63137
63138               if (multipolygon) {
63139                 areas[multipolygon.id] = {
63140                   entity: multipolygon.mergeTags(entity.tags),
63141                   area: Math.abs(entity.area(graph))
63142                 };
63143               } else if (!areas[entity.id]) {
63144                 areas[entity.id] = {
63145                   entity: entity,
63146                   area: Math.abs(entity.area(graph))
63147                 };
63148               }
63149             }
63150
63151             var fills = Object.values(areas).filter(function hasPath(a) {
63152               return path(a.entity);
63153             });
63154             fills.sort(function areaSort(a, b) {
63155               return b.area - a.area;
63156             });
63157             fills = fills.map(function (a) {
63158               return a.entity;
63159             });
63160             var strokes = fills.filter(function (area) {
63161               return area.type === 'way';
63162             });
63163             var data = {
63164               clip: fills,
63165               shadow: strokes,
63166               stroke: strokes,
63167               fill: fills
63168             };
63169             var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath-osm').filter(filter).data(data.clip, osmEntity.key);
63170             clipPaths.exit().remove();
63171             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-osm').attr('id', function (entity) {
63172               return 'ideditor-' + entity.id + '-clippath';
63173             });
63174             clipPathsEnter.append('path');
63175             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', path);
63176             var drawLayer = selection.selectAll('.layer-osm.areas');
63177             var touchLayer = selection.selectAll('.layer-touch.areas'); // Draw areas..
63178
63179             var areagroup = drawLayer.selectAll('g.areagroup').data(['fill', 'shadow', 'stroke']);
63180             areagroup = areagroup.enter().append('g').attr('class', function (d) {
63181               return 'areagroup area-' + d;
63182             }).merge(areagroup);
63183             var paths = areagroup.selectAll('path').filter(filter).data(function (layer) {
63184               return data[layer];
63185             }, osmEntity.key);
63186             paths.exit().remove();
63187             var fillpaths = selection.selectAll('.area-fill path.area').nodes();
63188             var bisect = d3_bisector(function (node) {
63189               return -node.__data__.area(graph);
63190             }).left;
63191
63192             function sortedByArea(entity) {
63193               if (this._parent.__data__ === 'fill') {
63194                 return fillpaths[bisect(fillpaths, -entity.area(graph))];
63195               }
63196             }
63197
63198             paths = paths.enter().insert('path', sortedByArea).merge(paths).each(function (entity) {
63199               var layer = this.parentNode.__data__;
63200               this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
63201
63202               if (layer === 'fill') {
63203                 this.setAttribute('clip-path', 'url(#ideditor-' + entity.id + '-clippath)');
63204                 this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
63205               }
63206             }).classed('added', function (d) {
63207               return !base.entities[d.id];
63208             }).classed('geometry-edited', function (d) {
63209               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
63210             }).classed('retagged', function (d) {
63211               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
63212             }).call(svgTagClasses()).attr('d', path); // Draw touch targets..
63213
63214             touchLayer.call(drawTargets, graph, data.stroke, filter);
63215           }
63216
63217           return drawAreas;
63218         }
63219
63220         var fastJsonStableStringify = function fastJsonStableStringify(data, opts) {
63221           if (!opts) opts = {};
63222           if (typeof opts === 'function') opts = {
63223             cmp: opts
63224           };
63225           var cycles = typeof opts.cycles === 'boolean' ? opts.cycles : false;
63226
63227           var cmp = opts.cmp && function (f) {
63228             return function (node) {
63229               return function (a, b) {
63230                 var aobj = {
63231                   key: a,
63232                   value: node[a]
63233                 };
63234                 var bobj = {
63235                   key: b,
63236                   value: node[b]
63237                 };
63238                 return f(aobj, bobj);
63239               };
63240             };
63241           }(opts.cmp);
63242
63243           var seen = [];
63244           return function stringify(node) {
63245             if (node && node.toJSON && typeof node.toJSON === 'function') {
63246               node = node.toJSON();
63247             }
63248
63249             if (node === undefined) return;
63250             if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
63251             if (_typeof(node) !== 'object') return JSON.stringify(node);
63252             var i, out;
63253
63254             if (Array.isArray(node)) {
63255               out = '[';
63256
63257               for (i = 0; i < node.length; i++) {
63258                 if (i) out += ',';
63259                 out += stringify(node[i]) || 'null';
63260               }
63261
63262               return out + ']';
63263             }
63264
63265             if (node === null) return 'null';
63266
63267             if (seen.indexOf(node) !== -1) {
63268               if (cycles) return JSON.stringify('__cycle__');
63269               throw new TypeError('Converting circular structure to JSON');
63270             }
63271
63272             var seenIndex = seen.push(node) - 1;
63273             var keys = Object.keys(node).sort(cmp && cmp(node));
63274             out = '';
63275
63276             for (i = 0; i < keys.length; i++) {
63277               var key = keys[i];
63278               var value = stringify(node[key]);
63279               if (!value) continue;
63280               if (out) out += ',';
63281               out += JSON.stringify(key) + ':' + value;
63282             }
63283
63284             seen.splice(seenIndex, 1);
63285             return '{' + out + '}';
63286           }(data);
63287         };
63288
63289         var $$2 = _export;
63290         var $entries = objectToArray.entries;
63291
63292         // `Object.entries` method
63293         // https://tc39.es/ecma262/#sec-object.entries
63294         $$2({ target: 'Object', stat: true }, {
63295           entries: function entries(O) {
63296             return $entries(O);
63297           }
63298         });
63299
63300         var _marked = /*#__PURE__*/regeneratorRuntime.mark(gpxGen),
63301             _marked3 = /*#__PURE__*/regeneratorRuntime.mark(kmlGen);
63302
63303         // cast array x into numbers
63304         // get the content of a text node, if any
63305         function nodeVal(x) {
63306           if (x && x.normalize) {
63307             x.normalize();
63308           }
63309
63310           return x && x.textContent || "";
63311         } // one Y child of X, if any, otherwise null
63312
63313
63314         function get1(x, y) {
63315           var n = x.getElementsByTagName(y);
63316           return n.length ? n[0] : null;
63317         }
63318
63319         function getLineStyle(extensions) {
63320           var style = {};
63321
63322           if (extensions) {
63323             var lineStyle = get1(extensions, "line");
63324
63325             if (lineStyle) {
63326               var color = nodeVal(get1(lineStyle, "color")),
63327                   opacity = parseFloat(nodeVal(get1(lineStyle, "opacity"))),
63328                   width = parseFloat(nodeVal(get1(lineStyle, "width")));
63329               if (color) style.stroke = color;
63330               if (!isNaN(opacity)) style["stroke-opacity"] = opacity; // GPX width is in mm, convert to px with 96 px per inch
63331
63332               if (!isNaN(width)) style["stroke-width"] = width * 96 / 25.4;
63333             }
63334           }
63335
63336           return style;
63337         } // get the contents of multiple text nodes, if present
63338
63339
63340         function getMulti(x, ys) {
63341           var o = {};
63342           var n;
63343           var k;
63344
63345           for (k = 0; k < ys.length; k++) {
63346             n = get1(x, ys[k]);
63347             if (n) o[ys[k]] = nodeVal(n);
63348           }
63349
63350           return o;
63351         }
63352
63353         function getProperties$1(node) {
63354           var prop = getMulti(node, ["name", "cmt", "desc", "type", "time", "keywords"]); // Parse additional data from our Garmin extension(s)
63355
63356           var extensions = node.getElementsByTagNameNS("http://www.garmin.com/xmlschemas/GpxExtensions/v3", "*");
63357
63358           for (var i = 0; i < extensions.length; i++) {
63359             var extension = extensions[i]; // Ignore nested extensions, like those on routepoints or trackpoints
63360
63361             if (extension.parentNode.parentNode === node) {
63362               prop[extension.tagName.replace(":", "_")] = nodeVal(extension);
63363             }
63364           }
63365
63366           var links = node.getElementsByTagName("link");
63367           if (links.length) prop.links = [];
63368
63369           for (var _i = 0; _i < links.length; _i++) {
63370             prop.links.push(Object.assign({
63371               href: links[_i].getAttribute("href")
63372             }, getMulti(links[_i], ["text", "type"])));
63373           }
63374
63375           return prop;
63376         }
63377
63378         function coordPair$1(x) {
63379           var ll = [parseFloat(x.getAttribute("lon")), parseFloat(x.getAttribute("lat"))];
63380           var ele = get1(x, "ele"); // handle namespaced attribute in browser
63381
63382           var heart = get1(x, "gpxtpx:hr") || get1(x, "hr");
63383           var time = get1(x, "time");
63384           var e;
63385
63386           if (ele) {
63387             e = parseFloat(nodeVal(ele));
63388
63389             if (!isNaN(e)) {
63390               ll.push(e);
63391             }
63392           }
63393
63394           var result = {
63395             coordinates: ll,
63396             time: time ? nodeVal(time) : null,
63397             extendedValues: []
63398           };
63399
63400           if (heart) {
63401             result.extendedValues.push(["heart", parseFloat(nodeVal(heart))]);
63402           }
63403
63404           var extensions = get1(x, "extensions");
63405
63406           if (extensions !== null) {
63407             for (var _i2 = 0, _arr = ["speed", "course", "hAcc", "vAcc"]; _i2 < _arr.length; _i2++) {
63408               var name = _arr[_i2];
63409               var v = parseFloat(nodeVal(get1(extensions, name)));
63410
63411               if (!isNaN(v)) {
63412                 result.extendedValues.push([name, v]);
63413               }
63414             }
63415           }
63416
63417           return result;
63418         }
63419
63420         function getRoute(node) {
63421           var line = getPoints$1(node, "rtept");
63422           if (!line) return;
63423           return {
63424             type: "Feature",
63425             properties: Object.assign(getProperties$1(node), getLineStyle(get1(node, "extensions")), {
63426               _gpxType: "rte"
63427             }),
63428             geometry: {
63429               type: "LineString",
63430               coordinates: line.line
63431             }
63432           };
63433         }
63434
63435         function getPoints$1(node, pointname) {
63436           var pts = node.getElementsByTagName(pointname);
63437           if (pts.length < 2) return; // Invalid line in GeoJSON
63438
63439           var line = [];
63440           var times = [];
63441           var extendedValues = {};
63442
63443           for (var i = 0; i < pts.length; i++) {
63444             var c = coordPair$1(pts[i]);
63445             line.push(c.coordinates);
63446             if (c.time) times.push(c.time);
63447
63448             for (var j = 0; j < c.extendedValues.length; j++) {
63449               var _c$extendedValues$j = _slicedToArray(c.extendedValues[j], 2),
63450                   name = _c$extendedValues$j[0],
63451                   val = _c$extendedValues$j[1];
63452
63453               var plural = name === "heart" ? name : name + "s";
63454
63455               if (!extendedValues[plural]) {
63456                 extendedValues[plural] = Array(pts.length).fill(null);
63457               }
63458
63459               extendedValues[plural][i] = val;
63460             }
63461           }
63462
63463           return {
63464             line: line,
63465             times: times,
63466             extendedValues: extendedValues
63467           };
63468         }
63469
63470         function getTrack(node) {
63471           var segments = node.getElementsByTagName("trkseg");
63472           var track = [];
63473           var times = [];
63474           var extractedLines = [];
63475
63476           for (var i = 0; i < segments.length; i++) {
63477             var line = getPoints$1(segments[i], "trkpt");
63478
63479             if (line) {
63480               extractedLines.push(line);
63481               if (line.times && line.times.length) times.push(line.times);
63482             }
63483           }
63484
63485           if (extractedLines.length === 0) return;
63486           var multi = extractedLines.length > 1;
63487           var properties = Object.assign(getProperties$1(node), getLineStyle(get1(node, "extensions")), {
63488             _gpxType: "trk"
63489           }, times.length ? {
63490             coordinateProperties: {
63491               times: multi ? times : times[0]
63492             }
63493           } : {});
63494
63495           for (var _i3 = 0; _i3 < extractedLines.length; _i3++) {
63496             var _line = extractedLines[_i3];
63497             track.push(_line.line);
63498
63499             for (var _i4 = 0, _Object$entries = Object.entries(_line.extendedValues); _i4 < _Object$entries.length; _i4++) {
63500               var _Object$entries$_i = _slicedToArray(_Object$entries[_i4], 2),
63501                   name = _Object$entries$_i[0],
63502                   val = _Object$entries$_i[1];
63503
63504               var props = properties;
63505
63506               if (name === "heart") {
63507                 if (!properties.coordinateProperties) {
63508                   properties.coordinateProperties = {};
63509                 }
63510
63511                 props = properties.coordinateProperties;
63512               }
63513
63514               if (multi) {
63515                 if (!props[name]) props[name] = extractedLines.map(function (line) {
63516                   return new Array(line.line.length).fill(null);
63517                 });
63518                 props[name][_i3] = val;
63519               } else {
63520                 props[name] = val;
63521               }
63522             }
63523           }
63524
63525           return {
63526             type: "Feature",
63527             properties: properties,
63528             geometry: multi ? {
63529               type: "MultiLineString",
63530               coordinates: track
63531             } : {
63532               type: "LineString",
63533               coordinates: track[0]
63534             }
63535           };
63536         }
63537
63538         function getPoint(node) {
63539           return {
63540             type: "Feature",
63541             properties: Object.assign(getProperties$1(node), getMulti(node, ["sym"])),
63542             geometry: {
63543               type: "Point",
63544               coordinates: coordPair$1(node).coordinates
63545             }
63546           };
63547         }
63548
63549         function gpxGen(doc) {
63550           var tracks, routes, waypoints, i, feature, _i5, _feature, _i6;
63551
63552           return regeneratorRuntime.wrap(function gpxGen$(_context) {
63553             while (1) {
63554               switch (_context.prev = _context.next) {
63555                 case 0:
63556                   tracks = doc.getElementsByTagName("trk");
63557                   routes = doc.getElementsByTagName("rte");
63558                   waypoints = doc.getElementsByTagName("wpt");
63559                   i = 0;
63560
63561                 case 4:
63562                   if (!(i < tracks.length)) {
63563                     _context.next = 12;
63564                     break;
63565                   }
63566
63567                   feature = getTrack(tracks[i]);
63568
63569                   if (!feature) {
63570                     _context.next = 9;
63571                     break;
63572                   }
63573
63574                   _context.next = 9;
63575                   return feature;
63576
63577                 case 9:
63578                   i++;
63579                   _context.next = 4;
63580                   break;
63581
63582                 case 12:
63583                   _i5 = 0;
63584
63585                 case 13:
63586                   if (!(_i5 < routes.length)) {
63587                     _context.next = 21;
63588                     break;
63589                   }
63590
63591                   _feature = getRoute(routes[_i5]);
63592
63593                   if (!_feature) {
63594                     _context.next = 18;
63595                     break;
63596                   }
63597
63598                   _context.next = 18;
63599                   return _feature;
63600
63601                 case 18:
63602                   _i5++;
63603                   _context.next = 13;
63604                   break;
63605
63606                 case 21:
63607                   _i6 = 0;
63608
63609                 case 22:
63610                   if (!(_i6 < waypoints.length)) {
63611                     _context.next = 28;
63612                     break;
63613                   }
63614
63615                   _context.next = 25;
63616                   return getPoint(waypoints[_i6]);
63617
63618                 case 25:
63619                   _i6++;
63620                   _context.next = 22;
63621                   break;
63622
63623                 case 28:
63624                 case "end":
63625                   return _context.stop();
63626               }
63627             }
63628           }, _marked);
63629         }
63630
63631         function gpx(doc) {
63632           return {
63633             type: "FeatureCollection",
63634             features: Array.from(gpxGen(doc))
63635           };
63636         }
63637
63638         var removeSpace = /\s*/g;
63639         var trimSpace = /^\s*|\s*$/g;
63640         var splitSpace = /\s+/; // generate a short, numeric hash of a string
63641
63642         function okhash(x) {
63643           if (!x || !x.length) return 0;
63644           var h = 0;
63645
63646           for (var i = 0; i < x.length; i++) {
63647             h = (h << 5) - h + x.charCodeAt(i) | 0;
63648           }
63649
63650           return h;
63651         } // get one coordinate from a coordinate array, if any
63652
63653
63654         function coord1(v) {
63655           return v.replace(removeSpace, "").split(",").map(parseFloat);
63656         } // get all coordinates from a coordinate array as [[],[]]
63657
63658
63659         function coord(v) {
63660           return v.replace(trimSpace, "").split(splitSpace).map(coord1);
63661         }
63662
63663         function xml2str(node) {
63664           if (node.xml !== undefined) return node.xml;
63665
63666           if (node.tagName) {
63667             var output = node.tagName;
63668
63669             for (var i = 0; i < node.attributes.length; i++) {
63670               output += node.attributes[i].name + node.attributes[i].value;
63671             }
63672
63673             for (var _i9 = 0; _i9 < node.childNodes.length; _i9++) {
63674               output += xml2str(node.childNodes[_i9]);
63675             }
63676
63677             return output;
63678           }
63679
63680           if (node.nodeName === "#text") {
63681             return (node.nodeValue || node.value || "").trim();
63682           }
63683
63684           if (node.nodeName === "#cdata-section") {
63685             return node.nodeValue;
63686           }
63687
63688           return "";
63689         }
63690
63691         var geotypes = ["Polygon", "LineString", "Point", "Track", "gx:Track"];
63692
63693         function kmlColor(properties, elem, prefix) {
63694           var v = nodeVal(get1(elem, "color")) || "";
63695           var colorProp = prefix == "stroke" || prefix === "fill" ? prefix : prefix + "-color";
63696
63697           if (v.substr(0, 1) === "#") {
63698             v = v.substr(1);
63699           }
63700
63701           if (v.length === 6 || v.length === 3) {
63702             properties[colorProp] = v;
63703           } else if (v.length === 8) {
63704             properties[prefix + "-opacity"] = parseInt(v.substr(0, 2), 16) / 255;
63705             properties[colorProp] = "#" + v.substr(6, 2) + v.substr(4, 2) + v.substr(2, 2);
63706           }
63707         }
63708
63709         function numericProperty(properties, elem, source, target) {
63710           var val = parseFloat(nodeVal(get1(elem, source)));
63711           if (!isNaN(val)) properties[target] = val;
63712         }
63713
63714         function gxCoords(root) {
63715           var elems = root.getElementsByTagName("coord");
63716           var coords = [];
63717           var times = [];
63718           if (elems.length === 0) elems = root.getElementsByTagName("gx:coord");
63719
63720           for (var i = 0; i < elems.length; i++) {
63721             coords.push(nodeVal(elems[i]).split(" ").map(parseFloat));
63722           }
63723
63724           var timeElems = root.getElementsByTagName("when");
63725
63726           for (var j = 0; j < timeElems.length; j++) {
63727             times.push(nodeVal(timeElems[j]));
63728           }
63729
63730           return {
63731             coords: coords,
63732             times: times
63733           };
63734         }
63735
63736         function getGeometry(root) {
63737           var geomNode;
63738           var geomNodes;
63739           var i;
63740           var j;
63741           var k;
63742           var geoms = [];
63743           var coordTimes = [];
63744
63745           if (get1(root, "MultiGeometry")) {
63746             return getGeometry(get1(root, "MultiGeometry"));
63747           }
63748
63749           if (get1(root, "MultiTrack")) {
63750             return getGeometry(get1(root, "MultiTrack"));
63751           }
63752
63753           if (get1(root, "gx:MultiTrack")) {
63754             return getGeometry(get1(root, "gx:MultiTrack"));
63755           }
63756
63757           for (i = 0; i < geotypes.length; i++) {
63758             geomNodes = root.getElementsByTagName(geotypes[i]);
63759
63760             if (geomNodes) {
63761               for (j = 0; j < geomNodes.length; j++) {
63762                 geomNode = geomNodes[j];
63763
63764                 if (geotypes[i] === "Point") {
63765                   geoms.push({
63766                     type: "Point",
63767                     coordinates: coord1(nodeVal(get1(geomNode, "coordinates")))
63768                   });
63769                 } else if (geotypes[i] === "LineString") {
63770                   geoms.push({
63771                     type: "LineString",
63772                     coordinates: coord(nodeVal(get1(geomNode, "coordinates")))
63773                   });
63774                 } else if (geotypes[i] === "Polygon") {
63775                   var rings = geomNode.getElementsByTagName("LinearRing"),
63776                       coords = [];
63777
63778                   for (k = 0; k < rings.length; k++) {
63779                     coords.push(coord(nodeVal(get1(rings[k], "coordinates"))));
63780                   }
63781
63782                   geoms.push({
63783                     type: "Polygon",
63784                     coordinates: coords
63785                   });
63786                 } else if (geotypes[i] === "Track" || geotypes[i] === "gx:Track") {
63787                   var track = gxCoords(geomNode);
63788                   geoms.push({
63789                     type: "LineString",
63790                     coordinates: track.coords
63791                   });
63792                   if (track.times.length) coordTimes.push(track.times);
63793                 }
63794               }
63795             }
63796           }
63797
63798           return {
63799             geoms: geoms,
63800             coordTimes: coordTimes
63801           };
63802         }
63803
63804         function getPlacemark(root, styleIndex, styleMapIndex, styleByHash) {
63805           var geomsAndTimes = getGeometry(root);
63806           var i;
63807           var properties = {};
63808           var name = nodeVal(get1(root, "name"));
63809           var address = nodeVal(get1(root, "address"));
63810           var styleUrl = nodeVal(get1(root, "styleUrl"));
63811           var description = nodeVal(get1(root, "description"));
63812           var timeSpan = get1(root, "TimeSpan");
63813           var timeStamp = get1(root, "TimeStamp");
63814           var extendedData = get1(root, "ExtendedData");
63815           var iconStyle = get1(root, "IconStyle");
63816           var labelStyle = get1(root, "LabelStyle");
63817           var lineStyle = get1(root, "LineStyle");
63818           var polyStyle = get1(root, "PolyStyle");
63819           var visibility = get1(root, "visibility");
63820           if (name) properties.name = name;
63821           if (address) properties.address = address;
63822
63823           if (styleUrl) {
63824             if (styleUrl[0] !== "#") {
63825               styleUrl = "#" + styleUrl;
63826             }
63827
63828             properties.styleUrl = styleUrl;
63829
63830             if (styleIndex[styleUrl]) {
63831               properties.styleHash = styleIndex[styleUrl];
63832             }
63833
63834             if (styleMapIndex[styleUrl]) {
63835               properties.styleMapHash = styleMapIndex[styleUrl];
63836               properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
63837             } // Try to populate the lineStyle or polyStyle since we got the style hash
63838
63839
63840             var style = styleByHash[properties.styleHash];
63841
63842             if (style) {
63843               if (!iconStyle) iconStyle = get1(style, "IconStyle");
63844               if (!labelStyle) labelStyle = get1(style, "LabelStyle");
63845               if (!lineStyle) lineStyle = get1(style, "LineStyle");
63846               if (!polyStyle) polyStyle = get1(style, "PolyStyle");
63847             }
63848           }
63849
63850           if (description) properties.description = description;
63851
63852           if (timeSpan) {
63853             var begin = nodeVal(get1(timeSpan, "begin"));
63854             var end = nodeVal(get1(timeSpan, "end"));
63855             properties.timespan = {
63856               begin: begin,
63857               end: end
63858             };
63859           }
63860
63861           if (timeStamp) {
63862             properties.timestamp = nodeVal(get1(timeStamp, "when"));
63863           }
63864
63865           if (iconStyle) {
63866             kmlColor(properties, iconStyle, "icon");
63867             numericProperty(properties, iconStyle, "scale", "icon-scale");
63868             numericProperty(properties, iconStyle, "heading", "icon-heading");
63869             var hotspot = get1(iconStyle, "hotSpot");
63870
63871             if (hotspot) {
63872               var left = parseFloat(hotspot.getAttribute("x"));
63873               var top = parseFloat(hotspot.getAttribute("y"));
63874               if (!isNaN(left) && !isNaN(top)) properties["icon-offset"] = [left, top];
63875             }
63876
63877             var icon = get1(iconStyle, "Icon");
63878
63879             if (icon) {
63880               var href = nodeVal(get1(icon, "href"));
63881               if (href) properties.icon = href;
63882             }
63883           }
63884
63885           if (labelStyle) {
63886             kmlColor(properties, labelStyle, "label");
63887             numericProperty(properties, labelStyle, "scale", "label-scale");
63888           }
63889
63890           if (lineStyle) {
63891             kmlColor(properties, lineStyle, "stroke");
63892             numericProperty(properties, lineStyle, "width", "stroke-width");
63893           }
63894
63895           if (polyStyle) {
63896             kmlColor(properties, polyStyle, "fill");
63897             var fill = nodeVal(get1(polyStyle, "fill"));
63898             var outline = nodeVal(get1(polyStyle, "outline"));
63899             if (fill) properties["fill-opacity"] = fill === "1" ? properties["fill-opacity"] || 1 : 0;
63900             if (outline) properties["stroke-opacity"] = outline === "1" ? properties["stroke-opacity"] || 1 : 0;
63901           }
63902
63903           if (extendedData) {
63904             var datas = extendedData.getElementsByTagName("Data"),
63905                 simpleDatas = extendedData.getElementsByTagName("SimpleData");
63906
63907             for (i = 0; i < datas.length; i++) {
63908               properties[datas[i].getAttribute("name")] = nodeVal(get1(datas[i], "value"));
63909             }
63910
63911             for (i = 0; i < simpleDatas.length; i++) {
63912               properties[simpleDatas[i].getAttribute("name")] = nodeVal(simpleDatas[i]);
63913             }
63914           }
63915
63916           if (visibility) {
63917             properties.visibility = nodeVal(visibility);
63918           }
63919
63920           if (geomsAndTimes.coordTimes.length) {
63921             properties.coordinateProperties = {
63922               times: geomsAndTimes.coordTimes.length === 1 ? geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes
63923             };
63924           }
63925
63926           var feature = {
63927             type: "Feature",
63928             geometry: geomsAndTimes.geoms.length === 0 ? null : geomsAndTimes.geoms.length === 1 ? geomsAndTimes.geoms[0] : {
63929               type: "GeometryCollection",
63930               geometries: geomsAndTimes.geoms
63931             },
63932             properties: properties
63933           };
63934           if (root.getAttribute("id")) feature.id = root.getAttribute("id");
63935           return feature;
63936         }
63937
63938         function kmlGen(doc) {
63939           var styleIndex, styleByHash, styleMapIndex, placemarks, styles, styleMaps, k, hash, l, pairs, pairsMap, m, j, feature;
63940           return regeneratorRuntime.wrap(function kmlGen$(_context3) {
63941             while (1) {
63942               switch (_context3.prev = _context3.next) {
63943                 case 0:
63944                   // styleindex keeps track of hashed styles in order to match feature
63945                   styleIndex = {};
63946                   styleByHash = {}; // stylemapindex keeps track of style maps to expose in properties
63947
63948                   styleMapIndex = {}; // atomic geospatial types supported by KML - MultiGeometry is
63949                   // handled separately
63950                   // all root placemarks in the file
63951
63952                   placemarks = doc.getElementsByTagName("Placemark");
63953                   styles = doc.getElementsByTagName("Style");
63954                   styleMaps = doc.getElementsByTagName("StyleMap");
63955
63956                   for (k = 0; k < styles.length; k++) {
63957                     hash = okhash(xml2str(styles[k])).toString(16);
63958                     styleIndex["#" + styles[k].getAttribute("id")] = hash;
63959                     styleByHash[hash] = styles[k];
63960                   }
63961
63962                   for (l = 0; l < styleMaps.length; l++) {
63963                     styleIndex["#" + styleMaps[l].getAttribute("id")] = okhash(xml2str(styleMaps[l])).toString(16);
63964                     pairs = styleMaps[l].getElementsByTagName("Pair");
63965                     pairsMap = {};
63966
63967                     for (m = 0; m < pairs.length; m++) {
63968                       pairsMap[nodeVal(get1(pairs[m], "key"))] = nodeVal(get1(pairs[m], "styleUrl"));
63969                     }
63970
63971                     styleMapIndex["#" + styleMaps[l].getAttribute("id")] = pairsMap;
63972                   }
63973
63974                   j = 0;
63975
63976                 case 9:
63977                   if (!(j < placemarks.length)) {
63978                     _context3.next = 17;
63979                     break;
63980                   }
63981
63982                   feature = getPlacemark(placemarks[j], styleIndex, styleMapIndex, styleByHash);
63983
63984                   if (!feature) {
63985                     _context3.next = 14;
63986                     break;
63987                   }
63988
63989                   _context3.next = 14;
63990                   return feature;
63991
63992                 case 14:
63993                   j++;
63994                   _context3.next = 9;
63995                   break;
63996
63997                 case 17:
63998                 case "end":
63999                   return _context3.stop();
64000               }
64001             }
64002           }, _marked3);
64003         }
64004
64005         function kml(doc) {
64006           return {
64007             type: "FeatureCollection",
64008             features: Array.from(kmlGen(doc))
64009           };
64010         }
64011
64012         var _initialized = false;
64013         var _enabled = false;
64014
64015         var _geojson;
64016
64017         function svgData(projection, context, dispatch) {
64018           var throttledRedraw = throttle(function () {
64019             dispatch.call('change');
64020           }, 1000);
64021
64022           var _showLabels = true;
64023           var detected = utilDetect();
64024           var layer = select(null);
64025
64026           var _vtService;
64027
64028           var _fileList;
64029
64030           var _template;
64031
64032           var _src;
64033
64034           function init() {
64035             if (_initialized) return; // run once
64036
64037             _geojson = {};
64038             _enabled = true;
64039
64040             function over(d3_event) {
64041               d3_event.stopPropagation();
64042               d3_event.preventDefault();
64043               d3_event.dataTransfer.dropEffect = 'copy';
64044             }
64045
64046             context.container().attr('dropzone', 'copy').on('drop.svgData', function (d3_event) {
64047               d3_event.stopPropagation();
64048               d3_event.preventDefault();
64049               if (!detected.filedrop) return;
64050               drawData.fileList(d3_event.dataTransfer.files);
64051             }).on('dragenter.svgData', over).on('dragexit.svgData', over).on('dragover.svgData', over);
64052             _initialized = true;
64053           }
64054
64055           function getService() {
64056             if (services.vectorTile && !_vtService) {
64057               _vtService = services.vectorTile;
64058
64059               _vtService.event.on('loadedData', throttledRedraw);
64060             } else if (!services.vectorTile && _vtService) {
64061               _vtService = null;
64062             }
64063
64064             return _vtService;
64065           }
64066
64067           function showLayer() {
64068             layerOn();
64069             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
64070               dispatch.call('change');
64071             });
64072           }
64073
64074           function hideLayer() {
64075             throttledRedraw.cancel();
64076             layer.transition().duration(250).style('opacity', 0).on('end', layerOff);
64077           }
64078
64079           function layerOn() {
64080             layer.style('display', 'block');
64081           }
64082
64083           function layerOff() {
64084             layer.selectAll('.viewfield-group').remove();
64085             layer.style('display', 'none');
64086           } // ensure that all geojson features in a collection have IDs
64087
64088
64089           function ensureIDs(gj) {
64090             if (!gj) return null;
64091
64092             if (gj.type === 'FeatureCollection') {
64093               for (var i = 0; i < gj.features.length; i++) {
64094                 ensureFeatureID(gj.features[i]);
64095               }
64096             } else {
64097               ensureFeatureID(gj);
64098             }
64099
64100             return gj;
64101           } // ensure that each single Feature object has a unique ID
64102
64103
64104           function ensureFeatureID(feature) {
64105             if (!feature) return;
64106             feature.__featurehash__ = utilHashcode(fastJsonStableStringify(feature));
64107             return feature;
64108           } // Prefer an array of Features instead of a FeatureCollection
64109
64110
64111           function getFeatures(gj) {
64112             if (!gj) return [];
64113
64114             if (gj.type === 'FeatureCollection') {
64115               return gj.features;
64116             } else {
64117               return [gj];
64118             }
64119           }
64120
64121           function featureKey(d) {
64122             return d.__featurehash__;
64123           }
64124
64125           function isPolygon(d) {
64126             return d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon';
64127           }
64128
64129           function clipPathID(d) {
64130             return 'ideditor-data-' + d.__featurehash__ + '-clippath';
64131           }
64132
64133           function featureClasses(d) {
64134             return ['data' + d.__featurehash__, d.geometry.type, isPolygon(d) ? 'area' : '', d.__layerID__ || ''].filter(Boolean).join(' ');
64135           }
64136
64137           function drawData(selection) {
64138             var vtService = getService();
64139             var getPath = svgPath(projection).geojson;
64140             var getAreaPath = svgPath(projection, null, true).geojson;
64141             var hasData = drawData.hasData();
64142             layer = selection.selectAll('.layer-mapdata').data(_enabled && hasData ? [0] : []);
64143             layer.exit().remove();
64144             layer = layer.enter().append('g').attr('class', 'layer-mapdata').merge(layer);
64145             var surface = context.surface();
64146             if (!surface || surface.empty()) return; // not ready to draw yet, starting up
64147             // Gather data
64148
64149             var geoData, polygonData;
64150
64151             if (_template && vtService) {
64152               // fetch data from vector tile service
64153               var sourceID = _template;
64154               vtService.loadTiles(sourceID, _template, projection);
64155               geoData = vtService.data(sourceID, projection);
64156             } else {
64157               geoData = getFeatures(_geojson);
64158             }
64159
64160             geoData = geoData.filter(getPath);
64161             polygonData = geoData.filter(isPolygon); // Draw clip paths for polygons
64162
64163             var clipPaths = surface.selectAll('defs').selectAll('.clipPath-data').data(polygonData, featureKey);
64164             clipPaths.exit().remove();
64165             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-data').attr('id', clipPathID);
64166             clipPathsEnter.append('path');
64167             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', getAreaPath); // Draw fill, shadow, stroke layers
64168
64169             var datagroups = layer.selectAll('g.datagroup').data(['fill', 'shadow', 'stroke']);
64170             datagroups = datagroups.enter().append('g').attr('class', function (d) {
64171               return 'datagroup datagroup-' + d;
64172             }).merge(datagroups); // Draw paths
64173
64174             var pathData = {
64175               fill: polygonData,
64176               shadow: geoData,
64177               stroke: geoData
64178             };
64179             var paths = datagroups.selectAll('path').data(function (layer) {
64180               return pathData[layer];
64181             }, featureKey); // exit
64182
64183             paths.exit().remove(); // enter/update
64184
64185             paths = paths.enter().append('path').attr('class', function (d) {
64186               var datagroup = this.parentNode.__data__;
64187               return 'pathdata ' + datagroup + ' ' + featureClasses(d);
64188             }).attr('clip-path', function (d) {
64189               var datagroup = this.parentNode.__data__;
64190               return datagroup === 'fill' ? 'url(#' + clipPathID(d) + ')' : null;
64191             }).merge(paths).attr('d', function (d) {
64192               var datagroup = this.parentNode.__data__;
64193               return datagroup === 'fill' ? getAreaPath(d) : getPath(d);
64194             }); // Draw labels
64195
64196             layer.call(drawLabels, 'label-halo', geoData).call(drawLabels, 'label', geoData);
64197
64198             function drawLabels(selection, textClass, data) {
64199               var labelPath = d3_geoPath(projection);
64200               var labelData = data.filter(function (d) {
64201                 return _showLabels && d.properties && (d.properties.desc || d.properties.name);
64202               });
64203               var labels = selection.selectAll('text.' + textClass).data(labelData, featureKey); // exit
64204
64205               labels.exit().remove(); // enter/update
64206
64207               labels = labels.enter().append('text').attr('class', function (d) {
64208                 return textClass + ' ' + featureClasses(d);
64209               }).merge(labels).text(function (d) {
64210                 return d.properties.desc || d.properties.name;
64211               }).attr('x', function (d) {
64212                 var centroid = labelPath.centroid(d);
64213                 return centroid[0] + 11;
64214               }).attr('y', function (d) {
64215                 var centroid = labelPath.centroid(d);
64216                 return centroid[1];
64217               });
64218             }
64219           }
64220
64221           function getExtension(fileName) {
64222             if (!fileName) return;
64223             var re = /\.(gpx|kml|(geo)?json)$/i;
64224             var match = fileName.toLowerCase().match(re);
64225             return match && match.length && match[0];
64226           }
64227
64228           function xmlToDom(textdata) {
64229             return new DOMParser().parseFromString(textdata, 'text/xml');
64230           }
64231
64232           drawData.setFile = function (extension, data) {
64233             _template = null;
64234             _fileList = null;
64235             _geojson = null;
64236             _src = null;
64237             var gj;
64238
64239             switch (extension) {
64240               case '.gpx':
64241                 gj = gpx(xmlToDom(data));
64242                 break;
64243
64244               case '.kml':
64245                 gj = kml(xmlToDom(data));
64246                 break;
64247
64248               case '.geojson':
64249               case '.json':
64250                 gj = JSON.parse(data);
64251                 break;
64252             }
64253
64254             gj = gj || {};
64255
64256             if (Object.keys(gj).length) {
64257               _geojson = ensureIDs(gj);
64258               _src = extension + ' data file';
64259               this.fitZoom();
64260             }
64261
64262             dispatch.call('change');
64263             return this;
64264           };
64265
64266           drawData.showLabels = function (val) {
64267             if (!arguments.length) return _showLabels;
64268             _showLabels = val;
64269             return this;
64270           };
64271
64272           drawData.enabled = function (val) {
64273             if (!arguments.length) return _enabled;
64274             _enabled = val;
64275
64276             if (_enabled) {
64277               showLayer();
64278             } else {
64279               hideLayer();
64280             }
64281
64282             dispatch.call('change');
64283             return this;
64284           };
64285
64286           drawData.hasData = function () {
64287             var gj = _geojson || {};
64288             return !!(_template || Object.keys(gj).length);
64289           };
64290
64291           drawData.template = function (val, src) {
64292             if (!arguments.length) return _template; // test source against OSM imagery blocklists..
64293
64294             var osm = context.connection();
64295
64296             if (osm) {
64297               var blocklists = osm.imageryBlocklists();
64298               var fail = false;
64299               var tested = 0;
64300               var regex;
64301
64302               for (var i = 0; i < blocklists.length; i++) {
64303                 regex = blocklists[i];
64304                 fail = regex.test(val);
64305                 tested++;
64306                 if (fail) break;
64307               } // ensure at least one test was run.
64308
64309
64310               if (!tested) {
64311                 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
64312                 fail = regex.test(val);
64313               }
64314             }
64315
64316             _template = val;
64317             _fileList = null;
64318             _geojson = null; // strip off the querystring/hash from the template,
64319             // it often includes the access token
64320
64321             _src = src || 'vectortile:' + val.split(/[?#]/)[0];
64322             dispatch.call('change');
64323             return this;
64324           };
64325
64326           drawData.geojson = function (gj, src) {
64327             if (!arguments.length) return _geojson;
64328             _template = null;
64329             _fileList = null;
64330             _geojson = null;
64331             _src = null;
64332             gj = gj || {};
64333
64334             if (Object.keys(gj).length) {
64335               _geojson = ensureIDs(gj);
64336               _src = src || 'unknown.geojson';
64337             }
64338
64339             dispatch.call('change');
64340             return this;
64341           };
64342
64343           drawData.fileList = function (fileList) {
64344             if (!arguments.length) return _fileList;
64345             _template = null;
64346             _fileList = fileList;
64347             _geojson = null;
64348             _src = null;
64349             if (!fileList || !fileList.length) return this;
64350             var f = fileList[0];
64351             var extension = getExtension(f.name);
64352             var reader = new FileReader();
64353
64354             reader.onload = function () {
64355               return function (e) {
64356                 drawData.setFile(extension, e.target.result);
64357               };
64358             }();
64359
64360             reader.readAsText(f);
64361             return this;
64362           };
64363
64364           drawData.url = function (url, defaultExtension) {
64365             _template = null;
64366             _fileList = null;
64367             _geojson = null;
64368             _src = null; // strip off any querystring/hash from the url before checking extension
64369
64370             var testUrl = url.split(/[?#]/)[0];
64371             var extension = getExtension(testUrl) || defaultExtension;
64372
64373             if (extension) {
64374               _template = null;
64375               d3_text(url).then(function (data) {
64376                 drawData.setFile(extension, data);
64377               })["catch"](function () {
64378                 /* ignore */
64379               });
64380             } else {
64381               drawData.template(url);
64382             }
64383
64384             return this;
64385           };
64386
64387           drawData.getSrc = function () {
64388             return _src || '';
64389           };
64390
64391           drawData.fitZoom = function () {
64392             var features = getFeatures(_geojson);
64393             if (!features.length) return;
64394             var map = context.map();
64395             var viewport = map.trimmedExtent().polygon();
64396             var coords = features.reduce(function (coords, feature) {
64397               var geom = feature.geometry;
64398               if (!geom) return coords;
64399               var c = geom.coordinates;
64400               /* eslint-disable no-fallthrough */
64401
64402               switch (geom.type) {
64403                 case 'Point':
64404                   c = [c];
64405
64406                 case 'MultiPoint':
64407                 case 'LineString':
64408                   break;
64409
64410                 case 'MultiPolygon':
64411                   c = utilArrayFlatten(c);
64412
64413                 case 'Polygon':
64414                 case 'MultiLineString':
64415                   c = utilArrayFlatten(c);
64416                   break;
64417               }
64418               /* eslint-enable no-fallthrough */
64419
64420
64421               return utilArrayUnion(coords, c);
64422             }, []);
64423
64424             if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
64425               var extent = geoExtent(d3_geoBounds({
64426                 type: 'LineString',
64427                 coordinates: coords
64428               }));
64429               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
64430             }
64431
64432             return this;
64433           };
64434
64435           init();
64436           return drawData;
64437         }
64438
64439         function svgDebug(projection, context) {
64440           function drawDebug(selection) {
64441             var showTile = context.getDebug('tile');
64442             var showCollision = context.getDebug('collision');
64443             var showImagery = context.getDebug('imagery');
64444             var showTouchTargets = context.getDebug('target');
64445             var showDownloaded = context.getDebug('downloaded');
64446             var debugData = [];
64447
64448             if (showTile) {
64449               debugData.push({
64450                 "class": 'red',
64451                 label: 'tile'
64452               });
64453             }
64454
64455             if (showCollision) {
64456               debugData.push({
64457                 "class": 'yellow',
64458                 label: 'collision'
64459               });
64460             }
64461
64462             if (showImagery) {
64463               debugData.push({
64464                 "class": 'orange',
64465                 label: 'imagery'
64466               });
64467             }
64468
64469             if (showTouchTargets) {
64470               debugData.push({
64471                 "class": 'pink',
64472                 label: 'touchTargets'
64473               });
64474             }
64475
64476             if (showDownloaded) {
64477               debugData.push({
64478                 "class": 'purple',
64479                 label: 'downloaded'
64480               });
64481             }
64482
64483             var legend = context.container().select('.main-content').selectAll('.debug-legend').data(debugData.length ? [0] : []);
64484             legend.exit().remove();
64485             legend = legend.enter().append('div').attr('class', 'fillD debug-legend').merge(legend);
64486             var legendItems = legend.selectAll('.debug-legend-item').data(debugData, function (d) {
64487               return d.label;
64488             });
64489             legendItems.exit().remove();
64490             legendItems.enter().append('span').attr('class', function (d) {
64491               return "debug-legend-item ".concat(d["class"]);
64492             }).text(function (d) {
64493               return d.label;
64494             });
64495             var layer = selection.selectAll('.layer-debug').data(showImagery || showDownloaded ? [0] : []);
64496             layer.exit().remove();
64497             layer = layer.enter().append('g').attr('class', 'layer-debug').merge(layer); // imagery
64498
64499             var extent = context.map().extent();
64500             _mainFileFetcher.get('imagery').then(function (d) {
64501               var hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
64502               var features = hits.map(function (d) {
64503                 return d.features[d.id];
64504               });
64505               var imagery = layer.selectAll('path.debug-imagery').data(features);
64506               imagery.exit().remove();
64507               imagery.enter().append('path').attr('class', 'debug-imagery debug orange');
64508             })["catch"](function () {
64509               /* ignore */
64510             }); // downloaded
64511
64512             var osm = context.connection();
64513             var dataDownloaded = [];
64514
64515             if (osm && showDownloaded) {
64516               var rtree = osm.caches('get').tile.rtree;
64517               dataDownloaded = rtree.all().map(function (bbox) {
64518                 return {
64519                   type: 'Feature',
64520                   properties: {
64521                     id: bbox.id
64522                   },
64523                   geometry: {
64524                     type: 'Polygon',
64525                     coordinates: [[[bbox.minX, bbox.minY], [bbox.minX, bbox.maxY], [bbox.maxX, bbox.maxY], [bbox.maxX, bbox.minY], [bbox.minX, bbox.minY]]]
64526                   }
64527                 };
64528               });
64529             }
64530
64531             var downloaded = layer.selectAll('path.debug-downloaded').data(showDownloaded ? dataDownloaded : []);
64532             downloaded.exit().remove();
64533             downloaded.enter().append('path').attr('class', 'debug-downloaded debug purple'); // update
64534
64535             layer.selectAll('path').attr('d', svgPath(projection).geojson);
64536           } // This looks strange because `enabled` methods on other layers are
64537           // chainable getter/setters, and this one is just a getter.
64538
64539
64540           drawDebug.enabled = function () {
64541             if (!arguments.length) {
64542               return context.getDebug('tile') || context.getDebug('collision') || context.getDebug('imagery') || context.getDebug('target') || context.getDebug('downloaded');
64543             } else {
64544               return this;
64545             }
64546           };
64547
64548           return drawDebug;
64549         }
64550
64551         /*
64552             A standalone SVG element that contains only a `defs` sub-element. To be
64553             used once globally, since defs IDs must be unique within a document.
64554         */
64555
64556         function svgDefs(context) {
64557           var _defsSelection = select(null);
64558
64559           var _spritesheetIds = ['iD-sprite', 'maki-sprite', 'temaki-sprite', 'fa-sprite', 'community-sprite'];
64560
64561           function drawDefs(selection) {
64562             _defsSelection = selection.append('defs'); // add markers
64563
64564             _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
64565             // (they can't inherit it from the line they're attached to),
64566             // so we need to manually define markers for each color of tag
64567             // (also, it's slightly nicer if we can control the
64568             // positioning for different tags)
64569
64570
64571             function addSidedMarker(name, color, offset) {
64572               _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);
64573             }
64574
64575             addSidedMarker('natural', 'rgb(170, 170, 170)', 0); // for a coastline, the arrows are (somewhat unintuitively) on
64576             // the water side, so let's color them blue (with a gap) to
64577             // give a stronger indication
64578
64579             addSidedMarker('coastline', '#77dede', 1);
64580             addSidedMarker('waterway', '#77dede', 1); // barriers have a dashed line, and separating the triangle
64581             // from the line visually suits that
64582
64583             addSidedMarker('barrier', '#ddd', 1);
64584             addSidedMarker('man_made', '#fff', 0);
64585
64586             _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');
64587
64588             _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
64589
64590
64591             var patterns = _defsSelection.selectAll('pattern').data([// pattern name, pattern image name
64592             ['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) {
64593               return 'ideditor-pattern-' + d[0];
64594             }).attr('width', 32).attr('height', 32).attr('patternUnits', 'userSpaceOnUse');
64595
64596             patterns.append('rect').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('class', function (d) {
64597               return 'pattern-color-' + d[0];
64598             });
64599             patterns.append('image').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('xlink:href', function (d) {
64600               return context.imagePath('pattern/' + d[1] + '.png');
64601             }); // add clip paths
64602
64603             _defsSelection.selectAll('clipPath').data([12, 18, 20, 32, 45]).enter().append('clipPath').attr('id', function (d) {
64604               return 'ideditor-clip-square-' + d;
64605             }).append('rect').attr('x', 0).attr('y', 0).attr('width', function (d) {
64606               return d;
64607             }).attr('height', function (d) {
64608               return d;
64609             }); // add symbol spritesheets
64610
64611
64612             addSprites(_spritesheetIds, true);
64613           }
64614
64615           function addSprites(ids, overrideColors) {
64616             _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
64617
64618             var spritesheets = _defsSelection.selectAll('.spritesheet').data(_spritesheetIds);
64619
64620             spritesheets.enter().append('g').attr('class', function (d) {
64621               return 'spritesheet spritesheet-' + d;
64622             }).each(function (d) {
64623               var url = context.imagePath(d + '.svg');
64624               var node = select(this).node();
64625               svg(url).then(function (svg) {
64626                 node.appendChild(select(svg.documentElement).attr('id', 'ideditor-' + d).node());
64627
64628                 if (overrideColors && d !== 'iD-sprite') {
64629                   // allow icon colors to be overridden..
64630                   select(node).selectAll('path').attr('fill', 'currentColor');
64631                 }
64632               })["catch"](function () {
64633                 /* ignore */
64634               });
64635             });
64636             spritesheets.exit().remove();
64637           }
64638
64639           drawDefs.addSprites = addSprites;
64640           return drawDefs;
64641         }
64642
64643         var _layerEnabled$2 = false;
64644
64645         var _qaService$2;
64646
64647         function svgKeepRight(projection, context, dispatch) {
64648           var throttledRedraw = throttle(function () {
64649             return dispatch.call('change');
64650           }, 1000);
64651
64652           var minZoom = 12;
64653           var touchLayer = select(null);
64654           var drawLayer = select(null);
64655           var layerVisible = false;
64656
64657           function markerPath(selection, klass) {
64658             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');
64659           } // Loosely-coupled keepRight service for fetching issues.
64660
64661
64662           function getService() {
64663             if (services.keepRight && !_qaService$2) {
64664               _qaService$2 = services.keepRight;
64665
64666               _qaService$2.on('loaded', throttledRedraw);
64667             } else if (!services.keepRight && _qaService$2) {
64668               _qaService$2 = null;
64669             }
64670
64671             return _qaService$2;
64672           } // Show the markers
64673
64674
64675           function editOn() {
64676             if (!layerVisible) {
64677               layerVisible = true;
64678               drawLayer.style('display', 'block');
64679             }
64680           } // Immediately remove the markers and their touch targets
64681
64682
64683           function editOff() {
64684             if (layerVisible) {
64685               layerVisible = false;
64686               drawLayer.style('display', 'none');
64687               drawLayer.selectAll('.qaItem.keepRight').remove();
64688               touchLayer.selectAll('.qaItem.keepRight').remove();
64689             }
64690           } // Enable the layer.  This shows the markers and transitions them to visible.
64691
64692
64693           function layerOn() {
64694             editOn();
64695             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
64696               return dispatch.call('change');
64697             });
64698           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
64699
64700
64701           function layerOff() {
64702             throttledRedraw.cancel();
64703             drawLayer.interrupt();
64704             touchLayer.selectAll('.qaItem.keepRight').remove();
64705             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
64706               editOff();
64707               dispatch.call('change');
64708             });
64709           } // Update the issue markers
64710
64711
64712           function updateMarkers() {
64713             if (!layerVisible || !_layerEnabled$2) return;
64714             var service = getService();
64715             var selectedID = context.selectedErrorID();
64716             var data = service ? service.getItems(projection) : [];
64717             var getTransform = svgPointTransform(projection); // Draw markers..
64718
64719             var markers = drawLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
64720               return d.id;
64721             }); // exit
64722
64723             markers.exit().remove(); // enter
64724
64725             var markersEnter = markers.enter().append('g').attr('class', function (d) {
64726               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
64727             });
64728             markersEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
64729             markersEnter.append('path').call(markerPath, 'shadow');
64730             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
64731
64732             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
64733               return d.id === selectedID;
64734             }).attr('transform', getTransform); // Draw targets..
64735
64736             if (touchLayer.empty()) return;
64737             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
64738             var targets = touchLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
64739               return d.id;
64740             }); // exit
64741
64742             targets.exit().remove(); // enter/update
64743
64744             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
64745               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
64746             }).attr('transform', getTransform);
64747
64748             function sortY(a, b) {
64749               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];
64750             }
64751           } // Draw the keepRight layer and schedule loading issues and updating markers.
64752
64753
64754           function drawKeepRight(selection) {
64755             var service = getService();
64756             var surface = context.surface();
64757
64758             if (surface && !surface.empty()) {
64759               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
64760             }
64761
64762             drawLayer = selection.selectAll('.layer-keepRight').data(service ? [0] : []);
64763             drawLayer.exit().remove();
64764             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-keepRight').style('display', _layerEnabled$2 ? 'block' : 'none').merge(drawLayer);
64765
64766             if (_layerEnabled$2) {
64767               if (service && ~~context.map().zoom() >= minZoom) {
64768                 editOn();
64769                 service.loadIssues(projection);
64770                 updateMarkers();
64771               } else {
64772                 editOff();
64773               }
64774             }
64775           } // Toggles the layer on and off
64776
64777
64778           drawKeepRight.enabled = function (val) {
64779             if (!arguments.length) return _layerEnabled$2;
64780             _layerEnabled$2 = val;
64781
64782             if (_layerEnabled$2) {
64783               layerOn();
64784             } else {
64785               layerOff();
64786
64787               if (context.selectedErrorID()) {
64788                 context.enter(modeBrowse(context));
64789               }
64790             }
64791
64792             dispatch.call('change');
64793             return this;
64794           };
64795
64796           drawKeepRight.supported = function () {
64797             return !!getService();
64798           };
64799
64800           return drawKeepRight;
64801         }
64802
64803         function svgGeolocate(projection) {
64804           var layer = select(null);
64805
64806           var _position;
64807
64808           function init() {
64809             if (svgGeolocate.initialized) return; // run once
64810
64811             svgGeolocate.enabled = false;
64812             svgGeolocate.initialized = true;
64813           }
64814
64815           function showLayer() {
64816             layer.style('display', 'block');
64817           }
64818
64819           function hideLayer() {
64820             layer.transition().duration(250).style('opacity', 0);
64821           }
64822
64823           function layerOn() {
64824             layer.style('opacity', 0).transition().duration(250).style('opacity', 1);
64825           }
64826
64827           function layerOff() {
64828             layer.style('display', 'none');
64829           }
64830
64831           function transform(d) {
64832             return svgPointTransform(projection)(d);
64833           }
64834
64835           function accuracy(accuracy, loc) {
64836             // converts accuracy to pixels...
64837             var degreesRadius = geoMetersToLat(accuracy),
64838                 tangentLoc = [loc[0], loc[1] + degreesRadius],
64839                 projectedTangent = projection(tangentLoc),
64840                 projectedLoc = projection([loc[0], loc[1]]); // southern most point will have higher pixel value...
64841
64842             return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
64843           }
64844
64845           function update() {
64846             var geolocation = {
64847               loc: [_position.coords.longitude, _position.coords.latitude]
64848             };
64849             var groups = layer.selectAll('.geolocations').selectAll('.geolocation').data([geolocation]);
64850             groups.exit().remove();
64851             var pointsEnter = groups.enter().append('g').attr('class', 'geolocation');
64852             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');
64853             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');
64854             groups.merge(pointsEnter).attr('transform', transform);
64855             layer.select('.geolocate-radius').attr('r', accuracy(_position.coords.accuracy, geolocation.loc));
64856           }
64857
64858           function drawLocation(selection) {
64859             var enabled = svgGeolocate.enabled;
64860             layer = selection.selectAll('.layer-geolocate').data([0]);
64861             layer.exit().remove();
64862             var layerEnter = layer.enter().append('g').attr('class', 'layer-geolocate').style('display', enabled ? 'block' : 'none');
64863             layerEnter.append('g').attr('class', 'geolocations');
64864             layer = layerEnter.merge(layer);
64865
64866             if (enabled) {
64867               update();
64868             } else {
64869               layerOff();
64870             }
64871           }
64872
64873           drawLocation.enabled = function (position, enabled) {
64874             if (!arguments.length) return svgGeolocate.enabled;
64875             _position = position;
64876             svgGeolocate.enabled = enabled;
64877
64878             if (svgGeolocate.enabled) {
64879               showLayer();
64880               layerOn();
64881             } else {
64882               hideLayer();
64883             }
64884
64885             return this;
64886           };
64887
64888           init();
64889           return drawLocation;
64890         }
64891
64892         function svgLabels(projection, context) {
64893           var path = d3_geoPath(projection);
64894           var detected = utilDetect();
64895           var baselineHack = detected.ie || detected.browser.toLowerCase() === 'edge' || detected.browser.toLowerCase() === 'firefox' && detected.version >= 70;
64896
64897           var _rdrawn = new RBush();
64898
64899           var _rskipped = new RBush();
64900
64901           var _textWidthCache = {};
64902           var _entitybboxes = {}; // Listed from highest to lowest priority
64903
64904           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]];
64905
64906           function shouldSkipIcon(preset) {
64907             var noIcons = ['building', 'landuse', 'natural'];
64908             return noIcons.some(function (s) {
64909               return preset.id.indexOf(s) >= 0;
64910             });
64911           }
64912
64913           function get(array, prop) {
64914             return function (d, i) {
64915               return array[i][prop];
64916             };
64917           }
64918
64919           function textWidth(text, size, elem) {
64920             var c = _textWidthCache[size];
64921             if (!c) c = _textWidthCache[size] = {};
64922
64923             if (c[text]) {
64924               return c[text];
64925             } else if (elem) {
64926               c[text] = elem.getComputedTextLength();
64927               return c[text];
64928             } else {
64929               var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
64930
64931               if (str === null) {
64932                 return size / 3 * 2 * text.length;
64933               } else {
64934                 return size / 3 * (2 * text.length + str.length);
64935               }
64936             }
64937           }
64938
64939           function drawLinePaths(selection, entities, filter, classes, labels) {
64940             var paths = selection.selectAll('path').filter(filter).data(entities, osmEntity.key); // exit
64941
64942             paths.exit().remove(); // enter/update
64943
64944             paths.enter().append('path').style('stroke-width', get(labels, 'font-size')).attr('id', function (d) {
64945               return 'ideditor-labelpath-' + d.id;
64946             }).attr('class', classes).merge(paths).attr('d', get(labels, 'lineString'));
64947           }
64948
64949           function drawLineLabels(selection, entities, filter, classes, labels) {
64950             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
64951
64952             texts.exit().remove(); // enter
64953
64954             texts.enter().append('text').attr('class', function (d, i) {
64955               return classes + ' ' + labels[i].classes + ' ' + d.id;
64956             }).attr('dy', baselineHack ? '0.35em' : null).append('textPath').attr('class', 'textpath'); // update
64957
64958             selection.selectAll('text.' + classes).selectAll('.textpath').filter(filter).data(entities, osmEntity.key).attr('startOffset', '50%').attr('xlink:href', function (d) {
64959               return '#ideditor-labelpath-' + d.id;
64960             }).text(utilDisplayNameForPath);
64961           }
64962
64963           function drawPointLabels(selection, entities, filter, classes, labels) {
64964             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
64965
64966             texts.exit().remove(); // enter/update
64967
64968             texts.enter().append('text').attr('class', function (d, i) {
64969               return classes + ' ' + labels[i].classes + ' ' + d.id;
64970             }).merge(texts).attr('x', get(labels, 'x')).attr('y', get(labels, 'y')).style('text-anchor', get(labels, 'textAnchor')).text(utilDisplayName).each(function (d, i) {
64971               textWidth(utilDisplayName(d), labels[i].height, this);
64972             });
64973           }
64974
64975           function drawAreaLabels(selection, entities, filter, classes, labels) {
64976             entities = entities.filter(hasText);
64977             labels = labels.filter(hasText);
64978             drawPointLabels(selection, entities, filter, classes, labels);
64979
64980             function hasText(d, i) {
64981               return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
64982             }
64983           }
64984
64985           function drawAreaIcons(selection, entities, filter, classes, labels) {
64986             var icons = selection.selectAll('use.' + classes).filter(filter).data(entities, osmEntity.key); // exit
64987
64988             icons.exit().remove(); // enter/update
64989
64990             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) {
64991               var preset = _mainPresetIndex.match(d, context.graph());
64992               var picon = preset && preset.icon;
64993
64994               if (!picon) {
64995                 return '';
64996               } else {
64997                 var isMaki = /^maki-/.test(picon);
64998                 return '#' + picon + (isMaki ? '-15' : '');
64999               }
65000             });
65001           }
65002
65003           function drawCollisionBoxes(selection, rtree, which) {
65004             var classes = 'debug ' + which + ' ' + (which === 'debug-skipped' ? 'orange' : 'yellow');
65005             var gj = [];
65006
65007             if (context.getDebug('collision')) {
65008               gj = rtree.all().map(function (d) {
65009                 return {
65010                   type: 'Polygon',
65011                   coordinates: [[[d.minX, d.minY], [d.maxX, d.minY], [d.maxX, d.maxY], [d.minX, d.maxY], [d.minX, d.minY]]]
65012                 };
65013               });
65014             }
65015
65016             var boxes = selection.selectAll('.' + which).data(gj); // exit
65017
65018             boxes.exit().remove(); // enter/update
65019
65020             boxes.enter().append('path').attr('class', classes).merge(boxes).attr('d', d3_geoPath());
65021           }
65022
65023           function drawLabels(selection, graph, entities, filter, dimensions, fullRedraw) {
65024             var wireframe = context.surface().classed('fill-wireframe');
65025             var zoom = geoScaleToZoom(projection.scale());
65026             var labelable = [];
65027             var renderNodeAs = {};
65028             var i, j, k, entity, geometry;
65029
65030             for (i = 0; i < labelStack.length; i++) {
65031               labelable.push([]);
65032             }
65033
65034             if (fullRedraw) {
65035               _rdrawn.clear();
65036
65037               _rskipped.clear();
65038
65039               _entitybboxes = {};
65040             } else {
65041               for (i = 0; i < entities.length; i++) {
65042                 entity = entities[i];
65043                 var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + 'I'] || []);
65044
65045                 for (j = 0; j < toRemove.length; j++) {
65046                   _rdrawn.remove(toRemove[j]);
65047
65048                   _rskipped.remove(toRemove[j]);
65049                 }
65050               }
65051             } // Loop through all the entities to do some preprocessing
65052
65053
65054             for (i = 0; i < entities.length; i++) {
65055               entity = entities[i];
65056               geometry = entity.geometry(graph); // Insert collision boxes around interesting points/vertices
65057
65058               if (geometry === 'point' || geometry === 'vertex' && isInterestingVertex(entity)) {
65059                 var hasDirections = entity.directions(graph, projection).length;
65060                 var markerPadding;
65061
65062                 if (!wireframe && geometry === 'point' && !(zoom >= 18 && hasDirections)) {
65063                   renderNodeAs[entity.id] = 'point';
65064                   markerPadding = 20; // extra y for marker height
65065                 } else {
65066                   renderNodeAs[entity.id] = 'vertex';
65067                   markerPadding = 0;
65068                 }
65069
65070                 var coord = projection(entity.loc);
65071                 var nodePadding = 10;
65072                 var bbox = {
65073                   minX: coord[0] - nodePadding,
65074                   minY: coord[1] - nodePadding - markerPadding,
65075                   maxX: coord[0] + nodePadding,
65076                   maxY: coord[1] + nodePadding
65077                 };
65078                 doInsert(bbox, entity.id + 'P');
65079               } // From here on, treat vertices like points
65080
65081
65082               if (geometry === 'vertex') {
65083                 geometry = 'point';
65084               } // Determine which entities are label-able
65085
65086
65087               var preset = geometry === 'area' && _mainPresetIndex.match(entity, graph);
65088               var icon = preset && !shouldSkipIcon(preset) && preset.icon;
65089               if (!icon && !utilDisplayName(entity)) continue;
65090
65091               for (k = 0; k < labelStack.length; k++) {
65092                 var matchGeom = labelStack[k][0];
65093                 var matchKey = labelStack[k][1];
65094                 var matchVal = labelStack[k][2];
65095                 var hasVal = entity.tags[matchKey];
65096
65097                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
65098                   labelable[k].push(entity);
65099                   break;
65100                 }
65101               }
65102             }
65103
65104             var positions = {
65105               point: [],
65106               line: [],
65107               area: []
65108             };
65109             var labelled = {
65110               point: [],
65111               line: [],
65112               area: []
65113             }; // Try and find a valid label for labellable entities
65114
65115             for (k = 0; k < labelable.length; k++) {
65116               var fontSize = labelStack[k][3];
65117
65118               for (i = 0; i < labelable[k].length; i++) {
65119                 entity = labelable[k][i];
65120                 geometry = entity.geometry(graph);
65121                 var getName = geometry === 'line' ? utilDisplayNameForPath : utilDisplayName;
65122                 var name = getName(entity);
65123                 var width = name && textWidth(name, fontSize);
65124                 var p = null;
65125
65126                 if (geometry === 'point' || geometry === 'vertex') {
65127                   // no point or vertex labels in wireframe mode
65128                   // no vertex labels at low zooms (vertices have no icons)
65129                   if (wireframe) continue;
65130                   var renderAs = renderNodeAs[entity.id];
65131                   if (renderAs === 'vertex' && zoom < 17) continue;
65132                   p = getPointLabel(entity, width, fontSize, renderAs);
65133                 } else if (geometry === 'line') {
65134                   p = getLineLabel(entity, width, fontSize);
65135                 } else if (geometry === 'area') {
65136                   p = getAreaLabel(entity, width, fontSize);
65137                 }
65138
65139                 if (p) {
65140                   if (geometry === 'vertex') {
65141                     geometry = 'point';
65142                   } // treat vertex like point
65143
65144
65145                   p.classes = geometry + ' tag-' + labelStack[k][1];
65146                   positions[geometry].push(p);
65147                   labelled[geometry].push(entity);
65148                 }
65149               }
65150             }
65151
65152             function isInterestingVertex(entity) {
65153               var selectedIDs = context.selectedIDs();
65154               return entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || selectedIDs.indexOf(entity.id) !== -1 || graph.parentWays(entity).some(function (parent) {
65155                 return selectedIDs.indexOf(parent.id) !== -1;
65156               });
65157             }
65158
65159             function getPointLabel(entity, width, height, geometry) {
65160               var y = geometry === 'point' ? -12 : 0;
65161               var pointOffsets = {
65162                 ltr: [15, y, 'start'],
65163                 rtl: [-15, y, 'end']
65164               };
65165               var textDirection = _mainLocalizer.textDirection();
65166               var coord = projection(entity.loc);
65167               var textPadding = 2;
65168               var offset = pointOffsets[textDirection];
65169               var p = {
65170                 height: height,
65171                 width: width,
65172                 x: coord[0] + offset[0],
65173                 y: coord[1] + offset[1],
65174                 textAnchor: offset[2]
65175               }; // insert a collision box for the text label..
65176
65177               var bbox;
65178
65179               if (textDirection === 'rtl') {
65180                 bbox = {
65181                   minX: p.x - width - textPadding,
65182                   minY: p.y - height / 2 - textPadding,
65183                   maxX: p.x + textPadding,
65184                   maxY: p.y + height / 2 + textPadding
65185                 };
65186               } else {
65187                 bbox = {
65188                   minX: p.x - textPadding,
65189                   minY: p.y - height / 2 - textPadding,
65190                   maxX: p.x + width + textPadding,
65191                   maxY: p.y + height / 2 + textPadding
65192                 };
65193               }
65194
65195               if (tryInsert([bbox], entity.id, true)) {
65196                 return p;
65197               }
65198             }
65199
65200             function getLineLabel(entity, width, height) {
65201               var viewport = geoExtent(context.projection.clipExtent()).polygon();
65202               var points = graph.childNodes(entity).map(function (node) {
65203                 return projection(node.loc);
65204               });
65205               var length = geoPathLength(points);
65206               if (length < width + 20) return; // % along the line to attempt to place the label
65207
65208               var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
65209               var padding = 3;
65210
65211               for (var i = 0; i < lineOffsets.length; i++) {
65212                 var offset = lineOffsets[i];
65213                 var middle = offset / 100 * length;
65214                 var start = middle - width / 2;
65215                 if (start < 0 || start + width > length) continue; // generate subpath and ignore paths that are invalid or don't cross viewport.
65216
65217                 var sub = subpath(points, start, start + width);
65218
65219                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
65220                   continue;
65221                 }
65222
65223                 var isReverse = reverse(sub);
65224
65225                 if (isReverse) {
65226                   sub = sub.reverse();
65227                 }
65228
65229                 var bboxes = [];
65230                 var boxsize = (height + 2) / 2;
65231
65232                 for (var j = 0; j < sub.length - 1; j++) {
65233                   var a = sub[j];
65234                   var b = sub[j + 1]; // split up the text into small collision boxes
65235
65236                   var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
65237
65238                   for (var box = 0; box < num; box++) {
65239                     var p = geoVecInterp(a, b, box / num);
65240                     var x0 = p[0] - boxsize - padding;
65241                     var y0 = p[1] - boxsize - padding;
65242                     var x1 = p[0] + boxsize + padding;
65243                     var y1 = p[1] + boxsize + padding;
65244                     bboxes.push({
65245                       minX: Math.min(x0, x1),
65246                       minY: Math.min(y0, y1),
65247                       maxX: Math.max(x0, x1),
65248                       maxY: Math.max(y0, y1)
65249                     });
65250                   }
65251                 }
65252
65253                 if (tryInsert(bboxes, entity.id, false)) {
65254                   // accept this one
65255                   return {
65256                     'font-size': height + 2,
65257                     lineString: lineString(sub),
65258                     startOffset: offset + '%'
65259                   };
65260                 }
65261               }
65262
65263               function reverse(p) {
65264                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
65265                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI / 2 && angle > -Math.PI / 2);
65266               }
65267
65268               function lineString(points) {
65269                 return 'M' + points.join('L');
65270               }
65271
65272               function subpath(points, from, to) {
65273                 var sofar = 0;
65274                 var start, end, i0, i1;
65275
65276                 for (var i = 0; i < points.length - 1; i++) {
65277                   var a = points[i];
65278                   var b = points[i + 1];
65279                   var current = geoVecLength(a, b);
65280                   var portion;
65281
65282                   if (!start && sofar + current >= from) {
65283                     portion = (from - sofar) / current;
65284                     start = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
65285                     i0 = i + 1;
65286                   }
65287
65288                   if (!end && sofar + current >= to) {
65289                     portion = (to - sofar) / current;
65290                     end = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
65291                     i1 = i + 1;
65292                   }
65293
65294                   sofar += current;
65295                 }
65296
65297                 var result = points.slice(i0, i1);
65298                 result.unshift(start);
65299                 result.push(end);
65300                 return result;
65301               }
65302             }
65303
65304             function getAreaLabel(entity, width, height) {
65305               var centroid = path.centroid(entity.asGeoJSON(graph));
65306               var extent = entity.extent(graph);
65307               var areaWidth = projection(extent[1])[0] - projection(extent[0])[0];
65308               if (isNaN(centroid[0]) || areaWidth < 20) return;
65309               var preset = _mainPresetIndex.match(entity, context.graph());
65310               var picon = preset && preset.icon;
65311               var iconSize = 17;
65312               var padding = 2;
65313               var p = {};
65314
65315               if (picon) {
65316                 // icon and label..
65317                 if (addIcon()) {
65318                   addLabel(iconSize + padding);
65319                   return p;
65320                 }
65321               } else {
65322                 // label only..
65323                 if (addLabel(0)) {
65324                   return p;
65325                 }
65326               }
65327
65328               function addIcon() {
65329                 var iconX = centroid[0] - iconSize / 2;
65330                 var iconY = centroid[1] - iconSize / 2;
65331                 var bbox = {
65332                   minX: iconX,
65333                   minY: iconY,
65334                   maxX: iconX + iconSize,
65335                   maxY: iconY + iconSize
65336                 };
65337
65338                 if (tryInsert([bbox], entity.id + 'I', true)) {
65339                   p.transform = 'translate(' + iconX + ',' + iconY + ')';
65340                   return true;
65341                 }
65342
65343                 return false;
65344               }
65345
65346               function addLabel(yOffset) {
65347                 if (width && areaWidth >= width + 20) {
65348                   var labelX = centroid[0];
65349                   var labelY = centroid[1] + yOffset;
65350                   var bbox = {
65351                     minX: labelX - width / 2 - padding,
65352                     minY: labelY - height / 2 - padding,
65353                     maxX: labelX + width / 2 + padding,
65354                     maxY: labelY + height / 2 + padding
65355                   };
65356
65357                   if (tryInsert([bbox], entity.id, true)) {
65358                     p.x = labelX;
65359                     p.y = labelY;
65360                     p.textAnchor = 'middle';
65361                     p.height = height;
65362                     return true;
65363                   }
65364                 }
65365
65366                 return false;
65367               }
65368             } // force insert a singular bounding box
65369             // singular box only, no array, id better be unique
65370
65371
65372             function doInsert(bbox, id) {
65373               bbox.id = id;
65374               var oldbox = _entitybboxes[id];
65375
65376               if (oldbox) {
65377                 _rdrawn.remove(oldbox);
65378               }
65379
65380               _entitybboxes[id] = bbox;
65381
65382               _rdrawn.insert(bbox);
65383             }
65384
65385             function tryInsert(bboxes, id, saveSkipped) {
65386               var skipped = false;
65387
65388               for (var i = 0; i < bboxes.length; i++) {
65389                 var bbox = bboxes[i];
65390                 bbox.id = id; // Check that label is visible
65391
65392                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
65393                   skipped = true;
65394                   break;
65395                 }
65396
65397                 if (_rdrawn.collides(bbox)) {
65398                   skipped = true;
65399                   break;
65400                 }
65401               }
65402
65403               _entitybboxes[id] = bboxes;
65404
65405               if (skipped) {
65406                 if (saveSkipped) {
65407                   _rskipped.load(bboxes);
65408                 }
65409               } else {
65410                 _rdrawn.load(bboxes);
65411               }
65412
65413               return !skipped;
65414             }
65415
65416             var layer = selection.selectAll('.layer-osm.labels');
65417             layer.selectAll('.labels-group').data(['halo', 'label', 'debug']).enter().append('g').attr('class', function (d) {
65418               return 'labels-group ' + d;
65419             });
65420             var halo = layer.selectAll('.labels-group.halo');
65421             var label = layer.selectAll('.labels-group.label');
65422             var debug = layer.selectAll('.labels-group.debug'); // points
65423
65424             drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
65425             drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point); // lines
65426
65427             drawLinePaths(layer, labelled.line, filter, '', positions.line);
65428             drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
65429             drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line); // areas
65430
65431             drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
65432             drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
65433             drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
65434             drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area); // debug
65435
65436             drawCollisionBoxes(debug, _rskipped, 'debug-skipped');
65437             drawCollisionBoxes(debug, _rdrawn, 'debug-drawn');
65438             layer.call(filterLabels);
65439           }
65440
65441           function filterLabels(selection) {
65442             var drawLayer = selection.selectAll('.layer-osm.labels');
65443             var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
65444             layers.selectAll('.nolabel').classed('nolabel', false);
65445             var mouse = context.map().mouse();
65446             var graph = context.graph();
65447             var selectedIDs = context.selectedIDs();
65448             var ids = [];
65449             var pad, bbox; // hide labels near the mouse
65450
65451             if (mouse) {
65452               pad = 20;
65453               bbox = {
65454                 minX: mouse[0] - pad,
65455                 minY: mouse[1] - pad,
65456                 maxX: mouse[0] + pad,
65457                 maxY: mouse[1] + pad
65458               };
65459
65460               var nearMouse = _rdrawn.search(bbox).map(function (entity) {
65461                 return entity.id;
65462               });
65463
65464               ids.push.apply(ids, nearMouse);
65465             } // hide labels on selected nodes (they look weird when dragging / haloed)
65466
65467
65468             for (var i = 0; i < selectedIDs.length; i++) {
65469               var entity = graph.hasEntity(selectedIDs[i]);
65470
65471               if (entity && entity.type === 'node') {
65472                 ids.push(selectedIDs[i]);
65473               }
65474             }
65475
65476             layers.selectAll(utilEntitySelector(ids)).classed('nolabel', true); // draw the mouse bbox if debugging is on..
65477
65478             var debug = selection.selectAll('.labels-group.debug');
65479             var gj = [];
65480
65481             if (context.getDebug('collision')) {
65482               gj = bbox ? [{
65483                 type: 'Polygon',
65484                 coordinates: [[[bbox.minX, bbox.minY], [bbox.maxX, bbox.minY], [bbox.maxX, bbox.maxY], [bbox.minX, bbox.maxY], [bbox.minX, bbox.minY]]]
65485               }] : [];
65486             }
65487
65488             var box = debug.selectAll('.debug-mouse').data(gj); // exit
65489
65490             box.exit().remove(); // enter/update
65491
65492             box.enter().append('path').attr('class', 'debug debug-mouse yellow').merge(box).attr('d', d3_geoPath());
65493           }
65494
65495           var throttleFilterLabels = throttle(filterLabels, 100);
65496
65497           drawLabels.observe = function (selection) {
65498             var listener = function listener() {
65499               throttleFilterLabels(selection);
65500             };
65501
65502             selection.on('mousemove.hidelabels', listener);
65503             context.on('enter.hidelabels', listener);
65504           };
65505
65506           drawLabels.off = function (selection) {
65507             throttleFilterLabels.cancel();
65508             selection.on('mousemove.hidelabels', null);
65509             context.on('enter.hidelabels', null);
65510           };
65511
65512           return drawLabels;
65513         }
65514
65515         var _layerEnabled$1 = false;
65516
65517         var _qaService$1;
65518
65519         function svgImproveOSM(projection, context, dispatch) {
65520           var throttledRedraw = throttle(function () {
65521             return dispatch.call('change');
65522           }, 1000);
65523
65524           var minZoom = 12;
65525           var touchLayer = select(null);
65526           var drawLayer = select(null);
65527           var layerVisible = false;
65528
65529           function markerPath(selection, klass) {
65530             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');
65531           } // Loosely-coupled improveOSM service for fetching issues
65532
65533
65534           function getService() {
65535             if (services.improveOSM && !_qaService$1) {
65536               _qaService$1 = services.improveOSM;
65537
65538               _qaService$1.on('loaded', throttledRedraw);
65539             } else if (!services.improveOSM && _qaService$1) {
65540               _qaService$1 = null;
65541             }
65542
65543             return _qaService$1;
65544           } // Show the markers
65545
65546
65547           function editOn() {
65548             if (!layerVisible) {
65549               layerVisible = true;
65550               drawLayer.style('display', 'block');
65551             }
65552           } // Immediately remove the markers and their touch targets
65553
65554
65555           function editOff() {
65556             if (layerVisible) {
65557               layerVisible = false;
65558               drawLayer.style('display', 'none');
65559               drawLayer.selectAll('.qaItem.improveOSM').remove();
65560               touchLayer.selectAll('.qaItem.improveOSM').remove();
65561             }
65562           } // Enable the layer.  This shows the markers and transitions them to visible.
65563
65564
65565           function layerOn() {
65566             editOn();
65567             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
65568               return dispatch.call('change');
65569             });
65570           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
65571
65572
65573           function layerOff() {
65574             throttledRedraw.cancel();
65575             drawLayer.interrupt();
65576             touchLayer.selectAll('.qaItem.improveOSM').remove();
65577             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
65578               editOff();
65579               dispatch.call('change');
65580             });
65581           } // Update the issue markers
65582
65583
65584           function updateMarkers() {
65585             if (!layerVisible || !_layerEnabled$1) return;
65586             var service = getService();
65587             var selectedID = context.selectedErrorID();
65588             var data = service ? service.getItems(projection) : [];
65589             var getTransform = svgPointTransform(projection); // Draw markers..
65590
65591             var markers = drawLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
65592               return d.id;
65593             }); // exit
65594
65595             markers.exit().remove(); // enter
65596
65597             var markersEnter = markers.enter().append('g').attr('class', function (d) {
65598               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
65599             });
65600             markersEnter.append('polygon').call(markerPath, 'shadow');
65601             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
65602             markersEnter.append('polygon').attr('fill', 'currentColor').call(markerPath, 'qaItem-fill');
65603             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
65604               var picon = d.icon;
65605
65606               if (!picon) {
65607                 return '';
65608               } else {
65609                 var isMaki = /^maki-/.test(picon);
65610                 return "#".concat(picon).concat(isMaki ? '-11' : '');
65611               }
65612             }); // update
65613
65614             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
65615               return d.id === selectedID;
65616             }).attr('transform', getTransform); // Draw targets..
65617
65618             if (touchLayer.empty()) return;
65619             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
65620             var targets = touchLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
65621               return d.id;
65622             }); // exit
65623
65624             targets.exit().remove(); // enter/update
65625
65626             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
65627               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
65628             }).attr('transform', getTransform);
65629
65630             function sortY(a, b) {
65631               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
65632             }
65633           } // Draw the ImproveOSM layer and schedule loading issues and updating markers.
65634
65635
65636           function drawImproveOSM(selection) {
65637             var service = getService();
65638             var surface = context.surface();
65639
65640             if (surface && !surface.empty()) {
65641               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
65642             }
65643
65644             drawLayer = selection.selectAll('.layer-improveOSM').data(service ? [0] : []);
65645             drawLayer.exit().remove();
65646             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-improveOSM').style('display', _layerEnabled$1 ? 'block' : 'none').merge(drawLayer);
65647
65648             if (_layerEnabled$1) {
65649               if (service && ~~context.map().zoom() >= minZoom) {
65650                 editOn();
65651                 service.loadIssues(projection);
65652                 updateMarkers();
65653               } else {
65654                 editOff();
65655               }
65656             }
65657           } // Toggles the layer on and off
65658
65659
65660           drawImproveOSM.enabled = function (val) {
65661             if (!arguments.length) return _layerEnabled$1;
65662             _layerEnabled$1 = val;
65663
65664             if (_layerEnabled$1) {
65665               layerOn();
65666             } else {
65667               layerOff();
65668
65669               if (context.selectedErrorID()) {
65670                 context.enter(modeBrowse(context));
65671               }
65672             }
65673
65674             dispatch.call('change');
65675             return this;
65676           };
65677
65678           drawImproveOSM.supported = function () {
65679             return !!getService();
65680           };
65681
65682           return drawImproveOSM;
65683         }
65684
65685         var _layerEnabled = false;
65686
65687         var _qaService;
65688
65689         function svgOsmose(projection, context, dispatch) {
65690           var throttledRedraw = throttle(function () {
65691             return dispatch.call('change');
65692           }, 1000);
65693
65694           var minZoom = 12;
65695           var touchLayer = select(null);
65696           var drawLayer = select(null);
65697           var layerVisible = false;
65698
65699           function markerPath(selection, klass) {
65700             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');
65701           } // Loosely-coupled osmose service for fetching issues
65702
65703
65704           function getService() {
65705             if (services.osmose && !_qaService) {
65706               _qaService = services.osmose;
65707
65708               _qaService.on('loaded', throttledRedraw);
65709             } else if (!services.osmose && _qaService) {
65710               _qaService = null;
65711             }
65712
65713             return _qaService;
65714           } // Show the markers
65715
65716
65717           function editOn() {
65718             if (!layerVisible) {
65719               layerVisible = true;
65720               drawLayer.style('display', 'block');
65721             }
65722           } // Immediately remove the markers and their touch targets
65723
65724
65725           function editOff() {
65726             if (layerVisible) {
65727               layerVisible = false;
65728               drawLayer.style('display', 'none');
65729               drawLayer.selectAll('.qaItem.osmose').remove();
65730               touchLayer.selectAll('.qaItem.osmose').remove();
65731             }
65732           } // Enable the layer.  This shows the markers and transitions them to visible.
65733
65734
65735           function layerOn() {
65736             editOn();
65737             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
65738               return dispatch.call('change');
65739             });
65740           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
65741
65742
65743           function layerOff() {
65744             throttledRedraw.cancel();
65745             drawLayer.interrupt();
65746             touchLayer.selectAll('.qaItem.osmose').remove();
65747             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
65748               editOff();
65749               dispatch.call('change');
65750             });
65751           } // Update the issue markers
65752
65753
65754           function updateMarkers() {
65755             if (!layerVisible || !_layerEnabled) return;
65756             var service = getService();
65757             var selectedID = context.selectedErrorID();
65758             var data = service ? service.getItems(projection) : [];
65759             var getTransform = svgPointTransform(projection); // Draw markers..
65760
65761             var markers = drawLayer.selectAll('.qaItem.osmose').data(data, function (d) {
65762               return d.id;
65763             }); // exit
65764
65765             markers.exit().remove(); // enter
65766
65767             var markersEnter = markers.enter().append('g').attr('class', function (d) {
65768               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
65769             });
65770             markersEnter.append('polygon').call(markerPath, 'shadow');
65771             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
65772             markersEnter.append('polygon').attr('fill', function (d) {
65773               return service.getColor(d.item);
65774             }).call(markerPath, 'qaItem-fill');
65775             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
65776               var picon = d.icon;
65777
65778               if (!picon) {
65779                 return '';
65780               } else {
65781                 var isMaki = /^maki-/.test(picon);
65782                 return "#".concat(picon).concat(isMaki ? '-11' : '');
65783               }
65784             }); // update
65785
65786             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
65787               return d.id === selectedID;
65788             }).attr('transform', getTransform); // Draw targets..
65789
65790             if (touchLayer.empty()) return;
65791             var fillClass = context.getDebug('target') ? 'pink' : 'nocolor';
65792             var targets = touchLayer.selectAll('.qaItem.osmose').data(data, function (d) {
65793               return d.id;
65794             }); // exit
65795
65796             targets.exit().remove(); // enter/update
65797
65798             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
65799               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
65800             }).attr('transform', getTransform);
65801
65802             function sortY(a, b) {
65803               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
65804             }
65805           } // Draw the Osmose layer and schedule loading issues and updating markers.
65806
65807
65808           function drawOsmose(selection) {
65809             var service = getService();
65810             var surface = context.surface();
65811
65812             if (surface && !surface.empty()) {
65813               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
65814             }
65815
65816             drawLayer = selection.selectAll('.layer-osmose').data(service ? [0] : []);
65817             drawLayer.exit().remove();
65818             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-osmose').style('display', _layerEnabled ? 'block' : 'none').merge(drawLayer);
65819
65820             if (_layerEnabled) {
65821               if (service && ~~context.map().zoom() >= minZoom) {
65822                 editOn();
65823                 service.loadIssues(projection);
65824                 updateMarkers();
65825               } else {
65826                 editOff();
65827               }
65828             }
65829           } // Toggles the layer on and off
65830
65831
65832           drawOsmose.enabled = function (val) {
65833             if (!arguments.length) return _layerEnabled;
65834             _layerEnabled = val;
65835
65836             if (_layerEnabled) {
65837               // Strings supplied by Osmose fetched before showing layer for first time
65838               // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented
65839               // Also, If layer is toggled quickly multiple requests are sent
65840               getService().loadStrings().then(layerOn)["catch"](function (err) {
65841                 console.log(err); // eslint-disable-line no-console
65842               });
65843             } else {
65844               layerOff();
65845
65846               if (context.selectedErrorID()) {
65847                 context.enter(modeBrowse(context));
65848               }
65849             }
65850
65851             dispatch.call('change');
65852             return this;
65853           };
65854
65855           drawOsmose.supported = function () {
65856             return !!getService();
65857           };
65858
65859           return drawOsmose;
65860         }
65861
65862         function svgStreetside(projection, context, dispatch) {
65863           var throttledRedraw = throttle(function () {
65864             dispatch.call('change');
65865           }, 1000);
65866
65867           var minZoom = 14;
65868           var minMarkerZoom = 16;
65869           var minViewfieldZoom = 18;
65870           var layer = select(null);
65871           var _viewerYaw = 0;
65872           var _selectedSequence = null;
65873
65874           var _streetside;
65875           /**
65876            * init().
65877            */
65878
65879
65880           function init() {
65881             if (svgStreetside.initialized) return; // run once
65882
65883             svgStreetside.enabled = false;
65884             svgStreetside.initialized = true;
65885           }
65886           /**
65887            * getService().
65888            */
65889
65890
65891           function getService() {
65892             if (services.streetside && !_streetside) {
65893               _streetside = services.streetside;
65894
65895               _streetside.event.on('viewerChanged.svgStreetside', viewerChanged).on('loadedImages.svgStreetside', throttledRedraw);
65896             } else if (!services.streetside && _streetside) {
65897               _streetside = null;
65898             }
65899
65900             return _streetside;
65901           }
65902           /**
65903            * showLayer().
65904            */
65905
65906
65907           function showLayer() {
65908             var service = getService();
65909             if (!service) return;
65910             editOn();
65911             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
65912               dispatch.call('change');
65913             });
65914           }
65915           /**
65916            * hideLayer().
65917            */
65918
65919
65920           function hideLayer() {
65921             throttledRedraw.cancel();
65922             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
65923           }
65924           /**
65925            * editOn().
65926            */
65927
65928
65929           function editOn() {
65930             layer.style('display', 'block');
65931           }
65932           /**
65933            * editOff().
65934            */
65935
65936
65937           function editOff() {
65938             layer.selectAll('.viewfield-group').remove();
65939             layer.style('display', 'none');
65940           }
65941           /**
65942            * click() Handles 'bubble' point click event.
65943            */
65944
65945
65946           function click(d3_event, d) {
65947             var service = getService();
65948             if (!service) return; // try to preserve the viewer rotation when staying on the same sequence
65949
65950             if (d.sequenceKey !== _selectedSequence) {
65951               _viewerYaw = 0; // reset
65952             }
65953
65954             _selectedSequence = d.sequenceKey;
65955             service.ensureViewerLoaded(context).then(function () {
65956               service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
65957             });
65958             context.map().centerEase(d.loc);
65959           }
65960           /**
65961            * mouseover().
65962            */
65963
65964
65965           function mouseover(d3_event, d) {
65966             var service = getService();
65967             if (service) service.setStyles(context, d);
65968           }
65969           /**
65970            * mouseout().
65971            */
65972
65973
65974           function mouseout() {
65975             var service = getService();
65976             if (service) service.setStyles(context, null);
65977           }
65978           /**
65979            * transform().
65980            */
65981
65982
65983           function transform(d) {
65984             var t = svgPointTransform(projection)(d);
65985             var rot = d.ca + _viewerYaw;
65986
65987             if (rot) {
65988               t += ' rotate(' + Math.floor(rot) + ',0,0)';
65989             }
65990
65991             return t;
65992           }
65993
65994           function viewerChanged() {
65995             var service = getService();
65996             if (!service) return;
65997             var viewer = service.viewer();
65998             if (!viewer) return; // update viewfield rotation
65999
66000             _viewerYaw = viewer.getYaw(); // avoid updating if the map is currently transformed
66001             // e.g. during drags or easing.
66002
66003             if (context.map().isTransformed()) return;
66004             layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
66005           }
66006
66007           function filterBubbles(bubbles) {
66008             var fromDate = context.photos().fromDate();
66009             var toDate = context.photos().toDate();
66010             var usernames = context.photos().usernames();
66011
66012             if (fromDate) {
66013               var fromTimestamp = new Date(fromDate).getTime();
66014               bubbles = bubbles.filter(function (bubble) {
66015                 return new Date(bubble.captured_at).getTime() >= fromTimestamp;
66016               });
66017             }
66018
66019             if (toDate) {
66020               var toTimestamp = new Date(toDate).getTime();
66021               bubbles = bubbles.filter(function (bubble) {
66022                 return new Date(bubble.captured_at).getTime() <= toTimestamp;
66023               });
66024             }
66025
66026             if (usernames) {
66027               bubbles = bubbles.filter(function (bubble) {
66028                 return usernames.indexOf(bubble.captured_by) !== -1;
66029               });
66030             }
66031
66032             return bubbles;
66033           }
66034
66035           function filterSequences(sequences) {
66036             var fromDate = context.photos().fromDate();
66037             var toDate = context.photos().toDate();
66038             var usernames = context.photos().usernames();
66039
66040             if (fromDate) {
66041               var fromTimestamp = new Date(fromDate).getTime();
66042               sequences = sequences.filter(function (sequences) {
66043                 return new Date(sequences.properties.captured_at).getTime() >= fromTimestamp;
66044               });
66045             }
66046
66047             if (toDate) {
66048               var toTimestamp = new Date(toDate).getTime();
66049               sequences = sequences.filter(function (sequences) {
66050                 return new Date(sequences.properties.captured_at).getTime() <= toTimestamp;
66051               });
66052             }
66053
66054             if (usernames) {
66055               sequences = sequences.filter(function (sequences) {
66056                 return usernames.indexOf(sequences.properties.captured_by) !== -1;
66057               });
66058             }
66059
66060             return sequences;
66061           }
66062           /**
66063            * update().
66064            */
66065
66066
66067           function update() {
66068             var viewer = context.container().select('.photoviewer');
66069             var selected = viewer.empty() ? undefined : viewer.datum();
66070             var z = ~~context.map().zoom();
66071             var showMarkers = z >= minMarkerZoom;
66072             var showViewfields = z >= minViewfieldZoom;
66073             var service = getService();
66074             var sequences = [];
66075             var bubbles = [];
66076
66077             if (context.photos().showsPanoramic()) {
66078               sequences = service ? service.sequences(projection) : [];
66079               bubbles = service && showMarkers ? service.bubbles(projection) : [];
66080               sequences = filterSequences(sequences);
66081               bubbles = filterBubbles(bubbles);
66082             }
66083
66084             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
66085               return d.properties.key;
66086             }); // exit
66087
66088             traces.exit().remove(); // enter/update
66089
66090             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
66091             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(bubbles, function (d) {
66092               // force reenter once bubbles are attached to a sequence
66093               return d.key + (d.sequenceKey ? 'v1' : 'v0');
66094             }); // exit
66095
66096             groups.exit().remove(); // enter
66097
66098             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
66099             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
66100
66101             var markers = groups.merge(groupsEnter).sort(function (a, b) {
66102               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
66103             }).attr('transform', transform).select('.viewfield-scale');
66104             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
66105             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
66106             viewfields.exit().remove(); // viewfields may or may not be drawn...
66107             // but if they are, draw below the circles
66108
66109             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
66110
66111             function viewfieldPath() {
66112               var d = this.parentNode.__data__;
66113
66114               if (d.pano) {
66115                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
66116               } else {
66117                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
66118               }
66119             }
66120           }
66121           /**
66122            * drawImages()
66123            * drawImages is the method that is returned (and that runs) every time 'svgStreetside()' is called.
66124            * 'svgStreetside()' is called from index.js
66125            */
66126
66127
66128           function drawImages(selection) {
66129             var enabled = svgStreetside.enabled;
66130             var service = getService();
66131             layer = selection.selectAll('.layer-streetside-images').data(service ? [0] : []);
66132             layer.exit().remove();
66133             var layerEnter = layer.enter().append('g').attr('class', 'layer-streetside-images').style('display', enabled ? 'block' : 'none');
66134             layerEnter.append('g').attr('class', 'sequences');
66135             layerEnter.append('g').attr('class', 'markers');
66136             layer = layerEnter.merge(layer);
66137
66138             if (enabled) {
66139               if (service && ~~context.map().zoom() >= minZoom) {
66140                 editOn();
66141                 update();
66142                 service.loadBubbles(projection);
66143               } else {
66144                 editOff();
66145               }
66146             }
66147           }
66148           /**
66149            * drawImages.enabled().
66150            */
66151
66152
66153           drawImages.enabled = function (_) {
66154             if (!arguments.length) return svgStreetside.enabled;
66155             svgStreetside.enabled = _;
66156
66157             if (svgStreetside.enabled) {
66158               showLayer();
66159               context.photos().on('change.streetside', update);
66160             } else {
66161               hideLayer();
66162               context.photos().on('change.streetside', null);
66163             }
66164
66165             dispatch.call('change');
66166             return this;
66167           };
66168           /**
66169            * drawImages.supported().
66170            */
66171
66172
66173           drawImages.supported = function () {
66174             return !!getService();
66175           };
66176
66177           init();
66178           return drawImages;
66179         }
66180
66181         function svgMapillaryImages(projection, context, dispatch) {
66182           var throttledRedraw = throttle(function () {
66183             dispatch.call('change');
66184           }, 1000);
66185
66186           var minZoom = 12;
66187           var minMarkerZoom = 16;
66188           var minViewfieldZoom = 18;
66189           var layer = select(null);
66190
66191           var _mapillary;
66192
66193           function init() {
66194             if (svgMapillaryImages.initialized) return; // run once
66195
66196             svgMapillaryImages.enabled = false;
66197             svgMapillaryImages.initialized = true;
66198           }
66199
66200           function getService() {
66201             if (services.mapillary && !_mapillary) {
66202               _mapillary = services.mapillary;
66203
66204               _mapillary.event.on('loadedImages', throttledRedraw);
66205             } else if (!services.mapillary && _mapillary) {
66206               _mapillary = null;
66207             }
66208
66209             return _mapillary;
66210           }
66211
66212           function showLayer() {
66213             var service = getService();
66214             if (!service) return;
66215             editOn();
66216             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
66217               dispatch.call('change');
66218             });
66219           }
66220
66221           function hideLayer() {
66222             throttledRedraw.cancel();
66223             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
66224           }
66225
66226           function editOn() {
66227             layer.style('display', 'block');
66228           }
66229
66230           function editOff() {
66231             layer.selectAll('.viewfield-group').remove();
66232             layer.style('display', 'none');
66233           }
66234
66235           function click(d3_event, image) {
66236             var service = getService();
66237             if (!service) return;
66238             service.ensureViewerLoaded(context).then(function () {
66239               service.selectImage(context, image.id).showViewer(context);
66240             });
66241             context.map().centerEase(image.loc);
66242           }
66243
66244           function mouseover(d3_event, image) {
66245             var service = getService();
66246             if (service) service.setStyles(context, image);
66247           }
66248
66249           function mouseout() {
66250             var service = getService();
66251             if (service) service.setStyles(context, null);
66252           }
66253
66254           function transform(d) {
66255             var t = svgPointTransform(projection)(d);
66256
66257             if (d.ca) {
66258               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
66259             }
66260
66261             return t;
66262           }
66263
66264           function filterImages(images) {
66265             var showsPano = context.photos().showsPanoramic();
66266             var showsFlat = context.photos().showsFlat();
66267             var fromDate = context.photos().fromDate();
66268             var toDate = context.photos().toDate();
66269
66270             if (!showsPano || !showsFlat) {
66271               images = images.filter(function (image) {
66272                 if (image.is_pano) return showsPano;
66273                 return showsFlat;
66274               });
66275             }
66276
66277             if (fromDate) {
66278               images = images.filter(function (image) {
66279                 return new Date(image.captured_at).getTime() >= new Date(fromDate).getTime();
66280               });
66281             }
66282
66283             if (toDate) {
66284               images = images.filter(function (image) {
66285                 return new Date(image.captured_at).getTime() <= new Date(toDate).getTime();
66286               });
66287             }
66288
66289             return images;
66290           }
66291
66292           function filterSequences(sequences) {
66293             var showsPano = context.photos().showsPanoramic();
66294             var showsFlat = context.photos().showsFlat();
66295             var fromDate = context.photos().fromDate();
66296             var toDate = context.photos().toDate();
66297
66298             if (!showsPano || !showsFlat) {
66299               sequences = sequences.filter(function (sequence) {
66300                 if (sequence.properties.hasOwnProperty('is_pano')) {
66301                   if (sequence.properties.is_pano) return showsPano;
66302                   return showsFlat;
66303                 }
66304
66305                 return false;
66306               });
66307             }
66308
66309             if (fromDate) {
66310               sequences = sequences.filter(function (sequence) {
66311                 return new Date(sequence.properties.captured_at).getTime() >= new Date(fromDate).getTime().toString();
66312               });
66313             }
66314
66315             if (toDate) {
66316               sequences = sequences.filter(function (sequence) {
66317                 return new Date(sequence.properties.captured_at).getTime() <= new Date(toDate).getTime().toString();
66318               });
66319             }
66320
66321             return sequences;
66322           }
66323
66324           function update() {
66325             var z = ~~context.map().zoom();
66326             var showMarkers = z >= minMarkerZoom;
66327             var showViewfields = z >= minViewfieldZoom;
66328             var service = getService();
66329             var sequences = service ? service.sequences(projection) : [];
66330             var images = service && showMarkers ? service.images(projection) : [];
66331             images = filterImages(images);
66332             sequences = filterSequences(sequences);
66333             service.filterViewer(context);
66334             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
66335               return d.properties.id;
66336             }); // exit
66337
66338             traces.exit().remove(); // enter/update
66339
66340             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
66341             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
66342               return d.id;
66343             }); // exit
66344
66345             groups.exit().remove(); // enter
66346
66347             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
66348             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
66349
66350             var markers = groups.merge(groupsEnter).sort(function (a, b) {
66351               return b.loc[1] - a.loc[1]; // sort Y
66352             }).attr('transform', transform).select('.viewfield-scale');
66353             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
66354             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
66355             viewfields.exit().remove();
66356             viewfields.enter() // viewfields may or may not be drawn...
66357             .insert('path', 'circle') // but if they are, draw below the circles
66358             .attr('class', 'viewfield').classed('pano', function () {
66359               return this.parentNode.__data__.is_pano;
66360             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
66361
66362             function viewfieldPath() {
66363               if (this.parentNode.__data__.is_pano) {
66364                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
66365               } else {
66366                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
66367               }
66368             }
66369           }
66370
66371           function drawImages(selection) {
66372             var enabled = svgMapillaryImages.enabled;
66373             var service = getService();
66374             layer = selection.selectAll('.layer-mapillary').data(service ? [0] : []);
66375             layer.exit().remove();
66376             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary').style('display', enabled ? 'block' : 'none');
66377             layerEnter.append('g').attr('class', 'sequences');
66378             layerEnter.append('g').attr('class', 'markers');
66379             layer = layerEnter.merge(layer);
66380
66381             if (enabled) {
66382               if (service && ~~context.map().zoom() >= minZoom) {
66383                 editOn();
66384                 update();
66385                 service.loadImages(projection);
66386               } else {
66387                 editOff();
66388               }
66389             }
66390           }
66391
66392           drawImages.enabled = function (_) {
66393             if (!arguments.length) return svgMapillaryImages.enabled;
66394             svgMapillaryImages.enabled = _;
66395
66396             if (svgMapillaryImages.enabled) {
66397               showLayer();
66398               context.photos().on('change.mapillary_images', update);
66399             } else {
66400               hideLayer();
66401               context.photos().on('change.mapillary_images', null);
66402             }
66403
66404             dispatch.call('change');
66405             return this;
66406           };
66407
66408           drawImages.supported = function () {
66409             return !!getService();
66410           };
66411
66412           init();
66413           return drawImages;
66414         }
66415
66416         function svgMapillaryPosition(projection, context) {
66417           var throttledRedraw = throttle(function () {
66418             update();
66419           }, 1000);
66420
66421           var minZoom = 12;
66422           var minViewfieldZoom = 18;
66423           var layer = select(null);
66424
66425           var _mapillary;
66426
66427           var viewerCompassAngle;
66428
66429           function init() {
66430             if (svgMapillaryPosition.initialized) return; // run once
66431
66432             svgMapillaryPosition.initialized = true;
66433           }
66434
66435           function getService() {
66436             if (services.mapillary && !_mapillary) {
66437               _mapillary = services.mapillary;
66438
66439               _mapillary.event.on('imageChanged', throttledRedraw);
66440
66441               _mapillary.event.on('bearingChanged', function (e) {
66442                 viewerCompassAngle = e.bearing;
66443                 if (context.map().isTransformed()) return;
66444                 layer.selectAll('.viewfield-group.currentView').filter(function (d) {
66445                   return d.is_pano;
66446                 }).attr('transform', transform);
66447               });
66448             } else if (!services.mapillary && _mapillary) {
66449               _mapillary = null;
66450             }
66451
66452             return _mapillary;
66453           }
66454
66455           function editOn() {
66456             layer.style('display', 'block');
66457           }
66458
66459           function editOff() {
66460             layer.selectAll('.viewfield-group').remove();
66461             layer.style('display', 'none');
66462           }
66463
66464           function transform(d) {
66465             var t = svgPointTransform(projection)(d);
66466
66467             if (d.is_pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
66468               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
66469             } else if (d.ca) {
66470               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
66471             }
66472
66473             return t;
66474           }
66475
66476           function update() {
66477             var z = ~~context.map().zoom();
66478             var showViewfields = z >= minViewfieldZoom;
66479             var service = getService();
66480             var image = service && service.getActiveImage();
66481             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(image ? [image] : [], function (d) {
66482               return d.id;
66483             }); // exit
66484
66485             groups.exit().remove(); // enter
66486
66487             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group currentView highlighted');
66488             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
66489
66490             var markers = groups.merge(groupsEnter).attr('transform', transform).select('.viewfield-scale');
66491             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
66492             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
66493             viewfields.exit().remove();
66494             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');
66495           }
66496
66497           function drawImages(selection) {
66498             var service = getService();
66499             layer = selection.selectAll('.layer-mapillary-position').data(service ? [0] : []);
66500             layer.exit().remove();
66501             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary-position');
66502             layerEnter.append('g').attr('class', 'markers');
66503             layer = layerEnter.merge(layer);
66504
66505             if (service && ~~context.map().zoom() >= minZoom) {
66506               editOn();
66507               update();
66508             } else {
66509               editOff();
66510             }
66511           }
66512
66513           drawImages.enabled = function () {
66514             update();
66515             return this;
66516           };
66517
66518           drawImages.supported = function () {
66519             return !!getService();
66520           };
66521
66522           init();
66523           return drawImages;
66524         }
66525
66526         function svgMapillarySigns(projection, context, dispatch) {
66527           var throttledRedraw = throttle(function () {
66528             dispatch.call('change');
66529           }, 1000);
66530
66531           var minZoom = 12;
66532           var layer = select(null);
66533
66534           var _mapillary;
66535
66536           function init() {
66537             if (svgMapillarySigns.initialized) return; // run once
66538
66539             svgMapillarySigns.enabled = false;
66540             svgMapillarySigns.initialized = true;
66541           }
66542
66543           function getService() {
66544             if (services.mapillary && !_mapillary) {
66545               _mapillary = services.mapillary;
66546
66547               _mapillary.event.on('loadedSigns', throttledRedraw);
66548             } else if (!services.mapillary && _mapillary) {
66549               _mapillary = null;
66550             }
66551
66552             return _mapillary;
66553           }
66554
66555           function showLayer() {
66556             var service = getService();
66557             if (!service) return;
66558             service.loadSignResources(context);
66559             editOn();
66560           }
66561
66562           function hideLayer() {
66563             throttledRedraw.cancel();
66564             editOff();
66565           }
66566
66567           function editOn() {
66568             layer.style('display', 'block');
66569           }
66570
66571           function editOff() {
66572             layer.selectAll('.icon-sign').remove();
66573             layer.style('display', 'none');
66574           }
66575
66576           function click(d3_event, d) {
66577             var service = getService();
66578             if (!service) return;
66579             context.map().centerEase(d.loc);
66580             var selectedImageId = service.getActiveImage() && service.getActiveImage().id;
66581             service.getDetections(d.id).then(function (detections) {
66582               if (detections.length) {
66583                 var imageId = detections[0].image.id;
66584
66585                 if (imageId === selectedImageId) {
66586                   service.highlightDetection(detections[0]).selectImage(context, imageId);
66587                 } else {
66588                   service.ensureViewerLoaded(context).then(function () {
66589                     service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
66590                   });
66591                 }
66592               }
66593             });
66594           }
66595
66596           function filterData(detectedFeatures) {
66597             var fromDate = context.photos().fromDate();
66598             var toDate = context.photos().toDate();
66599
66600             if (fromDate) {
66601               var fromTimestamp = new Date(fromDate).getTime();
66602               detectedFeatures = detectedFeatures.filter(function (feature) {
66603                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
66604               });
66605             }
66606
66607             if (toDate) {
66608               var toTimestamp = new Date(toDate).getTime();
66609               detectedFeatures = detectedFeatures.filter(function (feature) {
66610                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
66611               });
66612             }
66613
66614             return detectedFeatures;
66615           }
66616
66617           function update() {
66618             var service = getService();
66619             var data = service ? service.signs(projection) : [];
66620             data = filterData(data);
66621             var transform = svgPointTransform(projection);
66622             var signs = layer.selectAll('.icon-sign').data(data, function (d) {
66623               return d.id;
66624             }); // exit
66625
66626             signs.exit().remove(); // enter
66627
66628             var enter = signs.enter().append('g').attr('class', 'icon-sign icon-detected').on('click', click);
66629             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
66630               return '#' + d.value;
66631             });
66632             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
66633
66634             signs.merge(enter).attr('transform', transform);
66635           }
66636
66637           function drawSigns(selection) {
66638             var enabled = svgMapillarySigns.enabled;
66639             var service = getService();
66640             layer = selection.selectAll('.layer-mapillary-signs').data(service ? [0] : []);
66641             layer.exit().remove();
66642             layer = layer.enter().append('g').attr('class', 'layer-mapillary-signs layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
66643
66644             if (enabled) {
66645               if (service && ~~context.map().zoom() >= minZoom) {
66646                 editOn();
66647                 update();
66648                 service.loadSigns(projection);
66649                 service.showSignDetections(true);
66650               } else {
66651                 editOff();
66652               }
66653             } else if (service) {
66654               service.showSignDetections(false);
66655             }
66656           }
66657
66658           drawSigns.enabled = function (_) {
66659             if (!arguments.length) return svgMapillarySigns.enabled;
66660             svgMapillarySigns.enabled = _;
66661
66662             if (svgMapillarySigns.enabled) {
66663               showLayer();
66664               context.photos().on('change.mapillary_signs', update);
66665             } else {
66666               hideLayer();
66667               context.photos().on('change.mapillary_signs', null);
66668             }
66669
66670             dispatch.call('change');
66671             return this;
66672           };
66673
66674           drawSigns.supported = function () {
66675             return !!getService();
66676           };
66677
66678           init();
66679           return drawSigns;
66680         }
66681
66682         function svgMapillaryMapFeatures(projection, context, dispatch) {
66683           var throttledRedraw = throttle(function () {
66684             dispatch.call('change');
66685           }, 1000);
66686
66687           var minZoom = 12;
66688           var layer = select(null);
66689
66690           var _mapillary;
66691
66692           function init() {
66693             if (svgMapillaryMapFeatures.initialized) return; // run once
66694
66695             svgMapillaryMapFeatures.enabled = false;
66696             svgMapillaryMapFeatures.initialized = true;
66697           }
66698
66699           function getService() {
66700             if (services.mapillary && !_mapillary) {
66701               _mapillary = services.mapillary;
66702
66703               _mapillary.event.on('loadedMapFeatures', throttledRedraw);
66704             } else if (!services.mapillary && _mapillary) {
66705               _mapillary = null;
66706             }
66707
66708             return _mapillary;
66709           }
66710
66711           function showLayer() {
66712             var service = getService();
66713             if (!service) return;
66714             service.loadObjectResources(context);
66715             editOn();
66716           }
66717
66718           function hideLayer() {
66719             throttledRedraw.cancel();
66720             editOff();
66721           }
66722
66723           function editOn() {
66724             layer.style('display', 'block');
66725           }
66726
66727           function editOff() {
66728             layer.selectAll('.icon-map-feature').remove();
66729             layer.style('display', 'none');
66730           }
66731
66732           function click(d3_event, d) {
66733             var service = getService();
66734             if (!service) return;
66735             context.map().centerEase(d.loc);
66736             var selectedImageId = service.getActiveImage() && service.getActiveImage().id;
66737             service.getDetections(d.id).then(function (detections) {
66738               if (detections.length) {
66739                 var imageId = detections[0].image.id;
66740
66741                 if (imageId === selectedImageId) {
66742                   service.highlightDetection(detections[0]).selectImage(context, imageId);
66743                 } else {
66744                   service.ensureViewerLoaded(context).then(function () {
66745                     service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
66746                   });
66747                 }
66748               }
66749             });
66750           }
66751
66752           function filterData(detectedFeatures) {
66753             var fromDate = context.photos().fromDate();
66754             var toDate = context.photos().toDate();
66755
66756             if (fromDate) {
66757               detectedFeatures = detectedFeatures.filter(function (feature) {
66758                 return new Date(feature.last_seen_at).getTime() >= new Date(fromDate).getTime();
66759               });
66760             }
66761
66762             if (toDate) {
66763               detectedFeatures = detectedFeatures.filter(function (feature) {
66764                 return new Date(feature.first_seen_at).getTime() <= new Date(toDate).getTime();
66765               });
66766             }
66767
66768             return detectedFeatures;
66769           }
66770
66771           function update() {
66772             var service = getService();
66773             var data = service ? service.mapFeatures(projection) : [];
66774             data = filterData(data);
66775             var transform = svgPointTransform(projection);
66776             var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
66777               return d.id;
66778             }); // exit
66779
66780             mapFeatures.exit().remove(); // enter
66781
66782             var enter = mapFeatures.enter().append('g').attr('class', 'icon-map-feature icon-detected').on('click', click);
66783             enter.append('title').text(function (d) {
66784               var id = d.value.replace(/--/g, '.').replace(/-/g, '_');
66785               return _t('mapillary_map_features.' + id);
66786             });
66787             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
66788               if (d.value === 'object--billboard') {
66789                 // no billboard icon right now, so use the advertisement icon
66790                 return '#object--sign--advertisement';
66791               }
66792
66793               return '#' + d.value;
66794             });
66795             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
66796
66797             mapFeatures.merge(enter).attr('transform', transform);
66798           }
66799
66800           function drawMapFeatures(selection) {
66801             var enabled = svgMapillaryMapFeatures.enabled;
66802             var service = getService();
66803             layer = selection.selectAll('.layer-mapillary-map-features').data(service ? [0] : []);
66804             layer.exit().remove();
66805             layer = layer.enter().append('g').attr('class', 'layer-mapillary-map-features layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
66806
66807             if (enabled) {
66808               if (service && ~~context.map().zoom() >= minZoom) {
66809                 editOn();
66810                 update();
66811                 service.loadMapFeatures(projection);
66812                 service.showFeatureDetections(true);
66813               } else {
66814                 editOff();
66815               }
66816             } else if (service) {
66817               service.showFeatureDetections(false);
66818             }
66819           }
66820
66821           drawMapFeatures.enabled = function (_) {
66822             if (!arguments.length) return svgMapillaryMapFeatures.enabled;
66823             svgMapillaryMapFeatures.enabled = _;
66824
66825             if (svgMapillaryMapFeatures.enabled) {
66826               showLayer();
66827               context.photos().on('change.mapillary_map_features', update);
66828             } else {
66829               hideLayer();
66830               context.photos().on('change.mapillary_map_features', null);
66831             }
66832
66833             dispatch.call('change');
66834             return this;
66835           };
66836
66837           drawMapFeatures.supported = function () {
66838             return !!getService();
66839           };
66840
66841           init();
66842           return drawMapFeatures;
66843         }
66844
66845         function svgOpenstreetcamImages(projection, context, dispatch) {
66846           var throttledRedraw = throttle(function () {
66847             dispatch.call('change');
66848           }, 1000);
66849
66850           var minZoom = 12;
66851           var minMarkerZoom = 16;
66852           var minViewfieldZoom = 18;
66853           var layer = select(null);
66854
66855           var _openstreetcam;
66856
66857           function init() {
66858             if (svgOpenstreetcamImages.initialized) return; // run once
66859
66860             svgOpenstreetcamImages.enabled = false;
66861             svgOpenstreetcamImages.initialized = true;
66862           }
66863
66864           function getService() {
66865             if (services.openstreetcam && !_openstreetcam) {
66866               _openstreetcam = services.openstreetcam;
66867
66868               _openstreetcam.event.on('loadedImages', throttledRedraw);
66869             } else if (!services.openstreetcam && _openstreetcam) {
66870               _openstreetcam = null;
66871             }
66872
66873             return _openstreetcam;
66874           }
66875
66876           function showLayer() {
66877             var service = getService();
66878             if (!service) return;
66879             editOn();
66880             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
66881               dispatch.call('change');
66882             });
66883           }
66884
66885           function hideLayer() {
66886             throttledRedraw.cancel();
66887             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
66888           }
66889
66890           function editOn() {
66891             layer.style('display', 'block');
66892           }
66893
66894           function editOff() {
66895             layer.selectAll('.viewfield-group').remove();
66896             layer.style('display', 'none');
66897           }
66898
66899           function click(d3_event, d) {
66900             var service = getService();
66901             if (!service) return;
66902             service.ensureViewerLoaded(context).then(function () {
66903               service.selectImage(context, d.key).showViewer(context);
66904             });
66905             context.map().centerEase(d.loc);
66906           }
66907
66908           function mouseover(d3_event, d) {
66909             var service = getService();
66910             if (service) service.setStyles(context, d);
66911           }
66912
66913           function mouseout() {
66914             var service = getService();
66915             if (service) service.setStyles(context, null);
66916           }
66917
66918           function transform(d) {
66919             var t = svgPointTransform(projection)(d);
66920
66921             if (d.ca) {
66922               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
66923             }
66924
66925             return t;
66926           }
66927
66928           function filterImages(images) {
66929             var fromDate = context.photos().fromDate();
66930             var toDate = context.photos().toDate();
66931             var usernames = context.photos().usernames();
66932
66933             if (fromDate) {
66934               var fromTimestamp = new Date(fromDate).getTime();
66935               images = images.filter(function (item) {
66936                 return new Date(item.captured_at).getTime() >= fromTimestamp;
66937               });
66938             }
66939
66940             if (toDate) {
66941               var toTimestamp = new Date(toDate).getTime();
66942               images = images.filter(function (item) {
66943                 return new Date(item.captured_at).getTime() <= toTimestamp;
66944               });
66945             }
66946
66947             if (usernames) {
66948               images = images.filter(function (item) {
66949                 return usernames.indexOf(item.captured_by) !== -1;
66950               });
66951             }
66952
66953             return images;
66954           }
66955
66956           function filterSequences(sequences) {
66957             var fromDate = context.photos().fromDate();
66958             var toDate = context.photos().toDate();
66959             var usernames = context.photos().usernames();
66960
66961             if (fromDate) {
66962               var fromTimestamp = new Date(fromDate).getTime();
66963               sequences = sequences.filter(function (image) {
66964                 return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
66965               });
66966             }
66967
66968             if (toDate) {
66969               var toTimestamp = new Date(toDate).getTime();
66970               sequences = sequences.filter(function (image) {
66971                 return new Date(image.properties.captured_at).getTime() <= toTimestamp;
66972               });
66973             }
66974
66975             if (usernames) {
66976               sequences = sequences.filter(function (image) {
66977                 return usernames.indexOf(image.properties.captured_by) !== -1;
66978               });
66979             }
66980
66981             return sequences;
66982           }
66983
66984           function update() {
66985             var viewer = context.container().select('.photoviewer');
66986             var selected = viewer.empty() ? undefined : viewer.datum();
66987             var z = ~~context.map().zoom();
66988             var showMarkers = z >= minMarkerZoom;
66989             var showViewfields = z >= minViewfieldZoom;
66990             var service = getService();
66991             var sequences = [];
66992             var images = [];
66993
66994             if (context.photos().showsFlat()) {
66995               sequences = service ? service.sequences(projection) : [];
66996               images = service && showMarkers ? service.images(projection) : [];
66997               sequences = filterSequences(sequences);
66998               images = filterImages(images);
66999             }
67000
67001             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
67002               return d.properties.key;
67003             }); // exit
67004
67005             traces.exit().remove(); // enter/update
67006
67007             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
67008             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
67009               return d.key;
67010             }); // exit
67011
67012             groups.exit().remove(); // enter
67013
67014             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
67015             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
67016
67017             var markers = groups.merge(groupsEnter).sort(function (a, b) {
67018               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1]; // sort Y
67019             }).attr('transform', transform).select('.viewfield-scale');
67020             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
67021             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
67022             viewfields.exit().remove();
67023             viewfields.enter() // viewfields may or may not be drawn...
67024             .insert('path', 'circle') // but if they are, draw below the circles
67025             .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');
67026           }
67027
67028           function drawImages(selection) {
67029             var enabled = svgOpenstreetcamImages.enabled,
67030                 service = getService();
67031             layer = selection.selectAll('.layer-openstreetcam').data(service ? [0] : []);
67032             layer.exit().remove();
67033             var layerEnter = layer.enter().append('g').attr('class', 'layer-openstreetcam').style('display', enabled ? 'block' : 'none');
67034             layerEnter.append('g').attr('class', 'sequences');
67035             layerEnter.append('g').attr('class', 'markers');
67036             layer = layerEnter.merge(layer);
67037
67038             if (enabled) {
67039               if (service && ~~context.map().zoom() >= minZoom) {
67040                 editOn();
67041                 update();
67042                 service.loadImages(projection);
67043               } else {
67044                 editOff();
67045               }
67046             }
67047           }
67048
67049           drawImages.enabled = function (_) {
67050             if (!arguments.length) return svgOpenstreetcamImages.enabled;
67051             svgOpenstreetcamImages.enabled = _;
67052
67053             if (svgOpenstreetcamImages.enabled) {
67054               showLayer();
67055               context.photos().on('change.openstreetcam_images', update);
67056             } else {
67057               hideLayer();
67058               context.photos().on('change.openstreetcam_images', null);
67059             }
67060
67061             dispatch.call('change');
67062             return this;
67063           };
67064
67065           drawImages.supported = function () {
67066             return !!getService();
67067           };
67068
67069           init();
67070           return drawImages;
67071         }
67072
67073         function svgOsm(projection, context, dispatch) {
67074           var enabled = true;
67075
67076           function drawOsm(selection) {
67077             selection.selectAll('.layer-osm').data(['covered', 'areas', 'lines', 'points', 'labels']).enter().append('g').attr('class', function (d) {
67078               return 'layer-osm ' + d;
67079             });
67080             selection.selectAll('.layer-osm.points').selectAll('.points-group').data(['points', 'midpoints', 'vertices', 'turns']).enter().append('g').attr('class', function (d) {
67081               return 'points-group ' + d;
67082             });
67083           }
67084
67085           function showLayer() {
67086             var layer = context.surface().selectAll('.data-layer.osm');
67087             layer.interrupt();
67088             layer.classed('disabled', false).style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
67089               dispatch.call('change');
67090             });
67091           }
67092
67093           function hideLayer() {
67094             var layer = context.surface().selectAll('.data-layer.osm');
67095             layer.interrupt();
67096             layer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
67097               layer.classed('disabled', true);
67098               dispatch.call('change');
67099             });
67100           }
67101
67102           drawOsm.enabled = function (val) {
67103             if (!arguments.length) return enabled;
67104             enabled = val;
67105
67106             if (enabled) {
67107               showLayer();
67108             } else {
67109               hideLayer();
67110             }
67111
67112             dispatch.call('change');
67113             return this;
67114           };
67115
67116           return drawOsm;
67117         }
67118
67119         var _notesEnabled = false;
67120
67121         var _osmService;
67122
67123         function svgNotes(projection, context, dispatch) {
67124           if (!dispatch) {
67125             dispatch = dispatch$8('change');
67126           }
67127
67128           var throttledRedraw = throttle(function () {
67129             dispatch.call('change');
67130           }, 1000);
67131
67132           var minZoom = 12;
67133           var touchLayer = select(null);
67134           var drawLayer = select(null);
67135           var _notesVisible = false;
67136
67137           function markerPath(selection, klass) {
67138             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');
67139           } // Loosely-coupled osm service for fetching notes.
67140
67141
67142           function getService() {
67143             if (services.osm && !_osmService) {
67144               _osmService = services.osm;
67145
67146               _osmService.on('loadedNotes', throttledRedraw);
67147             } else if (!services.osm && _osmService) {
67148               _osmService = null;
67149             }
67150
67151             return _osmService;
67152           } // Show the notes
67153
67154
67155           function editOn() {
67156             if (!_notesVisible) {
67157               _notesVisible = true;
67158               drawLayer.style('display', 'block');
67159             }
67160           } // Immediately remove the notes and their touch targets
67161
67162
67163           function editOff() {
67164             if (_notesVisible) {
67165               _notesVisible = false;
67166               drawLayer.style('display', 'none');
67167               drawLayer.selectAll('.note').remove();
67168               touchLayer.selectAll('.note').remove();
67169             }
67170           } // Enable the layer.  This shows the notes and transitions them to visible.
67171
67172
67173           function layerOn() {
67174             editOn();
67175             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
67176               dispatch.call('change');
67177             });
67178           } // Disable the layer.  This transitions the layer invisible and then hides the notes.
67179
67180
67181           function layerOff() {
67182             throttledRedraw.cancel();
67183             drawLayer.interrupt();
67184             touchLayer.selectAll('.note').remove();
67185             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
67186               editOff();
67187               dispatch.call('change');
67188             });
67189           } // Update the note markers
67190
67191
67192           function updateMarkers() {
67193             if (!_notesVisible || !_notesEnabled) return;
67194             var service = getService();
67195             var selectedID = context.selectedNoteID();
67196             var data = service ? service.notes(projection) : [];
67197             var getTransform = svgPointTransform(projection); // Draw markers..
67198
67199             var notes = drawLayer.selectAll('.note').data(data, function (d) {
67200               return d.status + d.id;
67201             }); // exit
67202
67203             notes.exit().remove(); // enter
67204
67205             var notesEnter = notes.enter().append('g').attr('class', function (d) {
67206               return 'note note-' + d.id + ' ' + d.status;
67207             }).classed('new', function (d) {
67208               return d.id < 0;
67209             });
67210             notesEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
67211             notesEnter.append('path').call(markerPath, 'shadow');
67212             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');
67213             notesEnter.selectAll('.icon-annotation').data(function (d) {
67214               return [d];
67215             }).enter().append('use').attr('class', 'icon-annotation').attr('width', '10px').attr('height', '10px').attr('x', '-3px').attr('y', '-19px').attr('xlink:href', function (d) {
67216               if (d.id < 0) return '#iD-icon-plus';
67217               if (d.status === 'open') return '#iD-icon-close';
67218               return '#iD-icon-apply';
67219             }); // update
67220
67221             notes.merge(notesEnter).sort(sortY).classed('selected', function (d) {
67222               var mode = context.mode();
67223               var isMoving = mode && mode.id === 'drag-note'; // no shadows when dragging
67224
67225               return !isMoving && d.id === selectedID;
67226             }).attr('transform', getTransform); // Draw targets..
67227
67228             if (touchLayer.empty()) return;
67229             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67230             var targets = touchLayer.selectAll('.note').data(data, function (d) {
67231               return d.id;
67232             }); // exit
67233
67234             targets.exit().remove(); // enter/update
67235
67236             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
67237               var newClass = d.id < 0 ? 'new' : '';
67238               return 'note target note-' + d.id + ' ' + fillClass + newClass;
67239             }).attr('transform', getTransform);
67240
67241             function sortY(a, b) {
67242               if (a.id === selectedID) return 1;
67243               if (b.id === selectedID) return -1;
67244               return b.loc[1] - a.loc[1];
67245             }
67246           } // Draw the notes layer and schedule loading notes and updating markers.
67247
67248
67249           function drawNotes(selection) {
67250             var service = getService();
67251             var surface = context.surface();
67252
67253             if (surface && !surface.empty()) {
67254               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
67255             }
67256
67257             drawLayer = selection.selectAll('.layer-notes').data(service ? [0] : []);
67258             drawLayer.exit().remove();
67259             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-notes').style('display', _notesEnabled ? 'block' : 'none').merge(drawLayer);
67260
67261             if (_notesEnabled) {
67262               if (service && ~~context.map().zoom() >= minZoom) {
67263                 editOn();
67264                 service.loadNotes(projection);
67265                 updateMarkers();
67266               } else {
67267                 editOff();
67268               }
67269             }
67270           } // Toggles the layer on and off
67271
67272
67273           drawNotes.enabled = function (val) {
67274             if (!arguments.length) return _notesEnabled;
67275             _notesEnabled = val;
67276
67277             if (_notesEnabled) {
67278               layerOn();
67279             } else {
67280               layerOff();
67281
67282               if (context.selectedNoteID()) {
67283                 context.enter(modeBrowse(context));
67284               }
67285             }
67286
67287             dispatch.call('change');
67288             return this;
67289           };
67290
67291           return drawNotes;
67292         }
67293
67294         function svgTouch() {
67295           function drawTouch(selection) {
67296             selection.selectAll('.layer-touch').data(['areas', 'lines', 'points', 'turns', 'markers']).enter().append('g').attr('class', function (d) {
67297               return 'layer-touch ' + d;
67298             });
67299           }
67300
67301           return drawTouch;
67302         }
67303
67304         function refresh(selection, node) {
67305           var cr = node.getBoundingClientRect();
67306           var prop = [cr.width, cr.height];
67307           selection.property('__dimensions__', prop);
67308           return prop;
67309         }
67310
67311         function utilGetDimensions(selection, force) {
67312           if (!selection || selection.empty()) {
67313             return [0, 0];
67314           }
67315
67316           var node = selection.node(),
67317               cached = selection.property('__dimensions__');
67318           return !cached || force ? refresh(selection, node) : cached;
67319         }
67320         function utilSetDimensions(selection, dimensions) {
67321           if (!selection || selection.empty()) {
67322             return selection;
67323           }
67324
67325           var node = selection.node();
67326
67327           if (dimensions === null) {
67328             refresh(selection, node);
67329             return selection;
67330           }
67331
67332           return selection.property('__dimensions__', [dimensions[0], dimensions[1]]).attr('width', dimensions[0]).attr('height', dimensions[1]);
67333         }
67334
67335         function svgLayers(projection, context) {
67336           var dispatch = dispatch$8('change');
67337           var svg = select(null);
67338           var _layers = [{
67339             id: 'osm',
67340             layer: svgOsm(projection, context, dispatch)
67341           }, {
67342             id: 'notes',
67343             layer: svgNotes(projection, context, dispatch)
67344           }, {
67345             id: 'data',
67346             layer: svgData(projection, context, dispatch)
67347           }, {
67348             id: 'keepRight',
67349             layer: svgKeepRight(projection, context, dispatch)
67350           }, {
67351             id: 'improveOSM',
67352             layer: svgImproveOSM(projection, context, dispatch)
67353           }, {
67354             id: 'osmose',
67355             layer: svgOsmose(projection, context, dispatch)
67356           }, {
67357             id: 'streetside',
67358             layer: svgStreetside(projection, context, dispatch)
67359           }, {
67360             id: 'mapillary',
67361             layer: svgMapillaryImages(projection, context, dispatch)
67362           }, {
67363             id: 'mapillary-position',
67364             layer: svgMapillaryPosition(projection, context)
67365           }, {
67366             id: 'mapillary-map-features',
67367             layer: svgMapillaryMapFeatures(projection, context, dispatch)
67368           }, {
67369             id: 'mapillary-signs',
67370             layer: svgMapillarySigns(projection, context, dispatch)
67371           }, {
67372             id: 'openstreetcam',
67373             layer: svgOpenstreetcamImages(projection, context, dispatch)
67374           }, {
67375             id: 'debug',
67376             layer: svgDebug(projection, context)
67377           }, {
67378             id: 'geolocate',
67379             layer: svgGeolocate(projection)
67380           }, {
67381             id: 'touch',
67382             layer: svgTouch()
67383           }];
67384
67385           function drawLayers(selection) {
67386             svg = selection.selectAll('.surface').data([0]);
67387             svg = svg.enter().append('svg').attr('class', 'surface').merge(svg);
67388             var defs = svg.selectAll('.surface-defs').data([0]);
67389             defs.enter().append('defs').attr('class', 'surface-defs');
67390             var groups = svg.selectAll('.data-layer').data(_layers);
67391             groups.exit().remove();
67392             groups.enter().append('g').attr('class', function (d) {
67393               return 'data-layer ' + d.id;
67394             }).merge(groups).each(function (d) {
67395               select(this).call(d.layer);
67396             });
67397           }
67398
67399           drawLayers.all = function () {
67400             return _layers;
67401           };
67402
67403           drawLayers.layer = function (id) {
67404             var obj = _layers.find(function (o) {
67405               return o.id === id;
67406             });
67407
67408             return obj && obj.layer;
67409           };
67410
67411           drawLayers.only = function (what) {
67412             var arr = [].concat(what);
67413
67414             var all = _layers.map(function (layer) {
67415               return layer.id;
67416             });
67417
67418             return drawLayers.remove(utilArrayDifference(all, arr));
67419           };
67420
67421           drawLayers.remove = function (what) {
67422             var arr = [].concat(what);
67423             arr.forEach(function (id) {
67424               _layers = _layers.filter(function (o) {
67425                 return o.id !== id;
67426               });
67427             });
67428             dispatch.call('change');
67429             return this;
67430           };
67431
67432           drawLayers.add = function (what) {
67433             var arr = [].concat(what);
67434             arr.forEach(function (obj) {
67435               if ('id' in obj && 'layer' in obj) {
67436                 _layers.push(obj);
67437               }
67438             });
67439             dispatch.call('change');
67440             return this;
67441           };
67442
67443           drawLayers.dimensions = function (val) {
67444             if (!arguments.length) return utilGetDimensions(svg);
67445             utilSetDimensions(svg, val);
67446             return this;
67447           };
67448
67449           return utilRebind(drawLayers, dispatch, 'on');
67450         }
67451
67452         function svgLines(projection, context) {
67453           var detected = utilDetect();
67454           var highway_stack = {
67455             motorway: 0,
67456             motorway_link: 1,
67457             trunk: 2,
67458             trunk_link: 3,
67459             primary: 4,
67460             primary_link: 5,
67461             secondary: 6,
67462             tertiary: 7,
67463             unclassified: 8,
67464             residential: 9,
67465             service: 10,
67466             footway: 11
67467           };
67468
67469           function drawTargets(selection, graph, entities, filter) {
67470             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67471             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
67472             var getPath = svgPath(projection).geojson;
67473             var activeID = context.activeID();
67474             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
67475
67476             var data = {
67477               targets: [],
67478               nopes: []
67479             };
67480             entities.forEach(function (way) {
67481               var features = svgSegmentWay(way, graph, activeID);
67482               data.targets.push.apply(data.targets, features.passive);
67483               data.nopes.push.apply(data.nopes, features.active);
67484             }); // Targets allow hover and vertex snapping
67485
67486             var targetData = data.targets.filter(getPath);
67487             var targets = selection.selectAll('.line.target-allowed').filter(function (d) {
67488               return filter(d.properties.entity);
67489             }).data(targetData, function key(d) {
67490               return d.id;
67491             }); // exit
67492
67493             targets.exit().remove();
67494
67495             var segmentWasEdited = function segmentWasEdited(d) {
67496               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
67497
67498               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
67499                 return false;
67500               }
67501
67502               return d.properties.nodes.some(function (n) {
67503                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
67504               });
67505             }; // enter/update
67506
67507
67508             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
67509               return 'way line target target-allowed ' + targetClass + d.id;
67510             }).classed('segment-edited', segmentWasEdited); // NOPE
67511
67512             var nopeData = data.nopes.filter(getPath);
67513             var nopes = selection.selectAll('.line.target-nope').filter(function (d) {
67514               return filter(d.properties.entity);
67515             }).data(nopeData, function key(d) {
67516               return d.id;
67517             }); // exit
67518
67519             nopes.exit().remove(); // enter/update
67520
67521             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
67522               return 'way line target target-nope ' + nopeClass + d.id;
67523             }).classed('segment-edited', segmentWasEdited);
67524           }
67525
67526           function drawLines(selection, graph, entities, filter) {
67527             var base = context.history().base();
67528
67529             function waystack(a, b) {
67530               var selected = context.selectedIDs();
67531               var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
67532               var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
67533
67534               if (a.tags.highway) {
67535                 scoreA -= highway_stack[a.tags.highway];
67536               }
67537
67538               if (b.tags.highway) {
67539                 scoreB -= highway_stack[b.tags.highway];
67540               }
67541
67542               return scoreA - scoreB;
67543             }
67544
67545             function drawLineGroup(selection, klass, isSelected) {
67546               // Note: Don't add `.selected` class in draw modes
67547               var mode = context.mode();
67548               var isDrawing = mode && /^draw/.test(mode.id);
67549               var selectedClass = !isDrawing && isSelected ? 'selected ' : '';
67550               var lines = selection.selectAll('path').filter(filter).data(getPathData(isSelected), osmEntity.key);
67551               lines.exit().remove(); // Optimization: Call expensive TagClasses only on enter selection. This
67552               // works because osmEntity.key is defined to include the entity v attribute.
67553
67554               lines.enter().append('path').attr('class', function (d) {
67555                 var prefix = 'way line'; // if this line isn't styled by its own tags
67556
67557                 if (!d.hasInterestingTags()) {
67558                   var parentRelations = graph.parentRelations(d);
67559                   var parentMultipolygons = parentRelations.filter(function (relation) {
67560                     return relation.isMultipolygon();
67561                   }); // and if it's a member of at least one multipolygon relation
67562
67563                   if (parentMultipolygons.length > 0 && // and only multipolygon relations
67564                   parentRelations.length === parentMultipolygons.length) {
67565                     // then fudge the classes to style this as an area edge
67566                     prefix = 'relation area';
67567                   }
67568                 }
67569
67570                 var oldMPClass = oldMultiPolygonOuters[d.id] ? 'old-multipolygon ' : '';
67571                 return prefix + ' ' + klass + ' ' + selectedClass + oldMPClass + d.id;
67572               }).classed('added', function (d) {
67573                 return !base.entities[d.id];
67574               }).classed('geometry-edited', function (d) {
67575                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
67576               }).classed('retagged', function (d) {
67577                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
67578               }).call(svgTagClasses()).merge(lines).sort(waystack).attr('d', getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
67579               return selection;
67580             }
67581
67582             function getPathData(isSelected) {
67583               return function () {
67584                 var layer = this.parentNode.__data__;
67585                 var data = pathdata[layer] || [];
67586                 return data.filter(function (d) {
67587                   if (isSelected) {
67588                     return context.selectedIDs().indexOf(d.id) !== -1;
67589                   } else {
67590                     return context.selectedIDs().indexOf(d.id) === -1;
67591                   }
67592                 });
67593               };
67594             }
67595
67596             function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
67597               var markergroup = layergroup.selectAll('g.' + groupclass).data([pathclass]);
67598               markergroup = markergroup.enter().append('g').attr('class', groupclass).merge(markergroup);
67599               var markers = markergroup.selectAll('path').filter(filter).data(function data() {
67600                 return groupdata[this.parentNode.__data__] || [];
67601               }, function key(d) {
67602                 return [d.id, d.index];
67603               });
67604               markers.exit().remove();
67605               markers = markers.enter().append('path').attr('class', pathclass).merge(markers).attr('marker-mid', marker).attr('d', function (d) {
67606                 return d.d;
67607               });
67608
67609               if (detected.ie) {
67610                 markers.each(function () {
67611                   this.parentNode.insertBefore(this, this);
67612                 });
67613               }
67614             }
67615
67616             var getPath = svgPath(projection, graph);
67617             var ways = [];
67618             var onewaydata = {};
67619             var sideddata = {};
67620             var oldMultiPolygonOuters = {};
67621
67622             for (var i = 0; i < entities.length; i++) {
67623               var entity = entities[i];
67624               var outer = osmOldMultipolygonOuterMember(entity, graph);
67625
67626               if (outer) {
67627                 ways.push(entity.mergeTags(outer.tags));
67628                 oldMultiPolygonOuters[outer.id] = true;
67629               } else if (entity.geometry(graph) === 'line') {
67630                 ways.push(entity);
67631               }
67632             }
67633
67634             ways = ways.filter(getPath);
67635             var pathdata = utilArrayGroupBy(ways, function (way) {
67636               return way.layer();
67637             });
67638             Object.keys(pathdata).forEach(function (k) {
67639               var v = pathdata[k];
67640               var onewayArr = v.filter(function (d) {
67641                 return d.isOneWay();
67642               });
67643               var onewaySegments = svgMarkerSegments(projection, graph, 35, function shouldReverse(entity) {
67644                 return entity.tags.oneway === '-1';
67645               }, function bothDirections(entity) {
67646                 return entity.tags.oneway === 'reversible' || entity.tags.oneway === 'alternating';
67647               });
67648               onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
67649               var sidedArr = v.filter(function (d) {
67650                 return d.isSided();
67651               });
67652               var sidedSegments = svgMarkerSegments(projection, graph, 30, function shouldReverse() {
67653                 return false;
67654               }, function bothDirections() {
67655                 return false;
67656               });
67657               sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
67658             });
67659             var covered = selection.selectAll('.layer-osm.covered'); // under areas
67660
67661             var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
67662
67663             var touchLayer = selection.selectAll('.layer-touch.lines'); // Draw lines..
67664
67665             [covered, uncovered].forEach(function (selection) {
67666               var range = selection === covered ? range$1(-10, 0) : range$1(0, 11);
67667               var layergroup = selection.selectAll('g.layergroup').data(range);
67668               layergroup = layergroup.enter().append('g').attr('class', function (d) {
67669                 return 'layergroup layer' + String(d);
67670               }).merge(layergroup);
67671               layergroup.selectAll('g.linegroup').data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted']).enter().append('g').attr('class', function (d) {
67672                 return 'linegroup line-' + d;
67673               });
67674               layergroup.selectAll('g.line-shadow').call(drawLineGroup, 'shadow', false);
67675               layergroup.selectAll('g.line-casing').call(drawLineGroup, 'casing', false);
67676               layergroup.selectAll('g.line-stroke').call(drawLineGroup, 'stroke', false);
67677               layergroup.selectAll('g.line-shadow-highlighted').call(drawLineGroup, 'shadow', true);
67678               layergroup.selectAll('g.line-casing-highlighted').call(drawLineGroup, 'casing', true);
67679               layergroup.selectAll('g.line-stroke-highlighted').call(drawLineGroup, 'stroke', true);
67680               addMarkers(layergroup, 'oneway', 'onewaygroup', onewaydata, 'url(#ideditor-oneway-marker)');
67681               addMarkers(layergroup, 'sided', 'sidedgroup', sideddata, function marker(d) {
67682                 var category = graph.entity(d.id).sidednessIdentifier();
67683                 return 'url(#ideditor-sided-marker-' + category + ')';
67684               });
67685             }); // Draw touch targets..
67686
67687             touchLayer.call(drawTargets, graph, ways, filter);
67688           }
67689
67690           return drawLines;
67691         }
67692
67693         function svgMidpoints(projection, context) {
67694           var targetRadius = 8;
67695
67696           function drawTargets(selection, graph, entities, filter) {
67697             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67698             var getTransform = svgPointTransform(projection).geojson;
67699             var data = entities.map(function (midpoint) {
67700               return {
67701                 type: 'Feature',
67702                 id: midpoint.id,
67703                 properties: {
67704                   target: true,
67705                   entity: midpoint
67706                 },
67707                 geometry: {
67708                   type: 'Point',
67709                   coordinates: midpoint.loc
67710                 }
67711               };
67712             });
67713             var targets = selection.selectAll('.midpoint.target').filter(function (d) {
67714               return filter(d.properties.entity);
67715             }).data(data, function key(d) {
67716               return d.id;
67717             }); // exit
67718
67719             targets.exit().remove(); // enter/update
67720
67721             targets.enter().append('circle').attr('r', targetRadius).merge(targets).attr('class', function (d) {
67722               return 'node midpoint target ' + fillClass + d.id;
67723             }).attr('transform', getTransform);
67724           }
67725
67726           function drawMidpoints(selection, graph, entities, filter, extent) {
67727             var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
67728             var touchLayer = selection.selectAll('.layer-touch.points');
67729             var mode = context.mode();
67730
67731             if (mode && mode.id !== 'select' || !context.map().withinEditableZoom()) {
67732               drawLayer.selectAll('.midpoint').remove();
67733               touchLayer.selectAll('.midpoint.target').remove();
67734               return;
67735             }
67736
67737             var poly = extent.polygon();
67738             var midpoints = {};
67739
67740             for (var i = 0; i < entities.length; i++) {
67741               var entity = entities[i];
67742               if (entity.type !== 'way') continue;
67743               if (!filter(entity)) continue;
67744               if (context.selectedIDs().indexOf(entity.id) < 0) continue;
67745               var nodes = graph.childNodes(entity);
67746
67747               for (var j = 0; j < nodes.length - 1; j++) {
67748                 var a = nodes[j];
67749                 var b = nodes[j + 1];
67750                 var id = [a.id, b.id].sort().join('-');
67751
67752                 if (midpoints[id]) {
67753                   midpoints[id].parents.push(entity);
67754                 } else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
67755                   var point = geoVecInterp(a.loc, b.loc, 0.5);
67756                   var loc = null;
67757
67758                   if (extent.intersects(point)) {
67759                     loc = point;
67760                   } else {
67761                     for (var k = 0; k < 4; k++) {
67762                       point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
67763
67764                       if (point && geoVecLength(projection(a.loc), projection(point)) > 20 && geoVecLength(projection(b.loc), projection(point)) > 20) {
67765                         loc = point;
67766                         break;
67767                       }
67768                     }
67769                   }
67770
67771                   if (loc) {
67772                     midpoints[id] = {
67773                       type: 'midpoint',
67774                       id: id,
67775                       loc: loc,
67776                       edge: [a.id, b.id],
67777                       parents: [entity]
67778                     };
67779                   }
67780                 }
67781               }
67782             }
67783
67784             function midpointFilter(d) {
67785               if (midpoints[d.id]) return true;
67786
67787               for (var i = 0; i < d.parents.length; i++) {
67788                 if (filter(d.parents[i])) {
67789                   return true;
67790                 }
67791               }
67792
67793               return false;
67794             }
67795
67796             var groups = drawLayer.selectAll('.midpoint').filter(midpointFilter).data(Object.values(midpoints), function (d) {
67797               return d.id;
67798             });
67799             groups.exit().remove();
67800             var enter = groups.enter().insert('g', ':first-child').attr('class', 'midpoint');
67801             enter.append('polygon').attr('points', '-6,8 10,0 -6,-8').attr('class', 'shadow');
67802             enter.append('polygon').attr('points', '-3,4 5,0 -3,-4').attr('class', 'fill');
67803             groups = groups.merge(enter).attr('transform', function (d) {
67804               var translate = svgPointTransform(projection);
67805               var a = graph.entity(d.edge[0]);
67806               var b = graph.entity(d.edge[1]);
67807               var angle = geoAngle(a, b, projection) * (180 / Math.PI);
67808               return translate(d) + ' rotate(' + angle + ')';
67809             }).call(svgTagClasses().tags(function (d) {
67810               return d.parents[0].tags;
67811             })); // Propagate data bindings.
67812
67813             groups.select('polygon.shadow');
67814             groups.select('polygon.fill'); // Draw touch targets..
67815
67816             touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
67817           }
67818
67819           return drawMidpoints;
67820         }
67821
67822         function svgPoints(projection, context) {
67823           function markerPath(selection, klass) {
67824             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');
67825           }
67826
67827           function sortY(a, b) {
67828             return b.loc[1] - a.loc[1];
67829           } // Avoid exit/enter if we're just moving stuff around.
67830           // The node will get a new version but we only need to run the update selection.
67831
67832
67833           function fastEntityKey(d) {
67834             var mode = context.mode();
67835             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
67836             return isMoving ? d.id : osmEntity.key(d);
67837           }
67838
67839           function drawTargets(selection, graph, entities, filter) {
67840             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67841             var getTransform = svgPointTransform(projection).geojson;
67842             var activeID = context.activeID();
67843             var data = [];
67844             entities.forEach(function (node) {
67845               if (activeID === node.id) return; // draw no target on the activeID
67846
67847               data.push({
67848                 type: 'Feature',
67849                 id: node.id,
67850                 properties: {
67851                   target: true,
67852                   entity: node
67853                 },
67854                 geometry: node.asGeoJSON()
67855               });
67856             });
67857             var targets = selection.selectAll('.point.target').filter(function (d) {
67858               return filter(d.properties.entity);
67859             }).data(data, function key(d) {
67860               return d.id;
67861             }); // exit
67862
67863             targets.exit().remove(); // enter/update
67864
67865             targets.enter().append('rect').attr('x', -10).attr('y', -26).attr('width', 20).attr('height', 30).merge(targets).attr('class', function (d) {
67866               return 'node point target ' + fillClass + d.id;
67867             }).attr('transform', getTransform);
67868           }
67869
67870           function drawPoints(selection, graph, entities, filter) {
67871             var wireframe = context.surface().classed('fill-wireframe');
67872             var zoom = geoScaleToZoom(projection.scale());
67873             var base = context.history().base(); // Points with a direction will render as vertices at higher zooms..
67874
67875             function renderAsPoint(entity) {
67876               return entity.geometry(graph) === 'point' && !(zoom >= 18 && entity.directions(graph, projection).length);
67877             } // All points will render as vertices in wireframe mode too..
67878
67879
67880             var points = wireframe ? [] : entities.filter(renderAsPoint);
67881             points.sort(sortY);
67882             var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
67883             var touchLayer = selection.selectAll('.layer-touch.points'); // Draw points..
67884
67885             var groups = drawLayer.selectAll('g.point').filter(filter).data(points, fastEntityKey);
67886             groups.exit().remove();
67887             var enter = groups.enter().append('g').attr('class', function (d) {
67888               return 'node point ' + d.id;
67889             }).order();
67890             enter.append('path').call(markerPath, 'shadow');
67891             enter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
67892             enter.append('path').call(markerPath, 'stroke');
67893             enter.append('use').attr('transform', 'translate(-5, -19)').attr('class', 'icon').attr('width', '11px').attr('height', '11px');
67894             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('added', function (d) {
67895               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
67896             }).classed('moved', function (d) {
67897               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
67898             }).classed('retagged', function (d) {
67899               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
67900             }).call(svgTagClasses());
67901             groups.select('.shadow'); // propagate bound data
67902
67903             groups.select('.stroke'); // propagate bound data
67904
67905             groups.select('.icon') // propagate bound data
67906             .attr('xlink:href', function (entity) {
67907               var preset = _mainPresetIndex.match(entity, graph);
67908               var picon = preset && preset.icon;
67909
67910               if (!picon) {
67911                 return '';
67912               } else {
67913                 var isMaki = /^maki-/.test(picon);
67914                 return '#' + picon + (isMaki ? '-11' : '');
67915               }
67916             }); // Draw touch targets..
67917
67918             touchLayer.call(drawTargets, graph, points, filter);
67919           }
67920
67921           return drawPoints;
67922         }
67923
67924         function svgTurns(projection, context) {
67925           function icon(turn) {
67926             var u = turn.u ? '-u' : '';
67927             if (turn.no) return '#iD-turn-no' + u;
67928             if (turn.only) return '#iD-turn-only' + u;
67929             return '#iD-turn-yes' + u;
67930           }
67931
67932           function drawTurns(selection, graph, turns) {
67933             function turnTransform(d) {
67934               var pxRadius = 50;
67935               var toWay = graph.entity(d.to.way);
67936               var toPoints = graph.childNodes(toWay).map(function (n) {
67937                 return n.loc;
67938               }).map(projection);
67939               var toLength = geoPathLength(toPoints);
67940               var mid = toLength / 2; // midpoint of destination way
67941
67942               var toNode = graph.entity(d.to.node);
67943               var toVertex = graph.entity(d.to.vertex);
67944               var a = geoAngle(toVertex, toNode, projection);
67945               var o = projection(toVertex.loc);
67946               var r = d.u ? 0 // u-turn: no radius
67947               : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius
67948               : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways
67949
67950               return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')';
67951             }
67952
67953             var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
67954             var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns..
67955
67956             var groups = drawLayer.selectAll('g.turn').data(turns, function (d) {
67957               return d.key;
67958             }); // exit
67959
67960             groups.exit().remove(); // enter
67961
67962             var groupsEnter = groups.enter().append('g').attr('class', function (d) {
67963               return 'turn ' + d.key;
67964             });
67965             var turnsEnter = groupsEnter.filter(function (d) {
67966               return !d.u;
67967             });
67968             turnsEnter.append('rect').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
67969             turnsEnter.append('use').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
67970             var uEnter = groupsEnter.filter(function (d) {
67971               return d.u;
67972             });
67973             uEnter.append('circle').attr('r', '16');
67974             uEnter.append('use').attr('transform', 'translate(-16, -16)').attr('width', '32').attr('height', '32'); // update
67975
67976             groups = groups.merge(groupsEnter).attr('opacity', function (d) {
67977               return d.direct === false ? '0.7' : null;
67978             }).attr('transform', turnTransform);
67979             groups.select('use').attr('xlink:href', icon);
67980             groups.select('rect'); // propagate bound data
67981
67982             groups.select('circle'); // propagate bound data
67983             // Draw touch targets..
67984
67985             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67986             groups = touchLayer.selectAll('g.turn').data(turns, function (d) {
67987               return d.key;
67988             }); // exit
67989
67990             groups.exit().remove(); // enter
67991
67992             groupsEnter = groups.enter().append('g').attr('class', function (d) {
67993               return 'turn ' + d.key;
67994             });
67995             turnsEnter = groupsEnter.filter(function (d) {
67996               return !d.u;
67997             });
67998             turnsEnter.append('rect').attr('class', 'target ' + fillClass).attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
67999             uEnter = groupsEnter.filter(function (d) {
68000               return d.u;
68001             });
68002             uEnter.append('circle').attr('class', 'target ' + fillClass).attr('r', '16'); // update
68003
68004             groups = groups.merge(groupsEnter).attr('transform', turnTransform);
68005             groups.select('rect'); // propagate bound data
68006
68007             groups.select('circle'); // propagate bound data
68008
68009             return this;
68010           }
68011
68012           return drawTurns;
68013         }
68014
68015         function svgVertices(projection, context) {
68016           var radiuses = {
68017             //       z16-, z17,   z18+,  w/icon
68018             shadow: [6, 7.5, 7.5, 12],
68019             stroke: [2.5, 3.5, 3.5, 8],
68020             fill: [1, 1.5, 1.5, 1.5]
68021           };
68022
68023           var _currHoverTarget;
68024
68025           var _currPersistent = {};
68026           var _currHover = {};
68027           var _prevHover = {};
68028           var _currSelected = {};
68029           var _prevSelected = {};
68030           var _radii = {};
68031
68032           function sortY(a, b) {
68033             return b.loc[1] - a.loc[1];
68034           } // Avoid exit/enter if we're just moving stuff around.
68035           // The node will get a new version but we only need to run the update selection.
68036
68037
68038           function fastEntityKey(d) {
68039             var mode = context.mode();
68040             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
68041             return isMoving ? d.id : osmEntity.key(d);
68042           }
68043
68044           function draw(selection, graph, vertices, sets, filter) {
68045             sets = sets || {
68046               selected: {},
68047               important: {},
68048               hovered: {}
68049             };
68050             var icons = {};
68051             var directions = {};
68052             var wireframe = context.surface().classed('fill-wireframe');
68053             var zoom = geoScaleToZoom(projection.scale());
68054             var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
68055             var activeID = context.activeID();
68056             var base = context.history().base();
68057
68058             function getIcon(d) {
68059               // always check latest entity, as fastEntityKey avoids enter/exit now
68060               var entity = graph.entity(d.id);
68061               if (entity.id in icons) return icons[entity.id];
68062               icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
68063               return icons[entity.id];
68064             } // memoize directions results, return false for empty arrays (for use in filter)
68065
68066
68067             function getDirections(entity) {
68068               if (entity.id in directions) return directions[entity.id];
68069               var angles = entity.directions(graph, projection);
68070               directions[entity.id] = angles.length ? angles : false;
68071               return angles;
68072             }
68073
68074             function updateAttributes(selection) {
68075               ['shadow', 'stroke', 'fill'].forEach(function (klass) {
68076                 var rads = radiuses[klass];
68077                 selection.selectAll('.' + klass).each(function (entity) {
68078                   var i = z && getIcon(entity);
68079                   var r = rads[i ? 3 : z]; // slightly increase the size of unconnected endpoints #3775
68080
68081                   if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
68082                     r += 1.5;
68083                   }
68084
68085                   if (klass === 'shadow') {
68086                     // remember this value, so we don't need to
68087                     _radii[entity.id] = r; // recompute it when we draw the touch targets
68088                   }
68089
68090                   select(this).attr('r', r).attr('visibility', i && klass === 'fill' ? 'hidden' : null);
68091                 });
68092               });
68093             }
68094
68095             vertices.sort(sortY);
68096             var groups = selection.selectAll('g.vertex').filter(filter).data(vertices, fastEntityKey); // exit
68097
68098             groups.exit().remove(); // enter
68099
68100             var enter = groups.enter().append('g').attr('class', function (d) {
68101               return 'node vertex ' + d.id;
68102             }).order();
68103             enter.append('circle').attr('class', 'shadow');
68104             enter.append('circle').attr('class', 'stroke'); // Vertices with tags get a fill.
68105
68106             enter.filter(function (d) {
68107               return d.hasInterestingTags();
68108             }).append('circle').attr('class', 'fill'); // update
68109
68110             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('sibling', function (d) {
68111               return d.id in sets.selected;
68112             }).classed('shared', function (d) {
68113               return graph.isShared(d);
68114             }).classed('endpoint', function (d) {
68115               return d.isEndpoint(graph);
68116             }).classed('added', function (d) {
68117               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
68118             }).classed('moved', function (d) {
68119               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
68120             }).classed('retagged', function (d) {
68121               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
68122             }).call(updateAttributes); // Vertices with icons get a `use`.
68123
68124             var iconUse = groups.selectAll('.icon').data(function data(d) {
68125               return zoom >= 17 && getIcon(d) ? [d] : [];
68126             }, fastEntityKey); // exit
68127
68128             iconUse.exit().remove(); // enter
68129
68130             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) {
68131               var picon = getIcon(d);
68132               var isMaki = /^maki-/.test(picon);
68133               return '#' + picon + (isMaki ? '-11' : '');
68134             }); // Vertices with directions get viewfields
68135
68136             var dgroups = groups.selectAll('.viewfieldgroup').data(function data(d) {
68137               return zoom >= 18 && getDirections(d) ? [d] : [];
68138             }, fastEntityKey); // exit
68139
68140             dgroups.exit().remove(); // enter/update
68141
68142             dgroups = dgroups.enter().insert('g', '.shadow').attr('class', 'viewfieldgroup').merge(dgroups);
68143             var viewfields = dgroups.selectAll('.viewfield').data(getDirections, function key(d) {
68144               return osmEntity.key(d);
68145             }); // exit
68146
68147             viewfields.exit().remove(); // enter/update
68148
68149             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) {
68150               return 'rotate(' + d + ')';
68151             });
68152           }
68153
68154           function drawTargets(selection, graph, entities, filter) {
68155             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
68156             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
68157             var getTransform = svgPointTransform(projection).geojson;
68158             var activeID = context.activeID();
68159             var data = {
68160               targets: [],
68161               nopes: []
68162             };
68163             entities.forEach(function (node) {
68164               if (activeID === node.id) return; // draw no target on the activeID
68165
68166               var vertexType = svgPassiveVertex(node, graph, activeID);
68167
68168               if (vertexType !== 0) {
68169                 // passive or adjacent - allow to connect
68170                 data.targets.push({
68171                   type: 'Feature',
68172                   id: node.id,
68173                   properties: {
68174                     target: true,
68175                     entity: node
68176                   },
68177                   geometry: node.asGeoJSON()
68178                 });
68179               } else {
68180                 data.nopes.push({
68181                   type: 'Feature',
68182                   id: node.id + '-nope',
68183                   properties: {
68184                     nope: true,
68185                     target: true,
68186                     entity: node
68187                   },
68188                   geometry: node.asGeoJSON()
68189                 });
68190               }
68191             }); // Targets allow hover and vertex snapping
68192
68193             var targets = selection.selectAll('.vertex.target-allowed').filter(function (d) {
68194               return filter(d.properties.entity);
68195             }).data(data.targets, function key(d) {
68196               return d.id;
68197             }); // exit
68198
68199             targets.exit().remove(); // enter/update
68200
68201             targets.enter().append('circle').attr('r', function (d) {
68202               return _radii[d.id] || radiuses.shadow[3];
68203             }).merge(targets).attr('class', function (d) {
68204               return 'node vertex target target-allowed ' + targetClass + d.id;
68205             }).attr('transform', getTransform); // NOPE
68206
68207             var nopes = selection.selectAll('.vertex.target-nope').filter(function (d) {
68208               return filter(d.properties.entity);
68209             }).data(data.nopes, function key(d) {
68210               return d.id;
68211             }); // exit
68212
68213             nopes.exit().remove(); // enter/update
68214
68215             nopes.enter().append('circle').attr('r', function (d) {
68216               return _radii[d.properties.entity.id] || radiuses.shadow[3];
68217             }).merge(nopes).attr('class', function (d) {
68218               return 'node vertex target target-nope ' + nopeClass + d.id;
68219             }).attr('transform', getTransform);
68220           } // Points can also render as vertices:
68221           // 1. in wireframe mode or
68222           // 2. at higher zooms if they have a direction
68223
68224
68225           function renderAsVertex(entity, graph, wireframe, zoom) {
68226             var geometry = entity.geometry(graph);
68227             return geometry === 'vertex' || geometry === 'point' && (wireframe || zoom >= 18 && entity.directions(graph, projection).length);
68228           }
68229
68230           function isEditedNode(node, base, head) {
68231             var baseNode = base.entities[node.id];
68232             var headNode = head.entities[node.id];
68233             return !headNode || !baseNode || !fastDeepEqual(headNode.tags, baseNode.tags) || !fastDeepEqual(headNode.loc, baseNode.loc);
68234           }
68235
68236           function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
68237             var results = {};
68238             var seenIds = {};
68239
68240             function addChildVertices(entity) {
68241               // avoid redundant work and infinite recursion of circular relations
68242               if (seenIds[entity.id]) return;
68243               seenIds[entity.id] = true;
68244               var geometry = entity.geometry(graph);
68245
68246               if (!context.features().isHiddenFeature(entity, graph, geometry)) {
68247                 var i;
68248
68249                 if (entity.type === 'way') {
68250                   for (i = 0; i < entity.nodes.length; i++) {
68251                     var child = graph.hasEntity(entity.nodes[i]);
68252
68253                     if (child) {
68254                       addChildVertices(child);
68255                     }
68256                   }
68257                 } else if (entity.type === 'relation') {
68258                   for (i = 0; i < entity.members.length; i++) {
68259                     var member = graph.hasEntity(entity.members[i].id);
68260
68261                     if (member) {
68262                       addChildVertices(member);
68263                     }
68264                   }
68265                 } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
68266                   results[entity.id] = entity;
68267                 }
68268               }
68269             }
68270
68271             ids.forEach(function (id) {
68272               var entity = graph.hasEntity(id);
68273               if (!entity) return;
68274
68275               if (entity.type === 'node') {
68276                 if (renderAsVertex(entity, graph, wireframe, zoom)) {
68277                   results[entity.id] = entity;
68278                   graph.parentWays(entity).forEach(function (entity) {
68279                     addChildVertices(entity);
68280                   });
68281                 }
68282               } else {
68283                 // way, relation
68284                 addChildVertices(entity);
68285               }
68286             });
68287             return results;
68288           }
68289
68290           function drawVertices(selection, graph, entities, filter, extent, fullRedraw) {
68291             var wireframe = context.surface().classed('fill-wireframe');
68292             var visualDiff = context.surface().classed('highlight-edited');
68293             var zoom = geoScaleToZoom(projection.scale());
68294             var mode = context.mode();
68295             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
68296             var base = context.history().base();
68297             var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
68298             var touchLayer = selection.selectAll('.layer-touch.points');
68299
68300             if (fullRedraw) {
68301               _currPersistent = {};
68302               _radii = {};
68303             } // Collect important vertices from the `entities` list..
68304             // (during a partial redraw, it will not contain everything)
68305
68306
68307             for (var i = 0; i < entities.length; i++) {
68308               var entity = entities[i];
68309               var geometry = entity.geometry(graph);
68310               var keep = false; // a point that looks like a vertex..
68311
68312               if (geometry === 'point' && renderAsVertex(entity, graph, wireframe, zoom)) {
68313                 _currPersistent[entity.id] = entity;
68314                 keep = true; // a vertex of some importance..
68315               } else if (geometry === 'vertex' && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
68316                 _currPersistent[entity.id] = entity;
68317                 keep = true;
68318               } // whatever this is, it's not a persistent vertex..
68319
68320
68321               if (!keep && !fullRedraw) {
68322                 delete _currPersistent[entity.id];
68323               }
68324             } // 3 sets of vertices to consider:
68325
68326
68327             var sets = {
68328               persistent: _currPersistent,
68329               // persistent = important vertices (render always)
68330               selected: _currSelected,
68331               // selected + siblings of selected (render always)
68332               hovered: _currHover // hovered + siblings of hovered (render only in draw modes)
68333
68334             };
68335             var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent); // Draw the vertices..
68336             // The filter function controls the scope of what objects d3 will touch (exit/enter/update)
68337             // Adjust the filter function to expand the scope beyond whatever entities were passed in.
68338
68339             var filterRendered = function filterRendered(d) {
68340               return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
68341             };
68342
68343             drawLayer.call(draw, graph, currentVisible(all), sets, filterRendered); // Draw touch targets..
68344             // When drawing, render all targets (not just those affected by a partial redraw)
68345
68346             var filterTouch = function filterTouch(d) {
68347               return isMoving ? true : filterRendered(d);
68348             };
68349
68350             touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
68351
68352             function currentVisible(which) {
68353               return Object.keys(which).map(graph.hasEntity, graph) // the current version of this entity
68354               .filter(function (entity) {
68355                 return entity && entity.intersects(extent, graph);
68356               });
68357             }
68358           } // partial redraw - only update the selected items..
68359
68360
68361           drawVertices.drawSelected = function (selection, graph, extent) {
68362             var wireframe = context.surface().classed('fill-wireframe');
68363             var zoom = geoScaleToZoom(projection.scale());
68364             _prevSelected = _currSelected || {};
68365
68366             if (context.map().isInWideSelection()) {
68367               _currSelected = {};
68368               context.selectedIDs().forEach(function (id) {
68369                 var entity = graph.hasEntity(id);
68370                 if (!entity) return;
68371
68372                 if (entity.type === 'node') {
68373                   if (renderAsVertex(entity, graph, wireframe, zoom)) {
68374                     _currSelected[entity.id] = entity;
68375                   }
68376                 }
68377               });
68378             } else {
68379               _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
68380             } // note that drawVertices will add `_currSelected` automatically if needed..
68381
68382
68383             var filter = function filter(d) {
68384               return d.id in _prevSelected;
68385             };
68386
68387             drawVertices(selection, graph, Object.values(_prevSelected), filter, extent, false);
68388           }; // partial redraw - only update the hovered items..
68389
68390
68391           drawVertices.drawHover = function (selection, graph, target, extent) {
68392             if (target === _currHoverTarget) return; // continue only if something changed
68393
68394             var wireframe = context.surface().classed('fill-wireframe');
68395             var zoom = geoScaleToZoom(projection.scale());
68396             _prevHover = _currHover || {};
68397             _currHoverTarget = target;
68398             var entity = target && target.properties && target.properties.entity;
68399
68400             if (entity) {
68401               _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
68402             } else {
68403               _currHover = {};
68404             } // note that drawVertices will add `_currHover` automatically if needed..
68405
68406
68407             var filter = function filter(d) {
68408               return d.id in _prevHover;
68409             };
68410
68411             drawVertices(selection, graph, Object.values(_prevHover), filter, extent, false);
68412           };
68413
68414           return drawVertices;
68415         }
68416
68417         function utilBindOnce(target, type, listener, capture) {
68418           var typeOnce = type + '.once';
68419
68420           function one() {
68421             target.on(typeOnce, null);
68422             listener.apply(this, arguments);
68423           }
68424
68425           target.on(typeOnce, one, capture);
68426           return this;
68427         }
68428
68429         function defaultFilter(d3_event) {
68430           return !d3_event.ctrlKey && !d3_event.button;
68431         }
68432
68433         function defaultExtent() {
68434           var e = this;
68435
68436           if (e instanceof SVGElement) {
68437             e = e.ownerSVGElement || e;
68438
68439             if (e.hasAttribute('viewBox')) {
68440               e = e.viewBox.baseVal;
68441               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
68442             }
68443
68444             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
68445           }
68446
68447           return [[0, 0], [e.clientWidth, e.clientHeight]];
68448         }
68449
68450         function defaultWheelDelta(d3_event) {
68451           return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 0.002);
68452         }
68453
68454         function defaultConstrain(transform, extent, translateExtent) {
68455           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
68456               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
68457               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
68458               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
68459           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));
68460         }
68461
68462         function utilZoomPan() {
68463           var filter = defaultFilter,
68464               extent = defaultExtent,
68465               constrain = defaultConstrain,
68466               wheelDelta = defaultWheelDelta,
68467               scaleExtent = [0, Infinity],
68468               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
68469               interpolate = interpolateZoom,
68470               dispatch = dispatch$8('start', 'zoom', 'end'),
68471               _wheelDelay = 150,
68472               _transform = identity$2,
68473               _activeGesture;
68474
68475           function zoom(selection) {
68476             selection.on('pointerdown.zoom', pointerdown).on('wheel.zoom', wheeled).style('touch-action', 'none').style('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
68477             select(window).on('pointermove.zoompan', pointermove).on('pointerup.zoompan pointercancel.zoompan', pointerup);
68478           }
68479
68480           zoom.transform = function (collection, transform, point) {
68481             var selection = collection.selection ? collection.selection() : collection;
68482
68483             if (collection !== selection) {
68484               schedule(collection, transform, point);
68485             } else {
68486               selection.interrupt().each(function () {
68487                 gesture(this, arguments).start(null).zoom(null, null, typeof transform === 'function' ? transform.apply(this, arguments) : transform).end(null);
68488               });
68489             }
68490           };
68491
68492           zoom.scaleBy = function (selection, k, p) {
68493             zoom.scaleTo(selection, function () {
68494               var k0 = _transform.k,
68495                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
68496               return k0 * k1;
68497             }, p);
68498           };
68499
68500           zoom.scaleTo = function (selection, k, p) {
68501             zoom.transform(selection, function () {
68502               var e = extent.apply(this, arguments),
68503                   t0 = _transform,
68504                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p,
68505                   p1 = t0.invert(p0),
68506                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
68507               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
68508             }, p);
68509           };
68510
68511           zoom.translateBy = function (selection, x, y) {
68512             zoom.transform(selection, function () {
68513               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);
68514             });
68515           };
68516
68517           zoom.translateTo = function (selection, x, y, p) {
68518             zoom.transform(selection, function () {
68519               var e = extent.apply(this, arguments),
68520                   t = _transform,
68521                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p;
68522               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);
68523             }, p);
68524           };
68525
68526           function scale(transform, k) {
68527             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
68528             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
68529           }
68530
68531           function translate(transform, p0, p1) {
68532             var x = p0[0] - p1[0] * transform.k,
68533                 y = p0[1] - p1[1] * transform.k;
68534             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
68535           }
68536
68537           function centroid(extent) {
68538             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
68539           }
68540
68541           function schedule(transition, transform, point) {
68542             transition.on('start.zoom', function () {
68543               gesture(this, arguments).start(null);
68544             }).on('interrupt.zoom end.zoom', function () {
68545               gesture(this, arguments).end(null);
68546             }).tween('zoom', function () {
68547               var that = this,
68548                   args = arguments,
68549                   g = gesture(that, args),
68550                   e = extent.apply(that, args),
68551                   p = !point ? centroid(e) : typeof point === 'function' ? point.apply(that, args) : point,
68552                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
68553                   a = _transform,
68554                   b = typeof transform === 'function' ? transform.apply(that, args) : transform,
68555                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
68556               return function (t) {
68557                 if (t === 1) {
68558                   // Avoid rounding error on end.
68559                   t = b;
68560                 } else {
68561                   var l = i(t);
68562                   var k = w / l[2];
68563                   t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
68564                 }
68565
68566                 g.zoom(null, null, t);
68567               };
68568             });
68569           }
68570
68571           function gesture(that, args, clean) {
68572             return !clean && _activeGesture || new Gesture(that, args);
68573           }
68574
68575           function Gesture(that, args) {
68576             this.that = that;
68577             this.args = args;
68578             this.active = 0;
68579             this.extent = extent.apply(that, args);
68580           }
68581
68582           Gesture.prototype = {
68583             start: function start(d3_event) {
68584               if (++this.active === 1) {
68585                 _activeGesture = this;
68586                 dispatch.call('start', this, d3_event);
68587               }
68588
68589               return this;
68590             },
68591             zoom: function zoom(d3_event, key, transform) {
68592               if (this.mouse && key !== 'mouse') this.mouse[1] = transform.invert(this.mouse[0]);
68593               if (this.pointer0 && key !== 'touch') this.pointer0[1] = transform.invert(this.pointer0[0]);
68594               if (this.pointer1 && key !== 'touch') this.pointer1[1] = transform.invert(this.pointer1[0]);
68595               _transform = transform;
68596               dispatch.call('zoom', this, d3_event, key, transform);
68597               return this;
68598             },
68599             end: function end(d3_event) {
68600               if (--this.active === 0) {
68601                 _activeGesture = null;
68602                 dispatch.call('end', this, d3_event);
68603               }
68604
68605               return this;
68606             }
68607           };
68608
68609           function wheeled(d3_event) {
68610             if (!filter.apply(this, arguments)) return;
68611             var g = gesture(this, arguments),
68612                 t = _transform,
68613                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
68614                 p = utilFastMouse(this)(d3_event); // If the mouse is in the same location as before, reuse it.
68615             // If there were recent wheel events, reset the wheel idle timeout.
68616
68617             if (g.wheel) {
68618               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
68619                 g.mouse[1] = t.invert(g.mouse[0] = p);
68620               }
68621
68622               clearTimeout(g.wheel); // Otherwise, capture the mouse point and location at the start.
68623             } else {
68624               g.mouse = [p, t.invert(p)];
68625               interrupt(this);
68626               g.start(d3_event);
68627             }
68628
68629             d3_event.preventDefault();
68630             d3_event.stopImmediatePropagation();
68631             g.wheel = setTimeout(wheelidled, _wheelDelay);
68632             g.zoom(d3_event, 'mouse', constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
68633
68634             function wheelidled() {
68635               g.wheel = null;
68636               g.end(d3_event);
68637             }
68638           }
68639
68640           var _downPointerIDs = new Set();
68641
68642           var _pointerLocGetter;
68643
68644           function pointerdown(d3_event) {
68645             _downPointerIDs.add(d3_event.pointerId);
68646
68647             if (!filter.apply(this, arguments)) return;
68648             var g = gesture(this, arguments, _downPointerIDs.size === 1);
68649             var started;
68650             d3_event.stopImmediatePropagation();
68651             _pointerLocGetter = utilFastMouse(this);
68652
68653             var loc = _pointerLocGetter(d3_event);
68654
68655             var p = [loc, _transform.invert(loc), d3_event.pointerId];
68656
68657             if (!g.pointer0) {
68658               g.pointer0 = p;
68659               started = true;
68660             } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
68661               g.pointer1 = p;
68662             }
68663
68664             if (started) {
68665               interrupt(this);
68666               g.start(d3_event);
68667             }
68668           }
68669
68670           function pointermove(d3_event) {
68671             if (!_downPointerIDs.has(d3_event.pointerId)) return;
68672             if (!_activeGesture || !_pointerLocGetter) return;
68673             var g = gesture(this, arguments);
68674             var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
68675             var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
68676
68677             if ((isPointer0 || isPointer1) && 'buttons' in d3_event && !d3_event.buttons) {
68678               // The pointer went up without ending the gesture somehow, e.g.
68679               // a down mouse was moved off the map and released. End it here.
68680               if (g.pointer0) _downPointerIDs["delete"](g.pointer0[2]);
68681               if (g.pointer1) _downPointerIDs["delete"](g.pointer1[2]);
68682               g.end(d3_event);
68683               return;
68684             }
68685
68686             d3_event.preventDefault();
68687             d3_event.stopImmediatePropagation();
68688
68689             var loc = _pointerLocGetter(d3_event);
68690
68691             var t, p, l;
68692             if (isPointer0) g.pointer0[0] = loc;else if (isPointer1) g.pointer1[0] = loc;
68693             t = _transform;
68694
68695             if (g.pointer1) {
68696               var p0 = g.pointer0[0],
68697                   l0 = g.pointer0[1],
68698                   p1 = g.pointer1[0],
68699                   l1 = g.pointer1[1],
68700                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
68701                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
68702               t = scale(t, Math.sqrt(dp / dl));
68703               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
68704               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
68705             } else if (g.pointer0) {
68706               p = g.pointer0[0];
68707               l = g.pointer0[1];
68708             } else {
68709               return;
68710             }
68711
68712             g.zoom(d3_event, 'touch', constrain(translate(t, p, l), g.extent, translateExtent));
68713           }
68714
68715           function pointerup(d3_event) {
68716             if (!_downPointerIDs.has(d3_event.pointerId)) return;
68717
68718             _downPointerIDs["delete"](d3_event.pointerId);
68719
68720             if (!_activeGesture) return;
68721             var g = gesture(this, arguments);
68722             d3_event.stopImmediatePropagation();
68723             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;
68724
68725             if (g.pointer1 && !g.pointer0) {
68726               g.pointer0 = g.pointer1;
68727               delete g.pointer1;
68728             }
68729
68730             if (g.pointer0) {
68731               g.pointer0[1] = _transform.invert(g.pointer0[0]);
68732             } else {
68733               g.end(d3_event);
68734             }
68735           }
68736
68737           zoom.wheelDelta = function (_) {
68738             return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
68739           };
68740
68741           zoom.filter = function (_) {
68742             return arguments.length ? (filter = utilFunctor(!!_), zoom) : filter;
68743           };
68744
68745           zoom.extent = function (_) {
68746             return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
68747           };
68748
68749           zoom.scaleExtent = function (_) {
68750             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
68751           };
68752
68753           zoom.translateExtent = function (_) {
68754             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]]];
68755           };
68756
68757           zoom.constrain = function (_) {
68758             return arguments.length ? (constrain = _, zoom) : constrain;
68759           };
68760
68761           zoom.interpolate = function (_) {
68762             return arguments.length ? (interpolate = _, zoom) : interpolate;
68763           };
68764
68765           zoom._transform = function (_) {
68766             return arguments.length ? (_transform = _, zoom) : _transform;
68767           };
68768
68769           return utilRebind(zoom, dispatch, 'on');
68770         }
68771
68772         // if pointer events are supported. Falls back to default `dblclick` event.
68773
68774         function utilDoubleUp() {
68775           var dispatch = dispatch$8('doubleUp');
68776           var _maxTimespan = 500; // milliseconds
68777
68778           var _maxDistance = 20; // web pixels; be somewhat generous to account for touch devices
68779
68780           var _pointer; // object representing the pointer that could trigger double up
68781
68782
68783           function pointerIsValidFor(loc) {
68784             // second pointerup must occur within a small timeframe after the first pointerdown
68785             return new Date().getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
68786             geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
68787           }
68788
68789           function pointerdown(d3_event) {
68790             // ignore right-click
68791             if (d3_event.ctrlKey || d3_event.button === 2) return;
68792             var loc = [d3_event.clientX, d3_event.clientY]; // Don't rely on pointerId here since it can change between pointerdown
68793             // events on touch devices
68794
68795             if (_pointer && !pointerIsValidFor(loc)) {
68796               // if this pointer is no longer valid, clear it so another can be started
68797               _pointer = undefined;
68798             }
68799
68800             if (!_pointer) {
68801               _pointer = {
68802                 startLoc: loc,
68803                 startTime: new Date().getTime(),
68804                 upCount: 0,
68805                 pointerId: d3_event.pointerId
68806               };
68807             } else {
68808               // double down
68809               _pointer.pointerId = d3_event.pointerId;
68810             }
68811           }
68812
68813           function pointerup(d3_event) {
68814             // ignore right-click
68815             if (d3_event.ctrlKey || d3_event.button === 2) return;
68816             if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
68817             _pointer.upCount += 1;
68818
68819             if (_pointer.upCount === 2) {
68820               // double up!
68821               var loc = [d3_event.clientX, d3_event.clientY];
68822
68823               if (pointerIsValidFor(loc)) {
68824                 var locInThis = utilFastMouse(this)(d3_event);
68825                 dispatch.call('doubleUp', this, d3_event, locInThis);
68826               } // clear the pointer info in any case
68827
68828
68829               _pointer = undefined;
68830             }
68831           }
68832
68833           function doubleUp(selection) {
68834             if ('PointerEvent' in window) {
68835               // dblclick isn't well supported on touch devices so manually use
68836               // pointer events if they're available
68837               selection.on('pointerdown.doubleUp', pointerdown).on('pointerup.doubleUp', pointerup);
68838             } else {
68839               // fallback to dblclick
68840               selection.on('dblclick.doubleUp', function (d3_event) {
68841                 dispatch.call('doubleUp', this, d3_event, utilFastMouse(this)(d3_event));
68842               });
68843             }
68844           }
68845
68846           doubleUp.off = function (selection) {
68847             selection.on('pointerdown.doubleUp', null).on('pointerup.doubleUp', null).on('dblclick.doubleUp', null);
68848           };
68849
68850           return utilRebind(doubleUp, dispatch, 'on');
68851         }
68852
68853         var TILESIZE = 256;
68854         var minZoom = 2;
68855         var maxZoom = 24;
68856         var kMin = geoZoomToScale(minZoom, TILESIZE);
68857         var kMax = geoZoomToScale(maxZoom, TILESIZE);
68858
68859         function clamp$1(num, min, max) {
68860           return Math.max(min, Math.min(num, max));
68861         }
68862
68863         function rendererMap(context) {
68864           var dispatch = dispatch$8('move', 'drawn', 'crossEditableZoom', 'hitMinZoom', 'changeHighlighting', 'changeAreaFill');
68865           var projection = context.projection;
68866           var curtainProjection = context.curtainProjection;
68867           var drawLayers;
68868           var drawPoints;
68869           var drawVertices;
68870           var drawLines;
68871           var drawAreas;
68872           var drawMidpoints;
68873           var drawLabels;
68874
68875           var _selection = select(null);
68876
68877           var supersurface = select(null);
68878           var wrapper = select(null);
68879           var surface = select(null);
68880           var _dimensions = [1, 1];
68881           var _dblClickZoomEnabled = true;
68882           var _redrawEnabled = true;
68883
68884           var _gestureTransformStart;
68885
68886           var _transformStart = projection.transform();
68887
68888           var _transformLast;
68889
68890           var _isTransformed = false;
68891           var _minzoom = 0;
68892
68893           var _getMouseCoords;
68894
68895           var _lastPointerEvent;
68896
68897           var _lastWithinEditableZoom; // whether a pointerdown event started the zoom
68898
68899
68900           var _pointerDown = false; // use pointer events on supported platforms; fallback to mouse events
68901
68902           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom
68903
68904
68905           var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom;
68906
68907           var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(interpolate$1).filter(zoomEventFilter).on('zoom.map', zoomPan).on('start.map', function (d3_event) {
68908             _pointerDown = d3_event && (d3_event.type === 'pointerdown' || d3_event.sourceEvent && d3_event.sourceEvent.type === 'pointerdown');
68909           }).on('end.map', function () {
68910             _pointerDown = false;
68911           });
68912
68913           var _doubleUpHandler = utilDoubleUp();
68914
68915           var scheduleRedraw = throttle(redraw, 750); // var isRedrawScheduled = false;
68916           // var pendingRedrawCall;
68917           // function scheduleRedraw() {
68918           //     // Only schedule the redraw if one has not already been set.
68919           //     if (isRedrawScheduled) return;
68920           //     isRedrawScheduled = true;
68921           //     var that = this;
68922           //     var args = arguments;
68923           //     pendingRedrawCall = window.requestIdleCallback(function () {
68924           //         // Reset the boolean so future redraws can be set.
68925           //         isRedrawScheduled = false;
68926           //         redraw.apply(that, args);
68927           //     }, { timeout: 1400 });
68928           // }
68929
68930
68931           function cancelPendingRedraw() {
68932             scheduleRedraw.cancel(); // isRedrawScheduled = false;
68933             // window.cancelIdleCallback(pendingRedrawCall);
68934           }
68935
68936           function map(selection) {
68937             _selection = selection;
68938             context.on('change.map', immediateRedraw);
68939             var osm = context.connection();
68940
68941             if (osm) {
68942               osm.on('change.map', immediateRedraw);
68943             }
68944
68945             function didUndoOrRedo(targetTransform) {
68946               var mode = context.mode().id;
68947               if (mode !== 'browse' && mode !== 'select') return;
68948
68949               if (targetTransform) {
68950                 map.transformEase(targetTransform);
68951               }
68952             }
68953
68954             context.history().on('merge.map', function () {
68955               scheduleRedraw();
68956             }).on('change.map', immediateRedraw).on('undone.map', function (stack, fromStack) {
68957               didUndoOrRedo(fromStack.transform);
68958             }).on('redone.map', function (stack) {
68959               didUndoOrRedo(stack.transform);
68960             });
68961             context.background().on('change.map', immediateRedraw);
68962             context.features().on('redraw.map', immediateRedraw);
68963             drawLayers.on('change.map', function () {
68964               context.background().updateImagery();
68965               immediateRedraw();
68966             });
68967             selection.on('wheel.map mousewheel.map', function (d3_event) {
68968               // disable swipe-to-navigate browser pages on trackpad/magic mouse – #5552
68969               d3_event.preventDefault();
68970             }).call(_zoomerPanner).call(_zoomerPanner.transform, projection.transform()).on('dblclick.zoom', null); // override d3-zoom dblclick handling
68971
68972             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
68973             // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
68974
68975             wrapper = supersurface.append('div').attr('class', 'layer layer-data');
68976             map.surface = surface = wrapper.call(drawLayers).selectAll('.surface');
68977             surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + 'down.zoom', function (d3_event) {
68978               _lastPointerEvent = d3_event;
68979
68980               if (d3_event.button === 2) {
68981                 d3_event.stopPropagation();
68982               }
68983             }, true).on(_pointerPrefix + 'up.zoom', function (d3_event) {
68984               _lastPointerEvent = d3_event;
68985
68986               if (resetTransform()) {
68987                 immediateRedraw();
68988               }
68989             }).on(_pointerPrefix + 'move.map', function (d3_event) {
68990               _lastPointerEvent = d3_event;
68991             }).on(_pointerPrefix + 'over.vertices', function (d3_event) {
68992               if (map.editableDataEnabled() && !_isTransformed) {
68993                 var hover = d3_event.target.__data__;
68994                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
68995                 dispatch.call('drawn', this, {
68996                   full: false
68997                 });
68998               }
68999             }).on(_pointerPrefix + 'out.vertices', function (d3_event) {
69000               if (map.editableDataEnabled() && !_isTransformed) {
69001                 var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
69002                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
69003                 dispatch.call('drawn', this, {
69004                   full: false
69005                 });
69006               }
69007             });
69008             var detected = utilDetect(); // only WebKit supports gesture events
69009
69010             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
69011             // but we only need to do this on desktop Safari anyway. – #7694
69012             !detected.isMobileWebKit) {
69013               // Desktop Safari sends gesture events for multitouch trackpad pinches.
69014               // We can listen for these and translate them into map zooms.
69015               surface.on('gesturestart.surface', function (d3_event) {
69016                 d3_event.preventDefault();
69017                 _gestureTransformStart = projection.transform();
69018               }).on('gesturechange.surface', gestureChange);
69019             } // must call after surface init
69020
69021
69022             updateAreaFill();
69023
69024             _doubleUpHandler.on('doubleUp.map', function (d3_event, p0) {
69025               if (!_dblClickZoomEnabled) return; // don't zoom if targeting something other than the map itself
69026
69027               if (_typeof(d3_event.target.__data__) === 'object' && // or area fills
69028               !select(d3_event.target).classed('fill')) return;
69029               var zoomOut = d3_event.shiftKey;
69030               var t = projection.transform();
69031               var p1 = t.invert(p0);
69032               t = t.scale(zoomOut ? 0.5 : 2);
69033               t.x = p0[0] - p1[0] * t.k;
69034               t.y = p0[1] - p1[1] * t.k;
69035               map.transformEase(t);
69036             });
69037
69038             context.on('enter.map', function () {
69039               if (!map.editableDataEnabled(true
69040               /* skip zoom check */
69041               )) return;
69042               if (_isTransformed) return; // redraw immediately any objects affected by a change in selectedIDs.
69043
69044               var graph = context.graph();
69045               var selectedAndParents = {};
69046               context.selectedIDs().forEach(function (id) {
69047                 var entity = graph.hasEntity(id);
69048
69049                 if (entity) {
69050                   selectedAndParents[entity.id] = entity;
69051
69052                   if (entity.type === 'node') {
69053                     graph.parentWays(entity).forEach(function (parent) {
69054                       selectedAndParents[parent.id] = parent;
69055                     });
69056                   }
69057                 }
69058               });
69059               var data = Object.values(selectedAndParents);
69060
69061               var filter = function filter(d) {
69062                 return d.id in selectedAndParents;
69063               };
69064
69065               data = context.features().filter(data, graph);
69066               surface.call(drawVertices.drawSelected, graph, map.extent()).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent());
69067               dispatch.call('drawn', this, {
69068                 full: false
69069               }); // redraw everything else later
69070
69071               scheduleRedraw();
69072             });
69073             map.dimensions(utilGetDimensions(selection));
69074           }
69075
69076           function zoomEventFilter(d3_event) {
69077             // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
69078             // Intercept `mousedown` and check if there is an orphaned zoom gesture.
69079             // This can happen if a previous `mousedown` occurred without a `mouseup`.
69080             // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
69081             // so that d3-zoom won't stop propagation of new `mousedown` events.
69082             if (d3_event.type === 'mousedown') {
69083               var hasOrphan = false;
69084               var listeners = window.__on;
69085
69086               for (var i = 0; i < listeners.length; i++) {
69087                 var listener = listeners[i];
69088
69089                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
69090                   hasOrphan = true;
69091                   break;
69092                 }
69093               }
69094
69095               if (hasOrphan) {
69096                 var event = window.CustomEvent;
69097
69098                 if (event) {
69099                   event = new event('mouseup');
69100                 } else {
69101                   event = window.document.createEvent('Event');
69102                   event.initEvent('mouseup', false, false);
69103                 } // Event needs to be dispatched with an event.view property.
69104
69105
69106                 event.view = window;
69107                 window.dispatchEvent(event);
69108               }
69109             }
69110
69111             return d3_event.button !== 2; // ignore right clicks
69112           }
69113
69114           function pxCenter() {
69115             return [_dimensions[0] / 2, _dimensions[1] / 2];
69116           }
69117
69118           function drawEditable(difference, extent) {
69119             var mode = context.mode();
69120             var graph = context.graph();
69121             var features = context.features();
69122             var all = context.history().intersects(map.extent());
69123             var fullRedraw = false;
69124             var data;
69125             var set;
69126             var filter;
69127             var applyFeatureLayerFilters = true;
69128
69129             if (map.isInWideSelection()) {
69130               data = [];
69131               utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function (id) {
69132                 var entity = context.hasEntity(id);
69133                 if (entity) data.push(entity);
69134               });
69135               fullRedraw = true;
69136               filter = utilFunctor(true); // selected features should always be visible, so we can skip filtering
69137
69138               applyFeatureLayerFilters = false;
69139             } else if (difference) {
69140               var complete = difference.complete(map.extent());
69141               data = Object.values(complete).filter(Boolean);
69142               set = new Set(Object.keys(complete));
69143
69144               filter = function filter(d) {
69145                 return set.has(d.id);
69146               };
69147
69148               features.clear(data);
69149             } else {
69150               // force a full redraw if gatherStats detects that a feature
69151               // should be auto-hidden (e.g. points or buildings)..
69152               if (features.gatherStats(all, graph, _dimensions)) {
69153                 extent = undefined;
69154               }
69155
69156               if (extent) {
69157                 data = context.history().intersects(map.extent().intersection(extent));
69158                 set = new Set(data.map(function (entity) {
69159                   return entity.id;
69160                 }));
69161
69162                 filter = function filter(d) {
69163                   return set.has(d.id);
69164                 };
69165               } else {
69166                 data = all;
69167                 fullRedraw = true;
69168                 filter = utilFunctor(true);
69169               }
69170             }
69171
69172             if (applyFeatureLayerFilters) {
69173               data = features.filter(data, graph);
69174             } else {
69175               context.features().resetStats();
69176             }
69177
69178             if (mode && mode.id === 'select') {
69179               // update selected vertices - the user might have just double-clicked a way,
69180               // creating a new vertex, triggering a partial redraw without a mode change
69181               surface.call(drawVertices.drawSelected, graph, map.extent());
69182             }
69183
69184             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);
69185             dispatch.call('drawn', this, {
69186               full: true
69187             });
69188           }
69189
69190           map.init = function () {
69191             drawLayers = svgLayers(projection, context);
69192             drawPoints = svgPoints(projection, context);
69193             drawVertices = svgVertices(projection, context);
69194             drawLines = svgLines(projection, context);
69195             drawAreas = svgAreas(projection, context);
69196             drawMidpoints = svgMidpoints(projection, context);
69197             drawLabels = svgLabels(projection, context);
69198           };
69199
69200           function editOff() {
69201             context.features().resetStats();
69202             surface.selectAll('.layer-osm *').remove();
69203             surface.selectAll('.layer-touch:not(.markers) *').remove();
69204             var allowed = {
69205               'browse': true,
69206               'save': true,
69207               'select-note': true,
69208               'select-data': true,
69209               'select-error': true
69210             };
69211             var mode = context.mode();
69212
69213             if (mode && !allowed[mode.id]) {
69214               context.enter(modeBrowse(context));
69215             }
69216
69217             dispatch.call('drawn', this, {
69218               full: true
69219             });
69220           }
69221
69222           function gestureChange(d3_event) {
69223             // Remap Safari gesture events to wheel events - #5492
69224             // We want these disabled most places, but enabled for zoom/unzoom on map surface
69225             // https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
69226             var e = d3_event;
69227             e.preventDefault();
69228             var props = {
69229               deltaMode: 0,
69230               // dummy values to ignore in zoomPan
69231               deltaY: 1,
69232               // dummy values to ignore in zoomPan
69233               clientX: e.clientX,
69234               clientY: e.clientY,
69235               screenX: e.screenX,
69236               screenY: e.screenY,
69237               x: e.x,
69238               y: e.y
69239             };
69240             var e2 = new WheelEvent('wheel', props);
69241             e2._scale = e.scale; // preserve the original scale
69242
69243             e2._rotation = e.rotation; // preserve the original rotation
69244
69245             _selection.node().dispatchEvent(e2);
69246           }
69247
69248           function zoomPan(event, key, transform) {
69249             var source = event && event.sourceEvent || event;
69250             var eventTransform = transform || event && event.transform;
69251             var x = eventTransform.x;
69252             var y = eventTransform.y;
69253             var k = eventTransform.k; // Special handling of 'wheel' events:
69254             // They might be triggered by the user scrolling the mouse wheel,
69255             // or 2-finger pinch/zoom gestures, the transform may need adjustment.
69256
69257             if (source && source.type === 'wheel') {
69258               // assume that the gesture is already handled by pointer events
69259               if (_pointerDown) return;
69260               var detected = utilDetect();
69261               var dX = source.deltaX;
69262               var dY = source.deltaY;
69263               var x2 = x;
69264               var y2 = y;
69265               var k2 = k;
69266               var t0, p0, p1; // Normalize mousewheel scroll speed (Firefox) - #3029
69267               // If wheel delta is provided in LINE units, recalculate it in PIXEL units
69268               // We are essentially redoing the calculations that occur here:
69269               //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
69270               // See this for more info:
69271               //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
69272
69273               if (source.deltaMode === 1
69274               /* LINE */
69275               ) {
69276                   // Convert from lines to pixels, more if the user is scrolling fast.
69277                   // (I made up the exp function to roughly match Firefox to what Chrome does)
69278                   // These numbers should be floats, because integers are treated as pan gesture below.
69279                   var lines = Math.abs(source.deltaY);
69280                   var sign = source.deltaY > 0 ? 1 : -1;
69281                   dY = sign * clamp$1(Math.exp((lines - 1) * 0.75) * 4.000244140625, 4.000244140625, // min
69282                   350.000244140625 // max
69283                   ); // On Firefox Windows and Linux we always get +/- the scroll line amount (default 3)
69284                   // There doesn't seem to be any scroll acceleration.
69285                   // This multiplier increases the speed a little bit - #5512
69286
69287                   if (detected.os !== 'mac') {
69288                     dY *= 5;
69289                   } // recalculate x2,y2,k2
69290
69291
69292                   t0 = _isTransformed ? _transformLast : _transformStart;
69293                   p0 = _getMouseCoords(source);
69294                   p1 = t0.invert(p0);
69295                   k2 = t0.k * Math.pow(2, -dY / 500);
69296                   k2 = clamp$1(k2, kMin, kMax);
69297                   x2 = p0[0] - p1[0] * k2;
69298                   y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (Safari) - #5492
69299                   // These are fake `wheel` events we made from Safari `gesturechange` events..
69300                 } else if (source._scale) {
69301                 // recalculate x2,y2,k2
69302                 t0 = _gestureTransformStart;
69303                 p0 = _getMouseCoords(source);
69304                 p1 = t0.invert(p0);
69305                 k2 = t0.k * source._scale;
69306                 k2 = clamp$1(k2, kMin, kMax);
69307                 x2 = p0[0] - p1[0] * k2;
69308                 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (all browsers except Safari) - #5492
69309                 // Pinch zooming via the `wheel` event will always have:
69310                 // - `ctrlKey = true`
69311                 // - `deltaY` is not round integer pixels (ignore `deltaX`)
69312               } else if (source.ctrlKey && !isInteger(dY)) {
69313                 dY *= 6; // slightly scale up whatever the browser gave us
69314                 // recalculate x2,y2,k2
69315
69316                 t0 = _isTransformed ? _transformLast : _transformStart;
69317                 p0 = _getMouseCoords(source);
69318                 p1 = t0.invert(p0);
69319                 k2 = t0.k * Math.pow(2, -dY / 500);
69320                 k2 = clamp$1(k2, kMin, kMax);
69321                 x2 = p0[0] - p1[0] * k2;
69322                 y2 = p0[1] - p1[1] * k2; // Trackpad scroll zooming with shift or alt/option key down
69323               } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
69324                 // recalculate x2,y2,k2
69325                 t0 = _isTransformed ? _transformLast : _transformStart;
69326                 p0 = _getMouseCoords(source);
69327                 p1 = t0.invert(p0);
69328                 k2 = t0.k * Math.pow(2, -dY / 500);
69329                 k2 = clamp$1(k2, kMin, kMax);
69330                 x2 = p0[0] - p1[0] * k2;
69331                 y2 = p0[1] - p1[1] * k2; // 2 finger map panning (Mac only, all browsers except Firefox #8595) - #5492, #5512
69332                 // Panning via the `wheel` event will always have:
69333                 // - `ctrlKey = false`
69334                 // - `deltaX`,`deltaY` are round integer pixels
69335               } else if (detected.os === 'mac' && detected.browser !== 'Firefox' && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
69336                 p1 = projection.translate();
69337                 x2 = p1[0] - dX;
69338                 y2 = p1[1] - dY;
69339                 k2 = projection.scale();
69340                 k2 = clamp$1(k2, kMin, kMax);
69341               } // something changed - replace the event transform
69342
69343
69344               if (x2 !== x || y2 !== y || k2 !== k) {
69345                 x = x2;
69346                 y = y2;
69347                 k = k2;
69348                 eventTransform = identity$2.translate(x2, y2).scale(k2);
69349
69350                 if (_zoomerPanner._transform) {
69351                   // utilZoomPan interface
69352                   _zoomerPanner._transform(eventTransform);
69353                 } else {
69354                   // d3_zoom interface
69355                   _selection.node().__zoom = eventTransform;
69356                 }
69357               }
69358             }
69359
69360             if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
69361               return; // no change
69362             }
69363
69364             if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
69365               surface.interrupt();
69366               dispatch.call('hitMinZoom', this, map);
69367               setCenterZoom(map.center(), context.minEditableZoom(), 0, true);
69368               scheduleRedraw();
69369               dispatch.call('move', this, map);
69370               return;
69371             }
69372
69373             projection.transform(eventTransform);
69374             var withinEditableZoom = map.withinEditableZoom();
69375
69376             if (_lastWithinEditableZoom !== withinEditableZoom) {
69377               if (_lastWithinEditableZoom !== undefined) {
69378                 // notify that the map zoomed in or out over the editable zoom threshold
69379                 dispatch.call('crossEditableZoom', this, withinEditableZoom);
69380               }
69381
69382               _lastWithinEditableZoom = withinEditableZoom;
69383             }
69384
69385             var scale = k / _transformStart.k;
69386             var tX = (x / scale - _transformStart.x) * scale;
69387             var tY = (y / scale - _transformStart.y) * scale;
69388
69389             if (context.inIntro()) {
69390               curtainProjection.transform({
69391                 x: x - tX,
69392                 y: y - tY,
69393                 k: k
69394               });
69395             }
69396
69397             if (source) {
69398               _lastPointerEvent = event;
69399             }
69400
69401             _isTransformed = true;
69402             _transformLast = eventTransform;
69403             utilSetTransform(supersurface, tX, tY, scale);
69404             scheduleRedraw();
69405             dispatch.call('move', this, map);
69406
69407             function isInteger(val) {
69408               return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
69409             }
69410           }
69411
69412           function resetTransform() {
69413             if (!_isTransformed) return false;
69414             utilSetTransform(supersurface, 0, 0);
69415             _isTransformed = false;
69416
69417             if (context.inIntro()) {
69418               curtainProjection.transform(projection.transform());
69419             }
69420
69421             return true;
69422           }
69423
69424           function redraw(difference, extent) {
69425             if (surface.empty() || !_redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws.
69426             // It would result in artifacts where differenced entities are redrawn with
69427             // one transform and unchanged entities with another.
69428
69429             if (resetTransform()) {
69430               difference = extent = undefined;
69431             }
69432
69433             var zoom = map.zoom();
69434             var z = String(~~zoom);
69435
69436             if (surface.attr('data-zoom') !== z) {
69437               surface.attr('data-zoom', z);
69438             } // class surface as `lowzoom` around z17-z18.5 (based on latitude)
69439
69440
69441             var lat = map.center()[1];
69442             var lowzoom = linear().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
69443             surface.classed('low-zoom', zoom <= lowzoom(lat));
69444
69445             if (!difference) {
69446               supersurface.call(context.background());
69447               wrapper.call(drawLayers);
69448             } // OSM
69449
69450
69451             if (map.editableDataEnabled() || map.isInWideSelection()) {
69452               context.loadTiles(projection);
69453               drawEditable(difference, extent);
69454             } else {
69455               editOff();
69456             }
69457
69458             _transformStart = projection.transform();
69459             return map;
69460           }
69461
69462           var immediateRedraw = function immediateRedraw(difference, extent) {
69463             if (!difference && !extent) cancelPendingRedraw();
69464             redraw(difference, extent);
69465           };
69466
69467           map.lastPointerEvent = function () {
69468             return _lastPointerEvent;
69469           };
69470
69471           map.mouse = function (d3_event) {
69472             var event = d3_event || _lastPointerEvent;
69473
69474             if (event) {
69475               var s;
69476
69477               while (s = event.sourceEvent) {
69478                 event = s;
69479               }
69480
69481               return _getMouseCoords(event);
69482             }
69483
69484             return null;
69485           }; // returns Lng/Lat
69486
69487
69488           map.mouseCoordinates = function () {
69489             var coord = map.mouse() || pxCenter();
69490             return projection.invert(coord);
69491           };
69492
69493           map.dblclickZoomEnable = function (val) {
69494             if (!arguments.length) return _dblClickZoomEnabled;
69495             _dblClickZoomEnabled = val;
69496             return map;
69497           };
69498
69499           map.redrawEnable = function (val) {
69500             if (!arguments.length) return _redrawEnabled;
69501             _redrawEnabled = val;
69502             return map;
69503           };
69504
69505           map.isTransformed = function () {
69506             return _isTransformed;
69507           };
69508
69509           function setTransform(t2, duration, force) {
69510             var t = projection.transform();
69511             if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) return false;
69512
69513             if (duration) {
69514               _selection.transition().duration(duration).on('start', function () {
69515                 map.startEase();
69516               }).call(_zoomerPanner.transform, identity$2.translate(t2.x, t2.y).scale(t2.k));
69517             } else {
69518               projection.transform(t2);
69519               _transformStart = t2;
69520
69521               _selection.call(_zoomerPanner.transform, _transformStart);
69522             }
69523
69524             return true;
69525           }
69526
69527           function setCenterZoom(loc2, z2, duration, force) {
69528             var c = map.center();
69529             var z = map.zoom();
69530             if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force) return false;
69531             var proj = geoRawMercator().transform(projection.transform()); // copy projection
69532
69533             var k2 = clamp$1(geoZoomToScale(z2, TILESIZE), kMin, kMax);
69534             proj.scale(k2);
69535             var t = proj.translate();
69536             var point = proj(loc2);
69537             var center = pxCenter();
69538             t[0] += center[0] - point[0];
69539             t[1] += center[1] - point[1];
69540             return setTransform(identity$2.translate(t[0], t[1]).scale(k2), duration, force);
69541           }
69542
69543           map.pan = function (delta, duration) {
69544             var t = projection.translate();
69545             var k = projection.scale();
69546             t[0] += delta[0];
69547             t[1] += delta[1];
69548
69549             if (duration) {
69550               _selection.transition().duration(duration).on('start', function () {
69551                 map.startEase();
69552               }).call(_zoomerPanner.transform, identity$2.translate(t[0], t[1]).scale(k));
69553             } else {
69554               projection.translate(t);
69555               _transformStart = projection.transform();
69556
69557               _selection.call(_zoomerPanner.transform, _transformStart);
69558
69559               dispatch.call('move', this, map);
69560               immediateRedraw();
69561             }
69562
69563             return map;
69564           };
69565
69566           map.dimensions = function (val) {
69567             if (!arguments.length) return _dimensions;
69568             _dimensions = val;
69569             drawLayers.dimensions(_dimensions);
69570             context.background().dimensions(_dimensions);
69571             projection.clipExtent([[0, 0], _dimensions]);
69572             _getMouseCoords = utilFastMouse(supersurface.node());
69573             scheduleRedraw();
69574             return map;
69575           };
69576
69577           function zoomIn(delta) {
69578             setCenterZoom(map.center(), ~~map.zoom() + delta, 250, true);
69579           }
69580
69581           function zoomOut(delta) {
69582             setCenterZoom(map.center(), ~~map.zoom() - delta, 250, true);
69583           }
69584
69585           map.zoomIn = function () {
69586             zoomIn(1);
69587           };
69588
69589           map.zoomInFurther = function () {
69590             zoomIn(4);
69591           };
69592
69593           map.canZoomIn = function () {
69594             return map.zoom() < maxZoom;
69595           };
69596
69597           map.zoomOut = function () {
69598             zoomOut(1);
69599           };
69600
69601           map.zoomOutFurther = function () {
69602             zoomOut(4);
69603           };
69604
69605           map.canZoomOut = function () {
69606             return map.zoom() > minZoom;
69607           };
69608
69609           map.center = function (loc2) {
69610             if (!arguments.length) {
69611               return projection.invert(pxCenter());
69612             }
69613
69614             if (setCenterZoom(loc2, map.zoom())) {
69615               dispatch.call('move', this, map);
69616             }
69617
69618             scheduleRedraw();
69619             return map;
69620           };
69621
69622           map.unobscuredCenterZoomEase = function (loc, zoom) {
69623             var offset = map.unobscuredOffsetPx();
69624             var proj = geoRawMercator().transform(projection.transform()); // copy projection
69625             // use the target zoom to calculate the offset center
69626
69627             proj.scale(geoZoomToScale(zoom, TILESIZE));
69628             var locPx = proj(loc);
69629             var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
69630             var offsetLoc = proj.invert(offsetLocPx);
69631             map.centerZoomEase(offsetLoc, zoom);
69632           };
69633
69634           map.unobscuredOffsetPx = function () {
69635             var openPane = context.container().select('.map-panes .map-pane.shown');
69636
69637             if (!openPane.empty()) {
69638               return [openPane.node().offsetWidth / 2, 0];
69639             }
69640
69641             return [0, 0];
69642           };
69643
69644           map.zoom = function (z2) {
69645             if (!arguments.length) {
69646               return Math.max(geoScaleToZoom(projection.scale(), TILESIZE), 0);
69647             }
69648
69649             if (z2 < _minzoom) {
69650               surface.interrupt();
69651               dispatch.call('hitMinZoom', this, map);
69652               z2 = context.minEditableZoom();
69653             }
69654
69655             if (setCenterZoom(map.center(), z2)) {
69656               dispatch.call('move', this, map);
69657             }
69658
69659             scheduleRedraw();
69660             return map;
69661           };
69662
69663           map.centerZoom = function (loc2, z2) {
69664             if (setCenterZoom(loc2, z2)) {
69665               dispatch.call('move', this, map);
69666             }
69667
69668             scheduleRedraw();
69669             return map;
69670           };
69671
69672           map.zoomTo = function (entity) {
69673             var extent = entity.extent(context.graph());
69674             if (!isFinite(extent.area())) return map;
69675             var z2 = clamp$1(map.trimmedExtentZoom(extent), 0, 20);
69676             return map.centerZoom(extent.center(), z2);
69677           };
69678
69679           map.centerEase = function (loc2, duration) {
69680             duration = duration || 250;
69681             setCenterZoom(loc2, map.zoom(), duration);
69682             return map;
69683           };
69684
69685           map.zoomEase = function (z2, duration) {
69686             duration = duration || 250;
69687             setCenterZoom(map.center(), z2, duration, false);
69688             return map;
69689           };
69690
69691           map.centerZoomEase = function (loc2, z2, duration) {
69692             duration = duration || 250;
69693             setCenterZoom(loc2, z2, duration, false);
69694             return map;
69695           };
69696
69697           map.transformEase = function (t2, duration) {
69698             duration = duration || 250;
69699             setTransform(t2, duration, false
69700             /* don't force */
69701             );
69702             return map;
69703           };
69704
69705           map.zoomToEase = function (obj, duration) {
69706             var extent;
69707
69708             if (Array.isArray(obj)) {
69709               obj.forEach(function (entity) {
69710                 var entityExtent = entity.extent(context.graph());
69711
69712                 if (!extent) {
69713                   extent = entityExtent;
69714                 } else {
69715                   extent = extent.extend(entityExtent);
69716                 }
69717               });
69718             } else {
69719               extent = obj.extent(context.graph());
69720             }
69721
69722             if (!isFinite(extent.area())) return map;
69723             var z2 = clamp$1(map.trimmedExtentZoom(extent), 0, 20);
69724             return map.centerZoomEase(extent.center(), z2, duration);
69725           };
69726
69727           map.startEase = function () {
69728             utilBindOnce(surface, _pointerPrefix + 'down.ease', function () {
69729               map.cancelEase();
69730             });
69731             return map;
69732           };
69733
69734           map.cancelEase = function () {
69735             _selection.interrupt();
69736
69737             return map;
69738           };
69739
69740           map.extent = function (val) {
69741             if (!arguments.length) {
69742               return new geoExtent(projection.invert([0, _dimensions[1]]), projection.invert([_dimensions[0], 0]));
69743             } else {
69744               var extent = geoExtent(val);
69745               map.centerZoom(extent.center(), map.extentZoom(extent));
69746             }
69747           };
69748
69749           map.trimmedExtent = function (val) {
69750             if (!arguments.length) {
69751               var headerY = 71;
69752               var footerY = 30;
69753               var pad = 10;
69754               return new geoExtent(projection.invert([pad, _dimensions[1] - footerY - pad]), projection.invert([_dimensions[0] - pad, headerY + pad]));
69755             } else {
69756               var extent = geoExtent(val);
69757               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
69758             }
69759           };
69760
69761           function calcExtentZoom(extent, dim) {
69762             var tl = projection([extent[0][0], extent[1][1]]);
69763             var br = projection([extent[1][0], extent[0][1]]); // Calculate maximum zoom that fits extent
69764
69765             var hFactor = (br[0] - tl[0]) / dim[0];
69766             var vFactor = (br[1] - tl[1]) / dim[1];
69767             var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
69768             var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
69769             var newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
69770             return newZoom;
69771           }
69772
69773           map.extentZoom = function (val) {
69774             return calcExtentZoom(geoExtent(val), _dimensions);
69775           };
69776
69777           map.trimmedExtentZoom = function (val) {
69778             var trimY = 120;
69779             var trimX = 40;
69780             var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
69781             return calcExtentZoom(geoExtent(val), trimmed);
69782           };
69783
69784           map.withinEditableZoom = function () {
69785             return map.zoom() >= context.minEditableZoom();
69786           };
69787
69788           map.isInWideSelection = function () {
69789             return !map.withinEditableZoom() && context.selectedIDs().length;
69790           };
69791
69792           map.editableDataEnabled = function (skipZoomCheck) {
69793             var layer = context.layers().layer('osm');
69794             if (!layer || !layer.enabled()) return false;
69795             return skipZoomCheck || map.withinEditableZoom();
69796           };
69797
69798           map.notesEditable = function () {
69799             var layer = context.layers().layer('notes');
69800             if (!layer || !layer.enabled()) return false;
69801             return map.withinEditableZoom();
69802           };
69803
69804           map.minzoom = function (val) {
69805             if (!arguments.length) return _minzoom;
69806             _minzoom = val;
69807             return map;
69808           };
69809
69810           map.toggleHighlightEdited = function () {
69811             surface.classed('highlight-edited', !surface.classed('highlight-edited'));
69812             map.pan([0, 0]); // trigger a redraw
69813
69814             dispatch.call('changeHighlighting', this);
69815           };
69816
69817           map.areaFillOptions = ['wireframe', 'partial', 'full'];
69818
69819           map.activeAreaFill = function (val) {
69820             if (!arguments.length) return corePreferences('area-fill') || 'partial';
69821             corePreferences('area-fill', val);
69822
69823             if (val !== 'wireframe') {
69824               corePreferences('area-fill-toggle', val);
69825             }
69826
69827             updateAreaFill();
69828             map.pan([0, 0]); // trigger a redraw
69829
69830             dispatch.call('changeAreaFill', this);
69831             return map;
69832           };
69833
69834           map.toggleWireframe = function () {
69835             var activeFill = map.activeAreaFill();
69836
69837             if (activeFill === 'wireframe') {
69838               activeFill = corePreferences('area-fill-toggle') || 'partial';
69839             } else {
69840               activeFill = 'wireframe';
69841             }
69842
69843             map.activeAreaFill(activeFill);
69844           };
69845
69846           function updateAreaFill() {
69847             var activeFill = map.activeAreaFill();
69848             map.areaFillOptions.forEach(function (opt) {
69849               surface.classed('fill-' + opt, Boolean(opt === activeFill));
69850             });
69851           }
69852
69853           map.layers = function () {
69854             return drawLayers;
69855           };
69856
69857           map.doubleUpHandler = function () {
69858             return _doubleUpHandler;
69859           };
69860
69861           return utilRebind(map, dispatch, 'on');
69862         }
69863
69864         function rendererPhotos(context) {
69865           var dispatch = dispatch$8('change');
69866           var _layerIDs = ['streetside', 'mapillary', 'mapillary-map-features', 'mapillary-signs', 'openstreetcam'];
69867           var _allPhotoTypes = ['flat', 'panoramic'];
69868
69869           var _shownPhotoTypes = _allPhotoTypes.slice(); // shallow copy
69870
69871
69872           var _dateFilters = ['fromDate', 'toDate'];
69873
69874           var _fromDate;
69875
69876           var _toDate;
69877
69878           var _usernames;
69879
69880           function photos() {}
69881
69882           function updateStorage() {
69883             if (window.mocha) return;
69884             var hash = utilStringQs(window.location.hash);
69885             var enabled = context.layers().all().filter(function (d) {
69886               return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
69887             }).map(function (d) {
69888               return d.id;
69889             });
69890
69891             if (enabled.length) {
69892               hash.photo_overlay = enabled.join(',');
69893             } else {
69894               delete hash.photo_overlay;
69895             }
69896
69897             window.location.replace('#' + utilQsString(hash, true));
69898           }
69899
69900           photos.overlayLayerIDs = function () {
69901             return _layerIDs;
69902           };
69903
69904           photos.allPhotoTypes = function () {
69905             return _allPhotoTypes;
69906           };
69907
69908           photos.dateFilters = function () {
69909             return _dateFilters;
69910           };
69911
69912           photos.dateFilterValue = function (val) {
69913             return val === _dateFilters[0] ? _fromDate : _toDate;
69914           };
69915
69916           photos.setDateFilter = function (type, val, updateUrl) {
69917             // validate the date
69918             var date = val && new Date(val);
69919
69920             if (date && !isNaN(date)) {
69921               val = date.toISOString().substr(0, 10);
69922             } else {
69923               val = null;
69924             }
69925
69926             if (type === _dateFilters[0]) {
69927               _fromDate = val;
69928
69929               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
69930                 _toDate = _fromDate;
69931               }
69932             }
69933
69934             if (type === _dateFilters[1]) {
69935               _toDate = val;
69936
69937               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
69938                 _fromDate = _toDate;
69939               }
69940             }
69941
69942             dispatch.call('change', this);
69943
69944             if (updateUrl) {
69945               var rangeString;
69946
69947               if (_fromDate || _toDate) {
69948                 rangeString = (_fromDate || '') + '_' + (_toDate || '');
69949               }
69950
69951               setUrlFilterValue('photo_dates', rangeString);
69952             }
69953           };
69954
69955           photos.setUsernameFilter = function (val, updateUrl) {
69956             if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(',');
69957
69958             if (val) {
69959               val = val.map(function (d) {
69960                 return d.trim();
69961               }).filter(Boolean);
69962
69963               if (!val.length) {
69964                 val = null;
69965               }
69966             }
69967
69968             _usernames = val;
69969             dispatch.call('change', this);
69970
69971             if (updateUrl) {
69972               var hashString;
69973
69974               if (_usernames) {
69975                 hashString = _usernames.join(',');
69976               }
69977
69978               setUrlFilterValue('photo_username', hashString);
69979             }
69980           };
69981
69982           function setUrlFilterValue(property, val) {
69983             if (!window.mocha) {
69984               var hash = utilStringQs(window.location.hash);
69985
69986               if (val) {
69987                 if (hash[property] === val) return;
69988                 hash[property] = val;
69989               } else {
69990                 if (!(property in hash)) return;
69991                 delete hash[property];
69992               }
69993
69994               window.location.replace('#' + utilQsString(hash, true));
69995             }
69996           }
69997
69998           function showsLayer(id) {
69999             var layer = context.layers().layer(id);
70000             return layer && layer.supported() && layer.enabled();
70001           }
70002
70003           photos.shouldFilterByDate = function () {
70004             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
70005           };
70006
70007           photos.shouldFilterByPhotoType = function () {
70008             return showsLayer('mapillary') || showsLayer('streetside') && showsLayer('openstreetcam');
70009           };
70010
70011           photos.shouldFilterByUsername = function () {
70012             return !showsLayer('mapillary') && showsLayer('openstreetcam') && !showsLayer('streetside');
70013           };
70014
70015           photos.showsPhotoType = function (val) {
70016             if (!photos.shouldFilterByPhotoType()) return true;
70017             return _shownPhotoTypes.indexOf(val) !== -1;
70018           };
70019
70020           photos.showsFlat = function () {
70021             return photos.showsPhotoType('flat');
70022           };
70023
70024           photos.showsPanoramic = function () {
70025             return photos.showsPhotoType('panoramic');
70026           };
70027
70028           photos.fromDate = function () {
70029             return _fromDate;
70030           };
70031
70032           photos.toDate = function () {
70033             return _toDate;
70034           };
70035
70036           photos.togglePhotoType = function (val) {
70037             var index = _shownPhotoTypes.indexOf(val);
70038
70039             if (index !== -1) {
70040               _shownPhotoTypes.splice(index, 1);
70041             } else {
70042               _shownPhotoTypes.push(val);
70043             }
70044
70045             dispatch.call('change', this);
70046             return photos;
70047           };
70048
70049           photos.usernames = function () {
70050             return _usernames;
70051           };
70052
70053           photos.init = function () {
70054             var hash = utilStringQs(window.location.hash);
70055
70056             if (hash.photo_dates) {
70057               // expect format like `photo_dates=2019-01-01_2020-12-31`, but allow a couple different separators
70058               var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
70059               this.setDateFilter('fromDate', parts && parts.length >= 2 && parts[1], false);
70060               this.setDateFilter('toDate', parts && parts.length >= 3 && parts[2], false);
70061             }
70062
70063             if (hash.photo_username) {
70064               this.setUsernameFilter(hash.photo_username, false);
70065             }
70066
70067             if (hash.photo_overlay) {
70068               // support enabling photo layers by default via a URL parameter, e.g. `photo_overlay=openstreetcam;mapillary;streetside`
70069               var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ',').split(',');
70070               hashOverlayIDs.forEach(function (id) {
70071                 var layer = _layerIDs.indexOf(id) !== -1 && context.layers().layer(id);
70072                 if (layer && !layer.enabled()) layer.enabled(true);
70073               });
70074             }
70075
70076             if (hash.photo) {
70077               // support opening a photo via a URL parameter, e.g. `photo=mapillary-fztgSDtLpa08ohPZFZjeRQ`
70078               var photoIds = hash.photo.replace(/;/g, ',').split(',');
70079               var photoId = photoIds.length && photoIds[0].trim();
70080               var results = /(.*)\/(.*)/g.exec(photoId);
70081
70082               if (results && results.length >= 3) {
70083                 var serviceId = results[1];
70084                 var photoKey = results[2];
70085                 var service = services[serviceId];
70086
70087                 if (service && service.ensureViewerLoaded) {
70088                   // if we're showing a photo then make sure its layer is enabled too
70089                   var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
70090                   if (layer && !layer.enabled()) layer.enabled(true);
70091                   var baselineTime = Date.now();
70092                   service.on('loadedImages.rendererPhotos', function () {
70093                     // don't open the viewer if too much time has elapsed
70094                     if (Date.now() - baselineTime > 45000) {
70095                       service.on('loadedImages.rendererPhotos', null);
70096                       return;
70097                     }
70098
70099                     if (!service.cachedImage(photoKey)) return;
70100                     service.on('loadedImages.rendererPhotos', null);
70101                     service.ensureViewerLoaded(context).then(function () {
70102                       service.selectImage(context, photoKey).showViewer(context);
70103                     });
70104                   });
70105                 }
70106               }
70107             }
70108
70109             context.layers().on('change.rendererPhotos', updateStorage);
70110           };
70111
70112           return utilRebind(photos, dispatch, 'on');
70113         }
70114
70115         function uiAccount(context) {
70116           var osm = context.connection();
70117
70118           function update(selection) {
70119             if (!osm) return;
70120
70121             if (!osm.authenticated()) {
70122               selection.selectAll('.userLink, .logoutLink').classed('hide', true);
70123               return;
70124             }
70125
70126             osm.userDetails(function (err, details) {
70127               var userLink = selection.select('.userLink'),
70128                   logoutLink = selection.select('.logoutLink');
70129               userLink.html('');
70130               logoutLink.html('');
70131               if (err || !details) return;
70132               selection.selectAll('.userLink, .logoutLink').classed('hide', false); // Link
70133
70134               var userLinkA = userLink.append('a').attr('href', osm.userURL(details.display_name)).attr('target', '_blank'); // Add thumbnail or dont
70135
70136               if (details.image_url) {
70137                 userLinkA.append('img').attr('class', 'icon pre-text user-icon').attr('src', details.image_url);
70138               } else {
70139                 userLinkA.call(svgIcon('#iD-icon-avatar', 'pre-text light'));
70140               } // Add user name
70141
70142
70143               userLinkA.append('span').attr('class', 'label').html(details.display_name);
70144               logoutLink.append('a').attr('class', 'logout').attr('href', '#').html(_t.html('logout')).on('click.logout', function (d3_event) {
70145                 d3_event.preventDefault();
70146                 osm.logout();
70147               });
70148             });
70149           }
70150
70151           return function (selection) {
70152             selection.append('li').attr('class', 'userLink').classed('hide', true);
70153             selection.append('li').attr('class', 'logoutLink').classed('hide', true);
70154
70155             if (osm) {
70156               osm.on('change.account', function () {
70157                 update(selection);
70158               });
70159               update(selection);
70160             }
70161           };
70162         }
70163
70164         function uiAttribution(context) {
70165           var _selection = select(null);
70166
70167           function render(selection, data, klass) {
70168             var div = selection.selectAll(".".concat(klass)).data([0]);
70169             div = div.enter().append('div').attr('class', klass).merge(div);
70170             var attributions = div.selectAll('.attribution').data(data, function (d) {
70171               return d.id;
70172             });
70173             attributions.exit().remove();
70174             attributions = attributions.enter().append('span').attr('class', 'attribution').each(function (d, i, nodes) {
70175               var attribution = select(nodes[i]);
70176
70177               if (d.terms_html) {
70178                 attribution.html(d.terms_html);
70179                 return;
70180               }
70181
70182               if (d.terms_url) {
70183                 attribution = attribution.append('a').attr('href', d.terms_url).attr('target', '_blank');
70184               }
70185
70186               var sourceID = d.id.replace(/\./g, '<TX_DOT>');
70187               var terms_text = _t("imagery.".concat(sourceID, ".attribution.text"), {
70188                 "default": d.terms_text || d.id || d.name()
70189               });
70190
70191               if (d.icon && !d.overlay) {
70192                 attribution.append('img').attr('class', 'source-image').attr('src', d.icon);
70193               }
70194
70195               attribution.append('span').attr('class', 'attribution-text').html(terms_text);
70196             }).merge(attributions);
70197             var copyright = attributions.selectAll('.copyright-notice').data(function (d) {
70198               var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
70199               return notice ? [notice] : [];
70200             });
70201             copyright.exit().remove();
70202             copyright = copyright.enter().append('span').attr('class', 'copyright-notice').merge(copyright);
70203             copyright.html(String);
70204           }
70205
70206           function update() {
70207             var baselayer = context.background().baseLayerSource();
70208
70209             _selection.call(render, baselayer ? [baselayer] : [], 'base-layer-attribution');
70210
70211             var z = context.map().zoom();
70212             var overlays = context.background().overlayLayerSources() || [];
70213
70214             _selection.call(render, overlays.filter(function (s) {
70215               return s.validZoom(z);
70216             }), 'overlay-layer-attribution');
70217           }
70218
70219           return function (selection) {
70220             _selection = selection;
70221             context.background().on('change.attribution', update);
70222             context.map().on('move.attribution', throttle(update, 400, {
70223               leading: false
70224             }));
70225             update();
70226           };
70227         }
70228
70229         function uiContributors(context) {
70230           var osm = context.connection(),
70231               debouncedUpdate = debounce(function () {
70232             update();
70233           }, 1000),
70234               limit = 4,
70235               hidden = false,
70236               wrap = select(null);
70237
70238           function update() {
70239             if (!osm) return;
70240             var users = {},
70241                 entities = context.history().intersects(context.map().extent());
70242             entities.forEach(function (entity) {
70243               if (entity && entity.user) users[entity.user] = true;
70244             });
70245             var u = Object.keys(users),
70246                 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
70247             wrap.html('').call(svgIcon('#iD-icon-nearby', 'pre-text light'));
70248             var userList = select(document.createElement('span'));
70249             userList.selectAll().data(subset).enter().append('a').attr('class', 'user-link').attr('href', function (d) {
70250               return osm.userURL(d);
70251             }).attr('target', '_blank').html(String);
70252
70253             if (u.length > limit) {
70254               var count = select(document.createElement('span'));
70255               var othersNum = u.length - limit + 1;
70256               count.append('a').attr('target', '_blank').attr('href', function () {
70257                 return osm.changesetsURL(context.map().center(), context.map().zoom());
70258               }).html(othersNum);
70259               wrap.append('span').html(_t.html('contributors.truncated_list', {
70260                 n: othersNum,
70261                 users: userList.html(),
70262                 count: count.html()
70263               }));
70264             } else {
70265               wrap.append('span').html(_t.html('contributors.list', {
70266                 users: userList.html()
70267               }));
70268             }
70269
70270             if (!u.length) {
70271               hidden = true;
70272               wrap.transition().style('opacity', 0);
70273             } else if (hidden) {
70274               wrap.transition().style('opacity', 1);
70275             }
70276           }
70277
70278           return function (selection) {
70279             if (!osm) return;
70280             wrap = selection;
70281             update();
70282             osm.on('loaded.contributors', debouncedUpdate);
70283             context.map().on('move.contributors', debouncedUpdate);
70284           };
70285         }
70286
70287         var _popoverID = 0;
70288         function uiPopover(klass) {
70289           var _id = _popoverID++;
70290
70291           var _anchorSelection = select(null);
70292
70293           var popover = function popover(selection) {
70294             _anchorSelection = selection;
70295             selection.each(setup);
70296           };
70297
70298           var _animation = utilFunctor(false);
70299
70300           var _placement = utilFunctor('top'); // top, bottom, left, right
70301
70302
70303           var _alignment = utilFunctor('center'); // leading, center, trailing
70304
70305
70306           var _scrollContainer = utilFunctor(select(null));
70307
70308           var _content;
70309
70310           var _displayType = utilFunctor('');
70311
70312           var _hasArrow = utilFunctor(true); // use pointer events on supported platforms; fallback to mouse events
70313
70314
70315           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
70316
70317           popover.displayType = function (val) {
70318             if (arguments.length) {
70319               _displayType = utilFunctor(val);
70320               return popover;
70321             } else {
70322               return _displayType;
70323             }
70324           };
70325
70326           popover.hasArrow = function (val) {
70327             if (arguments.length) {
70328               _hasArrow = utilFunctor(val);
70329               return popover;
70330             } else {
70331               return _hasArrow;
70332             }
70333           };
70334
70335           popover.placement = function (val) {
70336             if (arguments.length) {
70337               _placement = utilFunctor(val);
70338               return popover;
70339             } else {
70340               return _placement;
70341             }
70342           };
70343
70344           popover.alignment = function (val) {
70345             if (arguments.length) {
70346               _alignment = utilFunctor(val);
70347               return popover;
70348             } else {
70349               return _alignment;
70350             }
70351           };
70352
70353           popover.scrollContainer = function (val) {
70354             if (arguments.length) {
70355               _scrollContainer = utilFunctor(val);
70356               return popover;
70357             } else {
70358               return _scrollContainer;
70359             }
70360           };
70361
70362           popover.content = function (val) {
70363             if (arguments.length) {
70364               _content = val;
70365               return popover;
70366             } else {
70367               return _content;
70368             }
70369           };
70370
70371           popover.isShown = function () {
70372             var popoverSelection = _anchorSelection.select('.popover-' + _id);
70373
70374             return !popoverSelection.empty() && popoverSelection.classed('in');
70375           };
70376
70377           popover.show = function () {
70378             _anchorSelection.each(show);
70379           };
70380
70381           popover.updateContent = function () {
70382             _anchorSelection.each(updateContent);
70383           };
70384
70385           popover.hide = function () {
70386             _anchorSelection.each(hide);
70387           };
70388
70389           popover.toggle = function () {
70390             _anchorSelection.each(toggle);
70391           };
70392
70393           popover.destroy = function (selection, selector) {
70394             // by default, just destroy the current popover
70395             selector = selector || '.popover-' + _id;
70396             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 () {
70397               return this.getAttribute('data-original-title') || this.getAttribute('title');
70398             }).attr('data-original-title', null).selectAll(selector).remove();
70399           };
70400
70401           popover.destroyAny = function (selection) {
70402             selection.call(popover.destroy, '.popover');
70403           };
70404
70405           function setup() {
70406             var anchor = select(this);
70407
70408             var animate = _animation.apply(this, arguments);
70409
70410             var popoverSelection = anchor.selectAll('.popover-' + _id).data([0]);
70411             var enter = popoverSelection.enter().append('div').attr('class', 'popover popover-' + _id + ' ' + (klass ? klass : '')).classed('arrowed', _hasArrow.apply(this, arguments));
70412             enter.append('div').attr('class', 'popover-arrow');
70413             enter.append('div').attr('class', 'popover-inner');
70414             popoverSelection = enter.merge(popoverSelection);
70415
70416             if (animate) {
70417               popoverSelection.classed('fade', true);
70418             }
70419
70420             var display = _displayType.apply(this, arguments);
70421
70422             if (display === 'hover') {
70423               var _lastNonMouseEnterTime;
70424
70425               anchor.on(_pointerPrefix + 'enter.popover', function (d3_event) {
70426                 if (d3_event.pointerType) {
70427                   if (d3_event.pointerType !== 'mouse') {
70428                     _lastNonMouseEnterTime = d3_event.timeStamp; // only allow hover behavior for mouse input
70429
70430                     return;
70431                   } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
70432                     // HACK: iOS 13.4 sends an erroneous `mouse` type pointerenter
70433                     // event for non-mouse interactions right after sending
70434                     // the correct type pointerenter event. Workaround by discarding
70435                     // any mouse event that occurs immediately after a non-mouse event.
70436                     return;
70437                   }
70438                 } // don't show if buttons are pressed, e.g. during click and drag of map
70439
70440
70441                 if (d3_event.buttons !== 0) return;
70442                 show.apply(this, arguments);
70443               }).on(_pointerPrefix + 'leave.popover', function () {
70444                 hide.apply(this, arguments);
70445               }) // show on focus too for better keyboard navigation support
70446               .on('focus.popover', function () {
70447                 show.apply(this, arguments);
70448               }).on('blur.popover', function () {
70449                 hide.apply(this, arguments);
70450               });
70451             } else if (display === 'clickFocus') {
70452               anchor.on(_pointerPrefix + 'down.popover', function (d3_event) {
70453                 d3_event.preventDefault();
70454                 d3_event.stopPropagation();
70455               }).on(_pointerPrefix + 'up.popover', function (d3_event) {
70456                 d3_event.preventDefault();
70457                 d3_event.stopPropagation();
70458               }).on('click.popover', toggle);
70459               popoverSelection // This attribute lets the popover take focus
70460               .attr('tabindex', 0).on('blur.popover', function () {
70461                 anchor.each(function () {
70462                   hide.apply(this, arguments);
70463                 });
70464               });
70465             }
70466           }
70467
70468           function show() {
70469             var anchor = select(this);
70470             var popoverSelection = anchor.selectAll('.popover-' + _id);
70471
70472             if (popoverSelection.empty()) {
70473               // popover was removed somehow, put it back
70474               anchor.call(popover.destroy);
70475               anchor.each(setup);
70476               popoverSelection = anchor.selectAll('.popover-' + _id);
70477             }
70478
70479             popoverSelection.classed('in', true);
70480
70481             var displayType = _displayType.apply(this, arguments);
70482
70483             if (displayType === 'clickFocus') {
70484               anchor.classed('active', true);
70485               popoverSelection.node().focus();
70486             }
70487
70488             anchor.each(updateContent);
70489           }
70490
70491           function updateContent() {
70492             var anchor = select(this);
70493
70494             if (_content) {
70495               anchor.selectAll('.popover-' + _id + ' > .popover-inner').call(_content.apply(this, arguments));
70496             }
70497
70498             updatePosition.apply(this, arguments); // hack: update multiple times to fix instances where the absolute offset is
70499             // set before the dynamic popover size is calculated by the browser
70500
70501             updatePosition.apply(this, arguments);
70502             updatePosition.apply(this, arguments);
70503           }
70504
70505           function updatePosition() {
70506             var anchor = select(this);
70507             var popoverSelection = anchor.selectAll('.popover-' + _id);
70508
70509             var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
70510
70511             var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
70512             var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
70513             var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
70514
70515             var placement = _placement.apply(this, arguments);
70516
70517             popoverSelection.classed('left', false).classed('right', false).classed('top', false).classed('bottom', false).classed(placement, true);
70518
70519             var alignment = _alignment.apply(this, arguments);
70520
70521             var alignFactor = 0.5;
70522
70523             if (alignment === 'leading') {
70524               alignFactor = 0;
70525             } else if (alignment === 'trailing') {
70526               alignFactor = 1;
70527             }
70528
70529             var anchorFrame = getFrame(anchor.node());
70530             var popoverFrame = getFrame(popoverSelection.node());
70531             var position;
70532
70533             switch (placement) {
70534               case 'top':
70535                 position = {
70536                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
70537                   y: anchorFrame.y - popoverFrame.h
70538                 };
70539                 break;
70540
70541               case 'bottom':
70542                 position = {
70543                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
70544                   y: anchorFrame.y + anchorFrame.h
70545                 };
70546                 break;
70547
70548               case 'left':
70549                 position = {
70550                   x: anchorFrame.x - popoverFrame.w,
70551                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
70552                 };
70553                 break;
70554
70555               case 'right':
70556                 position = {
70557                   x: anchorFrame.x + anchorFrame.w,
70558                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
70559                 };
70560                 break;
70561             }
70562
70563             if (position) {
70564               if (scrollNode && (placement === 'top' || placement === 'bottom')) {
70565                 var initialPosX = position.x;
70566
70567                 if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
70568                   position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
70569                 } else if (position.x < 10) {
70570                   position.x = 10;
70571                 }
70572
70573                 var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow'); // keep the arrow centered on the button, or as close as possible
70574
70575                 var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
70576                 arrow.style('left', ~~arrowPosX + 'px');
70577               }
70578
70579               popoverSelection.style('left', ~~position.x + 'px').style('top', ~~position.y + 'px');
70580             } else {
70581               popoverSelection.style('left', null).style('top', null);
70582             }
70583
70584             function getFrame(node) {
70585               var positionStyle = select(node).style('position');
70586
70587               if (positionStyle === 'absolute' || positionStyle === 'static') {
70588                 return {
70589                   x: node.offsetLeft - scrollLeft,
70590                   y: node.offsetTop - scrollTop,
70591                   w: node.offsetWidth,
70592                   h: node.offsetHeight
70593                 };
70594               } else {
70595                 return {
70596                   x: 0,
70597                   y: 0,
70598                   w: node.offsetWidth,
70599                   h: node.offsetHeight
70600                 };
70601               }
70602             }
70603           }
70604
70605           function hide() {
70606             var anchor = select(this);
70607
70608             if (_displayType.apply(this, arguments) === 'clickFocus') {
70609               anchor.classed('active', false);
70610             }
70611
70612             anchor.selectAll('.popover-' + _id).classed('in', false);
70613           }
70614
70615           function toggle() {
70616             if (select(this).select('.popover-' + _id).classed('in')) {
70617               hide.apply(this, arguments);
70618             } else {
70619               show.apply(this, arguments);
70620             }
70621           }
70622
70623           return popover;
70624         }
70625
70626         function uiTooltip(klass) {
70627           var tooltip = uiPopover((klass || '') + ' tooltip').displayType('hover');
70628
70629           var _title = function _title() {
70630             var title = this.getAttribute('data-original-title');
70631
70632             if (title) {
70633               return title;
70634             } else {
70635               title = this.getAttribute('title');
70636               this.removeAttribute('title');
70637               this.setAttribute('data-original-title', title);
70638             }
70639
70640             return title;
70641           };
70642
70643           var _heading = utilFunctor(null);
70644
70645           var _keys = utilFunctor(null);
70646
70647           tooltip.title = function (val) {
70648             if (!arguments.length) return _title;
70649             _title = utilFunctor(val);
70650             return tooltip;
70651           };
70652
70653           tooltip.heading = function (val) {
70654             if (!arguments.length) return _heading;
70655             _heading = utilFunctor(val);
70656             return tooltip;
70657           };
70658
70659           tooltip.keys = function (val) {
70660             if (!arguments.length) return _keys;
70661             _keys = utilFunctor(val);
70662             return tooltip;
70663           };
70664
70665           tooltip.content(function () {
70666             var heading = _heading.apply(this, arguments);
70667
70668             var text = _title.apply(this, arguments);
70669
70670             var keys = _keys.apply(this, arguments);
70671
70672             return function (selection) {
70673               var headingSelect = selection.selectAll('.tooltip-heading').data(heading ? [heading] : []);
70674               headingSelect.exit().remove();
70675               headingSelect.enter().append('div').attr('class', 'tooltip-heading').merge(headingSelect).html(heading);
70676               var textSelect = selection.selectAll('.tooltip-text').data(text ? [text] : []);
70677               textSelect.exit().remove();
70678               textSelect.enter().append('div').attr('class', 'tooltip-text').merge(textSelect).html(text);
70679               var keyhintWrap = selection.selectAll('.keyhint-wrap').data(keys && keys.length ? [0] : []);
70680               keyhintWrap.exit().remove();
70681               var keyhintWrapEnter = keyhintWrap.enter().append('div').attr('class', 'keyhint-wrap');
70682               keyhintWrapEnter.append('span').html(_t.html('tooltip_keyhint'));
70683               keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
70684               keyhintWrap.selectAll('kbd.shortcut').data(keys && keys.length ? keys : []).enter().append('kbd').attr('class', 'shortcut').html(function (d) {
70685                 return d;
70686               });
70687             };
70688           });
70689           return tooltip;
70690         }
70691
70692         function uiEditMenu(context) {
70693           var dispatch = dispatch$8('toggled');
70694
70695           var _menu = select(null);
70696
70697           var _operations = []; // the position the menu should be displayed relative to
70698
70699           var _anchorLoc = [0, 0];
70700           var _anchorLocLonLat = [0, 0]; // a string indicating how the menu was opened
70701
70702           var _triggerType = '';
70703           var _vpTopMargin = 85; // viewport top margin
70704
70705           var _vpBottomMargin = 45; // viewport bottom margin
70706
70707           var _vpSideMargin = 35; // viewport side margin
70708
70709           var _menuTop = false;
70710
70711           var _menuHeight;
70712
70713           var _menuWidth; // hardcode these values to make menu positioning easier
70714
70715
70716           var _verticalPadding = 4; // see also `.edit-menu .tooltip` CSS; include margin
70717
70718           var _tooltipWidth = 210; // offset the menu slightly from the target location
70719
70720           var _menuSideMargin = 10;
70721           var _tooltips = [];
70722
70723           var editMenu = function editMenu(selection) {
70724             var isTouchMenu = _triggerType.includes('touch') || _triggerType.includes('pen');
70725
70726             var ops = _operations.filter(function (op) {
70727               return !isTouchMenu || !op.mouseOnly;
70728             });
70729
70730             if (!ops.length) return;
70731             _tooltips = []; // Position the menu above the anchor for stylus and finger input
70732             // since the mapper's hand likely obscures the screen below the anchor
70733
70734             _menuTop = isTouchMenu; // Show labels for touch input since there aren't hover tooltips
70735
70736             var showLabels = isTouchMenu;
70737             var buttonHeight = showLabels ? 32 : 34;
70738
70739             if (showLabels) {
70740               // Get a general idea of the width based on the length of the label
70741               _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function (op) {
70742                 return op.title.length;
70743               })));
70744             } else {
70745               _menuWidth = 44;
70746             }
70747
70748             _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
70749             _menu = selection.append('div').attr('class', 'edit-menu').classed('touch-menu', isTouchMenu).style('padding', _verticalPadding + 'px 0');
70750
70751             var buttons = _menu.selectAll('.edit-menu-item').data(ops); // enter
70752
70753
70754             var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
70755               return 'edit-menu-item edit-menu-item-' + d.id;
70756             }).style('height', buttonHeight + 'px').on('click', click) // don't listen for `mouseup` because we only care about non-mouse pointer types
70757             .on('pointerup', pointerup).on('pointerdown mousedown', function pointerdown(d3_event) {
70758               // don't let button presses also act as map input - #1869
70759               d3_event.stopPropagation();
70760             }).on('mouseenter.highlight', function (d3_event, d) {
70761               if (!d.relatedEntityIds || select(this).classed('disabled')) return;
70762               utilHighlightEntities(d.relatedEntityIds(), true, context);
70763             }).on('mouseleave.highlight', function (d3_event, d) {
70764               if (!d.relatedEntityIds) return;
70765               utilHighlightEntities(d.relatedEntityIds(), false, context);
70766             });
70767             buttonsEnter.each(function (d) {
70768               var tooltip = uiTooltip().heading(d.title).title(d.tooltip()).keys([d.keys[0]]);
70769
70770               _tooltips.push(tooltip);
70771
70772               select(this).call(tooltip).append('div').attr('class', 'icon-wrap').call(svgIcon('#iD-operation-' + d.id, 'operation'));
70773             });
70774
70775             if (showLabels) {
70776               buttonsEnter.append('span').attr('class', 'label').html(function (d) {
70777                 return d.title;
70778               });
70779             } // update
70780
70781
70782             buttonsEnter.merge(buttons).classed('disabled', function (d) {
70783               return d.disabled();
70784             });
70785             updatePosition();
70786             var initialScale = context.projection.scale();
70787             context.map().on('move.edit-menu', function () {
70788               if (initialScale !== context.projection.scale()) {
70789                 editMenu.close();
70790               }
70791             }).on('drawn.edit-menu', function (info) {
70792               if (info.full) updatePosition();
70793             });
70794             var lastPointerUpType; // `pointerup` is always called before `click`
70795
70796             function pointerup(d3_event) {
70797               lastPointerUpType = d3_event.pointerType;
70798             }
70799
70800             function click(d3_event, operation) {
70801               d3_event.stopPropagation();
70802
70803               if (operation.relatedEntityIds) {
70804                 utilHighlightEntities(operation.relatedEntityIds(), false, context);
70805               }
70806
70807               if (operation.disabled()) {
70808                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
70809                   // there are no tooltips for touch interactions so flash feedback instead
70810                   context.ui().flash.duration(4000).iconName('#iD-operation-' + operation.id).iconClass('operation disabled').label(operation.tooltip)();
70811                 }
70812               } else {
70813                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
70814                   context.ui().flash.duration(2000).iconName('#iD-operation-' + operation.id).iconClass('operation').label(operation.annotation() || operation.title)();
70815                 }
70816
70817                 operation();
70818                 editMenu.close();
70819               }
70820
70821               lastPointerUpType = null;
70822             }
70823
70824             dispatch.call('toggled', this, true);
70825           };
70826
70827           function updatePosition() {
70828             if (!_menu || _menu.empty()) return;
70829             var anchorLoc = context.projection(_anchorLocLonLat);
70830             var viewport = context.surfaceRect();
70831
70832             if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
70833               // close the menu if it's gone offscreen
70834               editMenu.close();
70835               return;
70836             }
70837
70838             var menuLeft = displayOnLeft(viewport);
70839             var offset = [0, 0];
70840             offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
70841
70842             if (_menuTop) {
70843               if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
70844                 // menu is near top viewport edge, shift downward
70845                 offset[1] = -anchorLoc[1] + _vpTopMargin;
70846               } else {
70847                 offset[1] = -_menuHeight;
70848               }
70849             } else {
70850               if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
70851                 // menu is near bottom viewport edge, shift upwards
70852                 offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
70853               } else {
70854                 offset[1] = 0;
70855               }
70856             }
70857
70858             var origin = geoVecAdd(anchorLoc, offset);
70859
70860             _menu.style('left', origin[0] + 'px').style('top', origin[1] + 'px');
70861
70862             var tooltipSide = tooltipPosition(viewport, menuLeft);
70863
70864             _tooltips.forEach(function (tooltip) {
70865               tooltip.placement(tooltipSide);
70866             });
70867
70868             function displayOnLeft(viewport) {
70869               if (_mainLocalizer.textDirection() === 'ltr') {
70870                 if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport.width - _vpSideMargin) {
70871                   // right menu would be too close to the right viewport edge, go left
70872                   return true;
70873                 } // prefer right menu
70874
70875
70876                 return false;
70877               } else {
70878                 // rtl
70879                 if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
70880                   // left menu would be too close to the left viewport edge, go right
70881                   return false;
70882                 } // prefer left menu
70883
70884
70885                 return true;
70886               }
70887             }
70888
70889             function tooltipPosition(viewport, menuLeft) {
70890               if (_mainLocalizer.textDirection() === 'ltr') {
70891                 if (menuLeft) {
70892                   // if there's not room for a right-side menu then there definitely
70893                   // isn't room for right-side tooltips
70894                   return 'left';
70895                 }
70896
70897                 if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport.width - _vpSideMargin) {
70898                   // right tooltips would be too close to the right viewport edge, go left
70899                   return 'left';
70900                 } // prefer right tooltips
70901
70902
70903                 return 'right';
70904               } else {
70905                 // rtl
70906                 if (!menuLeft) {
70907                   return 'right';
70908                 }
70909
70910                 if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
70911                   // left tooltips would be too close to the left viewport edge, go right
70912                   return 'right';
70913                 } // prefer left tooltips
70914
70915
70916                 return 'left';
70917               }
70918             }
70919           }
70920
70921           editMenu.close = function () {
70922             context.map().on('move.edit-menu', null).on('drawn.edit-menu', null);
70923
70924             _menu.remove();
70925
70926             _tooltips = [];
70927             dispatch.call('toggled', this, false);
70928           };
70929
70930           editMenu.anchorLoc = function (val) {
70931             if (!arguments.length) return _anchorLoc;
70932             _anchorLoc = val;
70933             _anchorLocLonLat = context.projection.invert(_anchorLoc);
70934             return editMenu;
70935           };
70936
70937           editMenu.triggerType = function (val) {
70938             if (!arguments.length) return _triggerType;
70939             _triggerType = val;
70940             return editMenu;
70941           };
70942
70943           editMenu.operations = function (val) {
70944             if (!arguments.length) return _operations;
70945             _operations = val;
70946             return editMenu;
70947           };
70948
70949           return utilRebind(editMenu, dispatch, 'on');
70950         }
70951
70952         function uiFeatureInfo(context) {
70953           function update(selection) {
70954             var features = context.features();
70955             var stats = features.stats();
70956             var count = 0;
70957             var hiddenList = features.hidden().map(function (k) {
70958               if (stats[k]) {
70959                 count += stats[k];
70960                 return _t('inspector.title_count', {
70961                   title: _t.html('feature.' + k + '.description'),
70962                   count: stats[k]
70963                 });
70964               }
70965
70966               return null;
70967             }).filter(Boolean);
70968             selection.html('');
70969
70970             if (hiddenList.length) {
70971               var tooltipBehavior = uiTooltip().placement('top').title(function () {
70972                 return hiddenList.join('<br/>');
70973               });
70974               selection.append('a').attr('class', 'chip').attr('href', '#').html(_t.html('feature_info.hidden_warning', {
70975                 count: count
70976               })).call(tooltipBehavior).on('click', function (d3_event) {
70977                 tooltipBehavior.hide();
70978                 d3_event.preventDefault(); // open the Map Data pane
70979
70980                 context.ui().togglePanes(context.container().select('.map-panes .map-data-pane'));
70981               });
70982             }
70983
70984             selection.classed('hide', !hiddenList.length);
70985           }
70986
70987           return function (selection) {
70988             update(selection);
70989             context.features().on('change.feature_info', function () {
70990               update(selection);
70991             });
70992           };
70993         }
70994
70995         function uiFlash(context) {
70996           var _flashTimer;
70997
70998           var _duration = 2000;
70999           var _iconName = '#iD-icon-no';
71000           var _iconClass = 'disabled';
71001           var _label = '';
71002
71003           function flash() {
71004             if (_flashTimer) {
71005               _flashTimer.stop();
71006             }
71007
71008             context.container().select('.main-footer-wrap').classed('footer-hide', true).classed('footer-show', false);
71009             context.container().select('.flash-wrap').classed('footer-hide', false).classed('footer-show', true);
71010             var content = context.container().select('.flash-wrap').selectAll('.flash-content').data([0]); // Enter
71011
71012             var contentEnter = content.enter().append('div').attr('class', 'flash-content');
71013             var iconEnter = contentEnter.append('svg').attr('class', 'flash-icon icon').append('g').attr('transform', 'translate(10,10)');
71014             iconEnter.append('circle').attr('r', 9);
71015             iconEnter.append('use').attr('transform', 'translate(-7,-7)').attr('width', '14').attr('height', '14');
71016             contentEnter.append('div').attr('class', 'flash-text'); // Update
71017
71018             content = content.merge(contentEnter);
71019             content.selectAll('.flash-icon').attr('class', 'icon flash-icon ' + (_iconClass || ''));
71020             content.selectAll('.flash-icon use').attr('xlink:href', _iconName);
71021             content.selectAll('.flash-text').attr('class', 'flash-text').html(_label);
71022             _flashTimer = d3_timeout(function () {
71023               _flashTimer = null;
71024               context.container().select('.main-footer-wrap').classed('footer-hide', false).classed('footer-show', true);
71025               context.container().select('.flash-wrap').classed('footer-hide', true).classed('footer-show', false);
71026             }, _duration);
71027             return content;
71028           }
71029
71030           flash.duration = function (_) {
71031             if (!arguments.length) return _duration;
71032             _duration = _;
71033             return flash;
71034           };
71035
71036           flash.label = function (_) {
71037             if (!arguments.length) return _label;
71038             _label = _;
71039             return flash;
71040           };
71041
71042           flash.iconName = function (_) {
71043             if (!arguments.length) return _iconName;
71044             _iconName = _;
71045             return flash;
71046           };
71047
71048           flash.iconClass = function (_) {
71049             if (!arguments.length) return _iconClass;
71050             _iconClass = _;
71051             return flash;
71052           };
71053
71054           return flash;
71055         }
71056
71057         function uiFullScreen(context) {
71058           var element = context.container().node(); // var button = d3_select(null);
71059
71060           function getFullScreenFn() {
71061             if (element.requestFullscreen) {
71062               return element.requestFullscreen;
71063             } else if (element.msRequestFullscreen) {
71064               return element.msRequestFullscreen;
71065             } else if (element.mozRequestFullScreen) {
71066               return element.mozRequestFullScreen;
71067             } else if (element.webkitRequestFullscreen) {
71068               return element.webkitRequestFullscreen;
71069             }
71070           }
71071
71072           function getExitFullScreenFn() {
71073             if (document.exitFullscreen) {
71074               return document.exitFullscreen;
71075             } else if (document.msExitFullscreen) {
71076               return document.msExitFullscreen;
71077             } else if (document.mozCancelFullScreen) {
71078               return document.mozCancelFullScreen;
71079             } else if (document.webkitExitFullscreen) {
71080               return document.webkitExitFullscreen;
71081             }
71082           }
71083
71084           function isFullScreen() {
71085             return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
71086           }
71087
71088           function isSupported() {
71089             return !!getFullScreenFn();
71090           }
71091
71092           function fullScreen(d3_event) {
71093             d3_event.preventDefault();
71094
71095             if (!isFullScreen()) {
71096               // button.classed('active', true);
71097               getFullScreenFn().apply(element);
71098             } else {
71099               // button.classed('active', false);
71100               getExitFullScreenFn().apply(document);
71101             }
71102           }
71103
71104           return function () {
71105             // selection) {
71106             if (!isSupported()) return; // button = selection.append('button')
71107             //     .attr('title', t('full_screen'))
71108             //     .on('click', fullScreen)
71109             //     .call(tooltip);
71110             // button.append('span')
71111             //     .attr('class', 'icon full-screen');
71112
71113             var detected = utilDetect();
71114             var keys = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
71115             context.keybinding().on(keys, fullScreen);
71116           };
71117         }
71118
71119         function uiGeolocate(context) {
71120           var _geolocationOptions = {
71121             // prioritize speed and power usage over precision
71122             enableHighAccuracy: false,
71123             // don't hang indefinitely getting the location
71124             timeout: 6000 // 6sec
71125
71126           };
71127
71128           var _locating = uiLoading(context).message(_t.html('geolocate.locating')).blocking(true);
71129
71130           var _layer = context.layers().layer('geolocate');
71131
71132           var _position;
71133
71134           var _extent;
71135
71136           var _timeoutID;
71137
71138           var _button = select(null);
71139
71140           function click() {
71141             if (context.inIntro()) return;
71142
71143             if (!_layer.enabled() && !_locating.isShown()) {
71144               // This timeout ensures that we still call finish() even if
71145               // the user declines to share their location in Firefox
71146               _timeoutID = setTimeout(error, 10000
71147               /* 10sec */
71148               );
71149               context.container().call(_locating); // get the latest position even if we already have one
71150
71151               navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
71152             } else {
71153               _locating.close();
71154
71155               _layer.enabled(null, false);
71156
71157               updateButtonState();
71158             }
71159           }
71160
71161           function zoomTo() {
71162             context.enter(modeBrowse(context));
71163             var map = context.map();
71164
71165             _layer.enabled(_position, true);
71166
71167             updateButtonState();
71168             map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
71169           }
71170
71171           function success(geolocation) {
71172             _position = geolocation;
71173             var coords = _position.coords;
71174             _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
71175             zoomTo();
71176             finish();
71177           }
71178
71179           function error() {
71180             if (_position) {
71181               // use the position from a previous call if we have one
71182               zoomTo();
71183             } else {
71184               context.ui().flash.label(_t.html('geolocate.location_unavailable')).iconName('#iD-icon-geolocate')();
71185             }
71186
71187             finish();
71188           }
71189
71190           function finish() {
71191             _locating.close(); // unblock ui
71192
71193
71194             if (_timeoutID) {
71195               clearTimeout(_timeoutID);
71196             }
71197
71198             _timeoutID = undefined;
71199           }
71200
71201           function updateButtonState() {
71202             _button.classed('active', _layer.enabled());
71203           }
71204
71205           return function (selection) {
71206             if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
71207             _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')]));
71208             context.keybinding().on(_t('geolocate.key'), click);
71209           };
71210         }
71211
71212         function uiPanelBackground(context) {
71213           var background = context.background();
71214           var _currSourceName = null;
71215           var _metadata = {};
71216           var _metadataKeys = ['zoom', 'vintage', 'source', 'description', 'resolution', 'accuracy'];
71217
71218           var debouncedRedraw = debounce(redraw, 250);
71219
71220           function redraw(selection) {
71221             var source = background.baseLayerSource();
71222             if (!source) return;
71223             var isDG = source.id.match(/^DigitalGlobe/i) !== null;
71224             var sourceLabel = source.label();
71225
71226             if (_currSourceName !== sourceLabel) {
71227               _currSourceName = sourceLabel;
71228               _metadata = {};
71229             }
71230
71231             selection.html('');
71232             var list = selection.append('ul').attr('class', 'background-info');
71233             list.append('li').html(_currSourceName);
71234
71235             _metadataKeys.forEach(function (k) {
71236               // DigitalGlobe vintage is available in raster layers for now.
71237               if (isDG && k === 'vintage') return;
71238               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]);
71239             });
71240
71241             debouncedGetMetadata(selection);
71242             var toggleTiles = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
71243             selection.append('a').html(_t.html('info_panels.background.' + toggleTiles)).attr('href', '#').attr('class', 'button button-toggle-tiles').on('click', function (d3_event) {
71244               d3_event.preventDefault();
71245               context.setDebug('tile', !context.getDebug('tile'));
71246               selection.call(redraw);
71247             });
71248
71249             if (isDG) {
71250               var key = source.id + '-vintage';
71251               var sourceVintage = context.background().findSource(key);
71252               var showsVintage = context.background().showsLayer(sourceVintage);
71253               var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
71254               selection.append('a').html(_t.html('info_panels.background.' + toggleVintage)).attr('href', '#').attr('class', 'button button-toggle-vintage').on('click', function (d3_event) {
71255                 d3_event.preventDefault();
71256                 context.background().toggleOverlayLayer(sourceVintage);
71257                 selection.call(redraw);
71258               });
71259             } // disable if necessary
71260
71261
71262             ['DigitalGlobe-Premium', 'DigitalGlobe-Standard'].forEach(function (layerId) {
71263               if (source.id !== layerId) {
71264                 var key = layerId + '-vintage';
71265                 var sourceVintage = context.background().findSource(key);
71266
71267                 if (context.background().showsLayer(sourceVintage)) {
71268                   context.background().toggleOverlayLayer(sourceVintage);
71269                 }
71270               }
71271             });
71272           }
71273
71274           var debouncedGetMetadata = debounce(getMetadata, 250);
71275
71276           function getMetadata(selection) {
71277             var tile = context.container().select('.layer-background img.tile-center'); // tile near viewport center
71278
71279             if (tile.empty()) return;
71280             var sourceName = _currSourceName;
71281             var d = tile.datum();
71282             var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
71283             var center = context.map().center(); // update zoom
71284
71285             _metadata.zoom = String(zoom);
71286             selection.selectAll('.background-info-list-zoom').classed('hide', false).selectAll('.background-info-span-zoom').html(_metadata.zoom);
71287             if (!d || !d.length >= 3) return;
71288             background.baseLayerSource().getMetadata(center, d, function (err, result) {
71289               if (err || _currSourceName !== sourceName) return; // update vintage
71290
71291               var vintage = result.vintage;
71292               _metadata.vintage = vintage && vintage.range || _t('info_panels.background.unknown');
71293               selection.selectAll('.background-info-list-vintage').classed('hide', false).selectAll('.background-info-span-vintage').html(_metadata.vintage); // update other _metadata
71294
71295               _metadataKeys.forEach(function (k) {
71296                 if (k === 'zoom' || k === 'vintage') return; // done already
71297
71298                 var val = result[k];
71299                 _metadata[k] = val;
71300                 selection.selectAll('.background-info-list-' + k).classed('hide', !val).selectAll('.background-info-span-' + k).html(val);
71301               });
71302             });
71303           }
71304
71305           var panel = function panel(selection) {
71306             selection.call(redraw);
71307             context.map().on('drawn.info-background', function () {
71308               selection.call(debouncedRedraw);
71309             }).on('move.info-background', function () {
71310               selection.call(debouncedGetMetadata);
71311             });
71312           };
71313
71314           panel.off = function () {
71315             context.map().on('drawn.info-background', null).on('move.info-background', null);
71316           };
71317
71318           panel.id = 'background';
71319           panel.label = _t.html('info_panels.background.title');
71320           panel.key = _t('info_panels.background.key');
71321           return panel;
71322         }
71323
71324         function uiPanelHistory(context) {
71325           var osm;
71326
71327           function displayTimestamp(timestamp) {
71328             if (!timestamp) return _t('info_panels.history.unknown');
71329             var options = {
71330               day: 'numeric',
71331               month: 'short',
71332               year: 'numeric',
71333               hour: 'numeric',
71334               minute: 'numeric',
71335               second: 'numeric'
71336             };
71337             var d = new Date(timestamp);
71338             if (isNaN(d.getTime())) return _t('info_panels.history.unknown');
71339             return d.toLocaleString(_mainLocalizer.localeCode(), options);
71340           }
71341
71342           function displayUser(selection, userName) {
71343             if (!userName) {
71344               selection.append('span').html(_t.html('info_panels.history.unknown'));
71345               return;
71346             }
71347
71348             selection.append('span').attr('class', 'user-name').html(userName);
71349             var links = selection.append('div').attr('class', 'links');
71350
71351             if (osm) {
71352               links.append('a').attr('class', 'user-osm-link').attr('href', osm.userURL(userName)).attr('target', '_blank').html('OSM');
71353             }
71354
71355             links.append('a').attr('class', 'user-hdyc-link').attr('href', 'https://hdyc.neis-one.org/?' + userName).attr('target', '_blank').attr('tabindex', -1).html('HDYC');
71356           }
71357
71358           function displayChangeset(selection, changeset) {
71359             if (!changeset) {
71360               selection.append('span').html(_t.html('info_panels.history.unknown'));
71361               return;
71362             }
71363
71364             selection.append('span').attr('class', 'changeset-id').html(changeset);
71365             var links = selection.append('div').attr('class', 'links');
71366
71367             if (osm) {
71368               links.append('a').attr('class', 'changeset-osm-link').attr('href', osm.changesetURL(changeset)).attr('target', '_blank').html('OSM');
71369             }
71370
71371             links.append('a').attr('class', 'changeset-osmcha-link').attr('href', 'https://osmcha.org/changesets/' + changeset).attr('target', '_blank').html('OSMCha');
71372             links.append('a').attr('class', 'changeset-achavi-link').attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset).attr('target', '_blank').html('Achavi');
71373           }
71374
71375           function redraw(selection) {
71376             var selectedNoteID = context.selectedNoteID();
71377             osm = context.connection();
71378             var selected, note, entity;
71379
71380             if (selectedNoteID && osm) {
71381               // selected 1 note
71382               selected = [_t('note.note') + ' ' + selectedNoteID];
71383               note = osm.getNote(selectedNoteID);
71384             } else {
71385               // selected 1..n entities
71386               selected = context.selectedIDs().filter(function (e) {
71387                 return context.hasEntity(e);
71388               });
71389
71390               if (selected.length) {
71391                 entity = context.entity(selected[0]);
71392               }
71393             }
71394
71395             var singular = selected.length === 1 ? selected[0] : null;
71396             selection.html('');
71397             selection.append('h4').attr('class', 'history-heading').html(singular || _t.html('info_panels.selected', {
71398               n: selected.length
71399             }));
71400             if (!singular) return;
71401
71402             if (entity) {
71403               selection.call(redrawEntity, entity);
71404             } else if (note) {
71405               selection.call(redrawNote, note);
71406             }
71407           }
71408
71409           function redrawNote(selection, note) {
71410             if (!note || note.isNew()) {
71411               selection.append('div').html(_t.html('info_panels.history.note_no_history'));
71412               return;
71413             }
71414
71415             var list = selection.append('ul');
71416             list.append('li').html(_t.html('info_panels.history.note_comments') + ':').append('span').html(note.comments.length);
71417
71418             if (note.comments.length) {
71419               list.append('li').html(_t.html('info_panels.history.note_created_date') + ':').append('span').html(displayTimestamp(note.comments[0].date));
71420               list.append('li').html(_t.html('info_panels.history.note_created_user') + ':').call(displayUser, note.comments[0].user);
71421             }
71422
71423             if (osm) {
71424               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'));
71425             }
71426           }
71427
71428           function redrawEntity(selection, entity) {
71429             if (!entity || entity.isNew()) {
71430               selection.append('div').html(_t.html('info_panels.history.no_history'));
71431               return;
71432             }
71433
71434             var links = selection.append('div').attr('class', 'links');
71435
71436             if (osm) {
71437               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');
71438             }
71439
71440             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');
71441             var list = selection.append('ul');
71442             list.append('li').html(_t.html('info_panels.history.version') + ':').append('span').html(entity.version);
71443             list.append('li').html(_t.html('info_panels.history.last_edit') + ':').append('span').html(displayTimestamp(entity.timestamp));
71444             list.append('li').html(_t.html('info_panels.history.edited_by') + ':').call(displayUser, entity.user);
71445             list.append('li').html(_t.html('info_panels.history.changeset') + ':').call(displayChangeset, entity.changeset);
71446           }
71447
71448           var panel = function panel(selection) {
71449             selection.call(redraw);
71450             context.map().on('drawn.info-history', function () {
71451               selection.call(redraw);
71452             });
71453             context.on('enter.info-history', function () {
71454               selection.call(redraw);
71455             });
71456           };
71457
71458           panel.off = function () {
71459             context.map().on('drawn.info-history', null);
71460             context.on('enter.info-history', null);
71461           };
71462
71463           panel.id = 'history';
71464           panel.label = _t.html('info_panels.history.title');
71465           panel.key = _t('info_panels.history.key');
71466           return panel;
71467         }
71468
71469         var OSM_PRECISION = 7;
71470         /**
71471          * Returns a localized representation of the given length measurement.
71472          *
71473          * @param {Number} m area in meters
71474          * @param {Boolean} isImperial true for U.S. customary units; false for metric
71475          */
71476
71477         function displayLength(m, isImperial) {
71478           var d = m * (isImperial ? 3.28084 : 1);
71479           var unit;
71480
71481           if (isImperial) {
71482             if (d >= 5280) {
71483               d /= 5280;
71484               unit = 'miles';
71485             } else {
71486               unit = 'feet';
71487             }
71488           } else {
71489             if (d >= 1000) {
71490               d /= 1000;
71491               unit = 'kilometers';
71492             } else {
71493               unit = 'meters';
71494             }
71495           }
71496
71497           return _t('units.' + unit, {
71498             quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
71499               maximumSignificantDigits: 4
71500             })
71501           });
71502         }
71503         /**
71504          * Returns a localized representation of the given area measurement.
71505          *
71506          * @param {Number} m2 area in square meters
71507          * @param {Boolean} isImperial true for U.S. customary units; false for metric
71508          */
71509
71510         function displayArea(m2, isImperial) {
71511           var locale = _mainLocalizer.localeCode();
71512           var d = m2 * (isImperial ? 10.7639111056 : 1);
71513           var d1, d2, area;
71514           var unit1 = '';
71515           var unit2 = '';
71516
71517           if (isImperial) {
71518             if (d >= 6969600) {
71519               // > 0.25mi² show mi²
71520               d1 = d / 27878400;
71521               unit1 = 'square_miles';
71522             } else {
71523               d1 = d;
71524               unit1 = 'square_feet';
71525             }
71526
71527             if (d > 4356 && d < 43560000) {
71528               // 0.1 - 1000 acres
71529               d2 = d / 43560;
71530               unit2 = 'acres';
71531             }
71532           } else {
71533             if (d >= 250000) {
71534               // > 0.25km² show km²
71535               d1 = d / 1000000;
71536               unit1 = 'square_kilometers';
71537             } else {
71538               d1 = d;
71539               unit1 = 'square_meters';
71540             }
71541
71542             if (d > 1000 && d < 10000000) {
71543               // 0.1 - 1000 hectares
71544               d2 = d / 10000;
71545               unit2 = 'hectares';
71546             }
71547           }
71548
71549           area = _t('units.' + unit1, {
71550             quantity: d1.toLocaleString(locale, {
71551               maximumSignificantDigits: 4
71552             })
71553           });
71554
71555           if (d2) {
71556             return _t('units.area_pair', {
71557               area1: area,
71558               area2: _t('units.' + unit2, {
71559                 quantity: d2.toLocaleString(locale, {
71560                   maximumSignificantDigits: 2
71561                 })
71562               })
71563             });
71564           } else {
71565             return area;
71566           }
71567         }
71568
71569         function wrap(x, min, max) {
71570           var d = max - min;
71571           return ((x - min) % d + d) % d + min;
71572         }
71573
71574         function clamp(x, min, max) {
71575           return Math.max(min, Math.min(x, max));
71576         }
71577
71578         function displayCoordinate(deg, pos, neg) {
71579           var locale = _mainLocalizer.localeCode();
71580           var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
71581           var sec = (min - Math.floor(min)) * 60;
71582           var displayDegrees = _t('units.arcdegrees', {
71583             quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
71584           });
71585           var displayCoordinate;
71586
71587           if (Math.floor(sec) > 0) {
71588             displayCoordinate = displayDegrees + _t('units.arcminutes', {
71589               quantity: Math.floor(min).toLocaleString(locale)
71590             }) + _t('units.arcseconds', {
71591               quantity: Math.round(sec).toLocaleString(locale)
71592             });
71593           } else if (Math.floor(min) > 0) {
71594             displayCoordinate = displayDegrees + _t('units.arcminutes', {
71595               quantity: Math.round(min).toLocaleString(locale)
71596             });
71597           } else {
71598             displayCoordinate = _t('units.arcdegrees', {
71599               quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
71600             });
71601           }
71602
71603           if (deg === 0) {
71604             return displayCoordinate;
71605           } else {
71606             return _t('units.coordinate', {
71607               coordinate: displayCoordinate,
71608               direction: _t('units.' + (deg > 0 ? pos : neg))
71609             });
71610           }
71611         }
71612         /**
71613          * Returns given coordinate pair in degree-minute-second format.
71614          *
71615          * @param {Array<Number>} coord longitude and latitude
71616          */
71617
71618
71619         function dmsCoordinatePair(coord) {
71620           return _t('units.coordinate_pair', {
71621             latitude: displayCoordinate(clamp(coord[1], -90, 90), 'north', 'south'),
71622             longitude: displayCoordinate(wrap(coord[0], -180, 180), 'east', 'west')
71623           });
71624         }
71625         /**
71626          * Returns the given coordinate pair in decimal format.
71627          * note: unlocalized to avoid comma ambiguity - see #4765
71628          *
71629          * @param {Array<Number>} coord longitude and latitude
71630          */
71631
71632         function decimalCoordinatePair(coord) {
71633           return _t('units.coordinate_pair', {
71634             latitude: clamp(coord[1], -90, 90).toFixed(OSM_PRECISION),
71635             longitude: wrap(coord[0], -180, 180).toFixed(OSM_PRECISION)
71636           });
71637         }
71638
71639         function uiPanelLocation(context) {
71640           var currLocation = '';
71641
71642           function redraw(selection) {
71643             selection.html('');
71644             var list = selection.append('ul'); // Mouse coordinates
71645
71646             var coord = context.map().mouseCoordinates();
71647
71648             if (coord.some(isNaN)) {
71649               coord = context.map().center();
71650             }
71651
71652             list.append('li').html(dmsCoordinatePair(coord)).append('li').html(decimalCoordinatePair(coord)); // Location Info
71653
71654             selection.append('div').attr('class', 'location-info').html(currLocation || ' ');
71655             debouncedGetLocation(selection, coord);
71656           }
71657
71658           var debouncedGetLocation = debounce(getLocation, 250);
71659
71660           function getLocation(selection, coord) {
71661             if (!services.geocoder) {
71662               currLocation = _t('info_panels.location.unknown_location');
71663               selection.selectAll('.location-info').html(currLocation);
71664             } else {
71665               services.geocoder.reverse(coord, function (err, result) {
71666                 currLocation = result ? result.display_name : _t('info_panels.location.unknown_location');
71667                 selection.selectAll('.location-info').html(currLocation);
71668               });
71669             }
71670           }
71671
71672           var panel = function panel(selection) {
71673             selection.call(redraw);
71674             context.surface().on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'move.info-location', function () {
71675               selection.call(redraw);
71676             });
71677           };
71678
71679           panel.off = function () {
71680             context.surface().on('.info-location', null);
71681           };
71682
71683           panel.id = 'location';
71684           panel.label = _t.html('info_panels.location.title');
71685           panel.key = _t('info_panels.location.key');
71686           return panel;
71687         }
71688
71689         function uiPanelMeasurement(context) {
71690           function radiansToMeters(r) {
71691             // using WGS84 authalic radius (6371007.1809 m)
71692             return r * 6371007.1809;
71693           }
71694
71695           function steradiansToSqmeters(r) {
71696             // http://gis.stackexchange.com/a/124857/40446
71697             return r / (4 * Math.PI) * 510065621724000;
71698           }
71699
71700           function toLineString(feature) {
71701             if (feature.type === 'LineString') return feature;
71702             var result = {
71703               type: 'LineString',
71704               coordinates: []
71705             };
71706
71707             if (feature.type === 'Polygon') {
71708               result.coordinates = feature.coordinates[0];
71709             } else if (feature.type === 'MultiPolygon') {
71710               result.coordinates = feature.coordinates[0][0];
71711             }
71712
71713             return result;
71714           }
71715
71716           var _isImperial = !_mainLocalizer.usesMetric();
71717
71718           function redraw(selection) {
71719             var graph = context.graph();
71720             var selectedNoteID = context.selectedNoteID();
71721             var osm = services.osm;
71722             var localeCode = _mainLocalizer.localeCode();
71723             var heading;
71724             var center, location, centroid;
71725             var closed, geometry;
71726             var totalNodeCount,
71727                 length = 0,
71728                 area = 0,
71729                 distance;
71730
71731             if (selectedNoteID && osm) {
71732               // selected 1 note
71733               var note = osm.getNote(selectedNoteID);
71734               heading = _t('note.note') + ' ' + selectedNoteID;
71735               location = note.loc;
71736               geometry = 'note';
71737             } else {
71738               // selected 1..n entities
71739               var selectedIDs = context.selectedIDs().filter(function (id) {
71740                 return context.hasEntity(id);
71741               });
71742               var selected = selectedIDs.map(function (id) {
71743                 return context.entity(id);
71744               });
71745               heading = selected.length === 1 ? selected[0].id : _t('info_panels.selected', {
71746                 n: selected.length
71747               });
71748
71749               if (selected.length) {
71750                 var extent = geoExtent();
71751
71752                 for (var i in selected) {
71753                   var entity = selected[i];
71754
71755                   extent._extend(entity.extent(graph));
71756
71757                   geometry = entity.geometry(graph);
71758
71759                   if (geometry === 'line' || geometry === 'area') {
71760                     closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
71761                     var feature = entity.asGeoJSON(graph);
71762                     length += radiansToMeters(d3_geoLength(toLineString(feature)));
71763                     centroid = d3_geoPath(context.projection).centroid(entity.asGeoJSON(graph));
71764                     centroid = centroid && context.projection.invert(centroid);
71765
71766                     if (!centroid || !isFinite(centroid[0]) || !isFinite(centroid[1])) {
71767                       centroid = entity.extent(graph).center();
71768                     }
71769
71770                     if (closed) {
71771                       area += steradiansToSqmeters(entity.area(graph));
71772                     }
71773                   }
71774                 }
71775
71776                 if (selected.length > 1) {
71777                   geometry = null;
71778                   closed = null;
71779                   centroid = null;
71780                 }
71781
71782                 if (selected.length === 2 && selected[0].type === 'node' && selected[1].type === 'node') {
71783                   distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
71784                 }
71785
71786                 if (selected.length === 1 && selected[0].type === 'node') {
71787                   location = selected[0].loc;
71788                 } else {
71789                   totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
71790                 }
71791
71792                 if (!location && !centroid) {
71793                   center = extent.center();
71794                 }
71795               }
71796             }
71797
71798             selection.html('');
71799
71800             if (heading) {
71801               selection.append('h4').attr('class', 'measurement-heading').html(heading);
71802             }
71803
71804             var list = selection.append('ul');
71805             var coordItem;
71806
71807             if (geometry) {
71808               list.append('li').html(_t.html('info_panels.measurement.geometry') + ':').append('span').html(closed ? _t('info_panels.measurement.closed_' + geometry) : _t('geometry.' + geometry));
71809             }
71810
71811             if (totalNodeCount) {
71812               list.append('li').html(_t.html('info_panels.measurement.node_count') + ':').append('span').html(totalNodeCount.toLocaleString(localeCode));
71813             }
71814
71815             if (area) {
71816               list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, _isImperial));
71817             }
71818
71819             if (length) {
71820               list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, _isImperial));
71821             }
71822
71823             if (typeof distance === 'number') {
71824               list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, _isImperial));
71825             }
71826
71827             if (location) {
71828               coordItem = list.append('li').html(_t.html('info_panels.measurement.location') + ':');
71829               coordItem.append('span').html(dmsCoordinatePair(location));
71830               coordItem.append('span').html(decimalCoordinatePair(location));
71831             }
71832
71833             if (centroid) {
71834               coordItem = list.append('li').html(_t.html('info_panels.measurement.centroid') + ':');
71835               coordItem.append('span').html(dmsCoordinatePair(centroid));
71836               coordItem.append('span').html(decimalCoordinatePair(centroid));
71837             }
71838
71839             if (center) {
71840               coordItem = list.append('li').html(_t.html('info_panels.measurement.center') + ':');
71841               coordItem.append('span').html(dmsCoordinatePair(center));
71842               coordItem.append('span').html(decimalCoordinatePair(center));
71843             }
71844
71845             if (length || area || typeof distance === 'number') {
71846               var toggle = _isImperial ? 'imperial' : 'metric';
71847               selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
71848                 d3_event.preventDefault();
71849                 _isImperial = !_isImperial;
71850                 selection.call(redraw);
71851               });
71852             }
71853           }
71854
71855           var panel = function panel(selection) {
71856             selection.call(redraw);
71857             context.map().on('drawn.info-measurement', function () {
71858               selection.call(redraw);
71859             });
71860             context.on('enter.info-measurement', function () {
71861               selection.call(redraw);
71862             });
71863           };
71864
71865           panel.off = function () {
71866             context.map().on('drawn.info-measurement', null);
71867             context.on('enter.info-measurement', null);
71868           };
71869
71870           panel.id = 'measurement';
71871           panel.label = _t.html('info_panels.measurement.title');
71872           panel.key = _t('info_panels.measurement.key');
71873           return panel;
71874         }
71875
71876         var uiInfoPanels = {
71877           background: uiPanelBackground,
71878           history: uiPanelHistory,
71879           location: uiPanelLocation,
71880           measurement: uiPanelMeasurement
71881         };
71882
71883         function uiInfo(context) {
71884           var ids = Object.keys(uiInfoPanels);
71885           var wasActive = ['measurement'];
71886           var panels = {};
71887           var active = {}; // create panels
71888
71889           ids.forEach(function (k) {
71890             if (!panels[k]) {
71891               panels[k] = uiInfoPanels[k](context);
71892               active[k] = false;
71893             }
71894           });
71895
71896           function info(selection) {
71897             function redraw() {
71898               var activeids = ids.filter(function (k) {
71899                 return active[k];
71900               }).sort();
71901               var containers = infoPanels.selectAll('.panel-container').data(activeids, function (k) {
71902                 return k;
71903               });
71904               containers.exit().style('opacity', 1).transition().duration(200).style('opacity', 0).on('end', function (d) {
71905                 select(this).call(panels[d].off).remove();
71906               });
71907               var enter = containers.enter().append('div').attr('class', function (d) {
71908                 return 'fillD2 panel-container panel-container-' + d;
71909               });
71910               enter.style('opacity', 0).transition().duration(200).style('opacity', 1);
71911               var title = enter.append('div').attr('class', 'panel-title fillD2');
71912               title.append('h3').html(function (d) {
71913                 return panels[d].label;
71914               });
71915               title.append('button').attr('class', 'close').on('click', function (d3_event, d) {
71916                 d3_event.stopImmediatePropagation();
71917                 d3_event.preventDefault();
71918                 info.toggle(d);
71919               }).call(svgIcon('#iD-icon-close'));
71920               enter.append('div').attr('class', function (d) {
71921                 return 'panel-content panel-content-' + d;
71922               }); // redraw the panels
71923
71924               infoPanels.selectAll('.panel-content').each(function (d) {
71925                 select(this).call(panels[d]);
71926               });
71927             }
71928
71929             info.toggle = function (which) {
71930               var activeids = ids.filter(function (k) {
71931                 return active[k];
71932               });
71933
71934               if (which) {
71935                 // toggle one
71936                 active[which] = !active[which];
71937
71938                 if (activeids.length === 1 && activeids[0] === which) {
71939                   // none active anymore
71940                   wasActive = [which];
71941                 }
71942
71943                 context.container().select('.' + which + '-panel-toggle-item').classed('active', active[which]).select('input').property('checked', active[which]);
71944               } else {
71945                 // toggle all
71946                 if (activeids.length) {
71947                   wasActive = activeids;
71948                   activeids.forEach(function (k) {
71949                     active[k] = false;
71950                   });
71951                 } else {
71952                   wasActive.forEach(function (k) {
71953                     active[k] = true;
71954                   });
71955                 }
71956               }
71957
71958               redraw();
71959             };
71960
71961             var infoPanels = selection.selectAll('.info-panels').data([0]);
71962             infoPanels = infoPanels.enter().append('div').attr('class', 'info-panels').merge(infoPanels);
71963             redraw();
71964             context.keybinding().on(uiCmd('⌘' + _t('info_panels.key')), function (d3_event) {
71965               d3_event.stopImmediatePropagation();
71966               d3_event.preventDefault();
71967               info.toggle();
71968             });
71969             ids.forEach(function (k) {
71970               var key = _t('info_panels.' + k + '.key', {
71971                 "default": null
71972               });
71973               if (!key) return;
71974               context.keybinding().on(uiCmd('⌘⇧' + key), function (d3_event) {
71975                 d3_event.stopImmediatePropagation();
71976                 d3_event.preventDefault();
71977                 info.toggle(k);
71978               });
71979             });
71980           }
71981
71982           return info;
71983         }
71984
71985         function pointBox(loc, context) {
71986           var rect = context.surfaceRect();
71987           var point = context.curtainProjection(loc);
71988           return {
71989             left: point[0] + rect.left - 40,
71990             top: point[1] + rect.top - 60,
71991             width: 80,
71992             height: 90
71993           };
71994         }
71995         function pad(locOrBox, padding, context) {
71996           var box;
71997
71998           if (locOrBox instanceof Array) {
71999             var rect = context.surfaceRect();
72000             var point = context.curtainProjection(locOrBox);
72001             box = {
72002               left: point[0] + rect.left,
72003               top: point[1] + rect.top
72004             };
72005           } else {
72006             box = locOrBox;
72007           }
72008
72009           return {
72010             left: box.left - padding,
72011             top: box.top - padding,
72012             width: (box.width || 0) + 2 * padding,
72013             height: (box.width || 0) + 2 * padding
72014           };
72015         }
72016         function icon(name, svgklass, useklass) {
72017           return '<svg class="icon ' + (svgklass || '') + '">' + '<use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : '') + '></use></svg>';
72018         }
72019         var helpStringReplacements; // Returns the localized HTML element for `id` with a standardized set of icon, key, and
72020         // label replacements suitable for tutorials and documentation. Optionally supplemented
72021         // with custom `replacements`
72022
72023         function helpHtml(id, replacements) {
72024           // only load these the first time
72025           if (!helpStringReplacements) {
72026             helpStringReplacements = {
72027               // insert icons corresponding to various UI elements
72028               point_icon: icon('#iD-icon-point', 'inline'),
72029               line_icon: icon('#iD-icon-line', 'inline'),
72030               area_icon: icon('#iD-icon-area', 'inline'),
72031               note_icon: icon('#iD-icon-note', 'inline add-note'),
72032               plus: icon('#iD-icon-plus', 'inline'),
72033               minus: icon('#iD-icon-minus', 'inline'),
72034               layers_icon: icon('#iD-icon-layers', 'inline'),
72035               data_icon: icon('#iD-icon-data', 'inline'),
72036               inspect: icon('#iD-icon-inspect', 'inline'),
72037               help_icon: icon('#iD-icon-help', 'inline'),
72038               undo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo', 'inline'),
72039               redo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-undo' : '#iD-icon-redo', 'inline'),
72040               save_icon: icon('#iD-icon-save', 'inline'),
72041               // operation icons
72042               circularize_icon: icon('#iD-operation-circularize', 'inline operation'),
72043               continue_icon: icon('#iD-operation-continue', 'inline operation'),
72044               copy_icon: icon('#iD-operation-copy', 'inline operation'),
72045               delete_icon: icon('#iD-operation-delete', 'inline operation'),
72046               disconnect_icon: icon('#iD-operation-disconnect', 'inline operation'),
72047               downgrade_icon: icon('#iD-operation-downgrade', 'inline operation'),
72048               extract_icon: icon('#iD-operation-extract', 'inline operation'),
72049               merge_icon: icon('#iD-operation-merge', 'inline operation'),
72050               move_icon: icon('#iD-operation-move', 'inline operation'),
72051               orthogonalize_icon: icon('#iD-operation-orthogonalize', 'inline operation'),
72052               paste_icon: icon('#iD-operation-paste', 'inline operation'),
72053               reflect_long_icon: icon('#iD-operation-reflect-long', 'inline operation'),
72054               reflect_short_icon: icon('#iD-operation-reflect-short', 'inline operation'),
72055               reverse_icon: icon('#iD-operation-reverse', 'inline operation'),
72056               rotate_icon: icon('#iD-operation-rotate', 'inline operation'),
72057               split_icon: icon('#iD-operation-split', 'inline operation'),
72058               straighten_icon: icon('#iD-operation-straighten', 'inline operation'),
72059               // interaction icons
72060               leftclick: icon('#iD-walkthrough-mouse-left', 'inline operation'),
72061               rightclick: icon('#iD-walkthrough-mouse-right', 'inline operation'),
72062               mousewheel_icon: icon('#iD-walkthrough-mousewheel', 'inline operation'),
72063               tap_icon: icon('#iD-walkthrough-tap', 'inline operation'),
72064               doubletap_icon: icon('#iD-walkthrough-doubletap', 'inline operation'),
72065               longpress_icon: icon('#iD-walkthrough-longpress', 'inline operation'),
72066               touchdrag_icon: icon('#iD-walkthrough-touchdrag', 'inline operation'),
72067               pinch_icon: icon('#iD-walkthrough-pinch-apart', 'inline operation'),
72068               // insert keys; may be localized and platform-dependent
72069               shift: uiCmd.display('⇧'),
72070               alt: uiCmd.display('⌥'),
72071               "return": uiCmd.display('↵'),
72072               esc: _t.html('shortcuts.key.esc'),
72073               space: _t.html('shortcuts.key.space'),
72074               add_note_key: _t.html('modes.add_note.key'),
72075               help_key: _t.html('help.key'),
72076               shortcuts_key: _t.html('shortcuts.toggle.key'),
72077               // reference localized UI labels directly so that they'll always match
72078               save: _t.html('save.title'),
72079               undo: _t.html('undo.title'),
72080               redo: _t.html('redo.title'),
72081               upload: _t.html('commit.save'),
72082               point: _t.html('modes.add_point.title'),
72083               line: _t.html('modes.add_line.title'),
72084               area: _t.html('modes.add_area.title'),
72085               note: _t.html('modes.add_note.label'),
72086               circularize: _t.html('operations.circularize.title'),
72087               "continue": _t.html('operations.continue.title'),
72088               copy: _t.html('operations.copy.title'),
72089               "delete": _t.html('operations.delete.title'),
72090               disconnect: _t.html('operations.disconnect.title'),
72091               downgrade: _t.html('operations.downgrade.title'),
72092               extract: _t.html('operations.extract.title'),
72093               merge: _t.html('operations.merge.title'),
72094               move: _t.html('operations.move.title'),
72095               orthogonalize: _t.html('operations.orthogonalize.title'),
72096               paste: _t.html('operations.paste.title'),
72097               reflect_long: _t.html('operations.reflect.title.long'),
72098               reflect_short: _t.html('operations.reflect.title.short'),
72099               reverse: _t.html('operations.reverse.title'),
72100               rotate: _t.html('operations.rotate.title'),
72101               split: _t.html('operations.split.title'),
72102               straighten: _t.html('operations.straighten.title'),
72103               map_data: _t.html('map_data.title'),
72104               osm_notes: _t.html('map_data.layers.notes.title'),
72105               fields: _t.html('inspector.fields'),
72106               tags: _t.html('inspector.tags'),
72107               relations: _t.html('inspector.relations'),
72108               new_relation: _t.html('inspector.new_relation'),
72109               turn_restrictions: _t.html('_tagging.presets.fields.restrictions.label'),
72110               background_settings: _t.html('background.description'),
72111               imagery_offset: _t.html('background.fix_misalignment'),
72112               start_the_walkthrough: _t.html('splash.walkthrough'),
72113               help: _t.html('help.title'),
72114               ok: _t.html('intro.ok')
72115             };
72116           }
72117
72118           var reps;
72119
72120           if (replacements) {
72121             reps = Object.assign(replacements, helpStringReplacements);
72122           } else {
72123             reps = helpStringReplacements;
72124           }
72125
72126           return _t.html(id, reps) // use keyboard key styling for shortcuts
72127           .replace(/\`(.*?)\`/g, '<kbd>$1</kbd>');
72128         }
72129
72130         function slugify(text) {
72131           return text.toString().toLowerCase().replace(/\s+/g, '-') // Replace spaces with -
72132           .replace(/[^\w\-]+/g, '') // Remove all non-word chars
72133           .replace(/\-\-+/g, '-') // Replace multiple - with single -
72134           .replace(/^-+/, '') // Trim - from start of text
72135           .replace(/-+$/, ''); // Trim - from end of text
72136         } // console warning for missing walkthrough names
72137
72138
72139         var missingStrings = {};
72140
72141         function checkKey(key, text) {
72142           if (_t(key, {
72143             "default": undefined
72144           }) === undefined) {
72145             if (missingStrings.hasOwnProperty(key)) return; // warn once
72146
72147             missingStrings[key] = text;
72148             var missing = key + ': ' + text;
72149             if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
72150           }
72151         }
72152
72153         function localize(obj) {
72154           var key; // Assign name if entity has one..
72155
72156           var name = obj.tags && obj.tags.name;
72157
72158           if (name) {
72159             key = 'intro.graph.name.' + slugify(name);
72160             obj.tags.name = _t(key, {
72161               "default": name
72162             });
72163             checkKey(key, name);
72164           } // Assign street name if entity has one..
72165
72166
72167           var street = obj.tags && obj.tags['addr:street'];
72168
72169           if (street) {
72170             key = 'intro.graph.name.' + slugify(street);
72171             obj.tags['addr:street'] = _t(key, {
72172               "default": street
72173             });
72174             checkKey(key, street); // Add address details common across walkthrough..
72175
72176             var addrTags = ['block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood', 'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'];
72177             addrTags.forEach(function (k) {
72178               var key = 'intro.graph.' + k;
72179               var tag = 'addr:' + k;
72180               var val = obj.tags && obj.tags[tag];
72181               var str = _t(key, {
72182                 "default": val
72183               });
72184
72185               if (str) {
72186                 if (str.match(/^<.*>$/) !== null) {
72187                   delete obj.tags[tag];
72188                 } else {
72189                   obj.tags[tag] = str;
72190                 }
72191               }
72192             });
72193           }
72194
72195           return obj;
72196         } // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
72197
72198         function isMostlySquare(points) {
72199           // note: uses 15 here instead of the 12 from actionOrthogonalize because
72200           // actionOrthogonalize can actually straighten some larger angles as it iterates
72201           var threshold = 15; // degrees within right or straight
72202
72203           var lowerBound = Math.cos((90 - threshold) * Math.PI / 180); // near right
72204
72205           var upperBound = Math.cos(threshold * Math.PI / 180); // near straight
72206
72207           for (var i = 0; i < points.length; i++) {
72208             var a = points[(i - 1 + points.length) % points.length];
72209             var origin = points[i];
72210             var b = points[(i + 1) % points.length];
72211             var dotp = geoVecNormalizedDot(a, b, origin);
72212             var mag = Math.abs(dotp);
72213
72214             if (mag > lowerBound && mag < upperBound) {
72215               return false;
72216             }
72217           }
72218
72219           return true;
72220         }
72221         function selectMenuItem(context, operation) {
72222           return context.container().select('.edit-menu .edit-menu-item-' + operation);
72223         }
72224         function transitionTime(point1, point2) {
72225           var distance = geoSphericalDistance(point1, point2);
72226
72227           if (distance === 0) {
72228             return 0;
72229           } else if (distance < 80) {
72230             return 500;
72231           } else {
72232             return 1000;
72233           }
72234         }
72235
72236         // hide class, which sets display=none, and a d3 transition for opacity.
72237         // this will cause blinking when called repeatedly, so check that the
72238         // value actually changes between calls.
72239
72240         function uiToggle(show, callback) {
72241           return function (selection) {
72242             selection.style('opacity', show ? 0 : 1).classed('hide', false).transition().style('opacity', show ? 1 : 0).on('end', function () {
72243               select(this).classed('hide', !show).style('opacity', null);
72244               if (callback) callback.apply(this);
72245             });
72246           };
72247         }
72248
72249         function uiCurtain(containerNode) {
72250           var surface = select(null),
72251               tooltip = select(null),
72252               darkness = select(null);
72253
72254           function curtain(selection) {
72255             surface = selection.append('svg').attr('class', 'curtain').style('top', 0).style('left', 0);
72256             darkness = surface.append('path').attr('x', 0).attr('y', 0).attr('class', 'curtain-darkness');
72257             select(window).on('resize.curtain', resize);
72258             tooltip = selection.append('div').attr('class', 'tooltip');
72259             tooltip.append('div').attr('class', 'popover-arrow');
72260             tooltip.append('div').attr('class', 'popover-inner');
72261             resize();
72262
72263             function resize() {
72264               surface.attr('width', containerNode.clientWidth).attr('height', containerNode.clientHeight);
72265               curtain.cut(darkness.datum());
72266             }
72267           }
72268           /**
72269            * Reveal cuts the curtain to highlight the given box,
72270            * and shows a tooltip with instructions next to the box.
72271            *
72272            * @param  {String|ClientRect} [box]   box used to cut the curtain
72273            * @param  {String}    [text]          text for a tooltip
72274            * @param  {Object}    [options]
72275            * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
72276            * @param  {integer}   [options.duration]        transition time in milliseconds
72277            * @param  {string}    [options.buttonText]      if set, create a button with this text label
72278            * @param  {function}  [options.buttonCallback]  if set, the callback for the button
72279            * @param  {function}  [options.padding]         extra margin in px to put around bbox
72280            * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
72281            */
72282
72283
72284           curtain.reveal = function (box, html, options) {
72285             options = options || {};
72286
72287             if (typeof box === 'string') {
72288               box = select(box).node();
72289             }
72290
72291             if (box && box.getBoundingClientRect) {
72292               box = copyBox(box.getBoundingClientRect());
72293               var containerRect = containerNode.getBoundingClientRect();
72294               box.top -= containerRect.top;
72295               box.left -= containerRect.left;
72296             }
72297
72298             if (box && options.padding) {
72299               box.top -= options.padding;
72300               box.left -= options.padding;
72301               box.bottom += options.padding;
72302               box.right += options.padding;
72303               box.height += options.padding * 2;
72304               box.width += options.padding * 2;
72305             }
72306
72307             var tooltipBox;
72308
72309             if (options.tooltipBox) {
72310               tooltipBox = options.tooltipBox;
72311
72312               if (typeof tooltipBox === 'string') {
72313                 tooltipBox = select(tooltipBox).node();
72314               }
72315
72316               if (tooltipBox && tooltipBox.getBoundingClientRect) {
72317                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
72318               }
72319             } else {
72320               tooltipBox = box;
72321             }
72322
72323             if (tooltipBox && html) {
72324               if (html.indexOf('**') !== -1) {
72325                 if (html.indexOf('<span') === 0) {
72326                   html = html.replace(/^(<span.*?>)(.+?)(\*\*)/, '$1<span>$2</span>$3');
72327                 } else {
72328                   html = html.replace(/^(.+?)(\*\*)/, '<span>$1</span>$2');
72329                 } // pseudo markdown bold text for the instruction section..
72330
72331
72332                 html = html.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
72333               }
72334
72335               html = html.replace(/\*(.*?)\*/g, '<em>$1</em>'); // emphasis
72336
72337               html = html.replace(/\{br\}/g, '<br/><br/>'); // linebreak
72338
72339               if (options.buttonText && options.buttonCallback) {
72340                 html += '<div class="button-section">' + '<button href="#" class="button action">' + options.buttonText + '</button></div>';
72341               }
72342
72343               var classes = 'curtain-tooltip popover tooltip arrowed in ' + (options.tooltipClass || '');
72344               tooltip.classed(classes, true).selectAll('.popover-inner').html(html);
72345
72346               if (options.buttonText && options.buttonCallback) {
72347                 var button = tooltip.selectAll('.button-section .button.action');
72348                 button.on('click', function (d3_event) {
72349                   d3_event.preventDefault();
72350                   options.buttonCallback();
72351                 });
72352               }
72353
72354               var tip = copyBox(tooltip.node().getBoundingClientRect()),
72355                   w = containerNode.clientWidth,
72356                   h = containerNode.clientHeight,
72357                   tooltipWidth = 200,
72358                   tooltipArrow = 5,
72359                   side,
72360                   pos; // hack: this will have bottom placement,
72361               // so need to reserve extra space for the tooltip illustration.
72362
72363               if (options.tooltipClass === 'intro-mouse') {
72364                 tip.height += 80;
72365               } // trim box dimensions to just the portion that fits in the container..
72366
72367
72368               if (tooltipBox.top + tooltipBox.height > h) {
72369                 tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
72370               }
72371
72372               if (tooltipBox.left + tooltipBox.width > w) {
72373                 tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
72374               } // determine tooltip placement..
72375
72376
72377               if (tooltipBox.top + tooltipBox.height < 100) {
72378                 // tooltip below box..
72379                 side = 'bottom';
72380                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top + tooltipBox.height];
72381               } else if (tooltipBox.top > h - 140) {
72382                 // tooltip above box..
72383                 side = 'top';
72384                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top - tip.height];
72385               } else {
72386                 // tooltip to the side of the tooltipBox..
72387                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
72388
72389                 if (_mainLocalizer.textDirection() === 'rtl') {
72390                   if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
72391                     side = 'right';
72392                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
72393                   } else {
72394                     side = 'left';
72395                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
72396                   }
72397                 } else {
72398                   if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
72399                     side = 'left';
72400                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
72401                   } else {
72402                     side = 'right';
72403                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
72404                   }
72405                 }
72406               }
72407
72408               if (options.duration !== 0 || !tooltip.classed(side)) {
72409                 tooltip.call(uiToggle(true));
72410               }
72411
72412               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
72413               // (doesn't affect the placement of the popover-arrow)
72414
72415               var shiftY = 0;
72416
72417               if (side === 'left' || side === 'right') {
72418                 if (pos[1] < 60) {
72419                   shiftY = 60 - pos[1];
72420                 } else if (pos[1] + tip.height > h - 100) {
72421                   shiftY = h - pos[1] - tip.height - 100;
72422                 }
72423               }
72424
72425               tooltip.selectAll('.popover-inner').style('top', shiftY + 'px');
72426             } else {
72427               tooltip.classed('in', false).call(uiToggle(false));
72428             }
72429
72430             curtain.cut(box, options.duration);
72431             return tooltip;
72432           };
72433
72434           curtain.cut = function (datum, duration) {
72435             darkness.datum(datum).interrupt();
72436             var selection;
72437
72438             if (duration === 0) {
72439               selection = darkness;
72440             } else {
72441               selection = darkness.transition().duration(duration || 600).ease(linear$1);
72442             }
72443
72444             selection.attr('d', function (d) {
72445               var containerWidth = containerNode.clientWidth;
72446               var containerHeight = containerNode.clientHeight;
72447               var string = 'M 0,0 L 0,' + containerHeight + ' L ' + containerWidth + ',' + containerHeight + 'L' + containerWidth + ',0 Z';
72448               if (!d) return string;
72449               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';
72450             });
72451           };
72452
72453           curtain.remove = function () {
72454             surface.remove();
72455             tooltip.remove();
72456             select(window).on('resize.curtain', null);
72457           }; // ClientRects are immutable, so copy them to an object,
72458           // in case we need to trim the height/width.
72459
72460
72461           function copyBox(src) {
72462             return {
72463               top: src.top,
72464               right: src.right,
72465               bottom: src.bottom,
72466               left: src.left,
72467               width: src.width,
72468               height: src.height
72469             };
72470           }
72471
72472           return curtain;
72473         }
72474
72475         function uiIntroWelcome(context, reveal) {
72476           var dispatch = dispatch$8('done');
72477           var chapter = {
72478             title: 'intro.welcome.title'
72479           };
72480
72481           function welcome() {
72482             context.map().centerZoom([-85.63591, 41.94285], 19);
72483             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.welcome'), {
72484               buttonText: _t.html('intro.ok'),
72485               buttonCallback: practice
72486             });
72487           }
72488
72489           function practice() {
72490             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.practice'), {
72491               buttonText: _t.html('intro.ok'),
72492               buttonCallback: words
72493             });
72494           }
72495
72496           function words() {
72497             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.words'), {
72498               buttonText: _t.html('intro.ok'),
72499               buttonCallback: chapters
72500             });
72501           }
72502
72503           function chapters() {
72504             dispatch.call('done');
72505             reveal('.intro-nav-wrap .chapter-navigation', helpHtml('intro.welcome.chapters', {
72506               next: _t('intro.navigation.title')
72507             }));
72508           }
72509
72510           chapter.enter = function () {
72511             welcome();
72512           };
72513
72514           chapter.exit = function () {
72515             context.container().select('.curtain-tooltip.intro-mouse').selectAll('.counter').remove();
72516           };
72517
72518           chapter.restart = function () {
72519             chapter.exit();
72520             chapter.enter();
72521           };
72522
72523           return utilRebind(chapter, dispatch, 'on');
72524         }
72525
72526         function uiIntroNavigation(context, reveal) {
72527           var dispatch = dispatch$8('done');
72528           var timeouts = [];
72529           var hallId = 'n2061';
72530           var townHall = [-85.63591, 41.94285];
72531           var springStreetId = 'w397';
72532           var springStreetEndId = 'n1834';
72533           var springStreet = [-85.63582, 41.94255];
72534           var onewayField = _mainPresetIndex.field('oneway');
72535           var maxspeedField = _mainPresetIndex.field('maxspeed');
72536           var chapter = {
72537             title: 'intro.navigation.title'
72538           };
72539
72540           function timeout(f, t) {
72541             timeouts.push(window.setTimeout(f, t));
72542           }
72543
72544           function eventCancel(d3_event) {
72545             d3_event.stopPropagation();
72546             d3_event.preventDefault();
72547           }
72548
72549           function isTownHallSelected() {
72550             var ids = context.selectedIDs();
72551             return ids.length === 1 && ids[0] === hallId;
72552           }
72553
72554           function dragMap() {
72555             context.enter(modeBrowse(context));
72556             context.history().reset('initial');
72557             var msec = transitionTime(townHall, context.map().center());
72558
72559             if (msec) {
72560               reveal(null, null, {
72561                 duration: 0
72562               });
72563             }
72564
72565             context.map().centerZoomEase(townHall, 19, msec);
72566             timeout(function () {
72567               var centerStart = context.map().center();
72568               var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
72569               var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
72570               reveal('.surface', dragString);
72571               context.map().on('drawn.intro', function () {
72572                 reveal('.surface', dragString, {
72573                   duration: 0
72574                 });
72575               });
72576               context.map().on('move.intro', function () {
72577                 var centerNow = context.map().center();
72578
72579                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
72580                   context.map().on('move.intro', null);
72581                   timeout(function () {
72582                     continueTo(zoomMap);
72583                   }, 3000);
72584                 }
72585               });
72586             }, msec + 100);
72587
72588             function continueTo(nextStep) {
72589               context.map().on('move.intro drawn.intro', null);
72590               nextStep();
72591             }
72592           }
72593
72594           function zoomMap() {
72595             var zoomStart = context.map().zoom();
72596             var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
72597             var zoomString = helpHtml('intro.navigation.' + textId);
72598             reveal('.surface', zoomString);
72599             context.map().on('drawn.intro', function () {
72600               reveal('.surface', zoomString, {
72601                 duration: 0
72602               });
72603             });
72604             context.map().on('move.intro', function () {
72605               if (context.map().zoom() !== zoomStart) {
72606                 context.map().on('move.intro', null);
72607                 timeout(function () {
72608                   continueTo(features);
72609                 }, 3000);
72610               }
72611             });
72612
72613             function continueTo(nextStep) {
72614               context.map().on('move.intro drawn.intro', null);
72615               nextStep();
72616             }
72617           }
72618
72619           function features() {
72620             var onClick = function onClick() {
72621               continueTo(pointsLinesAreas);
72622             };
72623
72624             reveal('.surface', helpHtml('intro.navigation.features'), {
72625               buttonText: _t.html('intro.ok'),
72626               buttonCallback: onClick
72627             });
72628             context.map().on('drawn.intro', function () {
72629               reveal('.surface', helpHtml('intro.navigation.features'), {
72630                 duration: 0,
72631                 buttonText: _t.html('intro.ok'),
72632                 buttonCallback: onClick
72633               });
72634             });
72635
72636             function continueTo(nextStep) {
72637               context.map().on('drawn.intro', null);
72638               nextStep();
72639             }
72640           }
72641
72642           function pointsLinesAreas() {
72643             var onClick = function onClick() {
72644               continueTo(nodesWays);
72645             };
72646
72647             reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
72648               buttonText: _t.html('intro.ok'),
72649               buttonCallback: onClick
72650             });
72651             context.map().on('drawn.intro', function () {
72652               reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
72653                 duration: 0,
72654                 buttonText: _t.html('intro.ok'),
72655                 buttonCallback: onClick
72656               });
72657             });
72658
72659             function continueTo(nextStep) {
72660               context.map().on('drawn.intro', null);
72661               nextStep();
72662             }
72663           }
72664
72665           function nodesWays() {
72666             var onClick = function onClick() {
72667               continueTo(clickTownHall);
72668             };
72669
72670             reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
72671               buttonText: _t.html('intro.ok'),
72672               buttonCallback: onClick
72673             });
72674             context.map().on('drawn.intro', function () {
72675               reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
72676                 duration: 0,
72677                 buttonText: _t.html('intro.ok'),
72678                 buttonCallback: onClick
72679               });
72680             });
72681
72682             function continueTo(nextStep) {
72683               context.map().on('drawn.intro', null);
72684               nextStep();
72685             }
72686           }
72687
72688           function clickTownHall() {
72689             context.enter(modeBrowse(context));
72690             context.history().reset('initial');
72691             var entity = context.hasEntity(hallId);
72692             if (!entity) return;
72693             reveal(null, null, {
72694               duration: 0
72695             });
72696             context.map().centerZoomEase(entity.loc, 19, 500);
72697             timeout(function () {
72698               var entity = context.hasEntity(hallId);
72699               if (!entity) return;
72700               var box = pointBox(entity.loc, context);
72701               var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
72702               reveal(box, helpHtml('intro.navigation.' + textId));
72703               context.map().on('move.intro drawn.intro', function () {
72704                 var entity = context.hasEntity(hallId);
72705                 if (!entity) return;
72706                 var box = pointBox(entity.loc, context);
72707                 reveal(box, helpHtml('intro.navigation.' + textId), {
72708                   duration: 0
72709                 });
72710               });
72711               context.on('enter.intro', function () {
72712                 if (isTownHallSelected()) continueTo(selectedTownHall);
72713               });
72714             }, 550); // after centerZoomEase
72715
72716             context.history().on('change.intro', function () {
72717               if (!context.hasEntity(hallId)) {
72718                 continueTo(clickTownHall);
72719               }
72720             });
72721
72722             function continueTo(nextStep) {
72723               context.on('enter.intro', null);
72724               context.map().on('move.intro drawn.intro', null);
72725               context.history().on('change.intro', null);
72726               nextStep();
72727             }
72728           }
72729
72730           function selectedTownHall() {
72731             if (!isTownHallSelected()) return clickTownHall();
72732             var entity = context.hasEntity(hallId);
72733             if (!entity) return clickTownHall();
72734             var box = pointBox(entity.loc, context);
72735
72736             var onClick = function onClick() {
72737               continueTo(editorTownHall);
72738             };
72739
72740             reveal(box, helpHtml('intro.navigation.selected_townhall'), {
72741               buttonText: _t.html('intro.ok'),
72742               buttonCallback: onClick
72743             });
72744             context.map().on('move.intro drawn.intro', function () {
72745               var entity = context.hasEntity(hallId);
72746               if (!entity) return;
72747               var box = pointBox(entity.loc, context);
72748               reveal(box, helpHtml('intro.navigation.selected_townhall'), {
72749                 duration: 0,
72750                 buttonText: _t.html('intro.ok'),
72751                 buttonCallback: onClick
72752               });
72753             });
72754             context.history().on('change.intro', function () {
72755               if (!context.hasEntity(hallId)) {
72756                 continueTo(clickTownHall);
72757               }
72758             });
72759
72760             function continueTo(nextStep) {
72761               context.map().on('move.intro drawn.intro', null);
72762               context.history().on('change.intro', null);
72763               nextStep();
72764             }
72765           }
72766
72767           function editorTownHall() {
72768             if (!isTownHallSelected()) return clickTownHall(); // disallow scrolling
72769
72770             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
72771
72772             var onClick = function onClick() {
72773               continueTo(presetTownHall);
72774             };
72775
72776             reveal('.entity-editor-pane', helpHtml('intro.navigation.editor_townhall'), {
72777               buttonText: _t.html('intro.ok'),
72778               buttonCallback: onClick
72779             });
72780             context.on('exit.intro', function () {
72781               continueTo(clickTownHall);
72782             });
72783             context.history().on('change.intro', function () {
72784               if (!context.hasEntity(hallId)) {
72785                 continueTo(clickTownHall);
72786               }
72787             });
72788
72789             function continueTo(nextStep) {
72790               context.on('exit.intro', null);
72791               context.history().on('change.intro', null);
72792               context.container().select('.inspector-wrap').on('wheel.intro', null);
72793               nextStep();
72794             }
72795           }
72796
72797           function presetTownHall() {
72798             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
72799
72800             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
72801
72802             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel); // preset match, in case the user happened to change it.
72803
72804             var entity = context.entity(context.selectedIDs()[0]);
72805             var preset = _mainPresetIndex.match(entity, context.graph());
72806
72807             var onClick = function onClick() {
72808               continueTo(fieldsTownHall);
72809             };
72810
72811             reveal('.entity-editor-pane .section-feature-type', helpHtml('intro.navigation.preset_townhall', {
72812               preset: preset.name()
72813             }), {
72814               buttonText: _t.html('intro.ok'),
72815               buttonCallback: onClick
72816             });
72817             context.on('exit.intro', function () {
72818               continueTo(clickTownHall);
72819             });
72820             context.history().on('change.intro', function () {
72821               if (!context.hasEntity(hallId)) {
72822                 continueTo(clickTownHall);
72823               }
72824             });
72825
72826             function continueTo(nextStep) {
72827               context.on('exit.intro', null);
72828               context.history().on('change.intro', null);
72829               context.container().select('.inspector-wrap').on('wheel.intro', null);
72830               nextStep();
72831             }
72832           }
72833
72834           function fieldsTownHall() {
72835             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
72836
72837             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
72838
72839             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
72840
72841             var onClick = function onClick() {
72842               continueTo(closeTownHall);
72843             };
72844
72845             reveal('.entity-editor-pane .section-preset-fields', helpHtml('intro.navigation.fields_townhall'), {
72846               buttonText: _t.html('intro.ok'),
72847               buttonCallback: onClick
72848             });
72849             context.on('exit.intro', function () {
72850               continueTo(clickTownHall);
72851             });
72852             context.history().on('change.intro', function () {
72853               if (!context.hasEntity(hallId)) {
72854                 continueTo(clickTownHall);
72855               }
72856             });
72857
72858             function continueTo(nextStep) {
72859               context.on('exit.intro', null);
72860               context.history().on('change.intro', null);
72861               context.container().select('.inspector-wrap').on('wheel.intro', null);
72862               nextStep();
72863             }
72864           }
72865
72866           function closeTownHall() {
72867             if (!isTownHallSelected()) return clickTownHall();
72868             var selector = '.entity-editor-pane button.close svg use';
72869             var href = select(selector).attr('href') || '#iD-icon-close';
72870             reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
72871               button: icon(href, 'inline')
72872             }));
72873             context.on('exit.intro', function () {
72874               continueTo(searchStreet);
72875             });
72876             context.history().on('change.intro', function () {
72877               // update the close icon in the tooltip if the user edits something.
72878               var selector = '.entity-editor-pane button.close svg use';
72879               var href = select(selector).attr('href') || '#iD-icon-close';
72880               reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
72881                 button: icon(href, 'inline')
72882               }), {
72883                 duration: 0
72884               });
72885             });
72886
72887             function continueTo(nextStep) {
72888               context.on('exit.intro', null);
72889               context.history().on('change.intro', null);
72890               nextStep();
72891             }
72892           }
72893
72894           function searchStreet() {
72895             context.enter(modeBrowse(context));
72896             context.history().reset('initial'); // ensure spring street exists
72897
72898             var msec = transitionTime(springStreet, context.map().center());
72899
72900             if (msec) {
72901               reveal(null, null, {
72902                 duration: 0
72903               });
72904             }
72905
72906             context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
72907
72908             timeout(function () {
72909               reveal('.search-header input', helpHtml('intro.navigation.search_street', {
72910                 name: _t('intro.graph.name.spring-street')
72911               }));
72912               context.container().select('.search-header input').on('keyup.intro', checkSearchResult);
72913             }, msec + 100);
72914           }
72915
72916           function checkSearchResult() {
72917             var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
72918
72919             var firstName = first.select('.entity-name');
72920             var name = _t('intro.graph.name.spring-street');
72921
72922             if (!firstName.empty() && firstName.html() === name) {
72923               reveal(first.node(), helpHtml('intro.navigation.choose_street', {
72924                 name: name
72925               }), {
72926                 duration: 300
72927               });
72928               context.on('exit.intro', function () {
72929                 continueTo(selectedStreet);
72930               });
72931               context.container().select('.search-header input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
72932             }
72933
72934             function continueTo(nextStep) {
72935               context.on('exit.intro', null);
72936               context.container().select('.search-header input').on('keydown.intro', null).on('keyup.intro', null);
72937               nextStep();
72938             }
72939           }
72940
72941           function selectedStreet() {
72942             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
72943               return searchStreet();
72944             }
72945
72946             var onClick = function onClick() {
72947               continueTo(editorStreet);
72948             };
72949
72950             var entity = context.entity(springStreetEndId);
72951             var box = pointBox(entity.loc, context);
72952             box.height = 500;
72953             reveal(box, helpHtml('intro.navigation.selected_street', {
72954               name: _t('intro.graph.name.spring-street')
72955             }), {
72956               duration: 600,
72957               buttonText: _t.html('intro.ok'),
72958               buttonCallback: onClick
72959             });
72960             timeout(function () {
72961               context.map().on('move.intro drawn.intro', function () {
72962                 var entity = context.hasEntity(springStreetEndId);
72963                 if (!entity) return;
72964                 var box = pointBox(entity.loc, context);
72965                 box.height = 500;
72966                 reveal(box, helpHtml('intro.navigation.selected_street', {
72967                   name: _t('intro.graph.name.spring-street')
72968                 }), {
72969                   duration: 0,
72970                   buttonText: _t.html('intro.ok'),
72971                   buttonCallback: onClick
72972                 });
72973               });
72974             }, 600); // after reveal.
72975
72976             context.on('enter.intro', function (mode) {
72977               if (!context.hasEntity(springStreetId)) {
72978                 return continueTo(searchStreet);
72979               }
72980
72981               var ids = context.selectedIDs();
72982
72983               if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
72984                 // keep Spring Street selected..
72985                 context.enter(modeSelect(context, [springStreetId]));
72986               }
72987             });
72988             context.history().on('change.intro', function () {
72989               if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
72990                 timeout(function () {
72991                   continueTo(searchStreet);
72992                 }, 300); // after any transition (e.g. if user deleted intersection)
72993               }
72994             });
72995
72996             function continueTo(nextStep) {
72997               context.map().on('move.intro drawn.intro', null);
72998               context.on('enter.intro', null);
72999               context.history().on('change.intro', null);
73000               nextStep();
73001             }
73002           }
73003
73004           function editorStreet() {
73005             var selector = '.entity-editor-pane button.close svg use';
73006             var href = select(selector).attr('href') || '#iD-icon-close';
73007             reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
73008               button: icon(href, 'inline'),
73009               field1: onewayField.label(),
73010               field2: maxspeedField.label()
73011             }));
73012             context.on('exit.intro', function () {
73013               continueTo(play);
73014             });
73015             context.history().on('change.intro', function () {
73016               // update the close icon in the tooltip if the user edits something.
73017               var selector = '.entity-editor-pane button.close svg use';
73018               var href = select(selector).attr('href') || '#iD-icon-close';
73019               reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
73020                 button: icon(href, 'inline'),
73021                 field1: onewayField.label(),
73022                 field2: maxspeedField.label()
73023               }), {
73024                 duration: 0
73025               });
73026             });
73027
73028             function continueTo(nextStep) {
73029               context.on('exit.intro', null);
73030               context.history().on('change.intro', null);
73031               nextStep();
73032             }
73033           }
73034
73035           function play() {
73036             dispatch.call('done');
73037             reveal('.ideditor', helpHtml('intro.navigation.play', {
73038               next: _t('intro.points.title')
73039             }), {
73040               tooltipBox: '.intro-nav-wrap .chapter-point',
73041               buttonText: _t.html('intro.ok'),
73042               buttonCallback: function buttonCallback() {
73043                 reveal('.ideditor');
73044               }
73045             });
73046           }
73047
73048           chapter.enter = function () {
73049             dragMap();
73050           };
73051
73052           chapter.exit = function () {
73053             timeouts.forEach(window.clearTimeout);
73054             context.on('enter.intro exit.intro', null);
73055             context.map().on('move.intro drawn.intro', null);
73056             context.history().on('change.intro', null);
73057             context.container().select('.inspector-wrap').on('wheel.intro', null);
73058             context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
73059           };
73060
73061           chapter.restart = function () {
73062             chapter.exit();
73063             chapter.enter();
73064           };
73065
73066           return utilRebind(chapter, dispatch, 'on');
73067         }
73068
73069         function uiIntroPoint(context, reveal) {
73070           var dispatch = dispatch$8('done');
73071           var timeouts = [];
73072           var intersection = [-85.63279, 41.94394];
73073           var building = [-85.632422, 41.944045];
73074           var cafePreset = _mainPresetIndex.item('amenity/cafe');
73075           var _pointID = null;
73076           var chapter = {
73077             title: 'intro.points.title'
73078           };
73079
73080           function timeout(f, t) {
73081             timeouts.push(window.setTimeout(f, t));
73082           }
73083
73084           function eventCancel(d3_event) {
73085             d3_event.stopPropagation();
73086             d3_event.preventDefault();
73087           }
73088
73089           function addPoint() {
73090             context.enter(modeBrowse(context));
73091             context.history().reset('initial');
73092             var msec = transitionTime(intersection, context.map().center());
73093
73094             if (msec) {
73095               reveal(null, null, {
73096                 duration: 0
73097               });
73098             }
73099
73100             context.map().centerZoomEase(intersection, 19, msec);
73101             timeout(function () {
73102               var tooltip = reveal('button.add-point', helpHtml('intro.points.points_info') + '{br}' + helpHtml('intro.points.add_point'));
73103               _pointID = null;
73104               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-points');
73105               context.on('enter.intro', function (mode) {
73106                 if (mode.id !== 'add-point') return;
73107                 continueTo(placePoint);
73108               });
73109             }, msec + 100);
73110
73111             function continueTo(nextStep) {
73112               context.on('enter.intro', null);
73113               nextStep();
73114             }
73115           }
73116
73117           function placePoint() {
73118             if (context.mode().id !== 'add-point') {
73119               return chapter.restart();
73120             }
73121
73122             var pointBox = pad(building, 150, context);
73123             var textId = context.lastPointerType() === 'mouse' ? 'place_point' : 'place_point_touch';
73124             reveal(pointBox, helpHtml('intro.points.' + textId));
73125             context.map().on('move.intro drawn.intro', function () {
73126               pointBox = pad(building, 150, context);
73127               reveal(pointBox, helpHtml('intro.points.' + textId), {
73128                 duration: 0
73129               });
73130             });
73131             context.on('enter.intro', function (mode) {
73132               if (mode.id !== 'select') return chapter.restart();
73133               _pointID = context.mode().selectedIDs()[0];
73134               continueTo(searchPreset);
73135             });
73136
73137             function continueTo(nextStep) {
73138               context.map().on('move.intro drawn.intro', null);
73139               context.on('enter.intro', null);
73140               nextStep();
73141             }
73142           }
73143
73144           function searchPreset() {
73145             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73146               return addPoint();
73147             } // disallow scrolling
73148
73149
73150             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73151             context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73152             reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
73153               preset: cafePreset.name()
73154             }));
73155             context.on('enter.intro', function (mode) {
73156               if (!_pointID || !context.hasEntity(_pointID)) {
73157                 return continueTo(addPoint);
73158               }
73159
73160               var ids = context.selectedIDs();
73161
73162               if (mode.id !== 'select' || !ids.length || ids[0] !== _pointID) {
73163                 // keep the user's point selected..
73164                 context.enter(modeSelect(context, [_pointID])); // disallow scrolling
73165
73166                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73167                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73168                 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
73169                   preset: cafePreset.name()
73170                 }));
73171                 context.history().on('change.intro', null);
73172               }
73173             });
73174
73175             function checkPresetSearch() {
73176               var first = context.container().select('.preset-list-item:first-child');
73177
73178               if (first.classed('preset-amenity-cafe')) {
73179                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
73180                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.points.choose_cafe', {
73181                   preset: cafePreset.name()
73182                 }), {
73183                   duration: 300
73184                 });
73185                 context.history().on('change.intro', function () {
73186                   continueTo(aboutFeatureEditor);
73187                 });
73188               }
73189             }
73190
73191             function continueTo(nextStep) {
73192               context.on('enter.intro', null);
73193               context.history().on('change.intro', null);
73194               context.container().select('.inspector-wrap').on('wheel.intro', null);
73195               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73196               nextStep();
73197             }
73198           }
73199
73200           function aboutFeatureEditor() {
73201             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73202               return addPoint();
73203             }
73204
73205             timeout(function () {
73206               reveal('.entity-editor-pane', helpHtml('intro.points.feature_editor'), {
73207                 tooltipClass: 'intro-points-describe',
73208                 buttonText: _t.html('intro.ok'),
73209                 buttonCallback: function buttonCallback() {
73210                   continueTo(addName);
73211                 }
73212               });
73213             }, 400);
73214             context.on('exit.intro', function () {
73215               // if user leaves select mode here, just continue with the tutorial.
73216               continueTo(reselectPoint);
73217             });
73218
73219             function continueTo(nextStep) {
73220               context.on('exit.intro', null);
73221               nextStep();
73222             }
73223           }
73224
73225           function addName() {
73226             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73227               return addPoint();
73228             } // reset pane, in case user happened to change it..
73229
73230
73231             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73232             var addNameString = helpHtml('intro.points.fields_info') + '{br}' + helpHtml('intro.points.add_name');
73233             timeout(function () {
73234               // It's possible for the user to add a name in a previous step..
73235               // If so, don't tell them to add the name in this step.
73236               // Give them an OK button instead.
73237               var entity = context.entity(_pointID);
73238
73239               if (entity.tags.name) {
73240                 var tooltip = reveal('.entity-editor-pane', addNameString, {
73241                   tooltipClass: 'intro-points-describe',
73242                   buttonText: _t.html('intro.ok'),
73243                   buttonCallback: function buttonCallback() {
73244                     continueTo(addCloseEditor);
73245                   }
73246                 });
73247                 tooltip.select('.instruction').style('display', 'none');
73248               } else {
73249                 reveal('.entity-editor-pane', addNameString, {
73250                   tooltipClass: 'intro-points-describe'
73251                 });
73252               }
73253             }, 400);
73254             context.history().on('change.intro', function () {
73255               continueTo(addCloseEditor);
73256             });
73257             context.on('exit.intro', function () {
73258               // if user leaves select mode here, just continue with the tutorial.
73259               continueTo(reselectPoint);
73260             });
73261
73262             function continueTo(nextStep) {
73263               context.on('exit.intro', null);
73264               context.history().on('change.intro', null);
73265               nextStep();
73266             }
73267           }
73268
73269           function addCloseEditor() {
73270             // reset pane, in case user happened to change it..
73271             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73272             var selector = '.entity-editor-pane button.close svg use';
73273             var href = select(selector).attr('href') || '#iD-icon-close';
73274             context.on('exit.intro', function () {
73275               continueTo(reselectPoint);
73276             });
73277             reveal('.entity-editor-pane', helpHtml('intro.points.add_close', {
73278               button: icon(href, 'inline')
73279             }));
73280
73281             function continueTo(nextStep) {
73282               context.on('exit.intro', null);
73283               nextStep();
73284             }
73285           }
73286
73287           function reselectPoint() {
73288             if (!_pointID) return chapter.restart();
73289             var entity = context.hasEntity(_pointID);
73290             if (!entity) return chapter.restart(); // make sure it's still a cafe, in case user somehow changed it..
73291
73292             var oldPreset = _mainPresetIndex.match(entity, context.graph());
73293             context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
73294             context.enter(modeBrowse(context));
73295             var msec = transitionTime(entity.loc, context.map().center());
73296
73297             if (msec) {
73298               reveal(null, null, {
73299                 duration: 0
73300               });
73301             }
73302
73303             context.map().centerEase(entity.loc, msec);
73304             timeout(function () {
73305               var box = pointBox(entity.loc, context);
73306               reveal(box, helpHtml('intro.points.reselect'), {
73307                 duration: 600
73308               });
73309               timeout(function () {
73310                 context.map().on('move.intro drawn.intro', function () {
73311                   var entity = context.hasEntity(_pointID);
73312                   if (!entity) return chapter.restart();
73313                   var box = pointBox(entity.loc, context);
73314                   reveal(box, helpHtml('intro.points.reselect'), {
73315                     duration: 0
73316                   });
73317                 });
73318               }, 600); // after reveal..
73319
73320               context.on('enter.intro', function (mode) {
73321                 if (mode.id !== 'select') return;
73322                 continueTo(updatePoint);
73323               });
73324             }, msec + 100);
73325
73326             function continueTo(nextStep) {
73327               context.map().on('move.intro drawn.intro', null);
73328               context.on('enter.intro', null);
73329               nextStep();
73330             }
73331           }
73332
73333           function updatePoint() {
73334             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73335               return continueTo(reselectPoint);
73336             } // reset pane, in case user happened to untag the point..
73337
73338
73339             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73340             context.on('exit.intro', function () {
73341               continueTo(reselectPoint);
73342             });
73343             context.history().on('change.intro', function () {
73344               continueTo(updateCloseEditor);
73345             });
73346             timeout(function () {
73347               reveal('.entity-editor-pane', helpHtml('intro.points.update'), {
73348                 tooltipClass: 'intro-points-describe'
73349               });
73350             }, 400);
73351
73352             function continueTo(nextStep) {
73353               context.on('exit.intro', null);
73354               context.history().on('change.intro', null);
73355               nextStep();
73356             }
73357           }
73358
73359           function updateCloseEditor() {
73360             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73361               return continueTo(reselectPoint);
73362             } // reset pane, in case user happened to change it..
73363
73364
73365             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73366             context.on('exit.intro', function () {
73367               continueTo(rightClickPoint);
73368             });
73369             timeout(function () {
73370               reveal('.entity-editor-pane', helpHtml('intro.points.update_close', {
73371                 button: icon('#iD-icon-close', 'inline')
73372               }));
73373             }, 500);
73374
73375             function continueTo(nextStep) {
73376               context.on('exit.intro', null);
73377               nextStep();
73378             }
73379           }
73380
73381           function rightClickPoint() {
73382             if (!_pointID) return chapter.restart();
73383             var entity = context.hasEntity(_pointID);
73384             if (!entity) return chapter.restart();
73385             context.enter(modeBrowse(context));
73386             var box = pointBox(entity.loc, context);
73387             var textId = context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch';
73388             reveal(box, helpHtml('intro.points.' + textId), {
73389               duration: 600
73390             });
73391             timeout(function () {
73392               context.map().on('move.intro', function () {
73393                 var entity = context.hasEntity(_pointID);
73394                 if (!entity) return chapter.restart();
73395                 var box = pointBox(entity.loc, context);
73396                 reveal(box, helpHtml('intro.points.' + textId), {
73397                   duration: 0
73398                 });
73399               });
73400             }, 600); // after reveal
73401
73402             context.on('enter.intro', function (mode) {
73403               if (mode.id !== 'select') return;
73404               var ids = context.selectedIDs();
73405               if (ids.length !== 1 || ids[0] !== _pointID) return;
73406               timeout(function () {
73407                 var node = selectMenuItem(context, 'delete').node();
73408                 if (!node) return;
73409                 continueTo(enterDelete);
73410               }, 50); // after menu visible
73411             });
73412
73413             function continueTo(nextStep) {
73414               context.on('enter.intro', null);
73415               context.map().on('move.intro', null);
73416               nextStep();
73417             }
73418           }
73419
73420           function enterDelete() {
73421             if (!_pointID) return chapter.restart();
73422             var entity = context.hasEntity(_pointID);
73423             if (!entity) return chapter.restart();
73424             var node = selectMenuItem(context, 'delete').node();
73425
73426             if (!node) {
73427               return continueTo(rightClickPoint);
73428             }
73429
73430             reveal('.edit-menu', helpHtml('intro.points.delete'), {
73431               padding: 50
73432             });
73433             timeout(function () {
73434               context.map().on('move.intro', function () {
73435                 reveal('.edit-menu', helpHtml('intro.points.delete'), {
73436                   duration: 0,
73437                   padding: 50
73438                 });
73439               });
73440             }, 300); // after menu visible
73441
73442             context.on('exit.intro', function () {
73443               if (!_pointID) return chapter.restart();
73444               var entity = context.hasEntity(_pointID);
73445               if (entity) return continueTo(rightClickPoint); // point still exists
73446             });
73447             context.history().on('change.intro', function (changed) {
73448               if (changed.deleted().length) {
73449                 continueTo(undo);
73450               }
73451             });
73452
73453             function continueTo(nextStep) {
73454               context.map().on('move.intro', null);
73455               context.history().on('change.intro', null);
73456               context.on('exit.intro', null);
73457               nextStep();
73458             }
73459           }
73460
73461           function undo() {
73462             context.history().on('change.intro', function () {
73463               continueTo(play);
73464             });
73465             reveal('.top-toolbar button.undo-button', helpHtml('intro.points.undo'));
73466
73467             function continueTo(nextStep) {
73468               context.history().on('change.intro', null);
73469               nextStep();
73470             }
73471           }
73472
73473           function play() {
73474             dispatch.call('done');
73475             reveal('.ideditor', helpHtml('intro.points.play', {
73476               next: _t('intro.areas.title')
73477             }), {
73478               tooltipBox: '.intro-nav-wrap .chapter-area',
73479               buttonText: _t.html('intro.ok'),
73480               buttonCallback: function buttonCallback() {
73481                 reveal('.ideditor');
73482               }
73483             });
73484           }
73485
73486           chapter.enter = function () {
73487             addPoint();
73488           };
73489
73490           chapter.exit = function () {
73491             timeouts.forEach(window.clearTimeout);
73492             context.on('enter.intro exit.intro', null);
73493             context.map().on('move.intro drawn.intro', null);
73494             context.history().on('change.intro', null);
73495             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73496             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73497           };
73498
73499           chapter.restart = function () {
73500             chapter.exit();
73501             chapter.enter();
73502           };
73503
73504           return utilRebind(chapter, dispatch, 'on');
73505         }
73506
73507         function uiIntroArea(context, reveal) {
73508           var dispatch = dispatch$8('done');
73509           var playground = [-85.63552, 41.94159];
73510           var playgroundPreset = _mainPresetIndex.item('leisure/playground');
73511           var nameField = _mainPresetIndex.field('name');
73512           var descriptionField = _mainPresetIndex.field('description');
73513           var timeouts = [];
73514
73515           var _areaID;
73516
73517           var chapter = {
73518             title: 'intro.areas.title'
73519           };
73520
73521           function timeout(f, t) {
73522             timeouts.push(window.setTimeout(f, t));
73523           }
73524
73525           function eventCancel(d3_event) {
73526             d3_event.stopPropagation();
73527             d3_event.preventDefault();
73528           }
73529
73530           function revealPlayground(center, text, options) {
73531             var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
73532             var box = pad(center, padding, context);
73533             reveal(box, text, options);
73534           }
73535
73536           function addArea() {
73537             context.enter(modeBrowse(context));
73538             context.history().reset('initial');
73539             _areaID = null;
73540             var msec = transitionTime(playground, context.map().center());
73541
73542             if (msec) {
73543               reveal(null, null, {
73544                 duration: 0
73545               });
73546             }
73547
73548             context.map().centerZoomEase(playground, 19, msec);
73549             timeout(function () {
73550               var tooltip = reveal('button.add-area', helpHtml('intro.areas.add_playground'));
73551               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-areas');
73552               context.on('enter.intro', function (mode) {
73553                 if (mode.id !== 'add-area') return;
73554                 continueTo(startPlayground);
73555               });
73556             }, msec + 100);
73557
73558             function continueTo(nextStep) {
73559               context.on('enter.intro', null);
73560               nextStep();
73561             }
73562           }
73563
73564           function startPlayground() {
73565             if (context.mode().id !== 'add-area') {
73566               return chapter.restart();
73567             }
73568
73569             _areaID = null;
73570             context.map().zoomEase(19.5, 500);
73571             timeout(function () {
73572               var textId = context.lastPointerType() === 'mouse' ? 'starting_node_click' : 'starting_node_tap';
73573               var startDrawString = helpHtml('intro.areas.start_playground') + helpHtml('intro.areas.' + textId);
73574               revealPlayground(playground, startDrawString, {
73575                 duration: 250
73576               });
73577               timeout(function () {
73578                 context.map().on('move.intro drawn.intro', function () {
73579                   revealPlayground(playground, startDrawString, {
73580                     duration: 0
73581                   });
73582                 });
73583                 context.on('enter.intro', function (mode) {
73584                   if (mode.id !== 'draw-area') return chapter.restart();
73585                   continueTo(continuePlayground);
73586                 });
73587               }, 250); // after reveal
73588             }, 550); // after easing
73589
73590             function continueTo(nextStep) {
73591               context.map().on('move.intro drawn.intro', null);
73592               context.on('enter.intro', null);
73593               nextStep();
73594             }
73595           }
73596
73597           function continuePlayground() {
73598             if (context.mode().id !== 'draw-area') {
73599               return chapter.restart();
73600             }
73601
73602             _areaID = null;
73603             revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
73604               duration: 250
73605             });
73606             timeout(function () {
73607               context.map().on('move.intro drawn.intro', function () {
73608                 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
73609                   duration: 0
73610                 });
73611               });
73612             }, 250); // after reveal
73613
73614             context.on('enter.intro', function (mode) {
73615               if (mode.id === 'draw-area') {
73616                 var entity = context.hasEntity(context.selectedIDs()[0]);
73617
73618                 if (entity && entity.nodes.length >= 6) {
73619                   return continueTo(finishPlayground);
73620                 } else {
73621                   return;
73622                 }
73623               } else if (mode.id === 'select') {
73624                 _areaID = context.selectedIDs()[0];
73625                 return continueTo(searchPresets);
73626               } else {
73627                 return chapter.restart();
73628               }
73629             });
73630
73631             function continueTo(nextStep) {
73632               context.map().on('move.intro drawn.intro', null);
73633               context.on('enter.intro', null);
73634               nextStep();
73635             }
73636           }
73637
73638           function finishPlayground() {
73639             if (context.mode().id !== 'draw-area') {
73640               return chapter.restart();
73641             }
73642
73643             _areaID = null;
73644             var finishString = helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.areas.finish_playground');
73645             revealPlayground(playground, finishString, {
73646               duration: 250
73647             });
73648             timeout(function () {
73649               context.map().on('move.intro drawn.intro', function () {
73650                 revealPlayground(playground, finishString, {
73651                   duration: 0
73652                 });
73653               });
73654             }, 250); // after reveal
73655
73656             context.on('enter.intro', function (mode) {
73657               if (mode.id === 'draw-area') {
73658                 return;
73659               } else if (mode.id === 'select') {
73660                 _areaID = context.selectedIDs()[0];
73661                 return continueTo(searchPresets);
73662               } else {
73663                 return chapter.restart();
73664               }
73665             });
73666
73667             function continueTo(nextStep) {
73668               context.map().on('move.intro drawn.intro', null);
73669               context.on('enter.intro', null);
73670               nextStep();
73671             }
73672           }
73673
73674           function searchPresets() {
73675             if (!_areaID || !context.hasEntity(_areaID)) {
73676               return addArea();
73677             }
73678
73679             var ids = context.selectedIDs();
73680
73681             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73682               context.enter(modeSelect(context, [_areaID]));
73683             } // disallow scrolling
73684
73685
73686             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73687             timeout(function () {
73688               // reset pane, in case user somehow happened to change it..
73689               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
73690               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73691               reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
73692                 preset: playgroundPreset.name()
73693               }));
73694             }, 400); // after preset list pane visible..
73695
73696             context.on('enter.intro', function (mode) {
73697               if (!_areaID || !context.hasEntity(_areaID)) {
73698                 return continueTo(addArea);
73699               }
73700
73701               var ids = context.selectedIDs();
73702
73703               if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
73704                 // keep the user's area selected..
73705                 context.enter(modeSelect(context, [_areaID])); // reset pane, in case user somehow happened to change it..
73706
73707                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
73708
73709                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73710                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73711                 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
73712                   preset: playgroundPreset.name()
73713                 }));
73714                 context.history().on('change.intro', null);
73715               }
73716             });
73717
73718             function checkPresetSearch() {
73719               var first = context.container().select('.preset-list-item:first-child');
73720
73721               if (first.classed('preset-leisure-playground')) {
73722                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.areas.choose_playground', {
73723                   preset: playgroundPreset.name()
73724                 }), {
73725                   duration: 300
73726                 });
73727                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
73728                 context.history().on('change.intro', function () {
73729                   continueTo(clickAddField);
73730                 });
73731               }
73732             }
73733
73734             function continueTo(nextStep) {
73735               context.container().select('.inspector-wrap').on('wheel.intro', null);
73736               context.on('enter.intro', null);
73737               context.history().on('change.intro', null);
73738               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73739               nextStep();
73740             }
73741           }
73742
73743           function clickAddField() {
73744             if (!_areaID || !context.hasEntity(_areaID)) {
73745               return addArea();
73746             }
73747
73748             var ids = context.selectedIDs();
73749
73750             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73751               return searchPresets();
73752             }
73753
73754             if (!context.container().select('.form-field-description').empty()) {
73755               return continueTo(describePlayground);
73756             } // disallow scrolling
73757
73758
73759             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73760             timeout(function () {
73761               // reset pane, in case user somehow happened to change it..
73762               context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // It's possible for the user to add a description in a previous step..
73763               // If they did this already, just continue to next step.
73764
73765               var entity = context.entity(_areaID);
73766
73767               if (entity.tags.description) {
73768                 return continueTo(play);
73769               } // scroll "Add field" into view
73770
73771
73772               var box = context.container().select('.more-fields').node().getBoundingClientRect();
73773
73774               if (box.top > 300) {
73775                 var pane = context.container().select('.entity-editor-pane .inspector-body');
73776                 var start = pane.node().scrollTop;
73777                 var end = start + (box.top - 300);
73778                 pane.transition().duration(250).tween('scroll.inspector', function () {
73779                   var node = this;
73780                   var i = d3_interpolateNumber(start, end);
73781                   return function (t) {
73782                     node.scrollTop = i(t);
73783                   };
73784                 });
73785               }
73786
73787               timeout(function () {
73788                 reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', {
73789                   name: nameField.label(),
73790                   description: descriptionField.label()
73791                 }), {
73792                   duration: 300
73793                 });
73794                 context.container().select('.more-fields .combobox-input').on('click.intro', function () {
73795                   // Watch for the combobox to appear...
73796                   var watcher;
73797                   watcher = window.setInterval(function () {
73798                     if (!context.container().select('div.combobox').empty()) {
73799                       window.clearInterval(watcher);
73800                       continueTo(chooseDescriptionField);
73801                     }
73802                   }, 300);
73803                 });
73804               }, 300); // after "Add Field" visible
73805             }, 400); // after editor pane visible
73806
73807             context.on('exit.intro', function () {
73808               return continueTo(searchPresets);
73809             });
73810
73811             function continueTo(nextStep) {
73812               context.container().select('.inspector-wrap').on('wheel.intro', null);
73813               context.container().select('.more-fields .combobox-input').on('click.intro', null);
73814               context.on('exit.intro', null);
73815               nextStep();
73816             }
73817           }
73818
73819           function chooseDescriptionField() {
73820             if (!_areaID || !context.hasEntity(_areaID)) {
73821               return addArea();
73822             }
73823
73824             var ids = context.selectedIDs();
73825
73826             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73827               return searchPresets();
73828             }
73829
73830             if (!context.container().select('.form-field-description').empty()) {
73831               return continueTo(describePlayground);
73832             } // Make sure combobox is ready..
73833
73834
73835             if (context.container().select('div.combobox').empty()) {
73836               return continueTo(clickAddField);
73837             } // Watch for the combobox to go away..
73838
73839
73840             var watcher;
73841             watcher = window.setInterval(function () {
73842               if (context.container().select('div.combobox').empty()) {
73843                 window.clearInterval(watcher);
73844                 timeout(function () {
73845                   if (context.container().select('.form-field-description').empty()) {
73846                     continueTo(retryChooseDescription);
73847                   } else {
73848                     continueTo(describePlayground);
73849                   }
73850                 }, 300); // after description field added.
73851               }
73852             }, 300);
73853             reveal('div.combobox', helpHtml('intro.areas.choose_field', {
73854               field: descriptionField.label()
73855             }), {
73856               duration: 300
73857             });
73858             context.on('exit.intro', function () {
73859               return continueTo(searchPresets);
73860             });
73861
73862             function continueTo(nextStep) {
73863               if (watcher) window.clearInterval(watcher);
73864               context.on('exit.intro', null);
73865               nextStep();
73866             }
73867           }
73868
73869           function describePlayground() {
73870             if (!_areaID || !context.hasEntity(_areaID)) {
73871               return addArea();
73872             }
73873
73874             var ids = context.selectedIDs();
73875
73876             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73877               return searchPresets();
73878             } // reset pane, in case user happened to change it..
73879
73880
73881             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73882
73883             if (context.container().select('.form-field-description').empty()) {
73884               return continueTo(retryChooseDescription);
73885             }
73886
73887             context.on('exit.intro', function () {
73888               continueTo(play);
73889             });
73890             reveal('.entity-editor-pane', helpHtml('intro.areas.describe_playground', {
73891               button: icon('#iD-icon-close', 'inline')
73892             }), {
73893               duration: 300
73894             });
73895
73896             function continueTo(nextStep) {
73897               context.on('exit.intro', null);
73898               nextStep();
73899             }
73900           }
73901
73902           function retryChooseDescription() {
73903             if (!_areaID || !context.hasEntity(_areaID)) {
73904               return addArea();
73905             }
73906
73907             var ids = context.selectedIDs();
73908
73909             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73910               return searchPresets();
73911             } // reset pane, in case user happened to change it..
73912
73913
73914             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73915             reveal('.entity-editor-pane', helpHtml('intro.areas.retry_add_field', {
73916               field: descriptionField.label()
73917             }), {
73918               buttonText: _t.html('intro.ok'),
73919               buttonCallback: function buttonCallback() {
73920                 continueTo(clickAddField);
73921               }
73922             });
73923             context.on('exit.intro', function () {
73924               return continueTo(searchPresets);
73925             });
73926
73927             function continueTo(nextStep) {
73928               context.on('exit.intro', null);
73929               nextStep();
73930             }
73931           }
73932
73933           function play() {
73934             dispatch.call('done');
73935             reveal('.ideditor', helpHtml('intro.areas.play', {
73936               next: _t('intro.lines.title')
73937             }), {
73938               tooltipBox: '.intro-nav-wrap .chapter-line',
73939               buttonText: _t.html('intro.ok'),
73940               buttonCallback: function buttonCallback() {
73941                 reveal('.ideditor');
73942               }
73943             });
73944           }
73945
73946           chapter.enter = function () {
73947             addArea();
73948           };
73949
73950           chapter.exit = function () {
73951             timeouts.forEach(window.clearTimeout);
73952             context.on('enter.intro exit.intro', null);
73953             context.map().on('move.intro drawn.intro', null);
73954             context.history().on('change.intro', null);
73955             context.container().select('.inspector-wrap').on('wheel.intro', null);
73956             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73957             context.container().select('.more-fields .combobox-input').on('click.intro', null);
73958           };
73959
73960           chapter.restart = function () {
73961             chapter.exit();
73962             chapter.enter();
73963           };
73964
73965           return utilRebind(chapter, dispatch, 'on');
73966         }
73967
73968         function uiIntroLine(context, reveal) {
73969           var dispatch = dispatch$8('done');
73970           var timeouts = [];
73971           var _tulipRoadID = null;
73972           var flowerRoadID = 'w646';
73973           var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
73974           var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
73975           var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
73976           var roadCategory = _mainPresetIndex.item('category-road_minor');
73977           var residentialPreset = _mainPresetIndex.item('highway/residential');
73978           var woodRoadID = 'w525';
73979           var woodRoadEndID = 'n2862';
73980           var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
73981           var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
73982           var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
73983           var washingtonStreetID = 'w522';
73984           var twelfthAvenueID = 'w1';
73985           var eleventhAvenueEndID = 'n3550';
73986           var twelfthAvenueEndID = 'n5';
73987           var _washingtonSegmentID = null;
73988           var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
73989           var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
73990           var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
73991           var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
73992           var chapter = {
73993             title: 'intro.lines.title'
73994           };
73995
73996           function timeout(f, t) {
73997             timeouts.push(window.setTimeout(f, t));
73998           }
73999
74000           function eventCancel(d3_event) {
74001             d3_event.stopPropagation();
74002             d3_event.preventDefault();
74003           }
74004
74005           function addLine() {
74006             context.enter(modeBrowse(context));
74007             context.history().reset('initial');
74008             var msec = transitionTime(tulipRoadStart, context.map().center());
74009
74010             if (msec) {
74011               reveal(null, null, {
74012                 duration: 0
74013               });
74014             }
74015
74016             context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
74017             timeout(function () {
74018               var tooltip = reveal('button.add-line', helpHtml('intro.lines.add_line'));
74019               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-lines');
74020               context.on('enter.intro', function (mode) {
74021                 if (mode.id !== 'add-line') return;
74022                 continueTo(startLine);
74023               });
74024             }, msec + 100);
74025
74026             function continueTo(nextStep) {
74027               context.on('enter.intro', null);
74028               nextStep();
74029             }
74030           }
74031
74032           function startLine() {
74033             if (context.mode().id !== 'add-line') return chapter.restart();
74034             _tulipRoadID = null;
74035             var padding = 70 * Math.pow(2, context.map().zoom() - 18);
74036             var box = pad(tulipRoadStart, padding, context);
74037             box.height = box.height + 100;
74038             var textId = context.lastPointerType() === 'mouse' ? 'start_line' : 'start_line_tap';
74039             var startLineString = helpHtml('intro.lines.missing_road') + '{br}' + helpHtml('intro.lines.line_draw_info') + helpHtml('intro.lines.' + textId);
74040             reveal(box, startLineString);
74041             context.map().on('move.intro drawn.intro', function () {
74042               padding = 70 * Math.pow(2, context.map().zoom() - 18);
74043               box = pad(tulipRoadStart, padding, context);
74044               box.height = box.height + 100;
74045               reveal(box, startLineString, {
74046                 duration: 0
74047               });
74048             });
74049             context.on('enter.intro', function (mode) {
74050               if (mode.id !== 'draw-line') return chapter.restart();
74051               continueTo(drawLine);
74052             });
74053
74054             function continueTo(nextStep) {
74055               context.map().on('move.intro drawn.intro', null);
74056               context.on('enter.intro', null);
74057               nextStep();
74058             }
74059           }
74060
74061           function drawLine() {
74062             if (context.mode().id !== 'draw-line') return chapter.restart();
74063             _tulipRoadID = context.mode().selectedIDs()[0];
74064             context.map().centerEase(tulipRoadMidpoint, 500);
74065             timeout(function () {
74066               var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
74067               var box = pad(tulipRoadMidpoint, padding, context);
74068               box.height = box.height * 2;
74069               reveal(box, helpHtml('intro.lines.intersect', {
74070                 name: _t('intro.graph.name.flower-street')
74071               }));
74072               context.map().on('move.intro drawn.intro', function () {
74073                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
74074                 box = pad(tulipRoadMidpoint, padding, context);
74075                 box.height = box.height * 2;
74076                 reveal(box, helpHtml('intro.lines.intersect', {
74077                   name: _t('intro.graph.name.flower-street')
74078                 }), {
74079                   duration: 0
74080                 });
74081               });
74082             }, 550); // after easing..
74083
74084             context.history().on('change.intro', function () {
74085               if (isLineConnected()) {
74086                 continueTo(continueLine);
74087               }
74088             });
74089             context.on('enter.intro', function (mode) {
74090               if (mode.id === 'draw-line') {
74091                 return;
74092               } else if (mode.id === 'select') {
74093                 continueTo(retryIntersect);
74094                 return;
74095               } else {
74096                 return chapter.restart();
74097               }
74098             });
74099
74100             function continueTo(nextStep) {
74101               context.map().on('move.intro drawn.intro', null);
74102               context.history().on('change.intro', null);
74103               context.on('enter.intro', null);
74104               nextStep();
74105             }
74106           }
74107
74108           function isLineConnected() {
74109             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
74110
74111             if (!entity) return false;
74112             var drawNodes = context.graph().childNodes(entity);
74113             return drawNodes.some(function (node) {
74114               return context.graph().parentWays(node).some(function (parent) {
74115                 return parent.id === flowerRoadID;
74116               });
74117             });
74118           }
74119
74120           function retryIntersect() {
74121             select(window).on('pointerdown.intro mousedown.intro', eventCancel, true);
74122             var box = pad(tulipRoadIntersection, 80, context);
74123             reveal(box, helpHtml('intro.lines.retry_intersect', {
74124               name: _t('intro.graph.name.flower-street')
74125             }));
74126             timeout(chapter.restart, 3000);
74127           }
74128
74129           function continueLine() {
74130             if (context.mode().id !== 'draw-line') return chapter.restart();
74131
74132             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
74133
74134             if (!entity) return chapter.restart();
74135             context.map().centerEase(tulipRoadIntersection, 500);
74136             var continueLineText = helpHtml('intro.lines.continue_line') + '{br}' + helpHtml('intro.lines.finish_line_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.lines.finish_road');
74137             reveal('.surface', continueLineText);
74138             context.on('enter.intro', function (mode) {
74139               if (mode.id === 'draw-line') {
74140                 return;
74141               } else if (mode.id === 'select') {
74142                 return continueTo(chooseCategoryRoad);
74143               } else {
74144                 return chapter.restart();
74145               }
74146             });
74147
74148             function continueTo(nextStep) {
74149               context.on('enter.intro', null);
74150               nextStep();
74151             }
74152           }
74153
74154           function chooseCategoryRoad() {
74155             if (context.mode().id !== 'select') return chapter.restart();
74156             context.on('exit.intro', function () {
74157               return chapter.restart();
74158             });
74159             var button = context.container().select('.preset-category-road_minor .preset-list-button');
74160             if (button.empty()) return chapter.restart(); // disallow scrolling
74161
74162             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74163             timeout(function () {
74164               // reset pane, in case user somehow happened to change it..
74165               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
74166               reveal(button.node(), helpHtml('intro.lines.choose_category_road', {
74167                 category: roadCategory.name()
74168               }));
74169               button.on('click.intro', function () {
74170                 continueTo(choosePresetResidential);
74171               });
74172             }, 400); // after editor pane visible
74173
74174             function continueTo(nextStep) {
74175               context.container().select('.inspector-wrap').on('wheel.intro', null);
74176               context.container().select('.preset-list-button').on('click.intro', null);
74177               context.on('exit.intro', null);
74178               nextStep();
74179             }
74180           }
74181
74182           function choosePresetResidential() {
74183             if (context.mode().id !== 'select') return chapter.restart();
74184             context.on('exit.intro', function () {
74185               return chapter.restart();
74186             });
74187             var subgrid = context.container().select('.preset-category-road_minor .subgrid');
74188             if (subgrid.empty()) return chapter.restart();
74189             subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button').on('click.intro', function () {
74190               continueTo(retryPresetResidential);
74191             });
74192             subgrid.selectAll('.preset-highway-residential .preset-list-button').on('click.intro', function () {
74193               continueTo(nameRoad);
74194             });
74195             timeout(function () {
74196               reveal(subgrid.node(), helpHtml('intro.lines.choose_preset_residential', {
74197                 preset: residentialPreset.name()
74198               }), {
74199                 tooltipBox: '.preset-highway-residential .preset-list-button',
74200                 duration: 300
74201               });
74202             }, 300);
74203
74204             function continueTo(nextStep) {
74205               context.container().select('.preset-list-button').on('click.intro', null);
74206               context.on('exit.intro', null);
74207               nextStep();
74208             }
74209           } // selected wrong road type
74210
74211
74212           function retryPresetResidential() {
74213             if (context.mode().id !== 'select') return chapter.restart();
74214             context.on('exit.intro', function () {
74215               return chapter.restart();
74216             }); // disallow scrolling
74217
74218             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74219             timeout(function () {
74220               var button = context.container().select('.entity-editor-pane .preset-list-button');
74221               reveal(button.node(), helpHtml('intro.lines.retry_preset_residential', {
74222                 preset: residentialPreset.name()
74223               }));
74224               button.on('click.intro', function () {
74225                 continueTo(chooseCategoryRoad);
74226               });
74227             }, 500);
74228
74229             function continueTo(nextStep) {
74230               context.container().select('.inspector-wrap').on('wheel.intro', null);
74231               context.container().select('.preset-list-button').on('click.intro', null);
74232               context.on('exit.intro', null);
74233               nextStep();
74234             }
74235           }
74236
74237           function nameRoad() {
74238             context.on('exit.intro', function () {
74239               continueTo(didNameRoad);
74240             });
74241             timeout(function () {
74242               reveal('.entity-editor-pane', helpHtml('intro.lines.name_road', {
74243                 button: icon('#iD-icon-close', 'inline')
74244               }), {
74245                 tooltipClass: 'intro-lines-name_road'
74246               });
74247             }, 500);
74248
74249             function continueTo(nextStep) {
74250               context.on('exit.intro', null);
74251               nextStep();
74252             }
74253           }
74254
74255           function didNameRoad() {
74256             context.history().checkpoint('doneAddLine');
74257             timeout(function () {
74258               reveal('.surface', helpHtml('intro.lines.did_name_road'), {
74259                 buttonText: _t.html('intro.ok'),
74260                 buttonCallback: function buttonCallback() {
74261                   continueTo(updateLine);
74262                 }
74263               });
74264             }, 500);
74265
74266             function continueTo(nextStep) {
74267               nextStep();
74268             }
74269           }
74270
74271           function updateLine() {
74272             context.history().reset('doneAddLine');
74273
74274             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74275               return chapter.restart();
74276             }
74277
74278             var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
74279
74280             if (msec) {
74281               reveal(null, null, {
74282                 duration: 0
74283               });
74284             }
74285
74286             context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
74287             timeout(function () {
74288               var padding = 250 * Math.pow(2, context.map().zoom() - 19);
74289               var box = pad(woodRoadDragMidpoint, padding, context);
74290
74291               var advance = function advance() {
74292                 continueTo(addNode);
74293               };
74294
74295               reveal(box, helpHtml('intro.lines.update_line'), {
74296                 buttonText: _t.html('intro.ok'),
74297                 buttonCallback: advance
74298               });
74299               context.map().on('move.intro drawn.intro', function () {
74300                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
74301                 var box = pad(woodRoadDragMidpoint, padding, context);
74302                 reveal(box, helpHtml('intro.lines.update_line'), {
74303                   duration: 0,
74304                   buttonText: _t.html('intro.ok'),
74305                   buttonCallback: advance
74306                 });
74307               });
74308             }, msec + 100);
74309
74310             function continueTo(nextStep) {
74311               context.map().on('move.intro drawn.intro', null);
74312               nextStep();
74313             }
74314           }
74315
74316           function addNode() {
74317             context.history().reset('doneAddLine');
74318
74319             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74320               return chapter.restart();
74321             }
74322
74323             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
74324             var box = pad(woodRoadAddNode, padding, context);
74325             var addNodeString = helpHtml('intro.lines.add_node' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
74326             reveal(box, addNodeString);
74327             context.map().on('move.intro drawn.intro', function () {
74328               var padding = 40 * Math.pow(2, context.map().zoom() - 19);
74329               var box = pad(woodRoadAddNode, padding, context);
74330               reveal(box, addNodeString, {
74331                 duration: 0
74332               });
74333             });
74334             context.history().on('change.intro', function (changed) {
74335               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74336                 return continueTo(updateLine);
74337               }
74338
74339               if (changed.created().length === 1) {
74340                 timeout(function () {
74341                   continueTo(startDragEndpoint);
74342                 }, 500);
74343               }
74344             });
74345             context.on('enter.intro', function (mode) {
74346               if (mode.id !== 'select') {
74347                 continueTo(updateLine);
74348               }
74349             });
74350
74351             function continueTo(nextStep) {
74352               context.map().on('move.intro drawn.intro', null);
74353               context.history().on('change.intro', null);
74354               context.on('enter.intro', null);
74355               nextStep();
74356             }
74357           }
74358
74359           function startDragEndpoint() {
74360             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74361               return continueTo(updateLine);
74362             }
74363
74364             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74365             var box = pad(woodRoadDragEndpoint, padding, context);
74366             var startDragString = helpHtml('intro.lines.start_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch')) + helpHtml('intro.lines.drag_to_intersection');
74367             reveal(box, startDragString);
74368             context.map().on('move.intro drawn.intro', function () {
74369               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74370                 return continueTo(updateLine);
74371               }
74372
74373               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74374               var box = pad(woodRoadDragEndpoint, padding, context);
74375               reveal(box, startDragString, {
74376                 duration: 0
74377               });
74378               var entity = context.entity(woodRoadEndID);
74379
74380               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
74381                 continueTo(finishDragEndpoint);
74382               }
74383             });
74384
74385             function continueTo(nextStep) {
74386               context.map().on('move.intro drawn.intro', null);
74387               nextStep();
74388             }
74389           }
74390
74391           function finishDragEndpoint() {
74392             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74393               return continueTo(updateLine);
74394             }
74395
74396             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74397             var box = pad(woodRoadDragEndpoint, padding, context);
74398             var finishDragString = helpHtml('intro.lines.spot_looks_good') + helpHtml('intro.lines.finish_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
74399             reveal(box, finishDragString);
74400             context.map().on('move.intro drawn.intro', function () {
74401               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74402                 return continueTo(updateLine);
74403               }
74404
74405               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74406               var box = pad(woodRoadDragEndpoint, padding, context);
74407               reveal(box, finishDragString, {
74408                 duration: 0
74409               });
74410               var entity = context.entity(woodRoadEndID);
74411
74412               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
74413                 continueTo(startDragEndpoint);
74414               }
74415             });
74416             context.on('enter.intro', function () {
74417               continueTo(startDragMidpoint);
74418             });
74419
74420             function continueTo(nextStep) {
74421               context.map().on('move.intro drawn.intro', null);
74422               context.on('enter.intro', null);
74423               nextStep();
74424             }
74425           }
74426
74427           function startDragMidpoint() {
74428             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74429               return continueTo(updateLine);
74430             }
74431
74432             if (context.selectedIDs().indexOf(woodRoadID) === -1) {
74433               context.enter(modeSelect(context, [woodRoadID]));
74434             }
74435
74436             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
74437             var box = pad(woodRoadDragMidpoint, padding, context);
74438             reveal(box, helpHtml('intro.lines.start_drag_midpoint'));
74439             context.map().on('move.intro drawn.intro', function () {
74440               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74441                 return continueTo(updateLine);
74442               }
74443
74444               var padding = 80 * Math.pow(2, context.map().zoom() - 19);
74445               var box = pad(woodRoadDragMidpoint, padding, context);
74446               reveal(box, helpHtml('intro.lines.start_drag_midpoint'), {
74447                 duration: 0
74448               });
74449             });
74450             context.history().on('change.intro', function (changed) {
74451               if (changed.created().length === 1) {
74452                 continueTo(continueDragMidpoint);
74453               }
74454             });
74455             context.on('enter.intro', function (mode) {
74456               if (mode.id !== 'select') {
74457                 // keep Wood Road selected so midpoint triangles are drawn..
74458                 context.enter(modeSelect(context, [woodRoadID]));
74459               }
74460             });
74461
74462             function continueTo(nextStep) {
74463               context.map().on('move.intro drawn.intro', null);
74464               context.history().on('change.intro', null);
74465               context.on('enter.intro', null);
74466               nextStep();
74467             }
74468           }
74469
74470           function continueDragMidpoint() {
74471             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74472               return continueTo(updateLine);
74473             }
74474
74475             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74476             var box = pad(woodRoadDragEndpoint, padding, context);
74477             box.height += 400;
74478
74479             var advance = function advance() {
74480               context.history().checkpoint('doneUpdateLine');
74481               continueTo(deleteLines);
74482             };
74483
74484             reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
74485               buttonText: _t.html('intro.ok'),
74486               buttonCallback: advance
74487             });
74488             context.map().on('move.intro drawn.intro', function () {
74489               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74490                 return continueTo(updateLine);
74491               }
74492
74493               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74494               var box = pad(woodRoadDragEndpoint, padding, context);
74495               box.height += 400;
74496               reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
74497                 duration: 0,
74498                 buttonText: _t.html('intro.ok'),
74499                 buttonCallback: advance
74500               });
74501             });
74502
74503             function continueTo(nextStep) {
74504               context.map().on('move.intro drawn.intro', null);
74505               nextStep();
74506             }
74507           }
74508
74509           function deleteLines() {
74510             context.history().reset('doneUpdateLine');
74511             context.enter(modeBrowse(context));
74512
74513             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74514               return chapter.restart();
74515             }
74516
74517             var msec = transitionTime(deleteLinesLoc, context.map().center());
74518
74519             if (msec) {
74520               reveal(null, null, {
74521                 duration: 0
74522               });
74523             }
74524
74525             context.map().centerZoomEase(deleteLinesLoc, 18, msec);
74526             timeout(function () {
74527               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74528               var box = pad(deleteLinesLoc, padding, context);
74529               box.top -= 200;
74530               box.height += 400;
74531
74532               var advance = function advance() {
74533                 continueTo(rightClickIntersection);
74534               };
74535
74536               reveal(box, helpHtml('intro.lines.delete_lines', {
74537                 street: _t('intro.graph.name.12th-avenue')
74538               }), {
74539                 buttonText: _t.html('intro.ok'),
74540                 buttonCallback: advance
74541               });
74542               context.map().on('move.intro drawn.intro', function () {
74543                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74544                 var box = pad(deleteLinesLoc, padding, context);
74545                 box.top -= 200;
74546                 box.height += 400;
74547                 reveal(box, helpHtml('intro.lines.delete_lines', {
74548                   street: _t('intro.graph.name.12th-avenue')
74549                 }), {
74550                   duration: 0,
74551                   buttonText: _t.html('intro.ok'),
74552                   buttonCallback: advance
74553                 });
74554               });
74555               context.history().on('change.intro', function () {
74556                 timeout(function () {
74557                   continueTo(deleteLines);
74558                 }, 500); // after any transition (e.g. if user deleted intersection)
74559               });
74560             }, msec + 100);
74561
74562             function continueTo(nextStep) {
74563               context.map().on('move.intro drawn.intro', null);
74564               context.history().on('change.intro', null);
74565               nextStep();
74566             }
74567           }
74568
74569           function rightClickIntersection() {
74570             context.history().reset('doneUpdateLine');
74571             context.enter(modeBrowse(context));
74572             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
74573             var rightClickString = helpHtml('intro.lines.split_street', {
74574               street1: _t('intro.graph.name.11th-avenue'),
74575               street2: _t('intro.graph.name.washington-street')
74576             }) + helpHtml('intro.lines.' + (context.lastPointerType() === 'mouse' ? 'rightclick_intersection' : 'edit_menu_intersection_touch'));
74577             timeout(function () {
74578               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74579               var box = pad(eleventhAvenueEnd, padding, context);
74580               reveal(box, rightClickString);
74581               context.map().on('move.intro drawn.intro', function () {
74582                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74583                 var box = pad(eleventhAvenueEnd, padding, context);
74584                 reveal(box, rightClickString, {
74585                   duration: 0
74586                 });
74587               });
74588               context.on('enter.intro', function (mode) {
74589                 if (mode.id !== 'select') return;
74590                 var ids = context.selectedIDs();
74591                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
74592                 timeout(function () {
74593                   var node = selectMenuItem(context, 'split').node();
74594                   if (!node) return;
74595                   continueTo(splitIntersection);
74596                 }, 50); // after menu visible
74597               });
74598               context.history().on('change.intro', function () {
74599                 timeout(function () {
74600                   continueTo(deleteLines);
74601                 }, 300); // after any transition (e.g. if user deleted intersection)
74602               });
74603             }, 600);
74604
74605             function continueTo(nextStep) {
74606               context.map().on('move.intro drawn.intro', null);
74607               context.on('enter.intro', null);
74608               context.history().on('change.intro', null);
74609               nextStep();
74610             }
74611           }
74612
74613           function splitIntersection() {
74614             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74615               return continueTo(deleteLines);
74616             }
74617
74618             var node = selectMenuItem(context, 'split').node();
74619
74620             if (!node) {
74621               return continueTo(rightClickIntersection);
74622             }
74623
74624             var wasChanged = false;
74625             _washingtonSegmentID = null;
74626             reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
74627               street: _t('intro.graph.name.washington-street')
74628             }), {
74629               padding: 50
74630             });
74631             context.map().on('move.intro drawn.intro', function () {
74632               var node = selectMenuItem(context, 'split').node();
74633
74634               if (!wasChanged && !node) {
74635                 return continueTo(rightClickIntersection);
74636               }
74637
74638               reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
74639                 street: _t('intro.graph.name.washington-street')
74640               }), {
74641                 duration: 0,
74642                 padding: 50
74643               });
74644             });
74645             context.history().on('change.intro', function (changed) {
74646               wasChanged = true;
74647               timeout(function () {
74648                 if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
74649                   n: 1
74650                 })) {
74651                   _washingtonSegmentID = changed.created()[0].id;
74652                   continueTo(didSplit);
74653                 } else {
74654                   _washingtonSegmentID = null;
74655                   continueTo(retrySplit);
74656                 }
74657               }, 300); // after any transition (e.g. if user deleted intersection)
74658             });
74659
74660             function continueTo(nextStep) {
74661               context.map().on('move.intro drawn.intro', null);
74662               context.history().on('change.intro', null);
74663               nextStep();
74664             }
74665           }
74666
74667           function retrySplit() {
74668             context.enter(modeBrowse(context));
74669             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
74670
74671             var advance = function advance() {
74672               continueTo(rightClickIntersection);
74673             };
74674
74675             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74676             var box = pad(eleventhAvenueEnd, padding, context);
74677             reveal(box, helpHtml('intro.lines.retry_split'), {
74678               buttonText: _t.html('intro.ok'),
74679               buttonCallback: advance
74680             });
74681             context.map().on('move.intro drawn.intro', function () {
74682               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74683               var box = pad(eleventhAvenueEnd, padding, context);
74684               reveal(box, helpHtml('intro.lines.retry_split'), {
74685                 duration: 0,
74686                 buttonText: _t.html('intro.ok'),
74687                 buttonCallback: advance
74688               });
74689             });
74690
74691             function continueTo(nextStep) {
74692               context.map().on('move.intro drawn.intro', null);
74693               nextStep();
74694             }
74695           }
74696
74697           function didSplit() {
74698             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74699               return continueTo(rightClickIntersection);
74700             }
74701
74702             var ids = context.selectedIDs();
74703             var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
74704             var street = _t('intro.graph.name.washington-street');
74705             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74706             var box = pad(twelfthAvenue, padding, context);
74707             box.width = box.width / 2;
74708             reveal(box, helpHtml(string, {
74709               street1: street,
74710               street2: street
74711             }), {
74712               duration: 500
74713             });
74714             timeout(function () {
74715               context.map().centerZoomEase(twelfthAvenue, 18, 500);
74716               context.map().on('move.intro drawn.intro', function () {
74717                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74718                 var box = pad(twelfthAvenue, padding, context);
74719                 box.width = box.width / 2;
74720                 reveal(box, helpHtml(string, {
74721                   street1: street,
74722                   street2: street
74723                 }), {
74724                   duration: 0
74725                 });
74726               });
74727             }, 600); // after initial reveal and curtain cut
74728
74729             context.on('enter.intro', function () {
74730               var ids = context.selectedIDs();
74731
74732               if (ids.length === 1 && ids[0] === _washingtonSegmentID) {
74733                 continueTo(multiSelect);
74734               }
74735             });
74736             context.history().on('change.intro', function () {
74737               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74738                 return continueTo(rightClickIntersection);
74739               }
74740             });
74741
74742             function continueTo(nextStep) {
74743               context.map().on('move.intro drawn.intro', null);
74744               context.on('enter.intro', null);
74745               context.history().on('change.intro', null);
74746               nextStep();
74747             }
74748           }
74749
74750           function multiSelect() {
74751             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74752               return continueTo(rightClickIntersection);
74753             }
74754
74755             var ids = context.selectedIDs();
74756             var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
74757             var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
74758
74759             if (hasWashington && hasTwelfth) {
74760               return continueTo(multiRightClick);
74761             } else if (!hasWashington && !hasTwelfth) {
74762               return continueTo(didSplit);
74763             }
74764
74765             context.map().centerZoomEase(twelfthAvenue, 18, 500);
74766             timeout(function () {
74767               var selected, other, padding, box;
74768
74769               if (hasWashington) {
74770                 selected = _t('intro.graph.name.washington-street');
74771                 other = _t('intro.graph.name.12th-avenue');
74772                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
74773                 box = pad(twelfthAvenueEnd, padding, context);
74774                 box.width *= 3;
74775               } else {
74776                 selected = _t('intro.graph.name.12th-avenue');
74777                 other = _t('intro.graph.name.washington-street');
74778                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
74779                 box = pad(twelfthAvenue, padding, context);
74780                 box.width /= 2;
74781               }
74782
74783               reveal(box, helpHtml('intro.lines.multi_select', {
74784                 selected: selected,
74785                 other1: other
74786               }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
74787                 selected: selected,
74788                 other2: other
74789               }));
74790               context.map().on('move.intro drawn.intro', function () {
74791                 if (hasWashington) {
74792                   selected = _t('intro.graph.name.washington-street');
74793                   other = _t('intro.graph.name.12th-avenue');
74794                   padding = 60 * Math.pow(2, context.map().zoom() - 18);
74795                   box = pad(twelfthAvenueEnd, padding, context);
74796                   box.width *= 3;
74797                 } else {
74798                   selected = _t('intro.graph.name.12th-avenue');
74799                   other = _t('intro.graph.name.washington-street');
74800                   padding = 200 * Math.pow(2, context.map().zoom() - 18);
74801                   box = pad(twelfthAvenue, padding, context);
74802                   box.width /= 2;
74803                 }
74804
74805                 reveal(box, helpHtml('intro.lines.multi_select', {
74806                   selected: selected,
74807                   other1: other
74808                 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
74809                   selected: selected,
74810                   other2: other
74811                 }), {
74812                   duration: 0
74813                 });
74814               });
74815               context.on('enter.intro', function () {
74816                 continueTo(multiSelect);
74817               });
74818               context.history().on('change.intro', function () {
74819                 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74820                   return continueTo(rightClickIntersection);
74821                 }
74822               });
74823             }, 600);
74824
74825             function continueTo(nextStep) {
74826               context.map().on('move.intro drawn.intro', null);
74827               context.on('enter.intro', null);
74828               context.history().on('change.intro', null);
74829               nextStep();
74830             }
74831           }
74832
74833           function multiRightClick() {
74834             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74835               return continueTo(rightClickIntersection);
74836             }
74837
74838             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74839             var box = pad(twelfthAvenue, padding, context);
74840             var rightClickString = helpHtml('intro.lines.multi_select_success') + helpHtml('intro.lines.multi_' + (context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch'));
74841             reveal(box, rightClickString);
74842             context.map().on('move.intro drawn.intro', function () {
74843               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74844               var box = pad(twelfthAvenue, padding, context);
74845               reveal(box, rightClickString, {
74846                 duration: 0
74847               });
74848             });
74849             context.ui().editMenu().on('toggled.intro', function (open) {
74850               if (!open) return;
74851               timeout(function () {
74852                 var ids = context.selectedIDs();
74853
74854                 if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
74855                   var node = selectMenuItem(context, 'delete').node();
74856                   if (!node) return;
74857                   continueTo(multiDelete);
74858                 } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
74859                   return continueTo(multiSelect);
74860                 } else {
74861                   return continueTo(didSplit);
74862                 }
74863               }, 300); // after edit menu visible
74864             });
74865             context.history().on('change.intro', function () {
74866               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74867                 return continueTo(rightClickIntersection);
74868               }
74869             });
74870
74871             function continueTo(nextStep) {
74872               context.map().on('move.intro drawn.intro', null);
74873               context.ui().editMenu().on('toggled.intro', null);
74874               context.history().on('change.intro', null);
74875               nextStep();
74876             }
74877           }
74878
74879           function multiDelete() {
74880             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74881               return continueTo(rightClickIntersection);
74882             }
74883
74884             var node = selectMenuItem(context, 'delete').node();
74885             if (!node) return continueTo(multiRightClick);
74886             reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
74887               padding: 50
74888             });
74889             context.map().on('move.intro drawn.intro', function () {
74890               reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
74891                 duration: 0,
74892                 padding: 50
74893               });
74894             });
74895             context.on('exit.intro', function () {
74896               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
74897                 return continueTo(multiSelect); // left select mode but roads still exist
74898               }
74899             });
74900             context.history().on('change.intro', function () {
74901               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
74902                 continueTo(retryDelete); // changed something but roads still exist
74903               } else {
74904                 continueTo(play);
74905               }
74906             });
74907
74908             function continueTo(nextStep) {
74909               context.map().on('move.intro drawn.intro', null);
74910               context.on('exit.intro', null);
74911               context.history().on('change.intro', null);
74912               nextStep();
74913             }
74914           }
74915
74916           function retryDelete() {
74917             context.enter(modeBrowse(context));
74918             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74919             var box = pad(twelfthAvenue, padding, context);
74920             reveal(box, helpHtml('intro.lines.retry_delete'), {
74921               buttonText: _t.html('intro.ok'),
74922               buttonCallback: function buttonCallback() {
74923                 continueTo(multiSelect);
74924               }
74925             });
74926
74927             function continueTo(nextStep) {
74928               nextStep();
74929             }
74930           }
74931
74932           function play() {
74933             dispatch.call('done');
74934             reveal('.ideditor', helpHtml('intro.lines.play', {
74935               next: _t('intro.buildings.title')
74936             }), {
74937               tooltipBox: '.intro-nav-wrap .chapter-building',
74938               buttonText: _t.html('intro.ok'),
74939               buttonCallback: function buttonCallback() {
74940                 reveal('.ideditor');
74941               }
74942             });
74943           }
74944
74945           chapter.enter = function () {
74946             addLine();
74947           };
74948
74949           chapter.exit = function () {
74950             timeouts.forEach(window.clearTimeout);
74951             select(window).on('pointerdown.intro mousedown.intro', null, true);
74952             context.on('enter.intro exit.intro', null);
74953             context.map().on('move.intro drawn.intro', null);
74954             context.history().on('change.intro', null);
74955             context.container().select('.inspector-wrap').on('wheel.intro', null);
74956             context.container().select('.preset-list-button').on('click.intro', null);
74957           };
74958
74959           chapter.restart = function () {
74960             chapter.exit();
74961             chapter.enter();
74962           };
74963
74964           return utilRebind(chapter, dispatch, 'on');
74965         }
74966
74967         function uiIntroBuilding(context, reveal) {
74968           var dispatch = dispatch$8('done');
74969           var house = [-85.62815, 41.95638];
74970           var tank = [-85.62732, 41.95347];
74971           var buildingCatetory = _mainPresetIndex.item('category-building');
74972           var housePreset = _mainPresetIndex.item('building/house');
74973           var tankPreset = _mainPresetIndex.item('man_made/storage_tank');
74974           var timeouts = [];
74975           var _houseID = null;
74976           var _tankID = null;
74977           var chapter = {
74978             title: 'intro.buildings.title'
74979           };
74980
74981           function timeout(f, t) {
74982             timeouts.push(window.setTimeout(f, t));
74983           }
74984
74985           function eventCancel(d3_event) {
74986             d3_event.stopPropagation();
74987             d3_event.preventDefault();
74988           }
74989
74990           function revealHouse(center, text, options) {
74991             var padding = 160 * Math.pow(2, context.map().zoom() - 20);
74992             var box = pad(center, padding, context);
74993             reveal(box, text, options);
74994           }
74995
74996           function revealTank(center, text, options) {
74997             var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
74998             var box = pad(center, padding, context);
74999             reveal(box, text, options);
75000           }
75001
75002           function addHouse() {
75003             context.enter(modeBrowse(context));
75004             context.history().reset('initial');
75005             _houseID = null;
75006             var msec = transitionTime(house, context.map().center());
75007
75008             if (msec) {
75009               reveal(null, null, {
75010                 duration: 0
75011               });
75012             }
75013
75014             context.map().centerZoomEase(house, 19, msec);
75015             timeout(function () {
75016               var tooltip = reveal('button.add-area', helpHtml('intro.buildings.add_building'));
75017               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-buildings');
75018               context.on('enter.intro', function (mode) {
75019                 if (mode.id !== 'add-area') return;
75020                 continueTo(startHouse);
75021               });
75022             }, msec + 100);
75023
75024             function continueTo(nextStep) {
75025               context.on('enter.intro', null);
75026               nextStep();
75027             }
75028           }
75029
75030           function startHouse() {
75031             if (context.mode().id !== 'add-area') {
75032               return continueTo(addHouse);
75033             }
75034
75035             _houseID = null;
75036             context.map().zoomEase(20, 500);
75037             timeout(function () {
75038               var startString = helpHtml('intro.buildings.start_building') + helpHtml('intro.buildings.building_corner_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
75039               revealHouse(house, startString);
75040               context.map().on('move.intro drawn.intro', function () {
75041                 revealHouse(house, startString, {
75042                   duration: 0
75043                 });
75044               });
75045               context.on('enter.intro', function (mode) {
75046                 if (mode.id !== 'draw-area') return chapter.restart();
75047                 continueTo(continueHouse);
75048               });
75049             }, 550); // after easing
75050
75051             function continueTo(nextStep) {
75052               context.map().on('move.intro drawn.intro', null);
75053               context.on('enter.intro', null);
75054               nextStep();
75055             }
75056           }
75057
75058           function continueHouse() {
75059             if (context.mode().id !== 'draw-area') {
75060               return continueTo(addHouse);
75061             }
75062
75063             _houseID = null;
75064             var continueString = helpHtml('intro.buildings.continue_building') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_building');
75065             revealHouse(house, continueString);
75066             context.map().on('move.intro drawn.intro', function () {
75067               revealHouse(house, continueString, {
75068                 duration: 0
75069               });
75070             });
75071             context.on('enter.intro', function (mode) {
75072               if (mode.id === 'draw-area') {
75073                 return;
75074               } else if (mode.id === 'select') {
75075                 var graph = context.graph();
75076                 var way = context.entity(context.selectedIDs()[0]);
75077                 var nodes = graph.childNodes(way);
75078                 var points = utilArrayUniq(nodes).map(function (n) {
75079                   return context.projection(n.loc);
75080                 });
75081
75082                 if (isMostlySquare(points)) {
75083                   _houseID = way.id;
75084                   return continueTo(chooseCategoryBuilding);
75085                 } else {
75086                   return continueTo(retryHouse);
75087                 }
75088               } else {
75089                 return chapter.restart();
75090               }
75091             });
75092
75093             function continueTo(nextStep) {
75094               context.map().on('move.intro drawn.intro', null);
75095               context.on('enter.intro', null);
75096               nextStep();
75097             }
75098           }
75099
75100           function retryHouse() {
75101             var onClick = function onClick() {
75102               continueTo(addHouse);
75103             };
75104
75105             revealHouse(house, helpHtml('intro.buildings.retry_building'), {
75106               buttonText: _t.html('intro.ok'),
75107               buttonCallback: onClick
75108             });
75109             context.map().on('move.intro drawn.intro', function () {
75110               revealHouse(house, helpHtml('intro.buildings.retry_building'), {
75111                 duration: 0,
75112                 buttonText: _t.html('intro.ok'),
75113                 buttonCallback: onClick
75114               });
75115             });
75116
75117             function continueTo(nextStep) {
75118               context.map().on('move.intro drawn.intro', null);
75119               nextStep();
75120             }
75121           }
75122
75123           function chooseCategoryBuilding() {
75124             if (!_houseID || !context.hasEntity(_houseID)) {
75125               return addHouse();
75126             }
75127
75128             var ids = context.selectedIDs();
75129
75130             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
75131               context.enter(modeSelect(context, [_houseID]));
75132             } // disallow scrolling
75133
75134
75135             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75136             timeout(function () {
75137               // reset pane, in case user somehow happened to change it..
75138               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
75139               var button = context.container().select('.preset-category-building .preset-list-button');
75140               reveal(button.node(), helpHtml('intro.buildings.choose_category_building', {
75141                 category: buildingCatetory.name()
75142               }));
75143               button.on('click.intro', function () {
75144                 button.on('click.intro', null);
75145                 continueTo(choosePresetHouse);
75146               });
75147             }, 400); // after preset list pane visible..
75148
75149             context.on('enter.intro', function (mode) {
75150               if (!_houseID || !context.hasEntity(_houseID)) {
75151                 return continueTo(addHouse);
75152               }
75153
75154               var ids = context.selectedIDs();
75155
75156               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
75157                 return continueTo(chooseCategoryBuilding);
75158               }
75159             });
75160
75161             function continueTo(nextStep) {
75162               context.container().select('.inspector-wrap').on('wheel.intro', null);
75163               context.container().select('.preset-list-button').on('click.intro', null);
75164               context.on('enter.intro', null);
75165               nextStep();
75166             }
75167           }
75168
75169           function choosePresetHouse() {
75170             if (!_houseID || !context.hasEntity(_houseID)) {
75171               return addHouse();
75172             }
75173
75174             var ids = context.selectedIDs();
75175
75176             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
75177               context.enter(modeSelect(context, [_houseID]));
75178             } // disallow scrolling
75179
75180
75181             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75182             timeout(function () {
75183               // reset pane, in case user somehow happened to change it..
75184               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
75185               var button = context.container().select('.preset-building-house .preset-list-button');
75186               reveal(button.node(), helpHtml('intro.buildings.choose_preset_house', {
75187                 preset: housePreset.name()
75188               }), {
75189                 duration: 300
75190               });
75191               button.on('click.intro', function () {
75192                 button.on('click.intro', null);
75193                 continueTo(closeEditorHouse);
75194               });
75195             }, 400); // after preset list pane visible..
75196
75197             context.on('enter.intro', function (mode) {
75198               if (!_houseID || !context.hasEntity(_houseID)) {
75199                 return continueTo(addHouse);
75200               }
75201
75202               var ids = context.selectedIDs();
75203
75204               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
75205                 return continueTo(chooseCategoryBuilding);
75206               }
75207             });
75208
75209             function continueTo(nextStep) {
75210               context.container().select('.inspector-wrap').on('wheel.intro', null);
75211               context.container().select('.preset-list-button').on('click.intro', null);
75212               context.on('enter.intro', null);
75213               nextStep();
75214             }
75215           }
75216
75217           function closeEditorHouse() {
75218             if (!_houseID || !context.hasEntity(_houseID)) {
75219               return addHouse();
75220             }
75221
75222             var ids = context.selectedIDs();
75223
75224             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
75225               context.enter(modeSelect(context, [_houseID]));
75226             }
75227
75228             context.history().checkpoint('hasHouse');
75229             context.on('exit.intro', function () {
75230               continueTo(rightClickHouse);
75231             });
75232             timeout(function () {
75233               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
75234                 button: icon('#iD-icon-close', 'inline')
75235               }));
75236             }, 500);
75237
75238             function continueTo(nextStep) {
75239               context.on('exit.intro', null);
75240               nextStep();
75241             }
75242           }
75243
75244           function rightClickHouse() {
75245             if (!_houseID) return chapter.restart();
75246             context.enter(modeBrowse(context));
75247             context.history().reset('hasHouse');
75248             var zoom = context.map().zoom();
75249
75250             if (zoom < 20) {
75251               zoom = 20;
75252             }
75253
75254             context.map().centerZoomEase(house, zoom, 500);
75255             context.on('enter.intro', function (mode) {
75256               if (mode.id !== 'select') return;
75257               var ids = context.selectedIDs();
75258               if (ids.length !== 1 || ids[0] !== _houseID) return;
75259               timeout(function () {
75260                 var node = selectMenuItem(context, 'orthogonalize').node();
75261                 if (!node) return;
75262                 continueTo(clickSquare);
75263               }, 50); // after menu visible
75264             });
75265             context.map().on('move.intro drawn.intro', function () {
75266               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_building' : 'edit_menu_building_touch'));
75267               revealHouse(house, rightclickString, {
75268                 duration: 0
75269               });
75270             });
75271             context.history().on('change.intro', function () {
75272               continueTo(rightClickHouse);
75273             });
75274
75275             function continueTo(nextStep) {
75276               context.on('enter.intro', null);
75277               context.map().on('move.intro drawn.intro', null);
75278               context.history().on('change.intro', null);
75279               nextStep();
75280             }
75281           }
75282
75283           function clickSquare() {
75284             if (!_houseID) return chapter.restart();
75285             var entity = context.hasEntity(_houseID);
75286             if (!entity) return continueTo(rightClickHouse);
75287             var node = selectMenuItem(context, 'orthogonalize').node();
75288
75289             if (!node) {
75290               return continueTo(rightClickHouse);
75291             }
75292
75293             var wasChanged = false;
75294             reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
75295               padding: 50
75296             });
75297             context.on('enter.intro', function (mode) {
75298               if (mode.id === 'browse') {
75299                 continueTo(rightClickHouse);
75300               } else if (mode.id === 'move' || mode.id === 'rotate') {
75301                 continueTo(retryClickSquare);
75302               }
75303             });
75304             context.map().on('move.intro', function () {
75305               var node = selectMenuItem(context, 'orthogonalize').node();
75306
75307               if (!wasChanged && !node) {
75308                 return continueTo(rightClickHouse);
75309               }
75310
75311               reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
75312                 duration: 0,
75313                 padding: 50
75314               });
75315             });
75316             context.history().on('change.intro', function () {
75317               wasChanged = true;
75318               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
75319
75320               timeout(function () {
75321                 if (context.history().undoAnnotation() === _t('operations.orthogonalize.annotation.feature', {
75322                   n: 1
75323                 })) {
75324                   continueTo(doneSquare);
75325                 } else {
75326                   continueTo(retryClickSquare);
75327                 }
75328               }, 500); // after transitioned actions
75329             });
75330
75331             function continueTo(nextStep) {
75332               context.on('enter.intro', null);
75333               context.map().on('move.intro', null);
75334               context.history().on('change.intro', null);
75335               nextStep();
75336             }
75337           }
75338
75339           function retryClickSquare() {
75340             context.enter(modeBrowse(context));
75341             revealHouse(house, helpHtml('intro.buildings.retry_square'), {
75342               buttonText: _t.html('intro.ok'),
75343               buttonCallback: function buttonCallback() {
75344                 continueTo(rightClickHouse);
75345               }
75346             });
75347
75348             function continueTo(nextStep) {
75349               nextStep();
75350             }
75351           }
75352
75353           function doneSquare() {
75354             context.history().checkpoint('doneSquare');
75355             revealHouse(house, helpHtml('intro.buildings.done_square'), {
75356               buttonText: _t.html('intro.ok'),
75357               buttonCallback: function buttonCallback() {
75358                 continueTo(addTank);
75359               }
75360             });
75361
75362             function continueTo(nextStep) {
75363               nextStep();
75364             }
75365           }
75366
75367           function addTank() {
75368             context.enter(modeBrowse(context));
75369             context.history().reset('doneSquare');
75370             _tankID = null;
75371             var msec = transitionTime(tank, context.map().center());
75372
75373             if (msec) {
75374               reveal(null, null, {
75375                 duration: 0
75376               });
75377             }
75378
75379             context.map().centerZoomEase(tank, 19.5, msec);
75380             timeout(function () {
75381               reveal('button.add-area', helpHtml('intro.buildings.add_tank'));
75382               context.on('enter.intro', function (mode) {
75383                 if (mode.id !== 'add-area') return;
75384                 continueTo(startTank);
75385               });
75386             }, msec + 100);
75387
75388             function continueTo(nextStep) {
75389               context.on('enter.intro', null);
75390               nextStep();
75391             }
75392           }
75393
75394           function startTank() {
75395             if (context.mode().id !== 'add-area') {
75396               return continueTo(addTank);
75397             }
75398
75399             _tankID = null;
75400             timeout(function () {
75401               var startString = helpHtml('intro.buildings.start_tank') + helpHtml('intro.buildings.tank_edge_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
75402               revealTank(tank, startString);
75403               context.map().on('move.intro drawn.intro', function () {
75404                 revealTank(tank, startString, {
75405                   duration: 0
75406                 });
75407               });
75408               context.on('enter.intro', function (mode) {
75409                 if (mode.id !== 'draw-area') return chapter.restart();
75410                 continueTo(continueTank);
75411               });
75412             }, 550); // after easing
75413
75414             function continueTo(nextStep) {
75415               context.map().on('move.intro drawn.intro', null);
75416               context.on('enter.intro', null);
75417               nextStep();
75418             }
75419           }
75420
75421           function continueTank() {
75422             if (context.mode().id !== 'draw-area') {
75423               return continueTo(addTank);
75424             }
75425
75426             _tankID = null;
75427             var continueString = helpHtml('intro.buildings.continue_tank') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_tank');
75428             revealTank(tank, continueString);
75429             context.map().on('move.intro drawn.intro', function () {
75430               revealTank(tank, continueString, {
75431                 duration: 0
75432               });
75433             });
75434             context.on('enter.intro', function (mode) {
75435               if (mode.id === 'draw-area') {
75436                 return;
75437               } else if (mode.id === 'select') {
75438                 _tankID = context.selectedIDs()[0];
75439                 return continueTo(searchPresetTank);
75440               } else {
75441                 return continueTo(addTank);
75442               }
75443             });
75444
75445             function continueTo(nextStep) {
75446               context.map().on('move.intro drawn.intro', null);
75447               context.on('enter.intro', null);
75448               nextStep();
75449             }
75450           }
75451
75452           function searchPresetTank() {
75453             if (!_tankID || !context.hasEntity(_tankID)) {
75454               return addTank();
75455             }
75456
75457             var ids = context.selectedIDs();
75458
75459             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
75460               context.enter(modeSelect(context, [_tankID]));
75461             } // disallow scrolling
75462
75463
75464             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75465             timeout(function () {
75466               // reset pane, in case user somehow happened to change it..
75467               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
75468               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
75469               reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
75470                 preset: tankPreset.name()
75471               }));
75472             }, 400); // after preset list pane visible..
75473
75474             context.on('enter.intro', function (mode) {
75475               if (!_tankID || !context.hasEntity(_tankID)) {
75476                 return continueTo(addTank);
75477               }
75478
75479               var ids = context.selectedIDs();
75480
75481               if (mode.id !== 'select' || !ids.length || ids[0] !== _tankID) {
75482                 // keep the user's area selected..
75483                 context.enter(modeSelect(context, [_tankID])); // reset pane, in case user somehow happened to change it..
75484
75485                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
75486
75487                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75488                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
75489                 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
75490                   preset: tankPreset.name()
75491                 }));
75492                 context.history().on('change.intro', null);
75493               }
75494             });
75495
75496             function checkPresetSearch() {
75497               var first = context.container().select('.preset-list-item:first-child');
75498
75499               if (first.classed('preset-man_made-storage_tank')) {
75500                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.buildings.choose_tank', {
75501                   preset: tankPreset.name()
75502                 }), {
75503                   duration: 300
75504                 });
75505                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
75506                 context.history().on('change.intro', function () {
75507                   continueTo(closeEditorTank);
75508                 });
75509               }
75510             }
75511
75512             function continueTo(nextStep) {
75513               context.container().select('.inspector-wrap').on('wheel.intro', null);
75514               context.on('enter.intro', null);
75515               context.history().on('change.intro', null);
75516               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
75517               nextStep();
75518             }
75519           }
75520
75521           function closeEditorTank() {
75522             if (!_tankID || !context.hasEntity(_tankID)) {
75523               return addTank();
75524             }
75525
75526             var ids = context.selectedIDs();
75527
75528             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
75529               context.enter(modeSelect(context, [_tankID]));
75530             }
75531
75532             context.history().checkpoint('hasTank');
75533             context.on('exit.intro', function () {
75534               continueTo(rightClickTank);
75535             });
75536             timeout(function () {
75537               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
75538                 button: icon('#iD-icon-close', 'inline')
75539               }));
75540             }, 500);
75541
75542             function continueTo(nextStep) {
75543               context.on('exit.intro', null);
75544               nextStep();
75545             }
75546           }
75547
75548           function rightClickTank() {
75549             if (!_tankID) return continueTo(addTank);
75550             context.enter(modeBrowse(context));
75551             context.history().reset('hasTank');
75552             context.map().centerEase(tank, 500);
75553             timeout(function () {
75554               context.on('enter.intro', function (mode) {
75555                 if (mode.id !== 'select') return;
75556                 var ids = context.selectedIDs();
75557                 if (ids.length !== 1 || ids[0] !== _tankID) return;
75558                 timeout(function () {
75559                   var node = selectMenuItem(context, 'circularize').node();
75560                   if (!node) return;
75561                   continueTo(clickCircle);
75562                 }, 50); // after menu visible
75563               });
75564               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_tank' : 'edit_menu_tank_touch'));
75565               revealTank(tank, rightclickString);
75566               context.map().on('move.intro drawn.intro', function () {
75567                 revealTank(tank, rightclickString, {
75568                   duration: 0
75569                 });
75570               });
75571               context.history().on('change.intro', function () {
75572                 continueTo(rightClickTank);
75573               });
75574             }, 600);
75575
75576             function continueTo(nextStep) {
75577               context.on('enter.intro', null);
75578               context.map().on('move.intro drawn.intro', null);
75579               context.history().on('change.intro', null);
75580               nextStep();
75581             }
75582           }
75583
75584           function clickCircle() {
75585             if (!_tankID) return chapter.restart();
75586             var entity = context.hasEntity(_tankID);
75587             if (!entity) return continueTo(rightClickTank);
75588             var node = selectMenuItem(context, 'circularize').node();
75589
75590             if (!node) {
75591               return continueTo(rightClickTank);
75592             }
75593
75594             var wasChanged = false;
75595             reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
75596               padding: 50
75597             });
75598             context.on('enter.intro', function (mode) {
75599               if (mode.id === 'browse') {
75600                 continueTo(rightClickTank);
75601               } else if (mode.id === 'move' || mode.id === 'rotate') {
75602                 continueTo(retryClickCircle);
75603               }
75604             });
75605             context.map().on('move.intro', function () {
75606               var node = selectMenuItem(context, 'circularize').node();
75607
75608               if (!wasChanged && !node) {
75609                 return continueTo(rightClickTank);
75610               }
75611
75612               reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
75613                 duration: 0,
75614                 padding: 50
75615               });
75616             });
75617             context.history().on('change.intro', function () {
75618               wasChanged = true;
75619               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
75620
75621               timeout(function () {
75622                 if (context.history().undoAnnotation() === _t('operations.circularize.annotation.feature', {
75623                   n: 1
75624                 })) {
75625                   continueTo(play);
75626                 } else {
75627                   continueTo(retryClickCircle);
75628                 }
75629               }, 500); // after transitioned actions
75630             });
75631
75632             function continueTo(nextStep) {
75633               context.on('enter.intro', null);
75634               context.map().on('move.intro', null);
75635               context.history().on('change.intro', null);
75636               nextStep();
75637             }
75638           }
75639
75640           function retryClickCircle() {
75641             context.enter(modeBrowse(context));
75642             revealTank(tank, helpHtml('intro.buildings.retry_circle'), {
75643               buttonText: _t.html('intro.ok'),
75644               buttonCallback: function buttonCallback() {
75645                 continueTo(rightClickTank);
75646               }
75647             });
75648
75649             function continueTo(nextStep) {
75650               nextStep();
75651             }
75652           }
75653
75654           function play() {
75655             dispatch.call('done');
75656             reveal('.ideditor', helpHtml('intro.buildings.play', {
75657               next: _t('intro.startediting.title')
75658             }), {
75659               tooltipBox: '.intro-nav-wrap .chapter-startEditing',
75660               buttonText: _t.html('intro.ok'),
75661               buttonCallback: function buttonCallback() {
75662                 reveal('.ideditor');
75663               }
75664             });
75665           }
75666
75667           chapter.enter = function () {
75668             addHouse();
75669           };
75670
75671           chapter.exit = function () {
75672             timeouts.forEach(window.clearTimeout);
75673             context.on('enter.intro exit.intro', null);
75674             context.map().on('move.intro drawn.intro', null);
75675             context.history().on('change.intro', null);
75676             context.container().select('.inspector-wrap').on('wheel.intro', null);
75677             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
75678             context.container().select('.more-fields .combobox-input').on('click.intro', null);
75679           };
75680
75681           chapter.restart = function () {
75682             chapter.exit();
75683             chapter.enter();
75684           };
75685
75686           return utilRebind(chapter, dispatch, 'on');
75687         }
75688
75689         function uiIntroStartEditing(context, reveal) {
75690           var dispatch = dispatch$8('done', 'startEditing');
75691           var modalSelection = select(null);
75692           var chapter = {
75693             title: 'intro.startediting.title'
75694           };
75695
75696           function showHelp() {
75697             reveal('.map-control.help-control', helpHtml('intro.startediting.help'), {
75698               buttonText: _t.html('intro.ok'),
75699               buttonCallback: function buttonCallback() {
75700                 shortcuts();
75701               }
75702             });
75703           }
75704
75705           function shortcuts() {
75706             reveal('.map-control.help-control', helpHtml('intro.startediting.shortcuts'), {
75707               buttonText: _t.html('intro.ok'),
75708               buttonCallback: function buttonCallback() {
75709                 showSave();
75710               }
75711             });
75712           }
75713
75714           function showSave() {
75715             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
75716
75717             reveal('.top-toolbar button.save', helpHtml('intro.startediting.save'), {
75718               buttonText: _t.html('intro.ok'),
75719               buttonCallback: function buttonCallback() {
75720                 showStart();
75721               }
75722             });
75723           }
75724
75725           function showStart() {
75726             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
75727
75728             modalSelection = uiModal(context.container());
75729             modalSelection.select('.modal').attr('class', 'modal-splash modal');
75730             modalSelection.selectAll('.close').remove();
75731             var startbutton = modalSelection.select('.content').attr('class', 'fillL').append('button').attr('class', 'modal-section huge-modal-button').on('click', function () {
75732               modalSelection.remove();
75733             });
75734             startbutton.append('svg').attr('class', 'illustration').append('use').attr('xlink:href', '#iD-logo-walkthrough');
75735             startbutton.append('h2').html(_t.html('intro.startediting.start'));
75736             dispatch.call('startEditing');
75737           }
75738
75739           chapter.enter = function () {
75740             showHelp();
75741           };
75742
75743           chapter.exit = function () {
75744             modalSelection.remove();
75745             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
75746           };
75747
75748           return utilRebind(chapter, dispatch, 'on');
75749         }
75750
75751         var chapterUi = {
75752           welcome: uiIntroWelcome,
75753           navigation: uiIntroNavigation,
75754           point: uiIntroPoint,
75755           area: uiIntroArea,
75756           line: uiIntroLine,
75757           building: uiIntroBuilding,
75758           startEditing: uiIntroStartEditing
75759         };
75760         var chapterFlow = ['welcome', 'navigation', 'point', 'area', 'line', 'building', 'startEditing'];
75761         function uiIntro(context) {
75762           var INTRO_IMAGERY = 'EsriWorldImageryClarity';
75763           var _introGraph = {};
75764
75765           var _currChapter;
75766
75767           function intro(selection) {
75768             _mainFileFetcher.get('intro_graph').then(function (dataIntroGraph) {
75769               // create entities for intro graph and localize names
75770               for (var id in dataIntroGraph) {
75771                 if (!_introGraph[id]) {
75772                   _introGraph[id] = osmEntity(localize(dataIntroGraph[id]));
75773                 }
75774               }
75775
75776               selection.call(startIntro);
75777             })["catch"](function () {
75778               /* ignore */
75779             });
75780           }
75781
75782           function startIntro(selection) {
75783             context.enter(modeBrowse(context)); // Save current map state
75784
75785             var osm = context.connection();
75786             var history = context.history().toJSON();
75787             var hash = window.location.hash;
75788             var center = context.map().center();
75789             var zoom = context.map().zoom();
75790             var background = context.background().baseLayerSource();
75791             var overlays = context.background().overlayLayerSources();
75792             var opacity = context.container().selectAll('.main-map .layer-background').style('opacity');
75793             var caches = osm && osm.caches();
75794             var baseEntities = context.history().graph().base().entities; // Show sidebar and disable the sidebar resizing button
75795             // (this needs to be before `context.inIntro(true)`)
75796
75797             context.ui().sidebar.expand();
75798             context.container().selectAll('button.sidebar-toggle').classed('disabled', true); // Block saving
75799
75800             context.inIntro(true); // Load semi-real data used in intro
75801
75802             if (osm) {
75803               osm.toggle(false).reset();
75804             }
75805
75806             context.history().reset();
75807             context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
75808             context.history().checkpoint('initial'); // Setup imagery
75809
75810             var imagery = context.background().findSource(INTRO_IMAGERY);
75811
75812             if (imagery) {
75813               context.background().baseLayerSource(imagery);
75814             } else {
75815               context.background().bing();
75816             }
75817
75818             overlays.forEach(function (d) {
75819               return context.background().toggleOverlayLayer(d);
75820             }); // Setup data layers (only OSM)
75821
75822             var layers = context.layers();
75823             layers.all().forEach(function (item) {
75824               // if the layer has the function `enabled`
75825               if (typeof item.layer.enabled === 'function') {
75826                 item.layer.enabled(item.id === 'osm');
75827               }
75828             });
75829             context.container().selectAll('.main-map .layer-background').style('opacity', 1);
75830             var curtain = uiCurtain(context.container().node());
75831             selection.call(curtain); // Store that the user started the walkthrough..
75832
75833             corePreferences('walkthrough_started', 'yes'); // Restore previous walkthrough progress..
75834
75835             var storedProgress = corePreferences('walkthrough_progress') || '';
75836             var progress = storedProgress.split(';').filter(Boolean);
75837             var chapters = chapterFlow.map(function (chapter, i) {
75838               var s = chapterUi[chapter](context, curtain.reveal).on('done', function () {
75839                 buttons.filter(function (d) {
75840                   return d.title === s.title;
75841                 }).classed('finished', true);
75842
75843                 if (i < chapterFlow.length - 1) {
75844                   var next = chapterFlow[i + 1];
75845                   context.container().select("button.chapter-".concat(next)).classed('next', true);
75846                 } // Store walkthrough progress..
75847
75848
75849                 progress.push(chapter);
75850                 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';'));
75851               });
75852               return s;
75853             });
75854             chapters[chapters.length - 1].on('startEditing', function () {
75855               // Store walkthrough progress..
75856               progress.push('startEditing');
75857               corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';')); // Store if walkthrough is completed..
75858
75859               var incomplete = utilArrayDifference(chapterFlow, progress);
75860
75861               if (!incomplete.length) {
75862                 corePreferences('walkthrough_completed', 'yes');
75863               }
75864
75865               curtain.remove();
75866               navwrap.remove();
75867               context.container().selectAll('.main-map .layer-background').style('opacity', opacity);
75868               context.container().selectAll('button.sidebar-toggle').classed('disabled', false);
75869
75870               if (osm) {
75871                 osm.toggle(true).reset().caches(caches);
75872               }
75873
75874               context.history().reset().merge(Object.values(baseEntities));
75875               context.background().baseLayerSource(background);
75876               overlays.forEach(function (d) {
75877                 return context.background().toggleOverlayLayer(d);
75878               });
75879
75880               if (history) {
75881                 context.history().fromJSON(history, false);
75882               }
75883
75884               context.map().centerZoom(center, zoom);
75885               window.location.replace(hash);
75886               context.inIntro(false);
75887             });
75888             var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
75889             navwrap.append('svg').attr('class', 'intro-nav-wrap-logo').append('use').attr('xlink:href', '#iD-logo-walkthrough');
75890             var buttonwrap = navwrap.append('div').attr('class', 'joined').selectAll('button.chapter');
75891             var buttons = buttonwrap.data(chapters).enter().append('button').attr('class', function (d, i) {
75892               return "chapter chapter-".concat(chapterFlow[i]);
75893             }).on('click', enterChapter);
75894             buttons.append('span').html(function (d) {
75895               return _t.html(d.title);
75896             });
75897             buttons.append('span').attr('class', 'status').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
75898             enterChapter(null, chapters[0]);
75899
75900             function enterChapter(d3_event, newChapter) {
75901               if (_currChapter) {
75902                 _currChapter.exit();
75903               }
75904
75905               context.enter(modeBrowse(context));
75906               _currChapter = newChapter;
75907
75908               _currChapter.enter();
75909
75910               buttons.classed('next', false).classed('active', function (d) {
75911                 return d.title === _currChapter.title;
75912               });
75913             }
75914           }
75915
75916           return intro;
75917         }
75918
75919         function uiIssuesInfo(context) {
75920           var warningsItem = {
75921             id: 'warnings',
75922             count: 0,
75923             iconID: 'iD-icon-alert',
75924             descriptionID: 'issues.warnings_and_errors'
75925           };
75926           var resolvedItem = {
75927             id: 'resolved',
75928             count: 0,
75929             iconID: 'iD-icon-apply',
75930             descriptionID: 'issues.user_resolved_issues'
75931           };
75932
75933           function update(selection) {
75934             var shownItems = [];
75935             var liveIssues = context.validator().getIssues({
75936               what: corePreferences('validate-what') || 'edited',
75937               where: corePreferences('validate-where') || 'all'
75938             });
75939
75940             if (liveIssues.length) {
75941               warningsItem.count = liveIssues.length;
75942               shownItems.push(warningsItem);
75943             }
75944
75945             if (corePreferences('validate-what') === 'all') {
75946               var resolvedIssues = context.validator().getResolvedIssues();
75947
75948               if (resolvedIssues.length) {
75949                 resolvedItem.count = resolvedIssues.length;
75950                 shownItems.push(resolvedItem);
75951               }
75952             }
75953
75954             var chips = selection.selectAll('.chip').data(shownItems, function (d) {
75955               return d.id;
75956             });
75957             chips.exit().remove();
75958             var enter = chips.enter().append('a').attr('class', function (d) {
75959               return 'chip ' + d.id + '-count';
75960             }).attr('href', '#').each(function (d) {
75961               var chipSelection = select(this);
75962               var tooltipBehavior = uiTooltip().placement('top').title(_t.html(d.descriptionID));
75963               chipSelection.call(tooltipBehavior).on('click', function (d3_event) {
75964                 d3_event.preventDefault();
75965                 tooltipBehavior.hide(select(this)); // open the Issues pane
75966
75967                 context.ui().togglePanes(context.container().select('.map-panes .issues-pane'));
75968               });
75969               chipSelection.call(svgIcon('#' + d.iconID));
75970             });
75971             enter.append('span').attr('class', 'count');
75972             enter.merge(chips).selectAll('span.count').html(function (d) {
75973               return d.count.toString();
75974             });
75975           }
75976
75977           return function (selection) {
75978             update(selection);
75979             context.validator().on('validated.infobox', function () {
75980               update(selection);
75981             });
75982           };
75983         }
75984
75985         function uiMapInMap(context) {
75986           function mapInMap(selection) {
75987             var backgroundLayer = rendererTileLayer(context);
75988             var overlayLayers = {};
75989             var projection = geoRawMercator();
75990             var dataLayer = svgData(projection, context).showLabels(false);
75991             var debugLayer = svgDebug(projection, context);
75992             var zoom = d3_zoom().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on('start', zoomStarted).on('zoom', zoomed).on('end', zoomEnded);
75993             var wrap = select(null);
75994             var tiles = select(null);
75995             var viewport = select(null);
75996             var _isTransformed = false;
75997             var _isHidden = true;
75998             var _skipEvents = false;
75999             var _gesture = null;
76000             var _zDiff = 6; // by default, minimap renders at (main zoom - 6)
76001
76002             var _dMini; // dimensions of minimap
76003
76004
76005             var _cMini; // center pixel of minimap
76006
76007
76008             var _tStart; // transform at start of gesture
76009
76010
76011             var _tCurr; // transform at most recent event
76012
76013
76014             var _timeoutID;
76015
76016             function zoomStarted() {
76017               if (_skipEvents) return;
76018               _tStart = _tCurr = projection.transform();
76019               _gesture = null;
76020             }
76021
76022             function zoomed(d3_event) {
76023               if (_skipEvents) return;
76024               var x = d3_event.transform.x;
76025               var y = d3_event.transform.y;
76026               var k = d3_event.transform.k;
76027               var isZooming = k !== _tStart.k;
76028               var isPanning = x !== _tStart.x || y !== _tStart.y;
76029
76030               if (!isZooming && !isPanning) {
76031                 return; // no change
76032               } // lock in either zooming or panning, don't allow both in minimap.
76033
76034
76035               if (!_gesture) {
76036                 _gesture = isZooming ? 'zoom' : 'pan';
76037               }
76038
76039               var tMini = projection.transform();
76040               var tX, tY, scale;
76041
76042               if (_gesture === 'zoom') {
76043                 scale = k / tMini.k;
76044                 tX = (_cMini[0] / scale - _cMini[0]) * scale;
76045                 tY = (_cMini[1] / scale - _cMini[1]) * scale;
76046               } else {
76047                 k = tMini.k;
76048                 scale = 1;
76049                 tX = x - tMini.x;
76050                 tY = y - tMini.y;
76051               }
76052
76053               utilSetTransform(tiles, tX, tY, scale);
76054               utilSetTransform(viewport, 0, 0, scale);
76055               _isTransformed = true;
76056               _tCurr = identity$2.translate(x, y).scale(k);
76057               var zMain = geoScaleToZoom(context.projection.scale());
76058               var zMini = geoScaleToZoom(k);
76059               _zDiff = zMain - zMini;
76060               queueRedraw();
76061             }
76062
76063             function zoomEnded() {
76064               if (_skipEvents) return;
76065               if (_gesture !== 'pan') return;
76066               updateProjection();
76067               _gesture = null;
76068               context.map().center(projection.invert(_cMini)); // recenter main map..
76069             }
76070
76071             function updateProjection() {
76072               var loc = context.map().center();
76073               var tMain = context.projection.transform();
76074               var zMain = geoScaleToZoom(tMain.k);
76075               var zMini = Math.max(zMain - _zDiff, 0.5);
76076               var kMini = geoZoomToScale(zMini);
76077               projection.translate([tMain.x, tMain.y]).scale(kMini);
76078               var point = projection(loc);
76079               var mouse = _gesture === 'pan' ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
76080               var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
76081               var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
76082               projection.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
76083               _tCurr = projection.transform();
76084
76085               if (_isTransformed) {
76086                 utilSetTransform(tiles, 0, 0);
76087                 utilSetTransform(viewport, 0, 0);
76088                 _isTransformed = false;
76089               }
76090
76091               zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
76092               _skipEvents = true;
76093               wrap.call(zoom.transform, _tCurr);
76094               _skipEvents = false;
76095             }
76096
76097             function redraw() {
76098               clearTimeout(_timeoutID);
76099               if (_isHidden) return;
76100               updateProjection();
76101               var zMini = geoScaleToZoom(projection.scale()); // setup tile container
76102
76103               tiles = wrap.selectAll('.map-in-map-tiles').data([0]);
76104               tiles = tiles.enter().append('div').attr('class', 'map-in-map-tiles').merge(tiles); // redraw background
76105
76106               backgroundLayer.source(context.background().baseLayerSource()).projection(projection).dimensions(_dMini);
76107               var background = tiles.selectAll('.map-in-map-background').data([0]);
76108               background.enter().append('div').attr('class', 'map-in-map-background').merge(background).call(backgroundLayer); // redraw overlay
76109
76110               var overlaySources = context.background().overlayLayerSources();
76111               var activeOverlayLayers = [];
76112
76113               for (var i = 0; i < overlaySources.length; i++) {
76114                 if (overlaySources[i].validZoom(zMini)) {
76115                   if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
76116                   activeOverlayLayers.push(overlayLayers[i].source(overlaySources[i]).projection(projection).dimensions(_dMini));
76117                 }
76118               }
76119
76120               var overlay = tiles.selectAll('.map-in-map-overlay').data([0]);
76121               overlay = overlay.enter().append('div').attr('class', 'map-in-map-overlay').merge(overlay);
76122               var overlays = overlay.selectAll('div').data(activeOverlayLayers, function (d) {
76123                 return d.source().name();
76124               });
76125               overlays.exit().remove();
76126               overlays = overlays.enter().append('div').merge(overlays).each(function (layer) {
76127                 select(this).call(layer);
76128               });
76129               var dataLayers = tiles.selectAll('.map-in-map-data').data([0]);
76130               dataLayers.exit().remove();
76131               dataLayers = dataLayers.enter().append('svg').attr('class', 'map-in-map-data').merge(dataLayers).call(dataLayer).call(debugLayer); // redraw viewport bounding box
76132
76133               if (_gesture !== 'pan') {
76134                 var getPath = d3_geoPath(projection);
76135                 var bbox = {
76136                   type: 'Polygon',
76137                   coordinates: [context.map().extent().polygon()]
76138                 };
76139                 viewport = wrap.selectAll('.map-in-map-viewport').data([0]);
76140                 viewport = viewport.enter().append('svg').attr('class', 'map-in-map-viewport').merge(viewport);
76141                 var path = viewport.selectAll('.map-in-map-bbox').data([bbox]);
76142                 path.enter().append('path').attr('class', 'map-in-map-bbox').merge(path).attr('d', getPath).classed('thick', function (d) {
76143                   return getPath.area(d) < 30;
76144                 });
76145               }
76146             }
76147
76148             function queueRedraw() {
76149               clearTimeout(_timeoutID);
76150               _timeoutID = setTimeout(function () {
76151                 redraw();
76152               }, 750);
76153             }
76154
76155             function toggle(d3_event) {
76156               if (d3_event) d3_event.preventDefault();
76157               _isHidden = !_isHidden;
76158               context.container().select('.minimap-toggle-item').classed('active', !_isHidden).select('input').property('checked', !_isHidden);
76159
76160               if (_isHidden) {
76161                 wrap.style('display', 'block').style('opacity', '1').transition().duration(200).style('opacity', '0').on('end', function () {
76162                   selection.selectAll('.map-in-map').style('display', 'none');
76163                 });
76164               } else {
76165                 wrap.style('display', 'block').style('opacity', '0').transition().duration(200).style('opacity', '1').on('end', function () {
76166                   redraw();
76167                 });
76168               }
76169             }
76170
76171             uiMapInMap.toggle = toggle;
76172             wrap = selection.selectAll('.map-in-map').data([0]);
76173             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..
76174
76175             _dMini = [200, 150]; //utilGetDimensions(wrap);
76176
76177             _cMini = geoVecScale(_dMini, 0.5);
76178             context.map().on('drawn.map-in-map', function (drawn) {
76179               if (drawn.full === true) {
76180                 redraw();
76181               }
76182             });
76183             redraw();
76184             context.keybinding().on(_t('background.minimap.key'), toggle);
76185           }
76186
76187           return mapInMap;
76188         }
76189
76190         function uiNotice(context) {
76191           return function (selection) {
76192             var div = selection.append('div').attr('class', 'notice');
76193             var button = div.append('button').attr('class', 'zoom-to notice fillD').on('click', function () {
76194               context.map().zoomEase(context.minEditableZoom());
76195             }).on('wheel', function (d3_event) {
76196               // let wheel events pass through #4482
76197               var e2 = new WheelEvent(d3_event.type, d3_event);
76198               context.surface().node().dispatchEvent(e2);
76199             });
76200             button.call(svgIcon('#iD-icon-plus', 'pre-text')).append('span').attr('class', 'label').html(_t.html('zoom_in_edit'));
76201
76202             function disableTooHigh() {
76203               var canEdit = context.map().zoom() >= context.minEditableZoom();
76204               div.style('display', canEdit ? 'none' : 'block');
76205             }
76206
76207             context.map().on('move.notice', debounce(disableTooHigh, 500));
76208             disableTooHigh();
76209           };
76210         }
76211
76212         function uiPhotoviewer(context) {
76213           var dispatch = dispatch$8('resize');
76214
76215           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
76216
76217           function photoviewer(selection) {
76218             selection.append('button').attr('class', 'thumb-hide').on('click', function () {
76219               if (services.streetside) {
76220                 services.streetside.hideViewer(context);
76221               }
76222
76223               if (services.mapillary) {
76224                 services.mapillary.hideViewer(context);
76225               }
76226
76227               if (services.openstreetcam) {
76228                 services.openstreetcam.hideViewer(context);
76229               }
76230             }).append('div').call(svgIcon('#iD-icon-close'));
76231
76232             function preventDefault(d3_event) {
76233               d3_event.preventDefault();
76234             }
76235
76236             selection.append('button').attr('class', 'resize-handle-xy').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
76237               resizeOnX: true,
76238               resizeOnY: true
76239             }));
76240             selection.append('button').attr('class', 'resize-handle-x').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
76241               resizeOnX: true
76242             }));
76243             selection.append('button').attr('class', 'resize-handle-y').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
76244               resizeOnY: true
76245             }));
76246
76247             function buildResizeListener(target, eventName, dispatch, options) {
76248               var resizeOnX = !!options.resizeOnX;
76249               var resizeOnY = !!options.resizeOnY;
76250               var minHeight = options.minHeight || 240;
76251               var minWidth = options.minWidth || 320;
76252               var pointerId;
76253               var startX;
76254               var startY;
76255               var startWidth;
76256               var startHeight;
76257
76258               function startResize(d3_event) {
76259                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
76260                 d3_event.preventDefault();
76261                 d3_event.stopPropagation();
76262                 var mapSize = context.map().dimensions();
76263
76264                 if (resizeOnX) {
76265                   var maxWidth = mapSize[0];
76266                   var newWidth = clamp(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
76267                   target.style('width', newWidth + 'px');
76268                 }
76269
76270                 if (resizeOnY) {
76271                   var maxHeight = mapSize[1] - 90; // preserve space at top/bottom of map
76272
76273                   var newHeight = clamp(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
76274                   target.style('height', newHeight + 'px');
76275                 }
76276
76277                 dispatch.call(eventName, target, utilGetDimensions(target, true));
76278               }
76279
76280               function clamp(num, min, max) {
76281                 return Math.max(min, Math.min(num, max));
76282               }
76283
76284               function stopResize(d3_event) {
76285                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
76286                 d3_event.preventDefault();
76287                 d3_event.stopPropagation(); // remove all the listeners we added
76288
76289                 select(window).on('.' + eventName, null);
76290               }
76291
76292               return function initResize(d3_event) {
76293                 d3_event.preventDefault();
76294                 d3_event.stopPropagation();
76295                 pointerId = d3_event.pointerId || 'mouse';
76296                 startX = d3_event.clientX;
76297                 startY = d3_event.clientY;
76298                 var targetRect = target.node().getBoundingClientRect();
76299                 startWidth = targetRect.width;
76300                 startHeight = targetRect.height;
76301                 select(window).on(_pointerPrefix + 'move.' + eventName, startResize, false).on(_pointerPrefix + 'up.' + eventName, stopResize, false);
76302
76303                 if (_pointerPrefix === 'pointer') {
76304                   select(window).on('pointercancel.' + eventName, stopResize, false);
76305                 }
76306               };
76307             }
76308           }
76309
76310           photoviewer.onMapResize = function () {
76311             var photoviewer = context.container().select('.photoviewer');
76312             var content = context.container().select('.main-content');
76313             var mapDimensions = utilGetDimensions(content, true); // shrink photo viewer if it is too big
76314             // (-90 preserves space at top and bottom of map used by menus)
76315
76316             var photoDimensions = utilGetDimensions(photoviewer, true);
76317
76318             if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
76319               var setPhotoDimensions = [Math.min(photoDimensions[0], mapDimensions[0]), Math.min(photoDimensions[1], mapDimensions[1] - 90)];
76320               photoviewer.style('width', setPhotoDimensions[0] + 'px').style('height', setPhotoDimensions[1] + 'px');
76321               dispatch.call('resize', photoviewer, setPhotoDimensions);
76322             }
76323           };
76324
76325           return utilRebind(photoviewer, dispatch, 'on');
76326         }
76327
76328         function uiRestore(context) {
76329           return function (selection) {
76330             if (!context.history().hasRestorableChanges()) return;
76331             var modalSelection = uiModal(selection, true);
76332             modalSelection.select('.modal').attr('class', 'modal fillL');
76333             var introModal = modalSelection.select('.content');
76334             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('restore.heading'));
76335             introModal.append('div').attr('class', 'modal-section').append('p').html(_t.html('restore.description'));
76336             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
76337             var restore = buttonWrap.append('button').attr('class', 'restore').on('click', function () {
76338               context.history().restore();
76339               modalSelection.remove();
76340             });
76341             restore.append('svg').attr('class', 'logo logo-restore').append('use').attr('xlink:href', '#iD-logo-restore');
76342             restore.append('div').html(_t.html('restore.restore'));
76343             var reset = buttonWrap.append('button').attr('class', 'reset').on('click', function () {
76344               context.history().clearSaved();
76345               modalSelection.remove();
76346             });
76347             reset.append('svg').attr('class', 'logo logo-reset').append('use').attr('xlink:href', '#iD-logo-reset');
76348             reset.append('div').html(_t.html('restore.reset'));
76349             restore.node().focus();
76350           };
76351         }
76352
76353         function uiScale(context) {
76354           var projection = context.projection,
76355               isImperial = !_mainLocalizer.usesMetric(),
76356               maxLength = 180,
76357               tickHeight = 8;
76358
76359           function scaleDefs(loc1, loc2) {
76360             var lat = (loc2[1] + loc1[1]) / 2,
76361                 conversion = isImperial ? 3.28084 : 1,
76362                 dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
76363                 scale = {
76364               dist: 0,
76365               px: 0,
76366               text: ''
76367             },
76368                 buckets,
76369                 i,
76370                 val,
76371                 dLon;
76372
76373             if (isImperial) {
76374               buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
76375             } else {
76376               buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
76377             } // determine a user-friendly endpoint for the scale
76378
76379
76380             for (i = 0; i < buckets.length; i++) {
76381               val = buckets[i];
76382
76383               if (dist >= val) {
76384                 scale.dist = Math.floor(dist / val) * val;
76385                 break;
76386               } else {
76387                 scale.dist = +dist.toFixed(2);
76388               }
76389             }
76390
76391             dLon = geoMetersToLon(scale.dist / conversion, lat);
76392             scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
76393             scale.text = displayLength(scale.dist / conversion, isImperial);
76394             return scale;
76395           }
76396
76397           function update(selection) {
76398             // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
76399             var dims = context.map().dimensions(),
76400                 loc1 = projection.invert([0, dims[1]]),
76401                 loc2 = projection.invert([maxLength, dims[1]]),
76402                 scale = scaleDefs(loc1, loc2);
76403             selection.select('.scale-path').attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
76404             selection.select('.scale-text').style(_mainLocalizer.textDirection() === 'ltr' ? 'left' : 'right', scale.px + 16 + 'px').html(scale.text);
76405           }
76406
76407           return function (selection) {
76408             function switchUnits() {
76409               isImperial = !isImperial;
76410               selection.call(update);
76411             }
76412
76413             var scalegroup = selection.append('svg').attr('class', 'scale').on('click', switchUnits).append('g').attr('transform', 'translate(10,11)');
76414             scalegroup.append('path').attr('class', 'scale-path');
76415             selection.append('div').attr('class', 'scale-text');
76416             selection.call(update);
76417             context.map().on('move.scale', function () {
76418               update(selection);
76419             });
76420           };
76421         }
76422
76423         function uiShortcuts(context) {
76424           var detected = utilDetect();
76425           var _activeTab = 0;
76426
76427           var _modalSelection;
76428
76429           var _selection = select(null);
76430
76431           var _dataShortcuts;
76432
76433           function shortcutsModal(_modalSelection) {
76434             _modalSelection.select('.modal').classed('modal-shortcuts', true);
76435
76436             var content = _modalSelection.select('.content');
76437
76438             content.append('div').attr('class', 'modal-section').append('h3').html(_t.html('shortcuts.title'));
76439             _mainFileFetcher.get('shortcuts').then(function (data) {
76440               _dataShortcuts = data;
76441               content.call(render);
76442             })["catch"](function () {
76443               /* ignore */
76444             });
76445           }
76446
76447           function render(selection) {
76448             if (!_dataShortcuts) return;
76449             var wrapper = selection.selectAll('.wrapper').data([0]);
76450             var wrapperEnter = wrapper.enter().append('div').attr('class', 'wrapper modal-section');
76451             var tabsBar = wrapperEnter.append('div').attr('class', 'tabs-bar');
76452             var shortcutsList = wrapperEnter.append('div').attr('class', 'shortcuts-list');
76453             wrapper = wrapper.merge(wrapperEnter);
76454             var tabs = tabsBar.selectAll('.tab').data(_dataShortcuts);
76455             var tabsEnter = tabs.enter().append('a').attr('class', 'tab').attr('href', '#').on('click', function (d3_event, d) {
76456               d3_event.preventDefault();
76457
76458               var i = _dataShortcuts.indexOf(d);
76459
76460               _activeTab = i;
76461               render(selection);
76462             });
76463             tabsEnter.append('span').html(function (d) {
76464               return _t.html(d.text);
76465             }); // Update
76466
76467             wrapper.selectAll('.tab').classed('active', function (d, i) {
76468               return i === _activeTab;
76469             });
76470             var shortcuts = shortcutsList.selectAll('.shortcut-tab').data(_dataShortcuts);
76471             var shortcutsEnter = shortcuts.enter().append('div').attr('class', function (d) {
76472               return 'shortcut-tab shortcut-tab-' + d.tab;
76473             });
76474             var columnsEnter = shortcutsEnter.selectAll('.shortcut-column').data(function (d) {
76475               return d.columns;
76476             }).enter().append('table').attr('class', 'shortcut-column');
76477             var rowsEnter = columnsEnter.selectAll('.shortcut-row').data(function (d) {
76478               return d.rows;
76479             }).enter().append('tr').attr('class', 'shortcut-row');
76480             var sectionRows = rowsEnter.filter(function (d) {
76481               return !d.shortcuts;
76482             });
76483             sectionRows.append('td');
76484             sectionRows.append('td').attr('class', 'shortcut-section').append('h3').html(function (d) {
76485               return _t.html(d.text);
76486             });
76487             var shortcutRows = rowsEnter.filter(function (d) {
76488               return d.shortcuts;
76489             });
76490             var shortcutKeys = shortcutRows.append('td').attr('class', 'shortcut-keys');
76491             var modifierKeys = shortcutKeys.filter(function (d) {
76492               return d.modifiers;
76493             });
76494             modifierKeys.selectAll('kbd.modifier').data(function (d) {
76495               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
76496                 return ['⌘'];
76497               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
76498                 return [];
76499               } else {
76500                 return d.modifiers;
76501               }
76502             }).enter().each(function () {
76503               var selection = select(this);
76504               selection.append('kbd').attr('class', 'modifier').html(function (d) {
76505                 return uiCmd.display(d);
76506               });
76507               selection.append('span').html('+');
76508             });
76509             shortcutKeys.selectAll('kbd.shortcut').data(function (d) {
76510               var arr = d.shortcuts;
76511
76512               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
76513                 arr = ['Y'];
76514               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
76515                 arr = ['F11'];
76516               } // replace translations
76517
76518
76519               arr = arr.map(function (s) {
76520                 return uiCmd.display(s.indexOf('.') !== -1 ? _t(s) : s);
76521               });
76522               return utilArrayUniq(arr).map(function (s) {
76523                 return {
76524                   shortcut: s,
76525                   separator: d.separator,
76526                   suffix: d.suffix
76527                 };
76528               });
76529             }).enter().each(function (d, i, nodes) {
76530               var selection = select(this);
76531               var click = d.shortcut.toLowerCase().match(/(.*).click/);
76532
76533               if (click && click[1]) {
76534                 // replace "left_click", "right_click" with mouse icon
76535                 selection.call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation'));
76536               } else if (d.shortcut.toLowerCase() === 'long-press') {
76537                 selection.call(svgIcon('#iD-walkthrough-longpress', 'longpress operation'));
76538               } else if (d.shortcut.toLowerCase() === 'tap') {
76539                 selection.call(svgIcon('#iD-walkthrough-tap', 'tap operation'));
76540               } else {
76541                 selection.append('kbd').attr('class', 'shortcut').html(function (d) {
76542                   return d.shortcut;
76543                 });
76544               }
76545
76546               if (i < nodes.length - 1) {
76547                 selection.append('span').html(d.separator || "\xA0" + _t.html('shortcuts.or') + "\xA0");
76548               } else if (i === nodes.length - 1 && d.suffix) {
76549                 selection.append('span').html(d.suffix);
76550               }
76551             });
76552             shortcutKeys.filter(function (d) {
76553               return d.gesture;
76554             }).each(function () {
76555               var selection = select(this);
76556               selection.append('span').html('+');
76557               selection.append('span').attr('class', 'gesture').html(function (d) {
76558                 return _t.html(d.gesture);
76559               });
76560             });
76561             shortcutRows.append('td').attr('class', 'shortcut-desc').html(function (d) {
76562               return d.text ? _t.html(d.text) : "\xA0";
76563             }); // Update
76564
76565             wrapper.selectAll('.shortcut-tab').style('display', function (d, i) {
76566               return i === _activeTab ? 'flex' : 'none';
76567             });
76568           }
76569
76570           return function (selection, show) {
76571             _selection = selection;
76572
76573             if (show) {
76574               _modalSelection = uiModal(selection);
76575
76576               _modalSelection.call(shortcutsModal);
76577             } else {
76578               context.keybinding().on([_t('shortcuts.toggle.key'), '?'], function () {
76579                 if (context.container().selectAll('.modal-shortcuts').size()) {
76580                   // already showing
76581                   if (_modalSelection) {
76582                     _modalSelection.close();
76583
76584                     _modalSelection = null;
76585                   }
76586                 } else {
76587                   _modalSelection = uiModal(_selection);
76588
76589                   _modalSelection.call(shortcutsModal);
76590                 }
76591               });
76592             }
76593           };
76594         }
76595
76596         function uiDataHeader() {
76597           var _datum;
76598
76599           function dataHeader(selection) {
76600             var header = selection.selectAll('.data-header').data(_datum ? [_datum] : [], function (d) {
76601               return d.__featurehash__;
76602             });
76603             header.exit().remove();
76604             var headerEnter = header.enter().append('div').attr('class', 'data-header');
76605             var iconEnter = headerEnter.append('div').attr('class', 'data-header-icon');
76606             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-data', 'note-fill'));
76607             headerEnter.append('div').attr('class', 'data-header-label').html(_t.html('map_data.layers.custom.title'));
76608           }
76609
76610           dataHeader.datum = function (val) {
76611             if (!arguments.length) return _datum;
76612             _datum = val;
76613             return this;
76614           };
76615
76616           return dataHeader;
76617         }
76618
76619         // It is keyed on the `value` of the entry. Data should be an array of objects like:
76620         //   [{
76621         //       value:   'string value',  // required
76622         //       display: 'label html'     // optional
76623         //       title:   'hover text'     // optional
76624         //       terms:   ['search terms'] // optional
76625         //   }, ...]
76626
76627         var _comboHideTimerID;
76628
76629         function uiCombobox(context, klass) {
76630           var dispatch = dispatch$8('accept', 'cancel');
76631           var container = context.container();
76632           var _suggestions = [];
76633           var _data = [];
76634           var _fetched = {};
76635           var _selected = null;
76636           var _canAutocomplete = true;
76637           var _caseSensitive = false;
76638           var _cancelFetch = false;
76639           var _minItems = 2;
76640           var _tDown = 0;
76641
76642           var _mouseEnterHandler, _mouseLeaveHandler;
76643
76644           var _fetcher = function _fetcher(val, cb) {
76645             cb(_data.filter(function (d) {
76646               var terms = d.terms || [];
76647               terms.push(d.value);
76648               return terms.some(function (term) {
76649                 return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
76650               });
76651             }));
76652           };
76653
76654           var combobox = function combobox(input, attachTo) {
76655             if (!input || input.empty()) return;
76656             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 () {
76657               var parent = this.parentNode;
76658               var sibling = this.nextSibling;
76659               select(parent).selectAll('.combobox-caret').filter(function (d) {
76660                 return d === input.node();
76661               }).data([input.node()]).enter().insert('div', function () {
76662                 return sibling;
76663               }).attr('class', 'combobox-caret').on('mousedown.combo-caret', function (d3_event) {
76664                 d3_event.preventDefault(); // don't steal focus from input
76665
76666                 input.node().focus(); // focus the input as if it was clicked
76667
76668                 mousedown(d3_event);
76669               }).on('mouseup.combo-caret', function (d3_event) {
76670                 d3_event.preventDefault(); // don't steal focus from input
76671
76672                 mouseup(d3_event);
76673               });
76674             });
76675
76676             function mousedown(d3_event) {
76677               if (d3_event.button !== 0) return; // left click only
76678
76679               _tDown = +new Date(); // clear selection
76680
76681               var start = input.property('selectionStart');
76682               var end = input.property('selectionEnd');
76683
76684               if (start !== end) {
76685                 var val = utilGetSetValue(input);
76686                 input.node().setSelectionRange(val.length, val.length);
76687                 return;
76688               }
76689
76690               input.on('mouseup.combo-input', mouseup);
76691             }
76692
76693             function mouseup(d3_event) {
76694               input.on('mouseup.combo-input', null);
76695               if (d3_event.button !== 0) return; // left click only
76696
76697               if (input.node() !== document.activeElement) return; // exit if this input is not focused
76698
76699               var start = input.property('selectionStart');
76700               var end = input.property('selectionEnd');
76701               if (start !== end) return; // exit if user is selecting
76702               // not showing or showing for a different field - try to show it.
76703
76704               var combo = container.selectAll('.combobox');
76705
76706               if (combo.empty() || combo.datum() !== input.node()) {
76707                 var tOrig = _tDown;
76708                 window.setTimeout(function () {
76709                   if (tOrig !== _tDown) return; // exit if user double clicked
76710
76711                   fetchComboData('', function () {
76712                     show();
76713                     render();
76714                   });
76715                 }, 250);
76716               } else {
76717                 hide();
76718               }
76719             }
76720
76721             function focus() {
76722               fetchComboData(''); // prefetch values (may warm taginfo cache)
76723             }
76724
76725             function blur() {
76726               _comboHideTimerID = window.setTimeout(hide, 75);
76727             }
76728
76729             function show() {
76730               hide(); // remove any existing
76731
76732               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) {
76733                 // prevent moving focus out of the input field
76734                 d3_event.preventDefault();
76735               });
76736               container.on('scroll.combo-scroll', render, true);
76737             }
76738
76739             function hide() {
76740               if (_comboHideTimerID) {
76741                 window.clearTimeout(_comboHideTimerID);
76742                 _comboHideTimerID = undefined;
76743               }
76744
76745               container.selectAll('.combobox').remove();
76746               container.on('scroll.combo-scroll', null);
76747             }
76748
76749             function keydown(d3_event) {
76750               var shown = !container.selectAll('.combobox').empty();
76751               var tagName = input.node() ? input.node().tagName.toLowerCase() : '';
76752
76753               switch (d3_event.keyCode) {
76754                 case 8: // ⌫ Backspace
76755
76756                 case 46:
76757                   // ⌦ Delete
76758                   d3_event.stopPropagation();
76759                   _selected = null;
76760                   render();
76761                   input.on('input.combo-input', function () {
76762                     var start = input.property('selectionStart');
76763                     input.node().setSelectionRange(start, start);
76764                     input.on('input.combo-input', change);
76765                   });
76766                   break;
76767
76768                 case 9:
76769                   // ⇥ Tab
76770                   accept();
76771                   break;
76772
76773                 case 13:
76774                   // ↩ Return
76775                   d3_event.preventDefault();
76776                   d3_event.stopPropagation();
76777                   break;
76778
76779                 case 38:
76780                   // ↑ Up arrow
76781                   if (tagName === 'textarea' && !shown) return;
76782                   d3_event.preventDefault();
76783
76784                   if (tagName === 'input' && !shown) {
76785                     show();
76786                   }
76787
76788                   nav(-1);
76789                   break;
76790
76791                 case 40:
76792                   // ↓ Down arrow
76793                   if (tagName === 'textarea' && !shown) return;
76794                   d3_event.preventDefault();
76795
76796                   if (tagName === 'input' && !shown) {
76797                     show();
76798                   }
76799
76800                   nav(+1);
76801                   break;
76802               }
76803             }
76804
76805             function keyup(d3_event) {
76806               switch (d3_event.keyCode) {
76807                 case 27:
76808                   // ⎋ Escape
76809                   cancel();
76810                   break;
76811
76812                 case 13:
76813                   // ↩ Return
76814                   accept();
76815                   break;
76816               }
76817             } // Called whenever the input value is changed (e.g. on typing)
76818
76819
76820             function change() {
76821               fetchComboData(value(), function () {
76822                 _selected = null;
76823                 var val = input.property('value');
76824
76825                 if (_suggestions.length) {
76826                   if (input.property('selectionEnd') === val.length) {
76827                     _selected = tryAutocomplete();
76828                   }
76829
76830                   if (!_selected) {
76831                     _selected = val;
76832                   }
76833                 }
76834
76835                 if (val.length) {
76836                   var combo = container.selectAll('.combobox');
76837
76838                   if (combo.empty()) {
76839                     show();
76840                   }
76841                 } else {
76842                   hide();
76843                 }
76844
76845                 render();
76846               });
76847             } // Called when the user presses up/down arrows to navigate the list
76848
76849
76850             function nav(dir) {
76851               if (_suggestions.length) {
76852                 // try to determine previously selected index..
76853                 var index = -1;
76854
76855                 for (var i = 0; i < _suggestions.length; i++) {
76856                   if (_selected && _suggestions[i].value === _selected) {
76857                     index = i;
76858                     break;
76859                   }
76860                 } // pick new _selected
76861
76862
76863                 index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
76864                 _selected = _suggestions[index].value;
76865                 input.property('value', _selected);
76866               }
76867
76868               render();
76869               ensureVisible();
76870             }
76871
76872             function ensureVisible() {
76873               var combo = container.selectAll('.combobox');
76874               if (combo.empty()) return;
76875               var containerRect = container.node().getBoundingClientRect();
76876               var comboRect = combo.node().getBoundingClientRect();
76877
76878               if (comboRect.bottom > containerRect.bottom) {
76879                 var node = attachTo ? attachTo.node() : input.node();
76880                 node.scrollIntoView({
76881                   behavior: 'instant',
76882                   block: 'center'
76883                 });
76884                 render();
76885               } // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
76886
76887
76888               var selected = combo.selectAll('.combobox-option.selected').node();
76889
76890               if (selected) {
76891                 selected.scrollIntoView({
76892                   behavior: 'smooth',
76893                   block: 'nearest'
76894                 });
76895               }
76896             }
76897
76898             function value() {
76899               var value = input.property('value');
76900               var start = input.property('selectionStart');
76901               var end = input.property('selectionEnd');
76902
76903               if (start && end) {
76904                 value = value.substring(0, start);
76905               }
76906
76907               return value;
76908             }
76909
76910             function fetchComboData(v, cb) {
76911               _cancelFetch = false;
76912
76913               _fetcher.call(input, v, function (results) {
76914                 // already chose a value, don't overwrite or autocomplete it
76915                 if (_cancelFetch) return;
76916                 _suggestions = results;
76917                 results.forEach(function (d) {
76918                   _fetched[d.value] = d;
76919                 });
76920
76921                 if (cb) {
76922                   cb();
76923                 }
76924               });
76925             }
76926
76927             function tryAutocomplete() {
76928               if (!_canAutocomplete) return;
76929               var val = _caseSensitive ? value() : value().toLowerCase();
76930               if (!val) return; // Don't autocomplete if user is typing a number - #4935
76931
76932               if (!isNaN(parseFloat(val)) && isFinite(val)) return;
76933               var bestIndex = -1;
76934
76935               for (var i = 0; i < _suggestions.length; i++) {
76936                 var suggestion = _suggestions[i].value;
76937                 var compare = _caseSensitive ? suggestion : suggestion.toLowerCase(); // if search string matches suggestion exactly, pick it..
76938
76939                 if (compare === val) {
76940                   bestIndex = i;
76941                   break; // otherwise lock in the first result that starts with the search string..
76942                 } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
76943                   bestIndex = i;
76944                 }
76945               }
76946
76947               if (bestIndex !== -1) {
76948                 var bestVal = _suggestions[bestIndex].value;
76949                 input.property('value', bestVal);
76950                 input.node().setSelectionRange(val.length, bestVal.length);
76951                 return bestVal;
76952               }
76953             }
76954
76955             function render() {
76956               if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
76957                 hide();
76958                 return;
76959               }
76960
76961               var shown = !container.selectAll('.combobox').empty();
76962               if (!shown) return;
76963               var combo = container.selectAll('.combobox');
76964               var options = combo.selectAll('.combobox-option').data(_suggestions, function (d) {
76965                 return d.value;
76966               });
76967               options.exit().remove(); // enter/update
76968
76969               options.enter().append('a').attr('class', function (d) {
76970                 return 'combobox-option ' + (d.klass || '');
76971               }).attr('title', function (d) {
76972                 return d.title;
76973               }).html(function (d) {
76974                 return d.display || d.value;
76975               }).on('mouseenter', _mouseEnterHandler).on('mouseleave', _mouseLeaveHandler).merge(options).classed('selected', function (d) {
76976                 return d.value === _selected;
76977               }).on('click.combo-option', accept).order();
76978               var node = attachTo ? attachTo.node() : input.node();
76979               var containerRect = container.node().getBoundingClientRect();
76980               var rect = node.getBoundingClientRect();
76981               combo.style('left', rect.left + 5 - containerRect.left + 'px').style('width', rect.width - 10 + 'px').style('top', rect.height + rect.top - containerRect.top + 'px');
76982             } // Dispatches an 'accept' event
76983             // Then hides the combobox.
76984
76985
76986             function accept(d3_event, d) {
76987               _cancelFetch = true;
76988               var thiz = input.node();
76989
76990               if (d) {
76991                 // user clicked on a suggestion
76992                 utilGetSetValue(input, d.value); // replace field contents
76993
76994                 utilTriggerEvent(input, 'change');
76995               } // clear (and keep) selection
76996
76997
76998               var val = utilGetSetValue(input);
76999               thiz.setSelectionRange(val.length, val.length);
77000               d = _fetched[val];
77001               dispatch.call('accept', thiz, d, val);
77002               hide();
77003             } // Dispatches an 'cancel' event
77004             // Then hides the combobox.
77005
77006
77007             function cancel() {
77008               _cancelFetch = true;
77009               var thiz = input.node(); // clear (and remove) selection, and replace field contents
77010
77011               var val = utilGetSetValue(input);
77012               var start = input.property('selectionStart');
77013               var end = input.property('selectionEnd');
77014               val = val.slice(0, start) + val.slice(end);
77015               utilGetSetValue(input, val);
77016               thiz.setSelectionRange(val.length, val.length);
77017               dispatch.call('cancel', thiz);
77018               hide();
77019             }
77020           };
77021
77022           combobox.canAutocomplete = function (val) {
77023             if (!arguments.length) return _canAutocomplete;
77024             _canAutocomplete = val;
77025             return combobox;
77026           };
77027
77028           combobox.caseSensitive = function (val) {
77029             if (!arguments.length) return _caseSensitive;
77030             _caseSensitive = val;
77031             return combobox;
77032           };
77033
77034           combobox.data = function (val) {
77035             if (!arguments.length) return _data;
77036             _data = val;
77037             return combobox;
77038           };
77039
77040           combobox.fetcher = function (val) {
77041             if (!arguments.length) return _fetcher;
77042             _fetcher = val;
77043             return combobox;
77044           };
77045
77046           combobox.minItems = function (val) {
77047             if (!arguments.length) return _minItems;
77048             _minItems = val;
77049             return combobox;
77050           };
77051
77052           combobox.itemsMouseEnter = function (val) {
77053             if (!arguments.length) return _mouseEnterHandler;
77054             _mouseEnterHandler = val;
77055             return combobox;
77056           };
77057
77058           combobox.itemsMouseLeave = function (val) {
77059             if (!arguments.length) return _mouseLeaveHandler;
77060             _mouseLeaveHandler = val;
77061             return combobox;
77062           };
77063
77064           return utilRebind(combobox, dispatch, 'on');
77065         }
77066
77067         uiCombobox.off = function (input, context) {
77068           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);
77069           context.container().on('scroll.combo-scroll', null);
77070         };
77071
77072         function uiDisclosure(context, key, expandedDefault) {
77073           var dispatch = dispatch$8('toggled');
77074
77075           var _expanded;
77076
77077           var _label = utilFunctor('');
77078
77079           var _updatePreference = true;
77080
77081           var _content = function _content() {};
77082
77083           var disclosure = function disclosure(selection) {
77084             if (_expanded === undefined || _expanded === null) {
77085               // loading _expanded here allows it to be reset by calling `disclosure.expanded(null)`
77086               var preference = corePreferences('disclosure.' + key + '.expanded');
77087               _expanded = preference === null ? !!expandedDefault : preference === 'true';
77088             }
77089
77090             var hideToggle = selection.selectAll('.hide-toggle-' + key).data([0]); // enter
77091
77092             var hideToggleEnter = hideToggle.enter().append('a').attr('href', '#').attr('class', 'hide-toggle hide-toggle-' + key).call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
77093             hideToggleEnter.append('span').attr('class', 'hide-toggle-text'); // update
77094
77095             hideToggle = hideToggleEnter.merge(hideToggle);
77096             hideToggle.on('click', toggle).classed('expanded', _expanded);
77097             hideToggle.selectAll('.hide-toggle-text').html(_label());
77098             hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
77099             var wrap = selection.selectAll('.disclosure-wrap').data([0]); // enter/update
77100
77101             wrap = wrap.enter().append('div').attr('class', 'disclosure-wrap disclosure-wrap-' + key).merge(wrap).classed('hide', !_expanded);
77102
77103             if (_expanded) {
77104               wrap.call(_content);
77105             }
77106
77107             function toggle(d3_event) {
77108               d3_event.preventDefault();
77109               _expanded = !_expanded;
77110
77111               if (_updatePreference) {
77112                 corePreferences('disclosure.' + key + '.expanded', _expanded);
77113               }
77114
77115               hideToggle.classed('expanded', _expanded);
77116               hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
77117               wrap.call(uiToggle(_expanded));
77118
77119               if (_expanded) {
77120                 wrap.call(_content);
77121               }
77122
77123               dispatch.call('toggled', this, _expanded);
77124             }
77125           };
77126
77127           disclosure.label = function (val) {
77128             if (!arguments.length) return _label;
77129             _label = utilFunctor(val);
77130             return disclosure;
77131           };
77132
77133           disclosure.expanded = function (val) {
77134             if (!arguments.length) return _expanded;
77135             _expanded = val;
77136             return disclosure;
77137           };
77138
77139           disclosure.updatePreference = function (val) {
77140             if (!arguments.length) return _updatePreference;
77141             _updatePreference = val;
77142             return disclosure;
77143           };
77144
77145           disclosure.content = function (val) {
77146             if (!arguments.length) return _content;
77147             _content = val;
77148             return disclosure;
77149           };
77150
77151           return utilRebind(disclosure, dispatch, 'on');
77152         }
77153
77154         // Can be labeled and collapsible.
77155
77156         function uiSection(id, context) {
77157           var _classes = utilFunctor('');
77158
77159           var _shouldDisplay;
77160
77161           var _content;
77162
77163           var _disclosure;
77164
77165           var _label;
77166
77167           var _expandedByDefault = utilFunctor(true);
77168
77169           var _disclosureContent;
77170
77171           var _disclosureExpanded;
77172
77173           var _containerSelection = select(null);
77174
77175           var section = {
77176             id: id
77177           };
77178
77179           section.classes = function (val) {
77180             if (!arguments.length) return _classes;
77181             _classes = utilFunctor(val);
77182             return section;
77183           };
77184
77185           section.label = function (val) {
77186             if (!arguments.length) return _label;
77187             _label = utilFunctor(val);
77188             return section;
77189           };
77190
77191           section.expandedByDefault = function (val) {
77192             if (!arguments.length) return _expandedByDefault;
77193             _expandedByDefault = utilFunctor(val);
77194             return section;
77195           };
77196
77197           section.shouldDisplay = function (val) {
77198             if (!arguments.length) return _shouldDisplay;
77199             _shouldDisplay = utilFunctor(val);
77200             return section;
77201           };
77202
77203           section.content = function (val) {
77204             if (!arguments.length) return _content;
77205             _content = val;
77206             return section;
77207           };
77208
77209           section.disclosureContent = function (val) {
77210             if (!arguments.length) return _disclosureContent;
77211             _disclosureContent = val;
77212             return section;
77213           };
77214
77215           section.disclosureExpanded = function (val) {
77216             if (!arguments.length) return _disclosureExpanded;
77217             _disclosureExpanded = val;
77218             return section;
77219           }; // may be called multiple times
77220
77221
77222           section.render = function (selection) {
77223             _containerSelection = selection.selectAll('.section-' + id).data([0]);
77224
77225             var sectionEnter = _containerSelection.enter().append('div').attr('class', 'section section-' + id + ' ' + (_classes && _classes() || ''));
77226
77227             _containerSelection = sectionEnter.merge(_containerSelection);
77228
77229             _containerSelection.call(renderContent);
77230           };
77231
77232           section.reRender = function () {
77233             _containerSelection.call(renderContent);
77234           };
77235
77236           section.selection = function () {
77237             return _containerSelection;
77238           };
77239
77240           section.disclosure = function () {
77241             return _disclosure;
77242           }; // may be called multiple times
77243
77244
77245           function renderContent(selection) {
77246             if (_shouldDisplay) {
77247               var shouldDisplay = _shouldDisplay();
77248
77249               selection.classed('hide', !shouldDisplay);
77250
77251               if (!shouldDisplay) {
77252                 selection.html('');
77253                 return;
77254               }
77255             }
77256
77257             if (_disclosureContent) {
77258               if (!_disclosure) {
77259                 _disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault()).label(_label || '')
77260                 /*.on('toggled', function(expanded) {
77261                     if (expanded) { selection.node().parentNode.scrollTop += 200; }
77262                 })*/
77263                 .content(_disclosureContent);
77264               }
77265
77266               if (_disclosureExpanded !== undefined) {
77267                 _disclosure.expanded(_disclosureExpanded);
77268
77269                 _disclosureExpanded = undefined;
77270               }
77271
77272               selection.call(_disclosure);
77273               return;
77274             }
77275
77276             if (_content) {
77277               selection.call(_content);
77278             }
77279           }
77280
77281           return section;
77282         }
77283
77284         // {
77285         //   key: 'string',     // required
77286         //   value: 'string'    // optional
77287         // }
77288         //   -or-
77289         // {
77290         //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
77291         // }
77292         //
77293
77294         function uiTagReference(what) {
77295           var wikibase = what.qid ? services.wikidata : services.osmWikibase;
77296           var tagReference = {};
77297
77298           var _button = select(null);
77299
77300           var _body = select(null);
77301
77302           var _loaded;
77303
77304           var _showing;
77305
77306           function load() {
77307             if (!wikibase) return;
77308
77309             _button.classed('tag-reference-loading', true);
77310
77311             wikibase.getDocs(what, gotDocs);
77312           }
77313
77314           function gotDocs(err, docs) {
77315             _body.html('');
77316
77317             if (!docs || !docs.title) {
77318               _body.append('p').attr('class', 'tag-reference-description').html(_t.html('inspector.no_documentation_key'));
77319
77320               done();
77321               return;
77322             }
77323
77324             if (docs.imageURL) {
77325               _body.append('img').attr('class', 'tag-reference-wiki-image').attr('src', docs.imageURL).on('load', function () {
77326                 done();
77327               }).on('error', function () {
77328                 select(this).remove();
77329                 done();
77330               });
77331             } else {
77332               done();
77333             }
77334
77335             _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'));
77336
77337             if (docs.wiki) {
77338               _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));
77339             } // Add link to info about "good changeset comments" - #2923
77340
77341
77342             if (what.key === 'comment') {
77343               _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'));
77344             }
77345           }
77346
77347           function done() {
77348             _loaded = true;
77349
77350             _button.classed('tag-reference-loading', false);
77351
77352             _body.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1');
77353
77354             _showing = true;
77355
77356             _button.selectAll('svg.icon use').each(function () {
77357               var iconUse = select(this);
77358
77359               if (iconUse.attr('href') === '#iD-icon-info') {
77360                 iconUse.attr('href', '#iD-icon-info-filled');
77361               }
77362             });
77363           }
77364
77365           function hide() {
77366             _body.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
77367               _body.classed('expanded', false);
77368             });
77369
77370             _showing = false;
77371
77372             _button.selectAll('svg.icon use').each(function () {
77373               var iconUse = select(this);
77374
77375               if (iconUse.attr('href') === '#iD-icon-info-filled') {
77376                 iconUse.attr('href', '#iD-icon-info');
77377               }
77378             });
77379           }
77380
77381           tagReference.button = function (selection, klass, iconName) {
77382             _button = selection.selectAll('.tag-reference-button').data([0]);
77383             _button = _button.enter().append('button').attr('class', 'tag-reference-button ' + (klass || '')).attr('title', _t('icons.information')).call(svgIcon('#iD-icon-' + (iconName || 'inspect'))).merge(_button);
77384
77385             _button.on('click', function (d3_event) {
77386               d3_event.stopPropagation();
77387               d3_event.preventDefault();
77388               this.blur(); // avoid keeping focus on the button - #4641
77389
77390               if (_showing) {
77391                 hide();
77392               } else if (_loaded) {
77393                 done();
77394               } else {
77395                 load();
77396               }
77397             });
77398           };
77399
77400           tagReference.body = function (selection) {
77401             var itemID = what.qid || what.key + '-' + (what.value || '');
77402             _body = selection.selectAll('.tag-reference-body').data([itemID], function (d) {
77403               return d;
77404             });
77405
77406             _body.exit().remove();
77407
77408             _body = _body.enter().append('div').attr('class', 'tag-reference-body').style('max-height', '0').style('opacity', '0').merge(_body);
77409
77410             if (_showing === false) {
77411               hide();
77412             }
77413           };
77414
77415           tagReference.showing = function (val) {
77416             if (!arguments.length) return _showing;
77417             _showing = val;
77418             return tagReference;
77419           };
77420
77421           return tagReference;
77422         }
77423
77424         function uiSectionRawTagEditor(id, context) {
77425           var section = uiSection(id, context).classes('raw-tag-editor').label(function () {
77426             var count = Object.keys(_tags).filter(function (d) {
77427               return d;
77428             }).length;
77429             return _t('inspector.title_count', {
77430               title: _t.html('inspector.tags'),
77431               count: count
77432             });
77433           }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
77434           var taginfo = services.taginfo;
77435           var dispatch = dispatch$8('change');
77436           var availableViews = [{
77437             id: 'list',
77438             icon: '#fas-th-list'
77439           }, {
77440             id: 'text',
77441             icon: '#fas-i-cursor'
77442           }];
77443
77444           var _tagView = corePreferences('raw-tag-editor-view') || 'list'; // 'list, 'text'
77445
77446
77447           var _readOnlyTags = []; // the keys in the order we want them to display
77448
77449           var _orderedKeys = [];
77450           var _showBlank = false;
77451           var _pendingChange = null;
77452
77453           var _state;
77454
77455           var _presets;
77456
77457           var _tags;
77458
77459           var _entityIDs;
77460
77461           var _didInteract = false;
77462
77463           function interacted() {
77464             _didInteract = true;
77465           }
77466
77467           function renderDisclosureContent(wrap) {
77468             // remove deleted keys
77469             _orderedKeys = _orderedKeys.filter(function (key) {
77470               return _tags[key] !== undefined;
77471             }); // When switching to a different entity or changing the state (hover/select)
77472             // reorder the keys alphabetically.
77473             // We trigger this by emptying the `_orderedKeys` array, then it will be rebuilt here.
77474             // Otherwise leave their order alone - #5857, #5927
77475
77476             var all = Object.keys(_tags).sort();
77477             var missingKeys = utilArrayDifference(all, _orderedKeys);
77478
77479             for (var i in missingKeys) {
77480               _orderedKeys.push(missingKeys[i]);
77481             } // assemble row data
77482
77483
77484             var rowData = _orderedKeys.map(function (key, i) {
77485               return {
77486                 index: i,
77487                 key: key,
77488                 value: _tags[key]
77489               };
77490             }); // append blank row last, if necessary
77491
77492
77493             if (!rowData.length || _showBlank) {
77494               _showBlank = false;
77495               rowData.push({
77496                 index: rowData.length,
77497                 key: '',
77498                 value: ''
77499               });
77500             } // View Options
77501
77502
77503             var options = wrap.selectAll('.raw-tag-options').data([0]);
77504             options.exit().remove();
77505             var optionsEnter = options.enter().insert('div', ':first-child').attr('class', 'raw-tag-options');
77506             var optionEnter = optionsEnter.selectAll('.raw-tag-option').data(availableViews, function (d) {
77507               return d.id;
77508             }).enter();
77509             optionEnter.append('button').attr('class', function (d) {
77510               return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
77511             }).attr('title', function (d) {
77512               return _t('icons.' + d.id);
77513             }).on('click', function (d3_event, d) {
77514               _tagView = d.id;
77515               corePreferences('raw-tag-editor-view', d.id);
77516               wrap.selectAll('.raw-tag-option').classed('selected', function (datum) {
77517                 return datum === d;
77518               });
77519               wrap.selectAll('.tag-text').classed('hide', d.id !== 'text').each(setTextareaHeight);
77520               wrap.selectAll('.tag-list, .add-row').classed('hide', d.id !== 'list');
77521             }).each(function (d) {
77522               select(this).call(svgIcon(d.icon));
77523             }); // View as Text
77524
77525             var textData = rowsToText(rowData);
77526             var textarea = wrap.selectAll('.tag-text').data([0]);
77527             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);
77528             textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on('input', setTextareaHeight).on('focus', interacted).on('blur', textChanged).on('change', textChanged); // View as List
77529
77530             var list = wrap.selectAll('.tag-list').data([0]);
77531             list = list.enter().append('ul').attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : '')).merge(list); // Container for the Add button
77532
77533             var addRowEnter = wrap.selectAll('.add-row').data([0]).enter().append('div').attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
77534             addRowEnter.append('button').attr('class', 'add-tag').call(svgIcon('#iD-icon-plus', 'light')).on('click', addTag);
77535             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
77536
77537             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
77538             // Tag list items
77539
77540             var items = list.selectAll('.tag-row').data(rowData, function (d) {
77541               return d.key;
77542             });
77543             items.exit().each(unbind).remove(); // Enter
77544
77545             var itemsEnter = items.enter().append('li').attr('class', 'tag-row').classed('readonly', isReadOnly);
77546             var innerWrap = itemsEnter.append('div').attr('class', 'inner-wrap');
77547             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);
77548             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);
77549             innerWrap.append('button').attr('class', 'form-field-button remove').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete')); // Update
77550
77551             items = items.merge(itemsEnter).sort(function (a, b) {
77552               return a.index - b.index;
77553             });
77554             items.each(function (d) {
77555               var row = select(this);
77556               var key = row.select('input.key'); // propagate bound data
77557
77558               var value = row.select('input.value'); // propagate bound data
77559
77560               if (_entityIDs && taginfo && _state !== 'hover') {
77561                 bindTypeahead(key, value);
77562               }
77563
77564               var referenceOptions = {
77565                 key: d.key
77566               };
77567
77568               if (typeof d.value === 'string') {
77569                 referenceOptions.value = d.value;
77570               }
77571
77572               var reference = uiTagReference(referenceOptions);
77573
77574               if (_state === 'hover') {
77575                 reference.showing(false);
77576               }
77577
77578               row.select('.inner-wrap') // propagate bound data
77579               .call(reference.button);
77580               row.call(reference.body);
77581               row.select('button.remove'); // propagate bound data
77582             });
77583             items.selectAll('input.key').attr('title', function (d) {
77584               return d.key;
77585             }).call(utilGetSetValue, function (d) {
77586               return d.key;
77587             }).attr('readonly', function (d) {
77588               return isReadOnly(d) || typeof d.value !== 'string' || null;
77589             });
77590             items.selectAll('input.value').attr('title', function (d) {
77591               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : d.value;
77592             }).classed('mixed', function (d) {
77593               return Array.isArray(d.value);
77594             }).attr('placeholder', function (d) {
77595               return typeof d.value === 'string' ? null : _t('inspector.multiple_values');
77596             }).call(utilGetSetValue, function (d) {
77597               return typeof d.value === 'string' ? d.value : '';
77598             }).attr('readonly', function (d) {
77599               return isReadOnly(d) || null;
77600             });
77601             items.selectAll('button.remove').on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'down', removeTag); // 'click' fires too late - #5878
77602           }
77603
77604           function isReadOnly(d) {
77605             for (var i = 0; i < _readOnlyTags.length; i++) {
77606               if (d.key.match(_readOnlyTags[i]) !== null) {
77607                 return true;
77608               }
77609             }
77610
77611             return false;
77612           }
77613
77614           function setTextareaHeight() {
77615             if (_tagView !== 'text') return;
77616             var selection = select(this);
77617             var matches = selection.node().value.match(/\n/g);
77618             var lineCount = 2 + Number(matches && matches.length);
77619             var lineHeight = 20;
77620             selection.style('height', lineCount * lineHeight + 'px');
77621           }
77622
77623           function stringify(s) {
77624             return JSON.stringify(s).slice(1, -1); // without leading/trailing "
77625           }
77626
77627           function unstringify(s) {
77628             var leading = '';
77629             var trailing = '';
77630
77631             if (s.length < 1 || s.charAt(0) !== '"') {
77632               leading = '"';
77633             }
77634
77635             if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\') {
77636               trailing = '"';
77637             }
77638
77639             return JSON.parse(leading + s + trailing);
77640           }
77641
77642           function rowsToText(rows) {
77643             var str = rows.filter(function (row) {
77644               return row.key && row.key.trim() !== '';
77645             }).map(function (row) {
77646               var rawVal = row.value;
77647               if (typeof rawVal !== 'string') rawVal = '*';
77648               var val = rawVal ? stringify(rawVal) : '';
77649               return stringify(row.key) + '=' + val;
77650             }).join('\n');
77651
77652             if (_state !== 'hover' && str.length) {
77653               return str + '\n';
77654             }
77655
77656             return str;
77657           }
77658
77659           function textChanged() {
77660             var newText = this.value.trim();
77661             var newTags = {};
77662             newText.split('\n').forEach(function (row) {
77663               var m = row.match(/^\s*([^=]+)=(.*)$/);
77664
77665               if (m !== null) {
77666                 var k = context.cleanTagKey(unstringify(m[1].trim()));
77667                 var v = context.cleanTagValue(unstringify(m[2].trim()));
77668                 newTags[k] = v;
77669               }
77670             });
77671             var tagDiff = utilTagDiff(_tags, newTags);
77672             if (!tagDiff.length) return;
77673             _pendingChange = _pendingChange || {};
77674             tagDiff.forEach(function (change) {
77675               if (isReadOnly({
77676                 key: change.key
77677               })) return; // skip unchanged multiselection placeholders
77678
77679               if (change.newVal === '*' && typeof change.oldVal !== 'string') return;
77680
77681               if (change.type === '-') {
77682                 _pendingChange[change.key] = undefined;
77683               } else if (change.type === '+') {
77684                 _pendingChange[change.key] = change.newVal || '';
77685               }
77686             });
77687
77688             if (Object.keys(_pendingChange).length === 0) {
77689               _pendingChange = null;
77690               return;
77691             }
77692
77693             scheduleChange();
77694           }
77695
77696           function pushMore(d3_event) {
77697             // if pressing Tab on the last value field with content, add a blank row
77698             if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll('.tag-list li:last-child input.value').node() === this && utilGetSetValue(select(this))) {
77699               addTag();
77700             }
77701           }
77702
77703           function bindTypeahead(key, value) {
77704             if (isReadOnly(key.datum())) return;
77705
77706             if (Array.isArray(value.datum().value)) {
77707               value.call(uiCombobox(context, 'tag-value').minItems(1).fetcher(function (value, callback) {
77708                 var keyString = utilGetSetValue(key);
77709                 if (!_tags[keyString]) return;
77710
77711                 var data = _tags[keyString].filter(Boolean).map(function (tagValue) {
77712                   return {
77713                     value: tagValue,
77714                     title: tagValue
77715                   };
77716                 });
77717
77718                 callback(data);
77719               }));
77720               return;
77721             }
77722
77723             var geometry = context.graph().geometry(_entityIDs[0]);
77724             key.call(uiCombobox(context, 'tag-key').fetcher(function (value, callback) {
77725               taginfo.keys({
77726                 debounce: true,
77727                 geometry: geometry,
77728                 query: value
77729               }, function (err, data) {
77730                 if (!err) {
77731                   var filtered = data.filter(function (d) {
77732                     return _tags[d.value] === undefined;
77733                   });
77734                   callback(sort(value, filtered));
77735                 }
77736               });
77737             }));
77738             value.call(uiCombobox(context, 'tag-value').fetcher(function (value, callback) {
77739               taginfo.values({
77740                 debounce: true,
77741                 key: utilGetSetValue(key),
77742                 geometry: geometry,
77743                 query: value
77744               }, function (err, data) {
77745                 if (!err) callback(sort(value, data));
77746               });
77747             }));
77748
77749             function sort(value, data) {
77750               var sameletter = [];
77751               var other = [];
77752
77753               for (var i = 0; i < data.length; i++) {
77754                 if (data[i].value.substring(0, value.length) === value) {
77755                   sameletter.push(data[i]);
77756                 } else {
77757                   other.push(data[i]);
77758                 }
77759               }
77760
77761               return sameletter.concat(other);
77762             }
77763           }
77764
77765           function unbind() {
77766             var row = select(this);
77767             row.selectAll('input.key').call(uiCombobox.off, context);
77768             row.selectAll('input.value').call(uiCombobox.off, context);
77769           }
77770
77771           function keyChange(d3_event, d) {
77772             if (select(this).attr('readonly')) return;
77773             var kOld = d.key; // exit if we are currently about to delete this row anyway - #6366
77774
77775             if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
77776             var kNew = context.cleanTagKey(this.value.trim()); // allow no change if the key should be readonly
77777
77778             if (isReadOnly({
77779               key: kNew
77780             })) {
77781               this.value = kOld;
77782               return;
77783             }
77784
77785             if (kNew && kNew !== kOld && _tags[kNew] !== undefined) {
77786               // new key is already in use, switch focus to the existing row
77787               this.value = kOld; // reset the key
77788
77789               section.selection().selectAll('.tag-list input.value').each(function (d) {
77790                 if (d.key === kNew) {
77791                   // send focus to that other value combo instead
77792                   var input = select(this).node();
77793                   input.focus();
77794                   input.select();
77795                 }
77796               });
77797               return;
77798             }
77799
77800             var row = this.parentNode.parentNode;
77801             var inputVal = select(row).selectAll('input.value');
77802             var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
77803             _pendingChange = _pendingChange || {};
77804
77805             if (kOld) {
77806               _pendingChange[kOld] = undefined;
77807             }
77808
77809             _pendingChange[kNew] = vNew; // update the ordered key index so this row doesn't change position
77810
77811             var existingKeyIndex = _orderedKeys.indexOf(kOld);
77812
77813             if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
77814             d.key = kNew; // update datum to avoid exit/enter on tag update
77815
77816             d.value = vNew;
77817             this.value = kNew;
77818             utilGetSetValue(inputVal, vNew);
77819             scheduleChange();
77820           }
77821
77822           function valueChange(d3_event, d) {
77823             if (isReadOnly(d)) return; // exit if this is a multiselection and no value was entered
77824
77825             if (typeof d.value !== 'string' && !this.value) return; // exit if we are currently about to delete this row anyway - #6366
77826
77827             if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
77828             _pendingChange = _pendingChange || {};
77829             _pendingChange[d.key] = context.cleanTagValue(this.value);
77830             scheduleChange();
77831           }
77832
77833           function removeTag(d3_event, d) {
77834             if (isReadOnly(d)) return;
77835
77836             if (d.key === '') {
77837               // removing the blank row
77838               _showBlank = false;
77839               section.reRender();
77840             } else {
77841               // remove the key from the ordered key index
77842               _orderedKeys = _orderedKeys.filter(function (key) {
77843                 return key !== d.key;
77844               });
77845               _pendingChange = _pendingChange || {};
77846               _pendingChange[d.key] = undefined;
77847               scheduleChange();
77848             }
77849           }
77850
77851           function addTag() {
77852             // Delay render in case this click is blurring an edited combo.
77853             // Without the setTimeout, the `content` render would wipe out the pending tag change.
77854             window.setTimeout(function () {
77855               _showBlank = true;
77856               section.reRender();
77857               section.selection().selectAll('.tag-list li:last-child input.key').node().focus();
77858             }, 20);
77859           }
77860
77861           function scheduleChange() {
77862             // Cache IDs in case the editor is reloaded before the change event is called. - #6028
77863             var entityIDs = _entityIDs; // Delay change in case this change is blurring an edited combo. - #5878
77864
77865             window.setTimeout(function () {
77866               if (!_pendingChange) return;
77867               dispatch.call('change', this, entityIDs, _pendingChange);
77868               _pendingChange = null;
77869             }, 10);
77870           }
77871
77872           section.state = function (val) {
77873             if (!arguments.length) return _state;
77874
77875             if (_state !== val) {
77876               _orderedKeys = [];
77877               _state = val;
77878             }
77879
77880             return section;
77881           };
77882
77883           section.presets = function (val) {
77884             if (!arguments.length) return _presets;
77885             _presets = val;
77886
77887             if (_presets && _presets.length && _presets[0].isFallback()) {
77888               section.disclosureExpanded(true); // don't collapse the disclosure if the mapper used the raw tag editor - #1881
77889             } else if (!_didInteract) {
77890               section.disclosureExpanded(null);
77891             }
77892
77893             return section;
77894           };
77895
77896           section.tags = function (val) {
77897             if (!arguments.length) return _tags;
77898             _tags = val;
77899             return section;
77900           };
77901
77902           section.entityIDs = function (val) {
77903             if (!arguments.length) return _entityIDs;
77904
77905             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
77906               _entityIDs = val;
77907               _orderedKeys = [];
77908             }
77909
77910             return section;
77911           }; // pass an array of regular expressions to test against the tag key
77912
77913
77914           section.readOnlyTags = function (val) {
77915             if (!arguments.length) return _readOnlyTags;
77916             _readOnlyTags = val;
77917             return section;
77918           };
77919
77920           return utilRebind(section, dispatch, 'on');
77921         }
77922
77923         function uiDataEditor(context) {
77924           var dataHeader = uiDataHeader();
77925           var rawTagEditor = uiSectionRawTagEditor('custom-data-tag-editor', context).expandedByDefault(true).readOnlyTags([/./]);
77926
77927           var _datum;
77928
77929           function dataEditor(selection) {
77930             var header = selection.selectAll('.header').data([0]);
77931             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
77932             headerEnter.append('button').attr('class', 'close').on('click', function () {
77933               context.enter(modeBrowse(context));
77934             }).call(svgIcon('#iD-icon-close'));
77935             headerEnter.append('h3').html(_t.html('map_data.title'));
77936             var body = selection.selectAll('.body').data([0]);
77937             body = body.enter().append('div').attr('class', 'body').merge(body);
77938             var editor = body.selectAll('.data-editor').data([0]); // enter/update
77939
77940             editor.enter().append('div').attr('class', 'modal-section data-editor').merge(editor).call(dataHeader.datum(_datum));
77941             var rte = body.selectAll('.raw-tag-editor').data([0]); // enter/update
77942
77943             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);
77944           }
77945
77946           dataEditor.datum = function (val) {
77947             if (!arguments.length) return _datum;
77948             _datum = val;
77949             return this;
77950           };
77951
77952           return dataEditor;
77953         }
77954
77955         var sexagesimal = {exports: {}};
77956
77957         sexagesimal.exports = element;
77958         var pair_1 = sexagesimal.exports.pair = pair;
77959         sexagesimal.exports.format = format;
77960         sexagesimal.exports.formatPair = formatPair;
77961         sexagesimal.exports.coordToDMS = coordToDMS;
77962
77963         function element(input, dims) {
77964           var result = search(input, dims);
77965           return result === null ? null : result.val;
77966         }
77967
77968         function formatPair(input) {
77969           return format(input.lat, 'lat') + ' ' + format(input.lon, 'lon');
77970         } // Is 0 North or South?
77971
77972
77973         function format(input, dim) {
77974           var dms = coordToDMS(input, dim);
77975           return dms.whole + '° ' + (dms.minutes ? dms.minutes + '\' ' : '') + (dms.seconds ? dms.seconds + '" ' : '') + dms.dir;
77976         }
77977
77978         function coordToDMS(input, dim) {
77979           var dirs = {
77980             lat: ['N', 'S'],
77981             lon: ['E', 'W']
77982           }[dim] || '';
77983           var dir = dirs[input >= 0 ? 0 : 1];
77984           var abs = Math.abs(input);
77985           var whole = Math.floor(abs);
77986           var fraction = abs - whole;
77987           var fractionMinutes = fraction * 60;
77988           var minutes = Math.floor(fractionMinutes);
77989           var seconds = Math.floor((fractionMinutes - minutes) * 60);
77990           return {
77991             whole: whole,
77992             minutes: minutes,
77993             seconds: seconds,
77994             dir: dir
77995           };
77996         }
77997
77998         function search(input, dims) {
77999           if (!dims) dims = 'NSEW';
78000           if (typeof input !== 'string') return null;
78001           input = input.toUpperCase();
78002           var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
78003           var m = input.match(regex);
78004           if (!m) return null; // no match
78005
78006           var matched = m[0]; // extract dimension.. m[1] = leading, m[5] = trailing
78007
78008           var dim;
78009
78010           if (m[1] && m[5]) {
78011             // if matched both..
78012             dim = m[1]; // keep leading
78013
78014             matched = matched.slice(0, -1); // remove trailing dimension from match
78015           } else {
78016             dim = m[1] || m[5];
78017           } // if unrecognized dimension
78018
78019
78020           if (dim && dims.indexOf(dim) === -1) return null; // extract DMS
78021
78022           var deg = m[2] ? parseFloat(m[2]) : 0;
78023           var min = m[3] ? parseFloat(m[3]) / 60 : 0;
78024           var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
78025           var sign = deg < 0 ? -1 : 1;
78026           if (dim === 'S' || dim === 'W') sign *= -1;
78027           return {
78028             val: (Math.abs(deg) + min + sec) * sign,
78029             dim: dim,
78030             matched: matched,
78031             remain: input.slice(matched.length)
78032           };
78033         }
78034
78035         function pair(input, dims) {
78036           input = input.trim();
78037           var one = search(input, dims);
78038           if (!one) return null;
78039           input = one.remain.trim();
78040           var two = search(input, dims);
78041           if (!two || two.remain) return null;
78042
78043           if (one.dim) {
78044             return swapdim(one.val, two.val, one.dim);
78045           } else {
78046             return [one.val, two.val];
78047           }
78048         }
78049
78050         function swapdim(a, b, dim) {
78051           if (dim === 'N' || dim === 'S') return [a, b];
78052           if (dim === 'W' || dim === 'E') return [b, a];
78053         }
78054
78055         function uiFeatureList(context) {
78056           var _geocodeResults;
78057
78058           function featureList(selection) {
78059             var header = selection.append('div').attr('class', 'header fillL');
78060             header.append('h3').html(_t.html('inspector.feature_list'));
78061             var searchWrap = selection.append('div').attr('class', 'search-header');
78062             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
78063             var search = searchWrap.append('input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keypress', keypress).on('keydown', keydown).on('input', inputevent);
78064             var listWrap = selection.append('div').attr('class', 'inspector-body');
78065             var list = listWrap.append('div').attr('class', 'feature-list');
78066             context.on('exit.feature-list', clearSearch);
78067             context.map().on('drawn.feature-list', mapDrawn);
78068             context.keybinding().on(uiCmd('⌘F'), focusSearch);
78069
78070             function focusSearch(d3_event) {
78071               var mode = context.mode() && context.mode().id;
78072               if (mode !== 'browse') return;
78073               d3_event.preventDefault();
78074               search.node().focus();
78075             }
78076
78077             function keydown(d3_event) {
78078               if (d3_event.keyCode === 27) {
78079                 // escape
78080                 search.node().blur();
78081               }
78082             }
78083
78084             function keypress(d3_event) {
78085               var q = search.property('value'),
78086                   items = list.selectAll('.feature-list-item');
78087
78088               if (d3_event.keyCode === 13 && // ↩ Return
78089               q.length && items.size()) {
78090                 click(d3_event, items.datum());
78091               }
78092             }
78093
78094             function inputevent() {
78095               _geocodeResults = undefined;
78096               drawList();
78097             }
78098
78099             function clearSearch() {
78100               search.property('value', '');
78101               drawList();
78102             }
78103
78104             function mapDrawn(e) {
78105               if (e.full) {
78106                 drawList();
78107               }
78108             }
78109
78110             function features() {
78111               var result = [];
78112               var graph = context.graph();
78113               var visibleCenter = context.map().extent().center();
78114               var q = search.property('value').toLowerCase();
78115               if (!q) return result;
78116               var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
78117
78118               if (locationMatch) {
78119                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
78120                 result.push({
78121                   id: -1,
78122                   geometry: 'point',
78123                   type: _t('inspector.location'),
78124                   name: dmsCoordinatePair([loc[1], loc[0]]),
78125                   location: loc
78126                 });
78127               } // A location search takes priority over an ID search
78128
78129
78130               var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
78131
78132               if (idMatch) {
78133                 var elemType = idMatch[1].charAt(0);
78134                 var elemId = idMatch[2];
78135                 result.push({
78136                   id: elemType + elemId,
78137                   geometry: elemType === 'n' ? 'point' : elemType === 'w' ? 'line' : 'relation',
78138                   type: elemType === 'n' ? _t('inspector.node') : elemType === 'w' ? _t('inspector.way') : _t('inspector.relation'),
78139                   name: elemId
78140                 });
78141               }
78142
78143               var allEntities = graph.entities;
78144               var localResults = [];
78145
78146               for (var id in allEntities) {
78147                 var entity = allEntities[id];
78148                 if (!entity) continue;
78149                 var name = utilDisplayName(entity) || '';
78150                 if (name.toLowerCase().indexOf(q) < 0) continue;
78151                 var matched = _mainPresetIndex.match(entity, graph);
78152                 var type = matched && matched.name() || utilDisplayType(entity.id);
78153                 var extent = entity.extent(graph);
78154                 var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
78155                 localResults.push({
78156                   id: entity.id,
78157                   entity: entity,
78158                   geometry: entity.geometry(graph),
78159                   type: type,
78160                   name: name,
78161                   distance: distance
78162                 });
78163                 if (localResults.length > 100) break;
78164               }
78165
78166               localResults = localResults.sort(function byDistance(a, b) {
78167                 return a.distance - b.distance;
78168               });
78169               result = result.concat(localResults);
78170
78171               (_geocodeResults || []).forEach(function (d) {
78172                 if (d.osm_type && d.osm_id) {
78173                   // some results may be missing these - #1890
78174                   // Make a temporary osmEntity so we can preset match
78175                   // and better localize the search result - #4725
78176                   var id = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
78177                   var tags = {};
78178                   tags[d["class"]] = d.type;
78179                   var attrs = {
78180                     id: id,
78181                     type: d.osm_type,
78182                     tags: tags
78183                   };
78184
78185                   if (d.osm_type === 'way') {
78186                     // for ways, add some fake closed nodes
78187                     attrs.nodes = ['a', 'a']; // so that geometry area is possible
78188                   }
78189
78190                   var tempEntity = osmEntity(attrs);
78191                   var tempGraph = coreGraph([tempEntity]);
78192                   var matched = _mainPresetIndex.match(tempEntity, tempGraph);
78193                   var type = matched && matched.name() || utilDisplayType(id);
78194                   result.push({
78195                     id: tempEntity.id,
78196                     geometry: tempEntity.geometry(tempGraph),
78197                     type: type,
78198                     name: d.display_name,
78199                     extent: new geoExtent([parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])], [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
78200                   });
78201                 }
78202               });
78203
78204               if (q.match(/^[0-9]+$/)) {
78205                 // if query is just a number, possibly an OSM ID without a prefix
78206                 result.push({
78207                   id: 'n' + q,
78208                   geometry: 'point',
78209                   type: _t('inspector.node'),
78210                   name: q
78211                 });
78212                 result.push({
78213                   id: 'w' + q,
78214                   geometry: 'line',
78215                   type: _t('inspector.way'),
78216                   name: q
78217                 });
78218                 result.push({
78219                   id: 'r' + q,
78220                   geometry: 'relation',
78221                   type: _t('inspector.relation'),
78222                   name: q
78223                 });
78224               }
78225
78226               return result;
78227             }
78228
78229             function drawList() {
78230               var value = search.property('value');
78231               var results = features();
78232               list.classed('filtered', value.length);
78233               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'));
78234               resultsIndicator.append('span').attr('class', 'entity-name');
78235               list.selectAll('.no-results-item .entity-name').html(_t.html('geocoder.no_results_worldwide'));
78236
78237               if (services.geocoder) {
78238                 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'));
78239               }
78240
78241               list.selectAll('.no-results-item').style('display', value.length && !results.length ? 'block' : 'none');
78242               list.selectAll('.geocode-item').style('display', value && _geocodeResults === undefined ? 'block' : 'none');
78243               list.selectAll('.feature-list-item').data([-1]).remove();
78244               var items = list.selectAll('.feature-list-item').data(results, function (d) {
78245                 return d.id;
78246               });
78247               var enter = items.enter().insert('button', '.geocode-item').attr('class', 'feature-list-item').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
78248               var label = enter.append('div').attr('class', 'label');
78249               label.each(function (d) {
78250                 select(this).call(svgIcon('#iD-icon-' + d.geometry, 'pre-text'));
78251               });
78252               label.append('span').attr('class', 'entity-type').html(function (d) {
78253                 return d.type;
78254               });
78255               label.append('span').attr('class', 'entity-name').html(function (d) {
78256                 return d.name;
78257               });
78258               enter.style('opacity', 0).transition().style('opacity', 1);
78259               items.order();
78260               items.exit().remove();
78261             }
78262
78263             function mouseover(d3_event, d) {
78264               if (d.id === -1) return;
78265               utilHighlightEntities([d.id], true, context);
78266             }
78267
78268             function mouseout(d3_event, d) {
78269               if (d.id === -1) return;
78270               utilHighlightEntities([d.id], false, context);
78271             }
78272
78273             function click(d3_event, d) {
78274               d3_event.preventDefault();
78275
78276               if (d.location) {
78277                 context.map().centerZoomEase([d.location[1], d.location[0]], 19);
78278               } else if (d.entity) {
78279                 utilHighlightEntities([d.id], false, context);
78280                 context.enter(modeSelect(context, [d.entity.id]));
78281                 context.map().zoomToEase(d.entity);
78282               } else {
78283                 // download, zoom to, and select the entity with the given ID
78284                 context.zoomToEntity(d.id);
78285               }
78286             }
78287
78288             function geocoderSearch() {
78289               services.geocoder.search(search.property('value'), function (err, resp) {
78290                 _geocodeResults = resp || [];
78291                 drawList();
78292               });
78293             }
78294           }
78295
78296           return featureList;
78297         }
78298
78299         var $$1 = _export;
78300         var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
78301         var toLength$1 = toLength$q;
78302         var notARegExp$1 = notARegexp;
78303         var requireObjectCoercible$1 = requireObjectCoercible$e;
78304         var correctIsRegExpLogic$1 = correctIsRegexpLogic;
78305
78306         // eslint-disable-next-line es/no-string-prototype-startswith -- safe
78307         var $startsWith = ''.startsWith;
78308         var min$1 = Math.min;
78309
78310         var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegExpLogic$1('startsWith');
78311         // https://github.com/zloirock/core-js/pull/702
78312         var MDN_POLYFILL_BUG$1 = !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
78313           var descriptor = getOwnPropertyDescriptor$1(String.prototype, 'startsWith');
78314           return descriptor && !descriptor.writable;
78315         }();
78316
78317         // `String.prototype.startsWith` method
78318         // https://tc39.es/ecma262/#sec-string.prototype.startswith
78319         $$1({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1 }, {
78320           startsWith: function startsWith(searchString /* , position = 0 */) {
78321             var that = String(requireObjectCoercible$1(this));
78322             notARegExp$1(searchString);
78323             var index = toLength$1(min$1(arguments.length > 1 ? arguments[1] : undefined, that.length));
78324             var search = String(searchString);
78325             return $startsWith
78326               ? $startsWith.call(that, search, index)
78327               : that.slice(index, index + search.length) === search;
78328           }
78329         });
78330
78331         function uiSectionEntityIssues(context) {
78332           // Does the user prefer to expand the active issue?  Useful for viewing tag diff.
78333           // Expand by default so first timers see it - #6408, #8143
78334           var preference = corePreferences('entity-issues.reference.expanded');
78335
78336           var _expanded = preference === null ? true : preference === 'true';
78337
78338           var _entityIDs = [];
78339           var _issues = [];
78340
78341           var _activeIssueID;
78342
78343           var section = uiSection('entity-issues', context).shouldDisplay(function () {
78344             return _issues.length > 0;
78345           }).label(function () {
78346             return _t('inspector.title_count', {
78347               title: _t.html('issues.list_title'),
78348               count: _issues.length
78349             });
78350           }).disclosureContent(renderDisclosureContent);
78351           context.validator().on('validated.entity_issues', function () {
78352             // Refresh on validated events
78353             reloadIssues();
78354             section.reRender();
78355           }).on('focusedIssue.entity_issues', function (issue) {
78356             makeActiveIssue(issue.id);
78357           });
78358
78359           function reloadIssues() {
78360             _issues = context.validator().getSharedEntityIssues(_entityIDs, {
78361               includeDisabledRules: true
78362             });
78363           }
78364
78365           function makeActiveIssue(issueID) {
78366             _activeIssueID = issueID;
78367             section.selection().selectAll('.issue-container').classed('active', function (d) {
78368               return d.id === _activeIssueID;
78369             });
78370           }
78371
78372           function renderDisclosureContent(selection) {
78373             selection.classed('grouped-items-area', true);
78374             _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
78375             var containers = selection.selectAll('.issue-container').data(_issues, function (d) {
78376               return d.key;
78377             }); // Exit
78378
78379             containers.exit().remove(); // Enter
78380
78381             var containersEnter = containers.enter().append('div').attr('class', 'issue-container');
78382             var itemsEnter = containersEnter.append('div').attr('class', function (d) {
78383               return 'issue severity-' + d.severity;
78384             }).on('mouseover.highlight', function (d3_event, d) {
78385               // don't hover-highlight the selected entity
78386               var ids = d.entityIds.filter(function (e) {
78387                 return _entityIDs.indexOf(e) === -1;
78388               });
78389               utilHighlightEntities(ids, true, context);
78390             }).on('mouseout.highlight', function (d3_event, d) {
78391               var ids = d.entityIds.filter(function (e) {
78392                 return _entityIDs.indexOf(e) === -1;
78393               });
78394               utilHighlightEntities(ids, false, context);
78395             });
78396             var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
78397             var textEnter = labelsEnter.append('button').attr('class', 'issue-text').on('click', function (d3_event, d) {
78398               makeActiveIssue(d.id); // expand only the clicked item
78399
78400               var extent = d.extent(context.graph());
78401
78402               if (extent) {
78403                 var setZoom = Math.max(context.map().zoom(), 19);
78404                 context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
78405               }
78406             });
78407             textEnter.each(function (d) {
78408               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
78409               select(this).call(svgIcon(iconName, 'issue-icon'));
78410             });
78411             textEnter.append('span').attr('class', 'issue-message');
78412             var infoButton = labelsEnter.append('button').attr('class', 'issue-info-button').attr('title', _t('icons.information')).call(svgIcon('#iD-icon-inspect'));
78413             infoButton.on('click', function (d3_event) {
78414               d3_event.stopPropagation();
78415               d3_event.preventDefault();
78416               this.blur(); // avoid keeping focus on the button - #4641
78417
78418               var container = select(this.parentNode.parentNode.parentNode);
78419               var info = container.selectAll('.issue-info');
78420               var isExpanded = info.classed('expanded');
78421               _expanded = !isExpanded;
78422               corePreferences('entity-issues.reference.expanded', _expanded); // update preference
78423
78424               if (isExpanded) {
78425                 info.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
78426                   info.classed('expanded', false);
78427                 });
78428               } else {
78429                 info.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1').on('end', function () {
78430                   info.style('max-height', null);
78431                 });
78432               }
78433             });
78434             itemsEnter.append('ul').attr('class', 'issue-fix-list');
78435             containersEnter.append('div').attr('class', 'issue-info' + (_expanded ? ' expanded' : '')).style('max-height', _expanded ? null : '0').style('opacity', _expanded ? '1' : '0').each(function (d) {
78436               if (typeof d.reference === 'function') {
78437                 select(this).call(d.reference);
78438               } else {
78439                 select(this).html(_t.html('inspector.no_documentation_key'));
78440               }
78441             }); // Update
78442
78443             containers = containers.merge(containersEnter).classed('active', function (d) {
78444               return d.id === _activeIssueID;
78445             });
78446             containers.selectAll('.issue-message').html(function (d) {
78447               return d.message(context);
78448             }); // fixes
78449
78450             var fixLists = containers.selectAll('.issue-fix-list');
78451             var fixes = fixLists.selectAll('.issue-fix-item').data(function (d) {
78452               return d.fixes ? d.fixes(context) : [];
78453             }, function (fix) {
78454               return fix.id;
78455             });
78456             fixes.exit().remove();
78457             var fixesEnter = fixes.enter().append('li').attr('class', 'issue-fix-item');
78458             var buttons = fixesEnter.append('button').on('click', function (d3_event, d) {
78459               // not all fixes are actionable
78460               if (select(this).attr('disabled') || !d.onClick) return; // Don't run another fix for this issue within a second of running one
78461               // (Necessary for "Select a feature type" fix. Most fixes should only ever run once)
78462
78463               if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1000) return;
78464               d.issue.dateLastRanFix = new Date(); // remove hover-highlighting
78465
78466               utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
78467               new Promise(function (resolve, reject) {
78468                 d.onClick(context, resolve, reject);
78469
78470                 if (d.onClick.length <= 1) {
78471                   // if the fix doesn't take any completion parameters then consider it resolved
78472                   resolve();
78473                 }
78474               }).then(function () {
78475                 // revalidate whenever the fix has finished running successfully
78476                 context.validator().validate();
78477               });
78478             }).on('mouseover.highlight', function (d3_event, d) {
78479               utilHighlightEntities(d.entityIds, true, context);
78480             }).on('mouseout.highlight', function (d3_event, d) {
78481               utilHighlightEntities(d.entityIds, false, context);
78482             });
78483             buttons.each(function (d) {
78484               var iconName = d.icon || 'iD-icon-wrench';
78485
78486               if (iconName.startsWith('maki')) {
78487                 iconName += '-15';
78488               }
78489
78490               select(this).call(svgIcon('#' + iconName, 'fix-icon'));
78491             });
78492             buttons.append('span').attr('class', 'fix-message').html(function (d) {
78493               return d.title;
78494             });
78495             fixesEnter.merge(fixes).selectAll('button').classed('actionable', function (d) {
78496               return d.onClick;
78497             }).attr('disabled', function (d) {
78498               return d.onClick ? null : 'true';
78499             }).attr('title', function (d) {
78500               if (d.disabledReason) {
78501                 return d.disabledReason;
78502               }
78503
78504               return null;
78505             });
78506           }
78507
78508           section.entityIDs = function (val) {
78509             if (!arguments.length) return _entityIDs;
78510
78511             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
78512               _entityIDs = val;
78513               _activeIssueID = null;
78514               reloadIssues();
78515             }
78516
78517             return section;
78518           };
78519
78520           return section;
78521         }
78522
78523         function uiPresetIcon() {
78524           var _preset;
78525
78526           var _geometry;
78527
78528           var _sizeClass = 'medium';
78529
78530           function isSmall() {
78531             return _sizeClass === 'small';
78532           }
78533
78534           function presetIcon(selection) {
78535             selection.each(render);
78536           }
78537
78538           function getIcon(p, geom) {
78539             if (isSmall() && p.isFallback && p.isFallback()) return 'iD-icon-' + p.id;
78540             if (p.icon) return p.icon;
78541             if (geom === 'line') return 'iD-other-line';
78542             if (geom === 'vertex') return p.isFallback() ? '' : 'temaki-vertex';
78543             if (isSmall() && geom === 'point') return '';
78544             return 'maki-marker-stroked';
78545           }
78546
78547           function renderPointBorder(container, drawPoint) {
78548             var pointBorder = container.selectAll('.preset-icon-point-border').data(drawPoint ? [0] : []);
78549             pointBorder.exit().remove();
78550             var pointBorderEnter = pointBorder.enter();
78551             var w = 40;
78552             var h = 40;
78553             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');
78554             pointBorder = pointBorderEnter.merge(pointBorder);
78555           }
78556
78557           function renderCategoryBorder(container, category) {
78558             var categoryBorder = container.selectAll('.preset-icon-category-border').data(category ? [0] : []);
78559             categoryBorder.exit().remove();
78560             var categoryBorderEnter = categoryBorder.enter();
78561             var d = 60;
78562             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));
78563             ['fill', 'stroke'].forEach(function (klass) {
78564               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');
78565             });
78566             categoryBorder = categoryBorderEnter.merge(categoryBorder);
78567
78568             if (category) {
78569               var tagClasses = svgTagClasses().getClassesString(category.members.collection[0].addTags, '');
78570               categoryBorder.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
78571               categoryBorder.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
78572             }
78573           }
78574
78575           function renderCircleFill(container, drawVertex) {
78576             var vertexFill = container.selectAll('.preset-icon-fill-vertex').data(drawVertex ? [0] : []);
78577             vertexFill.exit().remove();
78578             var vertexFillEnter = vertexFill.enter();
78579             var w = 60;
78580             var h = 60;
78581             var d = 40;
78582             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);
78583             vertexFill = vertexFillEnter.merge(vertexFill);
78584           }
78585
78586           function renderSquareFill(container, drawArea, tagClasses) {
78587             var fill = container.selectAll('.preset-icon-fill-area').data(drawArea ? [0] : []);
78588             fill.exit().remove();
78589             var fillEnter = fill.enter();
78590             var d = isSmall() ? 40 : 60;
78591             var w = d;
78592             var h = d;
78593             var l = d * 2 / 3;
78594             var c1 = (w - l) / 2;
78595             var c2 = c1 + l;
78596             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));
78597             ['fill', 'stroke'].forEach(function (klass) {
78598               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));
78599             });
78600             var rVertex = 2.5;
78601             [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach(function (point) {
78602               fillEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', rVertex);
78603             });
78604
78605             if (!isSmall()) {
78606               var rMidpoint = 1.25;
78607               [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach(function (point) {
78608                 fillEnter.append('circle').attr('class', 'midpoint').attr('cx', point[0]).attr('cy', point[1]).attr('r', rMidpoint);
78609               });
78610             }
78611
78612             fill = fillEnter.merge(fill);
78613             fill.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
78614             fill.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
78615           }
78616
78617           function renderLine(container, drawLine, tagClasses) {
78618             var line = container.selectAll('.preset-icon-line').data(drawLine ? [0] : []);
78619             line.exit().remove();
78620             var lineEnter = line.enter();
78621             var d = isSmall() ? 40 : 60; // draw the line parametrically
78622
78623             var w = d;
78624             var h = d;
78625             var y = Math.round(d * 0.72);
78626             var l = Math.round(d * 0.6);
78627             var r = 2.5;
78628             var x1 = (w - l) / 2;
78629             var x2 = x1 + l;
78630             lineEnter = lineEnter.append('svg').attr('class', 'preset-icon-line').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
78631             ['casing', 'stroke'].forEach(function (klass) {
78632               lineEnter.append('path').attr('d', "M".concat(x1, " ").concat(y, " L").concat(x2, " ").concat(y)).attr('class', "line ".concat(klass));
78633             });
78634             [[x1 - 1, y], [x2 + 1, y]].forEach(function (point) {
78635               lineEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
78636             });
78637             line = lineEnter.merge(line);
78638             line.selectAll('path.stroke').attr('class', "line stroke ".concat(tagClasses));
78639             line.selectAll('path.casing').attr('class', "line casing ".concat(tagClasses));
78640           }
78641
78642           function renderRoute(container, drawRoute, p) {
78643             var route = container.selectAll('.preset-icon-route').data(drawRoute ? [0] : []);
78644             route.exit().remove();
78645             var routeEnter = route.enter();
78646             var d = isSmall() ? 40 : 60; // draw the route parametrically
78647
78648             var w = d;
78649             var h = d;
78650             var y1 = Math.round(d * 0.80);
78651             var y2 = Math.round(d * 0.68);
78652             var l = Math.round(d * 0.6);
78653             var r = 2;
78654             var x1 = (w - l) / 2;
78655             var x2 = x1 + l / 3;
78656             var x3 = x2 + l / 3;
78657             var x4 = x3 + l / 3;
78658             routeEnter = routeEnter.append('svg').attr('class', 'preset-icon-route').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
78659             ['casing', 'stroke'].forEach(function (klass) {
78660               routeEnter.append('path').attr('d', "M".concat(x1, " ").concat(y1, " L").concat(x2, " ").concat(y2)).attr('class', "segment0 line ".concat(klass));
78661               routeEnter.append('path').attr('d', "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y1)).attr('class', "segment1 line ".concat(klass));
78662               routeEnter.append('path').attr('d', "M".concat(x3, " ").concat(y1, " L").concat(x4, " ").concat(y2)).attr('class', "segment2 line ".concat(klass));
78663             });
78664             [[x1, y1], [x2, y2], [x3, y1], [x4, y2]].forEach(function (point) {
78665               routeEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
78666             });
78667             route = routeEnter.merge(route);
78668
78669             if (drawRoute) {
78670               var routeType = p.tags.type === 'waterway' ? 'waterway' : p.tags.route;
78671               var segmentPresetIDs = routeSegments[routeType];
78672
78673               for (var i in segmentPresetIDs) {
78674                 var segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i]);
78675                 var segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, '');
78676                 route.selectAll("path.stroke.segment".concat(i)).attr('class', "segment".concat(i, " line stroke ").concat(segmentTagClasses));
78677                 route.selectAll("path.casing.segment".concat(i)).attr('class', "segment".concat(i, " line casing ").concat(segmentTagClasses));
78678               }
78679             }
78680           }
78681
78682           function renderSvgIcon(container, picon, geom, isFramed, category, tagClasses) {
78683             var isMaki = picon && /^maki-/.test(picon);
78684             var isTemaki = picon && /^temaki-/.test(picon);
78685             var isFa = picon && /^fa[srb]-/.test(picon);
78686             var isiDIcon = picon && !(isMaki || isTemaki || isFa);
78687             var icon = container.selectAll('.preset-icon').data(picon ? [0] : []);
78688             icon.exit().remove();
78689             icon = icon.enter().append('div').attr('class', 'preset-icon').call(svgIcon('')).merge(icon);
78690             icon.attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')).classed('category', category).classed('framed', isFramed).classed('preset-icon-iD', isiDIcon);
78691             icon.selectAll('svg').attr('class', 'icon ' + picon + ' ' + (!isiDIcon && geom !== 'line' ? '' : tagClasses));
78692             var suffix = '';
78693
78694             if (isMaki) {
78695               suffix = isSmall() && geom === 'point' ? '-11' : '-15';
78696             }
78697
78698             icon.selectAll('use').attr('href', '#' + picon + suffix);
78699           }
78700
78701           function renderImageIcon(container, imageURL) {
78702             var imageIcon = container.selectAll('img.image-icon').data(imageURL ? [0] : []);
78703             imageIcon.exit().remove();
78704             imageIcon = imageIcon.enter().append('img').attr('class', 'image-icon').on('load', function () {
78705               return container.classed('showing-img', true);
78706             }).on('error', function () {
78707               return container.classed('showing-img', false);
78708             }).merge(imageIcon);
78709             imageIcon.attr('src', imageURL);
78710           } // Route icons are drawn with a zigzag annotation underneath:
78711           //     o   o
78712           //    / \ /
78713           //   o   o
78714           // This dataset defines the styles that are used to draw the zigzag segments.
78715
78716
78717           var routeSegments = {
78718             bicycle: ['highway/cycleway', 'highway/cycleway', 'highway/cycleway'],
78719             bus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
78720             trolleybus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
78721             detour: ['highway/tertiary', 'highway/residential', 'highway/unclassified'],
78722             ferry: ['route/ferry', 'route/ferry', 'route/ferry'],
78723             foot: ['highway/footway', 'highway/footway', 'highway/footway'],
78724             hiking: ['highway/path', 'highway/path', 'highway/path'],
78725             horse: ['highway/bridleway', 'highway/bridleway', 'highway/bridleway'],
78726             light_rail: ['railway/light_rail', 'railway/light_rail', 'railway/light_rail'],
78727             monorail: ['railway/monorail', 'railway/monorail', 'railway/monorail'],
78728             mtb: ['highway/path', 'highway/track', 'highway/bridleway'],
78729             pipeline: ['man_made/pipeline', 'man_made/pipeline', 'man_made/pipeline'],
78730             piste: ['piste/downhill', 'piste/hike', 'piste/nordic'],
78731             power: ['power/line', 'power/line', 'power/line'],
78732             road: ['highway/secondary', 'highway/primary', 'highway/trunk'],
78733             subway: ['railway/subway', 'railway/subway', 'railway/subway'],
78734             train: ['railway/rail', 'railway/rail', 'railway/rail'],
78735             tram: ['railway/tram', 'railway/tram', 'railway/tram'],
78736             waterway: ['waterway/stream', 'waterway/stream', 'waterway/stream']
78737           };
78738
78739           function render() {
78740             var p = _preset.apply(this, arguments);
78741
78742             var geom = _geometry ? _geometry.apply(this, arguments) : null;
78743
78744             if (geom === 'relation' && p.tags && (p.tags.type === 'route' && p.tags.route && routeSegments[p.tags.route] || p.tags.type === 'waterway')) {
78745               geom = 'route';
78746             }
78747
78748             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
78749             var isFallback = isSmall() && p.isFallback && p.isFallback();
78750             var imageURL = showThirdPartyIcons === 'true' && p.imageURL;
78751             var picon = getIcon(p, geom);
78752             var isCategory = !p.setTags;
78753             var drawPoint = picon && geom === 'point' && isSmall() && !isFallback;
78754             var drawVertex = picon !== null && geom === 'vertex' && (!isSmall() || !isFallback);
78755             var drawLine = picon && geom === 'line' && !isFallback && !isCategory;
78756             var drawArea = picon && geom === 'area' && !isFallback && !isCategory;
78757             var drawRoute = picon && geom === 'route';
78758             var isFramed = drawVertex || drawArea || drawLine || drawRoute || isCategory;
78759             var tags = !isCategory ? p.setTags({}, geom) : {};
78760
78761             for (var k in tags) {
78762               if (tags[k] === '*') {
78763                 tags[k] = 'yes';
78764               }
78765             }
78766
78767             var tagClasses = svgTagClasses().getClassesString(tags, '');
78768             var selection = select(this);
78769             var container = selection.selectAll('.preset-icon-container').data([0]);
78770             container = container.enter().append('div').attr('class', "preset-icon-container ".concat(_sizeClass)).merge(container);
78771             container.classed('showing-img', !!imageURL).classed('fallback', isFallback);
78772             renderCategoryBorder(container, isCategory && p);
78773             renderPointBorder(container, drawPoint);
78774             renderCircleFill(container, drawVertex);
78775             renderSquareFill(container, drawArea, tagClasses);
78776             renderLine(container, drawLine, tagClasses);
78777             renderRoute(container, drawRoute, p);
78778             renderSvgIcon(container, picon, geom, isFramed, isCategory, tagClasses);
78779             renderImageIcon(container, imageURL);
78780           }
78781
78782           presetIcon.preset = function (val) {
78783             if (!arguments.length) return _preset;
78784             _preset = utilFunctor(val);
78785             return presetIcon;
78786           };
78787
78788           presetIcon.geometry = function (val) {
78789             if (!arguments.length) return _geometry;
78790             _geometry = utilFunctor(val);
78791             return presetIcon;
78792           };
78793
78794           presetIcon.sizeClass = function (val) {
78795             if (!arguments.length) return _sizeClass;
78796             _sizeClass = val;
78797             return presetIcon;
78798           };
78799
78800           return presetIcon;
78801         }
78802
78803         function uiSectionFeatureType(context) {
78804           var dispatch = dispatch$8('choose');
78805           var _entityIDs = [];
78806           var _presets = [];
78807
78808           var _tagReference;
78809
78810           var section = uiSection('feature-type', context).label(_t.html('inspector.feature_type')).disclosureContent(renderDisclosureContent);
78811
78812           function renderDisclosureContent(selection) {
78813             selection.classed('preset-list-item', true);
78814             selection.classed('mixed-types', _presets.length > 1);
78815             var presetButtonWrap = selection.selectAll('.preset-list-button-wrap').data([0]).enter().append('div').attr('class', 'preset-list-button-wrap');
78816             var presetButton = presetButtonWrap.append('button').attr('class', 'preset-list-button preset-reset').call(uiTooltip().title(_t.html('inspector.back_tooltip')).placement('bottom'));
78817             presetButton.append('div').attr('class', 'preset-icon-container');
78818             presetButton.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
78819             presetButtonWrap.append('div').attr('class', 'accessory-buttons');
78820             var tagReferenceBodyWrap = selection.selectAll('.tag-reference-body-wrap').data([0]);
78821             tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append('div').attr('class', 'tag-reference-body-wrap').merge(tagReferenceBodyWrap); // update header
78822
78823             if (_tagReference) {
78824               selection.selectAll('.preset-list-button-wrap .accessory-buttons').style('display', _presets.length === 1 ? null : 'none').call(_tagReference.button);
78825               tagReferenceBodyWrap.style('display', _presets.length === 1 ? null : 'none').call(_tagReference.body);
78826             }
78827
78828             selection.selectAll('.preset-reset').on('click', function () {
78829               dispatch.call('choose', this, _presets);
78830             }).on('pointerdown pointerup mousedown mouseup', function (d3_event) {
78831               d3_event.preventDefault();
78832               d3_event.stopPropagation();
78833             });
78834             var geometries = entityGeometries();
78835             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')));
78836             var names = _presets.length === 1 ? [_presets[0].nameLabel(), _presets[0].subtitleLabel()].filter(Boolean) : [_t('inspector.multiple_types')];
78837             var label = selection.select('.label-inner');
78838             var nameparts = label.selectAll('.namepart').data(names, function (d) {
78839               return d;
78840             });
78841             nameparts.exit().remove();
78842             nameparts.enter().append('div').attr('class', 'namepart').html(function (d) {
78843               return d;
78844             });
78845           }
78846
78847           section.entityIDs = function (val) {
78848             if (!arguments.length) return _entityIDs;
78849             _entityIDs = val;
78850             return section;
78851           };
78852
78853           section.presets = function (val) {
78854             if (!arguments.length) return _presets; // don't reload the same preset
78855
78856             if (!utilArrayIdentical(val, _presets)) {
78857               _presets = val;
78858
78859               if (_presets.length === 1) {
78860                 _tagReference = uiTagReference(_presets[0].reference()).showing(false);
78861               }
78862             }
78863
78864             return section;
78865           };
78866
78867           function entityGeometries() {
78868             var counts = {};
78869
78870             for (var i in _entityIDs) {
78871               var geometry = context.graph().geometry(_entityIDs[i]);
78872               if (!counts[geometry]) counts[geometry] = 0;
78873               counts[geometry] += 1;
78874             }
78875
78876             return Object.keys(counts).sort(function (geom1, geom2) {
78877               return counts[geom2] - counts[geom1];
78878             });
78879           }
78880
78881           return utilRebind(section, dispatch, 'on');
78882         }
78883
78884         // It borrows some code from uiHelp
78885
78886         function uiFieldHelp(context, fieldName) {
78887           var fieldHelp = {};
78888
78889           var _inspector = select(null);
78890
78891           var _wrap = select(null);
78892
78893           var _body = select(null);
78894
78895           var fieldHelpKeys = {
78896             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']]]
78897           };
78898           var fieldHelpHeadings = {};
78899           var replacements = {
78900             distField: _t.html('restriction.controls.distance'),
78901             viaField: _t.html('restriction.controls.via'),
78902             fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
78903             allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
78904             restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
78905             onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
78906             allowTurn: icon('#iD-turn-yes', 'inline turn'),
78907             restrictTurn: icon('#iD-turn-no', 'inline turn'),
78908             onlyTurn: icon('#iD-turn-only', 'inline turn')
78909           }; // For each section, squash all the texts into a single markdown document
78910
78911           var docs = fieldHelpKeys[fieldName].map(function (key) {
78912             var helpkey = 'help.field.' + fieldName + '.' + key[0];
78913             var text = key[1].reduce(function (all, part) {
78914               var subkey = helpkey + '.' + part;
78915               var depth = fieldHelpHeadings[subkey]; // is this subkey a heading?
78916
78917               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
78918
78919               return all + hhh + _t.html(subkey, replacements) + '\n\n';
78920             }, '');
78921             return {
78922               key: helpkey,
78923               title: _t.html(helpkey + '.title'),
78924               html: marked_1(text.trim())
78925             };
78926           });
78927
78928           function show() {
78929             updatePosition();
78930
78931             _body.classed('hide', false).style('opacity', '0').transition().duration(200).style('opacity', '1');
78932           }
78933
78934           function hide() {
78935             _body.classed('hide', true).transition().duration(200).style('opacity', '0').on('end', function () {
78936               _body.classed('hide', true);
78937             });
78938           }
78939
78940           function clickHelp(index) {
78941             var d = docs[index];
78942             var tkeys = fieldHelpKeys[fieldName][index][1];
78943
78944             _body.selectAll('.field-help-nav-item').classed('active', function (d, i) {
78945               return i === index;
78946             });
78947
78948             var content = _body.selectAll('.field-help-content').html(d.html); // class the paragraphs so we can find and style them
78949
78950
78951             content.selectAll('p').attr('class', function (d, i) {
78952               return tkeys[i];
78953             }); // insert special content for certain help sections
78954
78955             if (d.key === 'help.field.restrictions.inspecting') {
78956               content.insert('img', 'p.from_shadow').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_inspect.gif'));
78957             } else if (d.key === 'help.field.restrictions.modifying') {
78958               content.insert('img', 'p.allow_turn').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_modify.gif'));
78959             }
78960           }
78961
78962           fieldHelp.button = function (selection) {
78963             if (_body.empty()) return;
78964             var button = selection.selectAll('.field-help-button').data([0]); // enter/update
78965
78966             button.enter().append('button').attr('class', 'field-help-button').call(svgIcon('#iD-icon-help')).merge(button).on('click', function (d3_event) {
78967               d3_event.stopPropagation();
78968               d3_event.preventDefault();
78969
78970               if (_body.classed('hide')) {
78971                 show();
78972               } else {
78973                 hide();
78974               }
78975             });
78976           };
78977
78978           function updatePosition() {
78979             var wrap = _wrap.node();
78980
78981             var inspector = _inspector.node();
78982
78983             var wRect = wrap.getBoundingClientRect();
78984             var iRect = inspector.getBoundingClientRect();
78985
78986             _body.style('top', wRect.top + inspector.scrollTop - iRect.top + 'px');
78987           }
78988
78989           fieldHelp.body = function (selection) {
78990             // This control expects the field to have a form-field-input-wrap div
78991             _wrap = selection.selectAll('.form-field-input-wrap');
78992             if (_wrap.empty()) return; // absolute position relative to the inspector, so it "floats" above the fields
78993
78994             _inspector = context.container().select('.sidebar .entity-editor-pane .inspector-body');
78995             if (_inspector.empty()) return;
78996             _body = _inspector.selectAll('.field-help-body').data([0]);
78997
78998             var enter = _body.enter().append('div').attr('class', 'field-help-body hide'); // initially hidden
78999
79000
79001             var titleEnter = enter.append('div').attr('class', 'field-help-title cf');
79002             titleEnter.append('h2').attr('class', _mainLocalizer.textDirection() === 'rtl' ? 'fr' : 'fl').html(_t.html('help.field.' + fieldName + '.title'));
79003             titleEnter.append('button').attr('class', 'fr close').on('click', function (d3_event) {
79004               d3_event.stopPropagation();
79005               d3_event.preventDefault();
79006               hide();
79007             }).call(svgIcon('#iD-icon-close'));
79008             var navEnter = enter.append('div').attr('class', 'field-help-nav cf');
79009             var titles = docs.map(function (d) {
79010               return d.title;
79011             });
79012             navEnter.selectAll('.field-help-nav-item').data(titles).enter().append('div').attr('class', 'field-help-nav-item').html(function (d) {
79013               return d;
79014             }).on('click', function (d3_event, d) {
79015               d3_event.stopPropagation();
79016               d3_event.preventDefault();
79017               clickHelp(titles.indexOf(d));
79018             });
79019             enter.append('div').attr('class', 'field-help-content');
79020             _body = _body.merge(enter);
79021             clickHelp(0);
79022           };
79023
79024           return fieldHelp;
79025         }
79026
79027         function uiFieldCheck(field, context) {
79028           var dispatch = dispatch$8('change');
79029           var options = field.options;
79030           var values = [];
79031           var texts = [];
79032
79033           var _tags;
79034
79035           var input = select(null);
79036           var text = select(null);
79037           var label = select(null);
79038           var reverser = select(null);
79039
79040           var _impliedYes;
79041
79042           var _entityIDs = [];
79043
79044           var _value;
79045
79046           if (options) {
79047             for (var i in options) {
79048               var v = options[i];
79049               values.push(v === 'undefined' ? undefined : v);
79050               texts.push(field.t.html('options.' + v, {
79051                 'default': v
79052               }));
79053             }
79054           } else {
79055             values = [undefined, 'yes'];
79056             texts = [_t.html('inspector.unknown'), _t.html('inspector.check.yes')];
79057
79058             if (field.type !== 'defaultCheck') {
79059               values.push('no');
79060               texts.push(_t.html('inspector.check.no'));
79061             }
79062           } // Checks tags to see whether an undefined value is "Assumed to be Yes"
79063
79064
79065           function checkImpliedYes() {
79066             _impliedYes = field.id === 'oneway_yes'; // hack: pretend `oneway` field is a `oneway_yes` field
79067             // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
79068
79069             if (field.id === 'oneway') {
79070               var entity = context.entity(_entityIDs[0]);
79071
79072               for (var key in entity.tags) {
79073                 if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
79074                   _impliedYes = true;
79075                   texts[0] = _t.html('_tagging.presets.fields.oneway_yes.options.undefined');
79076                   break;
79077                 }
79078               }
79079             }
79080           }
79081
79082           function reverserHidden() {
79083             if (!context.container().select('div.inspector-hover').empty()) return true;
79084             return !(_value === 'yes' || _impliedYes && !_value);
79085           }
79086
79087           function reverserSetText(selection) {
79088             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
79089             if (reverserHidden() || !entity) return selection;
79090             var first = entity.first();
79091             var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
79092             var pseudoDirection = first < last;
79093             var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
79094             selection.selectAll('.reverser-span').html(_t.html('inspector.check.reverser')).call(svgIcon(icon, 'inline'));
79095             return selection;
79096           }
79097
79098           var check = function check(selection) {
79099             checkImpliedYes();
79100             label = selection.selectAll('.form-field-input-wrap').data([0]);
79101             var enter = label.enter().append('label').attr('class', 'form-field-input-wrap form-field-input-check');
79102             enter.append('input').property('indeterminate', field.type !== 'defaultCheck').attr('type', 'checkbox').attr('id', field.domId);
79103             enter.append('span').html(texts[0]).attr('class', 'value');
79104
79105             if (field.type === 'onewayCheck') {
79106               enter.append('button').attr('class', 'reverser' + (reverserHidden() ? ' hide' : '')).append('span').attr('class', 'reverser-span');
79107             }
79108
79109             label = label.merge(enter);
79110             input = label.selectAll('input');
79111             text = label.selectAll('span.value');
79112             input.on('click', function (d3_event) {
79113               d3_event.stopPropagation();
79114               var t = {};
79115
79116               if (Array.isArray(_tags[field.key])) {
79117                 if (values.indexOf('yes') !== -1) {
79118                   t[field.key] = 'yes';
79119                 } else {
79120                   t[field.key] = values[0];
79121                 }
79122               } else {
79123                 t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
79124               } // Don't cycle through `alternating` or `reversible` states - #4970
79125               // (They are supported as translated strings, but should not toggle with clicks)
79126
79127
79128               if (t[field.key] === 'reversible' || t[field.key] === 'alternating') {
79129                 t[field.key] = values[0];
79130               }
79131
79132               dispatch.call('change', this, t);
79133             });
79134
79135             if (field.type === 'onewayCheck') {
79136               reverser = label.selectAll('.reverser');
79137               reverser.call(reverserSetText).on('click', function (d3_event) {
79138                 d3_event.preventDefault();
79139                 d3_event.stopPropagation();
79140                 context.perform(function (graph) {
79141                   for (var i in _entityIDs) {
79142                     graph = actionReverse(_entityIDs[i])(graph);
79143                   }
79144
79145                   return graph;
79146                 }, _t('operations.reverse.annotation.line', {
79147                   n: 1
79148                 })); // must manually revalidate since no 'change' event was called
79149
79150                 context.validator().validate();
79151                 select(this).call(reverserSetText);
79152               });
79153             }
79154           };
79155
79156           check.entityIDs = function (val) {
79157             if (!arguments.length) return _entityIDs;
79158             _entityIDs = val;
79159             return check;
79160           };
79161
79162           check.tags = function (tags) {
79163             _tags = tags;
79164
79165             function isChecked(val) {
79166               return val !== 'no' && val !== '' && val !== undefined && val !== null;
79167             }
79168
79169             function textFor(val) {
79170               if (val === '') val = undefined;
79171               var index = values.indexOf(val);
79172               return index !== -1 ? texts[index] : '"' + val + '"';
79173             }
79174
79175             checkImpliedYes();
79176             var isMixed = Array.isArray(tags[field.key]);
79177             _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
79178
79179             if (field.type === 'onewayCheck' && (_value === '1' || _value === '-1')) {
79180               _value = 'yes';
79181             }
79182
79183             input.property('indeterminate', isMixed || field.type !== 'defaultCheck' && !_value).property('checked', isChecked(_value));
79184             text.html(isMixed ? _t.html('inspector.multiple_values') : textFor(_value)).classed('mixed', isMixed);
79185             label.classed('set', !!_value);
79186
79187             if (field.type === 'onewayCheck') {
79188               reverser.classed('hide', reverserHidden()).call(reverserSetText);
79189             }
79190           };
79191
79192           check.focus = function () {
79193             input.node().focus();
79194           };
79195
79196           return utilRebind(check, dispatch, 'on');
79197         }
79198
79199         function uiFieldCombo(field, context) {
79200           var dispatch = dispatch$8('change');
79201
79202           var _isMulti = field.type === 'multiCombo' || field.type === 'manyCombo';
79203
79204           var _isNetwork = field.type === 'networkCombo';
79205
79206           var _isSemi = field.type === 'semiCombo';
79207
79208           var _optarray = field.options;
79209
79210           var _showTagInfoSuggestions = field.type !== 'manyCombo' && field.autoSuggestions !== false;
79211
79212           var _allowCustomValues = field.type !== 'manyCombo' && field.customValues !== false;
79213
79214           var _snake_case = field.snake_case || field.snake_case === undefined;
79215
79216           var _combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(field.caseSensitive).minItems(_isMulti || _isSemi ? 1 : 2);
79217
79218           var _container = select(null);
79219
79220           var _inputWrap = select(null);
79221
79222           var _input = select(null);
79223
79224           var _comboData = [];
79225           var _multiData = [];
79226           var _entityIDs = [];
79227
79228           var _tags;
79229
79230           var _countryCode;
79231
79232           var _staticPlaceholder; // initialize deprecated tags array
79233
79234
79235           var _dataDeprecated = [];
79236           _mainFileFetcher.get('deprecated').then(function (d) {
79237             _dataDeprecated = d;
79238           })["catch"](function () {
79239             /* ignore */
79240           }); // ensure multiCombo field.key ends with a ':'
79241
79242           if (_isMulti && field.key && /[^:]$/.test(field.key)) {
79243             field.key += ':';
79244           }
79245
79246           function snake(s) {
79247             return s.replace(/\s+/g, '_').toLowerCase();
79248           }
79249
79250           function clean(s) {
79251             return s.split(';').map(function (s) {
79252               return s.trim();
79253             }).join(';');
79254           } // returns the tag value for a display value
79255           // (for multiCombo, dval should be the key suffix, not the entire key)
79256
79257
79258           function tagValue(dval) {
79259             dval = clean(dval || '');
79260
79261             var found = _comboData.find(function (o) {
79262               return o.key && clean(o.value) === dval;
79263             });
79264
79265             if (found) return found.key;
79266
79267             if (field.type === 'typeCombo' && !dval) {
79268               return 'yes';
79269             }
79270
79271             return (_snake_case ? snake(dval) : dval) || undefined;
79272           } // returns the display value for a tag value
79273           // (for multiCombo, tval should be the key suffix, not the entire key)
79274
79275
79276           function displayValue(tval) {
79277             tval = tval || '';
79278
79279             if (field.hasTextForStringId('options.' + tval)) {
79280               return field.t('options.' + tval, {
79281                 "default": tval
79282               });
79283             }
79284
79285             if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
79286               return '';
79287             }
79288
79289             return tval;
79290           } // Compute the difference between arrays of objects by `value` property
79291           //
79292           // objectDifference([{value:1}, {value:2}, {value:3}], [{value:2}])
79293           // > [{value:1}, {value:3}]
79294           //
79295
79296
79297           function objectDifference(a, b) {
79298             return a.filter(function (d1) {
79299               return !b.some(function (d2) {
79300                 return !d2.isMixed && d1.value === d2.value;
79301               });
79302             });
79303           }
79304
79305           function initCombo(selection, attachTo) {
79306             if (!_allowCustomValues) {
79307               selection.attr('readonly', 'readonly');
79308             }
79309
79310             if (_showTagInfoSuggestions && services.taginfo) {
79311               selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
79312               setTaginfoValues('', setPlaceholder);
79313             } else {
79314               selection.call(_combobox, attachTo);
79315               setStaticValues(setPlaceholder);
79316             }
79317           }
79318
79319           function setStaticValues(callback) {
79320             if (!_optarray) return;
79321             _comboData = _optarray.map(function (v) {
79322               return {
79323                 key: v,
79324                 value: field.t('options.' + v, {
79325                   "default": v
79326                 }),
79327                 title: v,
79328                 display: field.t.html('options.' + v, {
79329                   "default": v
79330                 }),
79331                 klass: field.hasTextForStringId('options.' + v) ? '' : 'raw-option'
79332               };
79333             });
79334
79335             _combobox.data(objectDifference(_comboData, _multiData));
79336
79337             if (callback) callback(_comboData);
79338           }
79339
79340           function setTaginfoValues(q, callback) {
79341             var fn = _isMulti ? 'multikeys' : 'values';
79342             var query = (_isMulti ? field.key : '') + q;
79343             var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
79344
79345             if (hasCountryPrefix) {
79346               query = _countryCode + ':';
79347             }
79348
79349             var params = {
79350               debounce: q !== '',
79351               key: field.key,
79352               query: query
79353             };
79354
79355             if (_entityIDs.length) {
79356               params.geometry = context.graph().geometry(_entityIDs[0]);
79357             }
79358
79359             services.taginfo[fn](params, function (err, data) {
79360               if (err) return;
79361               data = data.filter(function (d) {
79362                 if (field.type === 'typeCombo' && d.value === 'yes') {
79363                   // don't show the fallback value
79364                   return false;
79365                 } // don't show values with very low usage
79366
79367
79368                 return !d.count || d.count > 10;
79369               });
79370               var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
79371
79372               if (deprecatedValues) {
79373                 // don't suggest deprecated tag values
79374                 data = data.filter(function (d) {
79375                   return deprecatedValues.indexOf(d.value) === -1;
79376                 });
79377               }
79378
79379               if (hasCountryPrefix) {
79380                 data = data.filter(function (d) {
79381                   return d.value.toLowerCase().indexOf(_countryCode + ':') === 0;
79382                 });
79383               } // hide the caret if there are no suggestions
79384
79385
79386               _container.classed('empty-combobox', data.length === 0);
79387
79388               _comboData = data.map(function (d) {
79389                 var k = d.value;
79390                 if (_isMulti) k = k.replace(field.key, '');
79391                 var label = field.t('options.' + k, {
79392                   "default": k
79393                 });
79394                 return {
79395                   key: k,
79396                   value: label,
79397                   display: field.t.html('options.' + k, {
79398                     "default": k
79399                   }),
79400                   title: d.title || label,
79401                   klass: field.hasTextForStringId('options.' + k) ? '' : 'raw-option'
79402                 };
79403               });
79404               _comboData = objectDifference(_comboData, _multiData);
79405               if (callback) callback(_comboData);
79406             });
79407           }
79408
79409           function setPlaceholder(values) {
79410             if (_isMulti || _isSemi) {
79411               _staticPlaceholder = field.placeholder() || _t('inspector.add');
79412             } else {
79413               var vals = values.map(function (d) {
79414                 return d.value;
79415               }).filter(function (s) {
79416                 return s.length < 20;
79417               });
79418               var placeholders = vals.length > 1 ? vals : values.map(function (d) {
79419                 return d.key;
79420               });
79421               _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(', ');
79422             }
79423
79424             if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
79425               _staticPlaceholder += '…';
79426             }
79427
79428             var ph;
79429
79430             if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
79431               ph = _t('inspector.multiple_values');
79432             } else {
79433               ph = _staticPlaceholder;
79434             }
79435
79436             _container.selectAll('input').attr('placeholder', ph);
79437           }
79438
79439           function change() {
79440             var t = {};
79441             var val;
79442
79443             if (_isMulti || _isSemi) {
79444               val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
79445
79446               _container.classed('active', false);
79447
79448               utilGetSetValue(_input, '');
79449               var vals = val.split(';').filter(Boolean);
79450               if (!vals.length) return;
79451
79452               if (_isMulti) {
79453                 utilArrayUniq(vals).forEach(function (v) {
79454                   var key = (field.key || '') + v;
79455
79456                   if (_tags) {
79457                     // don't set a multicombo value to 'yes' if it already has a non-'no' value
79458                     // e.g. `language:de=main`
79459                     var old = _tags[key];
79460                     if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
79461                   }
79462
79463                   key = context.cleanTagKey(key);
79464                   field.keys.push(key);
79465                   t[key] = 'yes';
79466                 });
79467               } else if (_isSemi) {
79468                 var arr = _multiData.map(function (d) {
79469                   return d.key;
79470                 });
79471
79472                 arr = arr.concat(vals);
79473                 t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
79474               }
79475
79476               window.setTimeout(function () {
79477                 _input.node().focus();
79478               }, 10);
79479             } else {
79480               var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string
79481
79482               if (!rawValue && Array.isArray(_tags[field.key])) return;
79483               val = context.cleanTagValue(tagValue(rawValue));
79484               t[field.key] = val || undefined;
79485             }
79486
79487             dispatch.call('change', this, t);
79488           }
79489
79490           function removeMultikey(d3_event, d) {
79491             d3_event.preventDefault();
79492             d3_event.stopPropagation();
79493             var t = {};
79494
79495             if (_isMulti) {
79496               t[d.key] = undefined;
79497             } else if (_isSemi) {
79498               var arr = _multiData.map(function (md) {
79499                 return md.key === d.key ? null : md.key;
79500               }).filter(Boolean);
79501
79502               arr = utilArrayUniq(arr);
79503               t[field.key] = arr.length ? arr.join(';') : undefined;
79504             }
79505
79506             dispatch.call('change', this, t);
79507           }
79508
79509           function combo(selection) {
79510             _container = selection.selectAll('.form-field-input-wrap').data([0]);
79511             var type = _isMulti || _isSemi ? 'multicombo' : 'combo';
79512             _container = _container.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + type).merge(_container);
79513
79514             if (_isMulti || _isSemi) {
79515               _container = _container.selectAll('.chiplist').data([0]);
79516               var listClass = 'chiplist'; // Use a separate line for each value in the Destinations and Via fields
79517               // to mimic highway exit signs
79518
79519               if (field.key === 'destination' || field.key === 'via') {
79520                 listClass += ' full-line-chips';
79521               }
79522
79523               _container = _container.enter().append('ul').attr('class', listClass).on('click', function () {
79524                 window.setTimeout(function () {
79525                   _input.node().focus();
79526                 }, 10);
79527               }).merge(_container);
79528               _inputWrap = _container.selectAll('.input-wrap').data([0]);
79529               _inputWrap = _inputWrap.enter().append('li').attr('class', 'input-wrap').merge(_inputWrap);
79530               _input = _inputWrap.selectAll('input').data([0]);
79531             } else {
79532               _input = _container.selectAll('input').data([0]);
79533             }
79534
79535             _input = _input.enter().append('input').attr('type', 'text').attr('id', field.domId).call(utilNoAuto).call(initCombo, selection).merge(_input);
79536
79537             if (_isNetwork) {
79538               var extent = combinedEntityExtent();
79539               var countryCode = extent && iso1A2Code(extent.center());
79540               _countryCode = countryCode && countryCode.toLowerCase();
79541             }
79542
79543             _input.on('change', change).on('blur', change);
79544
79545             _input.on('keydown.field', function (d3_event) {
79546               switch (d3_event.keyCode) {
79547                 case 13:
79548                   // ↩ Return
79549                   _input.node().blur(); // blurring also enters the value
79550
79551
79552                   d3_event.stopPropagation();
79553                   break;
79554               }
79555             });
79556
79557             if (_isMulti || _isSemi) {
79558               _combobox.on('accept', function () {
79559                 _input.node().blur();
79560
79561                 _input.node().focus();
79562               });
79563
79564               _input.on('focus', function () {
79565                 _container.classed('active', true);
79566               });
79567             }
79568           }
79569
79570           combo.tags = function (tags) {
79571             _tags = tags;
79572
79573             if (_isMulti || _isSemi) {
79574               _multiData = [];
79575               var maxLength;
79576
79577               if (_isMulti) {
79578                 // Build _multiData array containing keys already set..
79579                 for (var k in tags) {
79580                   if (field.key && k.indexOf(field.key) !== 0) continue;
79581                   if (!field.key && field.keys.indexOf(k) === -1) continue;
79582                   var v = tags[k];
79583                   if (!v || typeof v === 'string' && v.toLowerCase() === 'no') continue;
79584                   var suffix = field.key ? k.substr(field.key.length) : k;
79585
79586                   _multiData.push({
79587                     key: k,
79588                     value: displayValue(suffix),
79589                     isMixed: Array.isArray(v)
79590                   });
79591                 }
79592
79593                 if (field.key) {
79594                   // Set keys for form-field modified (needed for undo and reset buttons)..
79595                   field.keys = _multiData.map(function (d) {
79596                     return d.key;
79597                   }); // limit the input length so it fits after prepending the key prefix
79598
79599                   maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
79600                 } else {
79601                   maxLength = context.maxCharsForTagKey();
79602                 }
79603               } else if (_isSemi) {
79604                 var allValues = [];
79605                 var commonValues;
79606
79607                 if (Array.isArray(tags[field.key])) {
79608                   tags[field.key].forEach(function (tagVal) {
79609                     var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
79610                     allValues = allValues.concat(thisVals);
79611
79612                     if (!commonValues) {
79613                       commonValues = thisVals;
79614                     } else {
79615                       commonValues = commonValues.filter(function (value) {
79616                         return thisVals.includes(value);
79617                       });
79618                     }
79619                   });
79620                   allValues = utilArrayUniq(allValues).filter(Boolean);
79621                 } else {
79622                   allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
79623                   commonValues = allValues;
79624                 }
79625
79626                 _multiData = allValues.map(function (v) {
79627                   return {
79628                     key: v,
79629                     value: displayValue(v),
79630                     isMixed: !commonValues.includes(v)
79631                   };
79632                 });
79633                 var currLength = utilUnicodeCharsCount(commonValues.join(';')); // limit the input length to the remaining available characters
79634
79635                 maxLength = context.maxCharsForTagValue() - currLength;
79636
79637                 if (currLength > 0) {
79638                   // account for the separator if a new value will be appended to existing
79639                   maxLength -= 1;
79640                 }
79641               } // a negative maxlength doesn't make sense
79642
79643
79644               maxLength = Math.max(0, maxLength);
79645               var allowDragAndDrop = _isSemi // only semiCombo values are ordered
79646               && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options..
79647
79648               var available = objectDifference(_comboData, _multiData);
79649
79650               _combobox.data(available); // Hide 'Add' button if this field uses fixed set of
79651               // options and they're all currently used,
79652               // or if the field is already at its character limit
79653
79654
79655               var hideAdd = !_allowCustomValues && !available.length || maxLength <= 0;
79656
79657               _container.selectAll('.chiplist .input-wrap').style('display', hideAdd ? 'none' : null); // Render chips
79658
79659
79660               var chips = _container.selectAll('.chip').data(_multiData);
79661
79662               chips.exit().remove();
79663               var enter = chips.enter().insert('li', '.input-wrap').attr('class', 'chip');
79664               enter.append('span');
79665               enter.append('a');
79666               chips = chips.merge(enter).order().classed('raw-value', function (d) {
79667                 var k = d.key;
79668                 if (_isMulti) k = k.replace(field.key, '');
79669                 return !field.hasTextForStringId('options.' + k);
79670               }).classed('draggable', allowDragAndDrop).classed('mixed', function (d) {
79671                 return d.isMixed;
79672               }).attr('title', function (d) {
79673                 return d.isMixed ? _t('inspector.unshared_value_tooltip') : null;
79674               });
79675
79676               if (allowDragAndDrop) {
79677                 registerDragAndDrop(chips);
79678               }
79679
79680               chips.select('span').html(function (d) {
79681                 return d.value;
79682               });
79683               chips.select('a').attr('href', '#').on('click', removeMultikey).attr('class', 'remove').html('×');
79684             } else {
79685               var isMixed = Array.isArray(tags[field.key]);
79686               var mixedValues = isMixed && tags[field.key].map(function (val) {
79687                 return displayValue(val);
79688               }).filter(Boolean);
79689               var showsValue = !isMixed && tags[field.key] && !(field.type === 'typeCombo' && tags[field.key] === 'yes');
79690               var isRawValue = showsValue && !field.hasTextForStringId('options.' + tags[field.key]);
79691               var isKnownValue = showsValue && !isRawValue;
79692               var isReadOnly = !_allowCustomValues || isKnownValue;
79693               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) {
79694                 if (isReadOnly && isKnownValue && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
79695                   d3_event.preventDefault();
79696                   d3_event.stopPropagation();
79697                   var t = {};
79698                   t[field.key] = undefined;
79699                   dispatch.call('change', this, t);
79700                 }
79701               });
79702             }
79703           };
79704
79705           function registerDragAndDrop(selection) {
79706             // allow drag and drop re-ordering of chips
79707             var dragOrigin, targetIndex;
79708             selection.call(d3_drag().on('start', function (d3_event) {
79709               dragOrigin = {
79710                 x: d3_event.x,
79711                 y: d3_event.y
79712               };
79713               targetIndex = null;
79714             }).on('drag', function (d3_event) {
79715               var x = d3_event.x - dragOrigin.x,
79716                   y = d3_event.y - dragOrigin.y;
79717               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
79718               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
79719               var index = selection.nodes().indexOf(this);
79720               select(this).classed('dragging', true);
79721               targetIndex = null;
79722               var targetIndexOffsetTop = null;
79723               var draggedTagWidth = select(this).node().offsetWidth;
79724
79725               if (field.key === 'destination' || field.key === 'via') {
79726                 // meaning tags are full width
79727                 _container.selectAll('.chip').style('transform', function (d2, index2) {
79728                   var node = select(this).node();
79729
79730                   if (index === index2) {
79731                     return 'translate(' + x + 'px, ' + y + 'px)'; // move the dragged tag up the order
79732                   } else if (index2 > index && d3_event.y > node.offsetTop) {
79733                     if (targetIndex === null || index2 > targetIndex) {
79734                       targetIndex = index2;
79735                     }
79736
79737                     return 'translateY(-100%)'; // move the dragged tag down the order
79738                   } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
79739                     if (targetIndex === null || index2 < targetIndex) {
79740                       targetIndex = index2;
79741                     }
79742
79743                     return 'translateY(100%)';
79744                   }
79745
79746                   return null;
79747                 });
79748               } else {
79749                 _container.selectAll('.chip').each(function (d2, index2) {
79750                   var node = select(this).node(); // check the cursor is in the bounding box
79751
79752                   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) {
79753                     targetIndex = index2;
79754                     targetIndexOffsetTop = node.offsetTop;
79755                   }
79756                 }).style('transform', function (d2, index2) {
79757                   var node = select(this).node();
79758
79759                   if (index === index2) {
79760                     return 'translate(' + x + 'px, ' + y + 'px)';
79761                   } // only translate tags in the same row
79762
79763
79764                   if (node.offsetTop === targetIndexOffsetTop) {
79765                     if (index2 < index && index2 >= targetIndex) {
79766                       return 'translateX(' + draggedTagWidth + 'px)';
79767                     } else if (index2 > index && index2 <= targetIndex) {
79768                       return 'translateX(-' + draggedTagWidth + 'px)';
79769                     }
79770                   }
79771
79772                   return null;
79773                 });
79774               }
79775             }).on('end', function () {
79776               if (!select(this).classed('dragging')) {
79777                 return;
79778               }
79779
79780               var index = selection.nodes().indexOf(this);
79781               select(this).classed('dragging', false);
79782
79783               _container.selectAll('.chip').style('transform', null);
79784
79785               if (typeof targetIndex === 'number') {
79786                 var element = _multiData[index];
79787
79788                 _multiData.splice(index, 1);
79789
79790                 _multiData.splice(targetIndex, 0, element);
79791
79792                 var t = {};
79793
79794                 if (_multiData.length) {
79795                   t[field.key] = _multiData.map(function (element) {
79796                     return element.key;
79797                   }).join(';');
79798                 } else {
79799                   t[field.key] = undefined;
79800                 }
79801
79802                 dispatch.call('change', this, t);
79803               }
79804
79805               dragOrigin = undefined;
79806               targetIndex = undefined;
79807             }));
79808           }
79809
79810           combo.focus = function () {
79811             _input.node().focus();
79812           };
79813
79814           combo.entityIDs = function (val) {
79815             if (!arguments.length) return _entityIDs;
79816             _entityIDs = val;
79817             return combo;
79818           };
79819
79820           function combinedEntityExtent() {
79821             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
79822           }
79823
79824           return utilRebind(combo, dispatch, 'on');
79825         }
79826
79827         function uiFieldText(field, context) {
79828           var dispatch = dispatch$8('change');
79829           var input = select(null);
79830           var outlinkButton = select(null);
79831           var _entityIDs = [];
79832
79833           var _tags;
79834
79835           var _phoneFormats = {};
79836
79837           if (field.type === 'tel') {
79838             _mainFileFetcher.get('phone_formats').then(function (d) {
79839               _phoneFormats = d;
79840               updatePhonePlaceholder();
79841             })["catch"](function () {
79842               /* ignore */
79843             });
79844           }
79845
79846           function calcLocked() {
79847             // Protect certain fields that have a companion `*:wikidata` value
79848             var isLocked = (field.id === 'brand' || field.id === 'network' || field.id === 'operator' || field.id === 'flag') && _entityIDs.length && _entityIDs.some(function (entityID) {
79849               var entity = context.graph().hasEntity(entityID);
79850               if (!entity) return false; // Features linked to Wikidata are likely important and should be protected
79851
79852               if (entity.tags.wikidata) return true;
79853               var preset = _mainPresetIndex.match(entity, context.graph());
79854               var isSuggestion = preset && preset.suggestion; // Lock the field if there is a value and a companion `*:wikidata` value
79855
79856               var which = field.id; // 'brand', 'network', 'operator', 'flag'
79857
79858               return isSuggestion && !!entity.tags[which] && !!entity.tags[which + ':wikidata'];
79859             });
79860
79861             field.locked(isLocked);
79862           }
79863
79864           function i(selection) {
79865             calcLocked();
79866             var isLocked = field.locked();
79867             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
79868             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
79869             input = wrap.selectAll('input').data([0]);
79870             input = input.enter().append('input').attr('type', field.type === 'identifier' ? 'text' : field.type).attr('id', field.domId).classed(field.type, true).call(utilNoAuto).merge(input);
79871             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
79872
79873             if (field.type === 'tel') {
79874               updatePhonePlaceholder();
79875             } else if (field.type === 'number') {
79876               var rtl = _mainLocalizer.textDirection() === 'rtl';
79877               input.attr('type', 'text');
79878               var inc = field.increment;
79879               var buttons = wrap.selectAll('.increment, .decrement').data(rtl ? [inc, -inc] : [-inc, inc]);
79880               buttons.enter().append('button').attr('class', function (d) {
79881                 var which = d > 0 ? 'increment' : 'decrement';
79882                 return 'form-field-button ' + which;
79883               }).merge(buttons).on('click', function (d3_event, d) {
79884                 d3_event.preventDefault();
79885                 var raw_vals = input.node().value || '0';
79886                 var vals = raw_vals.split(';');
79887                 vals = vals.map(function (v) {
79888                   var num = parseFloat(v.trim(), 10);
79889                   return isFinite(num) ? clamped(num + d) : v.trim();
79890                 });
79891                 input.node().value = vals.join(';');
79892                 change()();
79893               });
79894             } else if (field.type === 'identifier' && field.urlFormat && field.pattern) {
79895               input.attr('type', 'text');
79896               outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
79897               outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
79898                 var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
79899
79900                 if (domainResults.length >= 2 && domainResults[1]) {
79901                   var domain = domainResults[1];
79902                   return _t('icons.view_on', {
79903                     domain: domain
79904                   });
79905                 }
79906
79907                 return '';
79908               }).on('click', function (d3_event) {
79909                 d3_event.preventDefault();
79910                 var value = validIdentifierValueForLink();
79911
79912                 if (value) {
79913                   var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
79914                   window.open(url, '_blank');
79915                 }
79916               }).merge(outlinkButton);
79917             } else if (field.type === 'url') {
79918               input.attr('type', 'text');
79919               outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
79920               outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
79921                 return _t('icons.visit_website');
79922               }).on('click', function (d3_event) {
79923                 d3_event.preventDefault();
79924                 var value = validIdentifierValueForLink();
79925                 if (value) window.open(value, '_blank');
79926               }).merge(outlinkButton);
79927             }
79928           }
79929
79930           function updatePhonePlaceholder() {
79931             if (input.empty() || !Object.keys(_phoneFormats).length) return;
79932             var extent = combinedEntityExtent();
79933             var countryCode = extent && iso1A2Code(extent.center());
79934
79935             var format = countryCode && _phoneFormats[countryCode.toLowerCase()];
79936
79937             if (format) input.attr('placeholder', format);
79938           }
79939
79940           function validIdentifierValueForLink() {
79941             var value = utilGetSetValue(input).trim().split(';')[0];
79942             if (field.type === 'url' && value) return value;
79943
79944             if (field.type === 'identifier' && field.pattern) {
79945               return value && value.match(new RegExp(field.pattern));
79946             }
79947
79948             return null;
79949           } // clamp number to min/max
79950
79951
79952           function clamped(num) {
79953             if (field.minValue !== undefined) {
79954               num = Math.max(num, field.minValue);
79955             }
79956
79957             if (field.maxValue !== undefined) {
79958               num = Math.min(num, field.maxValue);
79959             }
79960
79961             return num;
79962           }
79963
79964           function change(onInput) {
79965             return function () {
79966               var t = {};
79967               var val = utilGetSetValue(input);
79968               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
79969
79970               if (!val && Array.isArray(_tags[field.key])) return;
79971
79972               if (!onInput) {
79973                 if (field.type === 'number' && val) {
79974                   var vals = val.split(';');
79975                   vals = vals.map(function (v) {
79976                     var num = parseFloat(v.trim(), 10);
79977                     return isFinite(num) ? clamped(num) : v.trim();
79978                   });
79979                   val = vals.join(';');
79980                 }
79981
79982                 utilGetSetValue(input, val);
79983               }
79984
79985               t[field.key] = val || undefined;
79986               dispatch.call('change', this, t, onInput);
79987             };
79988           }
79989
79990           i.entityIDs = function (val) {
79991             if (!arguments.length) return _entityIDs;
79992             _entityIDs = val;
79993             return i;
79994           };
79995
79996           i.tags = function (tags) {
79997             _tags = tags;
79998             var isMixed = Array.isArray(tags[field.key]);
79999             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);
80000
80001             if (outlinkButton && !outlinkButton.empty()) {
80002               var disabled = !validIdentifierValueForLink();
80003               outlinkButton.classed('disabled', disabled);
80004             }
80005           };
80006
80007           i.focus = function () {
80008             var node = input.node();
80009             if (node) node.focus();
80010           };
80011
80012           function combinedEntityExtent() {
80013             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
80014           }
80015
80016           return utilRebind(i, dispatch, 'on');
80017         }
80018
80019         function uiFieldAccess(field, context) {
80020           var dispatch = dispatch$8('change');
80021           var items = select(null);
80022
80023           var _tags;
80024
80025           function access(selection) {
80026             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80027             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80028             var list = wrap.selectAll('ul').data([0]);
80029             list = list.enter().append('ul').attr('class', 'rows').merge(list);
80030             items = list.selectAll('li').data(field.keys); // Enter
80031
80032             var enter = items.enter().append('li').attr('class', function (d) {
80033               return 'labeled-input preset-access-' + d;
80034             });
80035             enter.append('span').attr('class', 'label preset-label-access').attr('for', function (d) {
80036               return 'preset-input-access-' + d;
80037             }).html(function (d) {
80038               return field.t.html('types.' + d);
80039             });
80040             enter.append('div').attr('class', 'preset-input-access-wrap').append('input').attr('type', 'text').attr('class', function (d) {
80041               return 'preset-input-access preset-input-access-' + d;
80042             }).call(utilNoAuto).each(function (d) {
80043               select(this).call(uiCombobox(context, 'access-' + d).data(access.options(d)));
80044             }); // Update
80045
80046             items = items.merge(enter);
80047             wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
80048           }
80049
80050           function change(d3_event, d) {
80051             var tag = {};
80052             var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
80053
80054             if (!value && typeof _tags[d] !== 'string') return;
80055             tag[d] = value || undefined;
80056             dispatch.call('change', this, tag);
80057           }
80058
80059           access.options = function (type) {
80060             var options = ['no', 'permissive', 'private', 'permit', 'destination'];
80061
80062             if (type !== 'access') {
80063               options.unshift('yes');
80064               options.push('designated');
80065
80066               if (type === 'bicycle') {
80067                 options.push('dismount');
80068               }
80069             }
80070
80071             return options.map(function (option) {
80072               return {
80073                 title: field.t('options.' + option + '.description'),
80074                 value: option
80075               };
80076             });
80077           };
80078
80079           var placeholdersByHighway = {
80080             footway: {
80081               foot: 'designated',
80082               motor_vehicle: 'no'
80083             },
80084             steps: {
80085               foot: 'yes',
80086               motor_vehicle: 'no',
80087               bicycle: 'no',
80088               horse: 'no'
80089             },
80090             pedestrian: {
80091               foot: 'yes',
80092               motor_vehicle: 'no'
80093             },
80094             cycleway: {
80095               motor_vehicle: 'no',
80096               bicycle: 'designated'
80097             },
80098             bridleway: {
80099               motor_vehicle: 'no',
80100               horse: 'designated'
80101             },
80102             path: {
80103               foot: 'yes',
80104               motor_vehicle: 'no',
80105               bicycle: 'yes',
80106               horse: 'yes'
80107             },
80108             motorway: {
80109               foot: 'no',
80110               motor_vehicle: 'yes',
80111               bicycle: 'no',
80112               horse: 'no'
80113             },
80114             trunk: {
80115               motor_vehicle: 'yes'
80116             },
80117             primary: {
80118               foot: 'yes',
80119               motor_vehicle: 'yes',
80120               bicycle: 'yes',
80121               horse: 'yes'
80122             },
80123             secondary: {
80124               foot: 'yes',
80125               motor_vehicle: 'yes',
80126               bicycle: 'yes',
80127               horse: 'yes'
80128             },
80129             tertiary: {
80130               foot: 'yes',
80131               motor_vehicle: 'yes',
80132               bicycle: 'yes',
80133               horse: 'yes'
80134             },
80135             residential: {
80136               foot: 'yes',
80137               motor_vehicle: 'yes',
80138               bicycle: 'yes',
80139               horse: 'yes'
80140             },
80141             unclassified: {
80142               foot: 'yes',
80143               motor_vehicle: 'yes',
80144               bicycle: 'yes',
80145               horse: 'yes'
80146             },
80147             service: {
80148               foot: 'yes',
80149               motor_vehicle: 'yes',
80150               bicycle: 'yes',
80151               horse: 'yes'
80152             },
80153             motorway_link: {
80154               foot: 'no',
80155               motor_vehicle: 'yes',
80156               bicycle: 'no',
80157               horse: 'no'
80158             },
80159             trunk_link: {
80160               motor_vehicle: 'yes'
80161             },
80162             primary_link: {
80163               foot: 'yes',
80164               motor_vehicle: 'yes',
80165               bicycle: 'yes',
80166               horse: 'yes'
80167             },
80168             secondary_link: {
80169               foot: 'yes',
80170               motor_vehicle: 'yes',
80171               bicycle: 'yes',
80172               horse: 'yes'
80173             },
80174             tertiary_link: {
80175               foot: 'yes',
80176               motor_vehicle: 'yes',
80177               bicycle: 'yes',
80178               horse: 'yes'
80179             }
80180           };
80181
80182           access.tags = function (tags) {
80183             _tags = tags;
80184             utilGetSetValue(items.selectAll('.preset-input-access'), function (d) {
80185               return typeof tags[d] === 'string' ? tags[d] : '';
80186             }).classed('mixed', function (d) {
80187               return tags[d] && Array.isArray(tags[d]);
80188             }).attr('title', function (d) {
80189               return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join('\n');
80190             }).attr('placeholder', function (d) {
80191               if (tags[d] && Array.isArray(tags[d])) {
80192                 return _t('inspector.multiple_values');
80193               }
80194
80195               if (d === 'access') {
80196                 return 'yes';
80197               }
80198
80199               if (tags.access && typeof tags.access === 'string') {
80200                 return tags.access;
80201               }
80202
80203               if (tags.highway) {
80204                 if (typeof tags.highway === 'string') {
80205                   if (placeholdersByHighway[tags.highway] && placeholdersByHighway[tags.highway][d]) {
80206                     return placeholdersByHighway[tags.highway][d];
80207                   }
80208                 } else {
80209                   var impliedAccesses = tags.highway.filter(Boolean).map(function (highwayVal) {
80210                     return placeholdersByHighway[highwayVal] && placeholdersByHighway[highwayVal][d];
80211                   }).filter(Boolean);
80212
80213                   if (impliedAccesses.length === tags.highway.length && new Set(impliedAccesses).size === 1) {
80214                     // if all the highway values have the same implied access for this type then use that
80215                     return impliedAccesses[0];
80216                   }
80217                 }
80218               }
80219
80220               return field.placeholder();
80221             });
80222           };
80223
80224           access.focus = function () {
80225             items.selectAll('.preset-input-access').node().focus();
80226           };
80227
80228           return utilRebind(access, dispatch, 'on');
80229         }
80230
80231         function uiFieldAddress(field, context) {
80232           var dispatch = dispatch$8('change');
80233
80234           var _selection = select(null);
80235
80236           var _wrap = select(null);
80237
80238           var addrField = _mainPresetIndex.field('address'); // needed for placeholder strings
80239
80240           var _entityIDs = [];
80241
80242           var _tags;
80243
80244           var _countryCode;
80245
80246           var _addressFormats = [{
80247             format: [['housenumber', 'street'], ['city', 'postcode']]
80248           }];
80249           _mainFileFetcher.get('address_formats').then(function (d) {
80250             _addressFormats = d;
80251
80252             if (!_selection.empty()) {
80253               _selection.call(address);
80254             }
80255           })["catch"](function () {
80256             /* ignore */
80257           });
80258
80259           function getNearStreets() {
80260             var extent = combinedEntityExtent();
80261             var l = extent.center();
80262             var box = geoExtent(l).padByMeters(200);
80263             var streets = context.history().intersects(box).filter(isAddressable).map(function (d) {
80264               var loc = context.projection([(extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2]);
80265               var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
80266               return {
80267                 title: d.tags.name,
80268                 value: d.tags.name,
80269                 dist: choice.distance
80270               };
80271             }).sort(function (a, b) {
80272               return a.dist - b.dist;
80273             });
80274             return utilArrayUniqBy(streets, 'value');
80275
80276             function isAddressable(d) {
80277               return d.tags.highway && d.tags.name && d.type === 'way';
80278             }
80279           }
80280
80281           function getNearCities() {
80282             var extent = combinedEntityExtent();
80283             var l = extent.center();
80284             var box = geoExtent(l).padByMeters(200);
80285             var cities = context.history().intersects(box).filter(isAddressable).map(function (d) {
80286               return {
80287                 title: d.tags['addr:city'] || d.tags.name,
80288                 value: d.tags['addr:city'] || d.tags.name,
80289                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
80290               };
80291             }).sort(function (a, b) {
80292               return a.dist - b.dist;
80293             });
80294             return utilArrayUniqBy(cities, 'value');
80295
80296             function isAddressable(d) {
80297               if (d.tags.name) {
80298                 if (d.tags.admin_level === '8' && d.tags.boundary === 'administrative') return true;
80299                 if (d.tags.border_type === 'city') return true;
80300                 if (d.tags.place === 'city' || d.tags.place === 'town' || d.tags.place === 'village') return true;
80301               }
80302
80303               if (d.tags['addr:city']) return true;
80304               return false;
80305             }
80306           }
80307
80308           function getNearValues(key) {
80309             var extent = combinedEntityExtent();
80310             var l = extent.center();
80311             var box = geoExtent(l).padByMeters(200);
80312             var results = context.history().intersects(box).filter(function hasTag(d) {
80313               return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
80314             }).map(function (d) {
80315               return {
80316                 title: d.tags[key],
80317                 value: d.tags[key],
80318                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
80319               };
80320             }).sort(function (a, b) {
80321               return a.dist - b.dist;
80322             });
80323             return utilArrayUniqBy(results, 'value');
80324           }
80325
80326           function updateForCountryCode() {
80327             if (!_countryCode) return;
80328             var addressFormat;
80329
80330             for (var i = 0; i < _addressFormats.length; i++) {
80331               var format = _addressFormats[i];
80332
80333               if (!format.countryCodes) {
80334                 addressFormat = format; // choose the default format, keep going
80335               } else if (format.countryCodes.indexOf(_countryCode) !== -1) {
80336                 addressFormat = format; // choose the country format, stop here
80337
80338                 break;
80339               }
80340             }
80341
80342             var dropdowns = addressFormat.dropdowns || ['city', 'county', 'country', 'district', 'hamlet', 'neighbourhood', 'place', 'postcode', 'province', 'quarter', 'state', 'street', 'subdistrict', 'suburb'];
80343             var widths = addressFormat.widths || {
80344               housenumber: 1 / 3,
80345               street: 2 / 3,
80346               city: 2 / 3,
80347               state: 1 / 4,
80348               postcode: 1 / 3
80349             };
80350
80351             function row(r) {
80352               // Normalize widths.
80353               var total = r.reduce(function (sum, key) {
80354                 return sum + (widths[key] || 0.5);
80355               }, 0);
80356               return r.map(function (key) {
80357                 return {
80358                   id: key,
80359                   width: (widths[key] || 0.5) / total
80360                 };
80361               });
80362             }
80363
80364             var rows = _wrap.selectAll('.addr-row').data(addressFormat.format, function (d) {
80365               return d.toString();
80366             });
80367
80368             rows.exit().remove();
80369             rows.enter().append('div').attr('class', 'addr-row').selectAll('input').data(row).enter().append('input').property('type', 'text').call(updatePlaceholder).attr('class', function (d) {
80370               return 'addr-' + d.id;
80371             }).call(utilNoAuto).each(addDropdown).style('width', function (d) {
80372               return d.width * 100 + '%';
80373             });
80374
80375             function addDropdown(d) {
80376               if (dropdowns.indexOf(d.id) === -1) return; // not a dropdown
80377
80378               var nearValues = d.id === 'street' ? getNearStreets : d.id === 'city' ? getNearCities : getNearValues;
80379               select(this).call(uiCombobox(context, 'address-' + d.id).minItems(1).caseSensitive(true).fetcher(function (value, callback) {
80380                 callback(nearValues('addr:' + d.id));
80381               }));
80382             }
80383
80384             _wrap.selectAll('input').on('blur', change()).on('change', change());
80385
80386             _wrap.selectAll('input:not(.combobox-input)').on('input', change(true));
80387
80388             if (_tags) updateTags(_tags);
80389           }
80390
80391           function address(selection) {
80392             _selection = selection;
80393             _wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80394             _wrap = _wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(_wrap);
80395             var extent = combinedEntityExtent();
80396
80397             if (extent) {
80398               var countryCode;
80399
80400               if (context.inIntro()) {
80401                 // localize the address format for the walkthrough
80402                 countryCode = _t('intro.graph.countrycode');
80403               } else {
80404                 var center = extent.center();
80405                 countryCode = iso1A2Code(center);
80406               }
80407
80408               if (countryCode) {
80409                 _countryCode = countryCode.toLowerCase();
80410                 updateForCountryCode();
80411               }
80412             }
80413           }
80414
80415           function change(onInput) {
80416             return function () {
80417               var tags = {};
80418
80419               _wrap.selectAll('input').each(function (subfield) {
80420                 var key = field.key + ':' + subfield.id;
80421                 var value = this.value;
80422                 if (!onInput) value = context.cleanTagValue(value); // don't override multiple values with blank string
80423
80424                 if (Array.isArray(_tags[key]) && !value) return;
80425                 tags[key] = value || undefined;
80426               });
80427
80428               dispatch.call('change', this, tags, onInput);
80429             };
80430           }
80431
80432           function updatePlaceholder(inputSelection) {
80433             return inputSelection.attr('placeholder', function (subfield) {
80434               if (_tags && Array.isArray(_tags[field.key + ':' + subfield.id])) {
80435                 return _t('inspector.multiple_values');
80436               }
80437
80438               if (_countryCode) {
80439                 var localkey = subfield.id + '!' + _countryCode;
80440                 var tkey = addrField.hasTextForStringId('placeholders.' + localkey) ? localkey : subfield.id;
80441                 return addrField.t('placeholders.' + tkey);
80442               }
80443             });
80444           }
80445
80446           function updateTags(tags) {
80447             utilGetSetValue(_wrap.selectAll('input'), function (subfield) {
80448               var val = tags[field.key + ':' + subfield.id];
80449               return typeof val === 'string' ? val : '';
80450             }).attr('title', function (subfield) {
80451               var val = tags[field.key + ':' + subfield.id];
80452               return val && Array.isArray(val) && val.filter(Boolean).join('\n');
80453             }).classed('mixed', function (subfield) {
80454               return Array.isArray(tags[field.key + ':' + subfield.id]);
80455             }).call(updatePlaceholder);
80456           }
80457
80458           function combinedEntityExtent() {
80459             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
80460           }
80461
80462           address.entityIDs = function (val) {
80463             if (!arguments.length) return _entityIDs;
80464             _entityIDs = val;
80465             return address;
80466           };
80467
80468           address.tags = function (tags) {
80469             _tags = tags;
80470             updateTags(tags);
80471           };
80472
80473           address.focus = function () {
80474             var node = _wrap.selectAll('input').node();
80475
80476             if (node) node.focus();
80477           };
80478
80479           return utilRebind(address, dispatch, 'on');
80480         }
80481
80482         function uiFieldCycleway(field, context) {
80483           var dispatch = dispatch$8('change');
80484           var items = select(null);
80485           var wrap = select(null);
80486
80487           var _tags;
80488
80489           function cycleway(selection) {
80490             function stripcolon(s) {
80491               return s.replace(':', '');
80492             }
80493
80494             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80495             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80496             var div = wrap.selectAll('ul').data([0]);
80497             div = div.enter().append('ul').attr('class', 'rows').merge(div);
80498             var keys = ['cycleway:left', 'cycleway:right'];
80499             items = div.selectAll('li').data(keys);
80500             var enter = items.enter().append('li').attr('class', function (d) {
80501               return 'labeled-input preset-cycleway-' + stripcolon(d);
80502             });
80503             enter.append('span').attr('class', 'label preset-label-cycleway').attr('for', function (d) {
80504               return 'preset-input-cycleway-' + stripcolon(d);
80505             }).html(function (d) {
80506               return field.t.html('types.' + d);
80507             });
80508             enter.append('div').attr('class', 'preset-input-cycleway-wrap').append('input').attr('type', 'text').attr('class', function (d) {
80509               return 'preset-input-cycleway preset-input-' + stripcolon(d);
80510             }).call(utilNoAuto).each(function (d) {
80511               select(this).call(uiCombobox(context, 'cycleway-' + stripcolon(d)).data(cycleway.options(d)));
80512             });
80513             items = items.merge(enter); // Update
80514
80515             wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
80516           }
80517
80518           function change(d3_event, key) {
80519             var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
80520
80521             if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
80522
80523             if (newValue === 'none' || newValue === '') {
80524               newValue = undefined;
80525             }
80526
80527             var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left';
80528             var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey];
80529
80530             if (otherValue && Array.isArray(otherValue)) {
80531               // we must always have an explicit value for comparison
80532               otherValue = otherValue[0];
80533             }
80534
80535             if (otherValue === 'none' || otherValue === '') {
80536               otherValue = undefined;
80537             }
80538
80539             var tag = {}; // If the left and right tags match, use the cycleway tag to tag both
80540             // sides the same way
80541
80542             if (newValue === otherValue) {
80543               tag = {
80544                 cycleway: newValue,
80545                 'cycleway:left': undefined,
80546                 'cycleway:right': undefined
80547               };
80548             } else {
80549               // Always set both left and right as changing one can affect the other
80550               tag = {
80551                 cycleway: undefined
80552               };
80553               tag[key] = newValue;
80554               tag[otherKey] = otherValue;
80555             }
80556
80557             dispatch.call('change', this, tag);
80558           }
80559
80560           cycleway.options = function () {
80561             return field.options.map(function (option) {
80562               return {
80563                 title: field.t('options.' + option + '.description'),
80564                 value: option
80565               };
80566             });
80567           };
80568
80569           cycleway.tags = function (tags) {
80570             _tags = tags; // If cycleway is set, use that instead of individual values
80571
80572             var commonValue = typeof tags.cycleway === 'string' && tags.cycleway;
80573             utilGetSetValue(items.selectAll('.preset-input-cycleway'), function (d) {
80574               if (commonValue) return commonValue;
80575               return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : '';
80576             }).attr('title', function (d) {
80577               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
80578                 var vals = [];
80579
80580                 if (Array.isArray(tags.cycleway)) {
80581                   vals = vals.concat(tags.cycleway);
80582                 }
80583
80584                 if (Array.isArray(tags[d])) {
80585                   vals = vals.concat(tags[d]);
80586                 }
80587
80588                 return vals.filter(Boolean).join('\n');
80589               }
80590
80591               return null;
80592             }).attr('placeholder', function (d) {
80593               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
80594                 return _t('inspector.multiple_values');
80595               }
80596
80597               return field.placeholder();
80598             }).classed('mixed', function (d) {
80599               return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
80600             });
80601           };
80602
80603           cycleway.focus = function () {
80604             var node = wrap.selectAll('input').node();
80605             if (node) node.focus();
80606           };
80607
80608           return utilRebind(cycleway, dispatch, 'on');
80609         }
80610
80611         function uiFieldLanes(field, context) {
80612           var dispatch = dispatch$8('change');
80613           var LANE_WIDTH = 40;
80614           var LANE_HEIGHT = 200;
80615           var _entityIDs = [];
80616
80617           function lanes(selection) {
80618             var lanesData = context.entity(_entityIDs[0]).lanes();
80619
80620             if (!context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
80621               selection.call(lanes.off);
80622               return;
80623             }
80624
80625             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80626             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80627             var surface = wrap.selectAll('.surface').data([0]);
80628             var d = utilGetDimensions(wrap);
80629             var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
80630             surface = surface.enter().append('svg').attr('width', d[0]).attr('height', 300).attr('class', 'surface').merge(surface);
80631             var lanesSelection = surface.selectAll('.lanes').data([0]);
80632             lanesSelection = lanesSelection.enter().append('g').attr('class', 'lanes').merge(lanesSelection);
80633             lanesSelection.attr('transform', function () {
80634               return 'translate(' + freeSpace / 2 + ', 0)';
80635             });
80636             var lane = lanesSelection.selectAll('.lane').data(lanesData.lanes);
80637             lane.exit().remove();
80638             var enter = lane.enter().append('g').attr('class', 'lane');
80639             enter.append('g').append('rect').attr('y', 50).attr('width', LANE_WIDTH).attr('height', LANE_HEIGHT);
80640             enter.append('g').attr('class', 'forward').append('text').attr('y', 40).attr('x', 14).html('▲');
80641             enter.append('g').attr('class', 'bothways').append('text').attr('y', 40).attr('x', 14).html('▲▼');
80642             enter.append('g').attr('class', 'backward').append('text').attr('y', 40).attr('x', 14).html('▼');
80643             lane = lane.merge(enter);
80644             lane.attr('transform', function (d) {
80645               return 'translate(' + LANE_WIDTH * d.index * 1.5 + ', 0)';
80646             });
80647             lane.select('.forward').style('visibility', function (d) {
80648               return d.direction === 'forward' ? 'visible' : 'hidden';
80649             });
80650             lane.select('.bothways').style('visibility', function (d) {
80651               return d.direction === 'bothways' ? 'visible' : 'hidden';
80652             });
80653             lane.select('.backward').style('visibility', function (d) {
80654               return d.direction === 'backward' ? 'visible' : 'hidden';
80655             });
80656           }
80657
80658           lanes.entityIDs = function (val) {
80659             _entityIDs = val;
80660           };
80661
80662           lanes.tags = function () {};
80663
80664           lanes.focus = function () {};
80665
80666           lanes.off = function () {};
80667
80668           return utilRebind(lanes, dispatch, 'on');
80669         }
80670         uiFieldLanes.supportsMultiselection = false;
80671
80672         var _languagesArray = [];
80673         function uiFieldLocalized(field, context) {
80674           var dispatch = dispatch$8('change', 'input');
80675           var wikipedia = services.wikipedia;
80676           var input = select(null);
80677           var localizedInputs = select(null);
80678
80679           var _countryCode;
80680
80681           var _tags; // A concern here in switching to async data means that _languagesArray will not
80682           // be available the first time through, so things like the fetchers and
80683           // the language() function will not work immediately.
80684
80685
80686           _mainFileFetcher.get('languages').then(loadLanguagesArray)["catch"](function () {
80687             /* ignore */
80688           });
80689           var _territoryLanguages = {};
80690           _mainFileFetcher.get('territory_languages').then(function (d) {
80691             _territoryLanguages = d;
80692           })["catch"](function () {
80693             /* ignore */
80694           }); // reuse these combos
80695
80696           var langCombo = uiCombobox(context, 'localized-lang').fetcher(fetchLanguages).minItems(0);
80697
80698           var _selection = select(null);
80699
80700           var _multilingual = [];
80701
80702           var _buttonTip = uiTooltip().title(_t.html('translate.translate')).placement('left');
80703
80704           var _wikiTitles;
80705
80706           var _entityIDs = [];
80707
80708           function loadLanguagesArray(dataLanguages) {
80709             if (_languagesArray.length !== 0) return; // some conversion is needed to ensure correct OSM tags are used
80710
80711             var replacements = {
80712               sr: 'sr-Cyrl',
80713               // in OSM, `sr` implies Cyrillic
80714               'sr-Cyrl': false // `sr-Cyrl` isn't used in OSM
80715
80716             };
80717
80718             for (var code in dataLanguages) {
80719               if (replacements[code] === false) continue;
80720               var metaCode = code;
80721               if (replacements[code]) metaCode = replacements[code];
80722
80723               _languagesArray.push({
80724                 localName: _mainLocalizer.languageName(metaCode, {
80725                   localOnly: true
80726                 }),
80727                 nativeName: dataLanguages[metaCode].nativeName,
80728                 code: code,
80729                 label: _mainLocalizer.languageName(metaCode)
80730               });
80731             }
80732           }
80733
80734           function calcLocked() {
80735             // Protect name field for suggestion presets that don't display a brand/operator field
80736             var isLocked = field.id === 'name' && _entityIDs.length && _entityIDs.some(function (entityID) {
80737               var entity = context.graph().hasEntity(entityID);
80738               if (!entity) return false; // Features linked to Wikidata are likely important and should be protected
80739
80740               if (entity.tags.wikidata) return true; // Assume the name has already been confirmed if its source has been researched
80741
80742               if (entity.tags['name:etymology:wikidata']) return true; // Lock the `name` if this is a suggestion preset that assigns the name,
80743               // and the preset does not display a `brand` or `operator` field.
80744               // (For presets like hotels, car dealerships, post offices, the `name` should remain editable)
80745               // see also similar logic in `outdated_tags.js`
80746
80747               var preset = _mainPresetIndex.match(entity, context.graph());
80748
80749               if (preset) {
80750                 var isSuggestion = preset.suggestion;
80751                 var fields = preset.fields();
80752                 var showsBrandField = fields.some(function (d) {
80753                   return d.id === 'brand';
80754                 });
80755                 var showsOperatorField = fields.some(function (d) {
80756                   return d.id === 'operator';
80757                 });
80758                 var setsName = preset.addTags.name;
80759                 var setsBrandWikidata = preset.addTags['brand:wikidata'];
80760                 var setsOperatorWikidata = preset.addTags['operator:wikidata'];
80761                 return isSuggestion && setsName && (setsBrandWikidata && !showsBrandField || setsOperatorWikidata && !showsOperatorField);
80762               }
80763
80764               return false;
80765             });
80766
80767             field.locked(isLocked);
80768           } // update _multilingual, maintaining the existing order
80769
80770
80771           function calcMultilingual(tags) {
80772             var existingLangsOrdered = _multilingual.map(function (item) {
80773               return item.lang;
80774             });
80775
80776             var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
80777
80778             for (var k in tags) {
80779               var m = k.match(/^(.*):(.*)$/);
80780
80781               if (m && m[1] === field.key && m[2]) {
80782                 var item = {
80783                   lang: m[2],
80784                   value: tags[k]
80785                 };
80786
80787                 if (existingLangs.has(item.lang)) {
80788                   // update the value
80789                   _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
80790                   existingLangs["delete"](item.lang);
80791                 } else {
80792                   _multilingual.push(item);
80793                 }
80794               }
80795             } // Don't remove items based on deleted tags, since this makes the UI
80796             // disappear unexpectedly when clearing values - #8164
80797
80798
80799             _multilingual.forEach(function (item) {
80800               if (item.lang && existingLangs.has(item.lang)) {
80801                 item.value = '';
80802               }
80803             });
80804           }
80805
80806           function localized(selection) {
80807             _selection = selection;
80808             calcLocked();
80809             var isLocked = field.locked();
80810             var wrap = selection.selectAll('.form-field-input-wrap').data([0]); // enter/update
80811
80812             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80813             input = wrap.selectAll('.localized-main').data([0]); // enter/update
80814
80815             input = input.enter().append('input').attr('type', 'text').attr('id', field.domId).attr('class', 'localized-main').call(utilNoAuto).merge(input);
80816             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
80817             var translateButton = wrap.selectAll('.localized-add').data([0]);
80818             translateButton = translateButton.enter().append('button').attr('class', 'localized-add form-field-button').call(svgIcon('#iD-icon-plus')).merge(translateButton);
80819             translateButton.classed('disabled', !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on('click', addNew);
80820
80821             if (_tags && !_multilingual.length) {
80822               calcMultilingual(_tags);
80823             }
80824
80825             localizedInputs = selection.selectAll('.localized-multilingual').data([0]);
80826             localizedInputs = localizedInputs.enter().append('div').attr('class', 'localized-multilingual').merge(localizedInputs);
80827             localizedInputs.call(renderMultilingual);
80828             localizedInputs.selectAll('button, input').classed('disabled', !!isLocked).attr('readonly', isLocked || null);
80829
80830             function addNew(d3_event) {
80831               d3_event.preventDefault();
80832               if (field.locked()) return;
80833               var defaultLang = _mainLocalizer.languageCode().toLowerCase();
80834
80835               var langExists = _multilingual.find(function (datum) {
80836                 return datum.lang === defaultLang;
80837               });
80838
80839               var isLangEn = defaultLang.indexOf('en') > -1;
80840
80841               if (isLangEn || langExists) {
80842                 defaultLang = '';
80843                 langExists = _multilingual.find(function (datum) {
80844                   return datum.lang === defaultLang;
80845                 });
80846               }
80847
80848               if (!langExists) {
80849                 // prepend the value so it appears at the top
80850                 _multilingual.unshift({
80851                   lang: defaultLang,
80852                   value: ''
80853                 });
80854
80855                 localizedInputs.call(renderMultilingual);
80856               }
80857             }
80858
80859             function change(onInput) {
80860               return function (d3_event) {
80861                 if (field.locked()) {
80862                   d3_event.preventDefault();
80863                   return;
80864                 }
80865
80866                 var val = utilGetSetValue(select(this));
80867                 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
80868
80869                 if (!val && Array.isArray(_tags[field.key])) return;
80870                 var t = {};
80871                 t[field.key] = val || undefined;
80872                 dispatch.call('change', this, t, onInput);
80873               };
80874             }
80875           }
80876
80877           function key(lang) {
80878             return field.key + ':' + lang;
80879           }
80880
80881           function changeLang(d3_event, d) {
80882             var tags = {}; // make sure unrecognized suffixes are lowercase - #7156
80883
80884             var lang = utilGetSetValue(select(this)).toLowerCase();
80885
80886             var language = _languagesArray.find(function (d) {
80887               return d.label.toLowerCase() === lang || d.localName && d.localName.toLowerCase() === lang || d.nativeName && d.nativeName.toLowerCase() === lang;
80888             });
80889
80890             if (language) lang = language.code;
80891
80892             if (d.lang && d.lang !== lang) {
80893               tags[key(d.lang)] = undefined;
80894             }
80895
80896             var newKey = lang && context.cleanTagKey(key(lang));
80897             var value = utilGetSetValue(select(this.parentNode).selectAll('.localized-value'));
80898
80899             if (newKey && value) {
80900               tags[newKey] = value;
80901             } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
80902               tags[newKey] = _wikiTitles[d.lang];
80903             }
80904
80905             d.lang = lang;
80906             dispatch.call('change', this, tags);
80907           }
80908
80909           function changeValue(d3_event, d) {
80910             if (!d.lang) return;
80911             var value = context.cleanTagValue(utilGetSetValue(select(this))) || undefined; // don't override multiple values with blank string
80912
80913             if (!value && Array.isArray(d.value)) return;
80914             var t = {};
80915             t[key(d.lang)] = value;
80916             d.value = value;
80917             dispatch.call('change', this, t);
80918           }
80919
80920           function fetchLanguages(value, cb) {
80921             var v = value.toLowerCase(); // show the user's language first
80922
80923             var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
80924
80925             if (_countryCode && _territoryLanguages[_countryCode]) {
80926               langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
80927             }
80928
80929             var langItems = [];
80930             langCodes.forEach(function (code) {
80931               var langItem = _languagesArray.find(function (item) {
80932                 return item.code === code;
80933               });
80934
80935               if (langItem) langItems.push(langItem);
80936             });
80937             langItems = utilArrayUniq(langItems.concat(_languagesArray));
80938             cb(langItems.filter(function (d) {
80939               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;
80940             }).map(function (d) {
80941               return {
80942                 value: d.label
80943               };
80944             }));
80945           }
80946
80947           function renderMultilingual(selection) {
80948             var entries = selection.selectAll('div.entry').data(_multilingual, function (d) {
80949               return d.lang;
80950             });
80951             entries.exit().style('top', '0').style('max-height', '240px').transition().duration(200).style('opacity', '0').style('max-height', '0px').remove();
80952             var entriesEnter = entries.enter().append('div').attr('class', 'entry').each(function (_, index) {
80953               var wrap = select(this);
80954               var domId = utilUniqueDomId(index);
80955               var label = wrap.append('label').attr('class', 'field-label').attr('for', domId);
80956               var text = label.append('span').attr('class', 'label-text');
80957               text.append('span').attr('class', 'label-textvalue').html(_t.html('translate.localized_translation_label'));
80958               text.append('span').attr('class', 'label-textannotation');
80959               label.append('button').attr('class', 'remove-icon-multilingual').on('click', function (d3_event, d) {
80960                 if (field.locked()) return;
80961                 d3_event.preventDefault(); // remove the UI item manually
80962
80963                 _multilingual.splice(_multilingual.indexOf(d), 1);
80964
80965                 var langKey = d.lang && key(d.lang);
80966
80967                 if (langKey && langKey in _tags) {
80968                   delete _tags[langKey]; // remove from entity tags
80969
80970                   var t = {};
80971                   t[langKey] = undefined;
80972                   dispatch.call('change', this, t);
80973                   return;
80974                 }
80975
80976                 renderMultilingual(selection);
80977               }).call(svgIcon('#iD-operation-delete'));
80978               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);
80979               wrap.append('input').attr('type', 'text').attr('class', 'localized-value').on('blur', changeValue).on('change', changeValue);
80980             });
80981             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 () {
80982               select(this).style('max-height', '').style('overflow', 'visible');
80983             });
80984             entries = entries.merge(entriesEnter);
80985             entries.order(); // allow removing the entry UIs even if there isn't a tag to remove
80986
80987             entries.classed('present', true);
80988             utilGetSetValue(entries.select('.localized-lang'), function (d) {
80989               var langItem = _languagesArray.find(function (item) {
80990                 return item.code === d.lang;
80991               });
80992
80993               if (langItem) return langItem.label;
80994               return d.lang;
80995             });
80996             utilGetSetValue(entries.select('.localized-value'), function (d) {
80997               return typeof d.value === 'string' ? d.value : '';
80998             }).attr('title', function (d) {
80999               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : null;
81000             }).attr('placeholder', function (d) {
81001               return Array.isArray(d.value) ? _t('inspector.multiple_values') : _t('translate.localized_translation_name');
81002             }).classed('mixed', function (d) {
81003               return Array.isArray(d.value);
81004             });
81005           }
81006
81007           localized.tags = function (tags) {
81008             _tags = tags; // Fetch translations from wikipedia
81009
81010             if (typeof tags.wikipedia === 'string' && !_wikiTitles) {
81011               _wikiTitles = {};
81012               var wm = tags.wikipedia.match(/([^:]+):(.+)/);
81013
81014               if (wm && wm[0] && wm[1]) {
81015                 wikipedia.translations(wm[1], wm[2], function (err, d) {
81016                   if (err || !d) return;
81017                   _wikiTitles = d;
81018                 });
81019               }
81020             }
81021
81022             var isMixed = Array.isArray(tags[field.key]);
81023             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);
81024             calcMultilingual(tags);
81025
81026             _selection.call(localized);
81027           };
81028
81029           localized.focus = function () {
81030             input.node().focus();
81031           };
81032
81033           localized.entityIDs = function (val) {
81034             if (!arguments.length) return _entityIDs;
81035             _entityIDs = val;
81036             _multilingual = [];
81037             loadCountryCode();
81038             return localized;
81039           };
81040
81041           function loadCountryCode() {
81042             var extent = combinedEntityExtent();
81043             var countryCode = extent && iso1A2Code(extent.center());
81044             _countryCode = countryCode && countryCode.toLowerCase();
81045           }
81046
81047           function combinedEntityExtent() {
81048             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81049           }
81050
81051           return utilRebind(localized, dispatch, 'on');
81052         }
81053
81054         function uiFieldRoadheight(field, context) {
81055           var dispatch = dispatch$8('change');
81056           var primaryUnitInput = select(null);
81057           var primaryInput = select(null);
81058           var secondaryInput = select(null);
81059           var secondaryUnitInput = select(null);
81060           var _entityIDs = [];
81061
81062           var _tags;
81063
81064           var _isImperial;
81065
81066           var primaryUnits = [{
81067             value: 'm',
81068             title: _t('inspector.roadheight.meter')
81069           }, {
81070             value: 'ft',
81071             title: _t('inspector.roadheight.foot')
81072           }];
81073           var unitCombo = uiCombobox(context, 'roadheight-unit').data(primaryUnits);
81074
81075           function roadheight(selection) {
81076             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81077             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81078             primaryInput = wrap.selectAll('input.roadheight-number').data([0]);
81079             primaryInput = primaryInput.enter().append('input').attr('type', 'text').attr('class', 'roadheight-number').attr('id', field.domId).call(utilNoAuto).merge(primaryInput);
81080             primaryInput.on('change', change).on('blur', change);
81081             var loc = combinedEntityExtent().center();
81082             _isImperial = roadHeightUnit(loc) === 'ft';
81083             primaryUnitInput = wrap.selectAll('input.roadheight-unit').data([0]);
81084             primaryUnitInput = primaryUnitInput.enter().append('input').attr('type', 'text').attr('class', 'roadheight-unit').call(unitCombo).merge(primaryUnitInput);
81085             primaryUnitInput.on('blur', changeUnits).on('change', changeUnits);
81086             secondaryInput = wrap.selectAll('input.roadheight-secondary-number').data([0]);
81087             secondaryInput = secondaryInput.enter().append('input').attr('type', 'text').attr('class', 'roadheight-secondary-number').call(utilNoAuto).merge(secondaryInput);
81088             secondaryInput.on('change', change).on('blur', change);
81089             secondaryUnitInput = wrap.selectAll('input.roadheight-secondary-unit').data([0]);
81090             secondaryUnitInput = secondaryUnitInput.enter().append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', true).classed('roadheight-secondary-unit', true).attr('readonly', 'readonly').merge(secondaryUnitInput);
81091
81092             function changeUnits() {
81093               _isImperial = utilGetSetValue(primaryUnitInput) === 'ft';
81094               utilGetSetValue(primaryUnitInput, _isImperial ? 'ft' : 'm');
81095               setUnitSuggestions();
81096               change();
81097             }
81098           }
81099
81100           function setUnitSuggestions() {
81101             utilGetSetValue(primaryUnitInput, _isImperial ? 'ft' : 'm');
81102           }
81103
81104           function change() {
81105             var tag = {};
81106             var primaryValue = utilGetSetValue(primaryInput).trim();
81107             var secondaryValue = utilGetSetValue(secondaryInput).trim(); // don't override multiple values with blank string
81108
81109             if (!primaryValue && !secondaryValue && Array.isArray(_tags[field.key])) return;
81110
81111             if (!primaryValue && !secondaryValue) {
81112               tag[field.key] = undefined;
81113             } else if (isNaN(primaryValue) || isNaN(secondaryValue) || !_isImperial) {
81114               tag[field.key] = context.cleanTagValue(primaryValue);
81115             } else {
81116               if (primaryValue !== '') {
81117                 primaryValue = context.cleanTagValue(primaryValue + '\'');
81118               }
81119
81120               if (secondaryValue !== '') {
81121                 secondaryValue = context.cleanTagValue(secondaryValue + '"');
81122               }
81123
81124               tag[field.key] = primaryValue + secondaryValue;
81125             }
81126
81127             dispatch.call('change', this, tag);
81128           }
81129
81130           roadheight.tags = function (tags) {
81131             _tags = tags;
81132             var primaryValue = tags[field.key];
81133             var secondaryValue;
81134             var isMixed = Array.isArray(primaryValue);
81135
81136             if (!isMixed) {
81137               if (primaryValue && (primaryValue.indexOf('\'') >= 0 || primaryValue.indexOf('"') >= 0)) {
81138                 secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
81139
81140                 if (secondaryValue !== null) {
81141                   secondaryValue = secondaryValue[1];
81142                 }
81143
81144                 primaryValue = primaryValue.match(/(-?[\d.]+)'/);
81145
81146                 if (primaryValue !== null) {
81147                   primaryValue = primaryValue[1];
81148                 }
81149
81150                 _isImperial = true;
81151               } else if (primaryValue) {
81152                 _isImperial = false;
81153               }
81154             }
81155
81156             setUnitSuggestions();
81157             utilGetSetValue(primaryInput, typeof primaryValue === 'string' ? primaryValue : '').attr('title', isMixed ? primaryValue.filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : _t('inspector.unknown')).classed('mixed', isMixed);
81158             utilGetSetValue(secondaryInput, typeof secondaryValue === 'string' ? secondaryValue : '').attr('placeholder', isMixed ? _t('inspector.multiple_values') : _isImperial ? '0' : null).classed('mixed', isMixed).classed('disabled', !_isImperial).attr('readonly', _isImperial ? null : 'readonly');
81159             secondaryUnitInput.attr('value', _isImperial ? _t('inspector.roadheight.inch') : null);
81160           };
81161
81162           roadheight.focus = function () {
81163             primaryInput.node().focus();
81164           };
81165
81166           roadheight.entityIDs = function (val) {
81167             _entityIDs = val;
81168           };
81169
81170           function combinedEntityExtent() {
81171             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81172           }
81173
81174           return utilRebind(roadheight, dispatch, 'on');
81175         }
81176
81177         function uiFieldRoadspeed(field, context) {
81178           var dispatch = dispatch$8('change');
81179           var unitInput = select(null);
81180           var input = select(null);
81181           var _entityIDs = [];
81182
81183           var _tags;
81184
81185           var _isImperial;
81186
81187           var speedCombo = uiCombobox(context, 'roadspeed');
81188           var unitCombo = uiCombobox(context, 'roadspeed-unit').data(['km/h', 'mph'].map(comboValues));
81189           var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
81190           var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
81191
81192           function roadspeed(selection) {
81193             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81194             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81195             input = wrap.selectAll('input.roadspeed-number').data([0]);
81196             input = input.enter().append('input').attr('type', 'text').attr('class', 'roadspeed-number').attr('id', field.domId).call(utilNoAuto).call(speedCombo).merge(input);
81197             input.on('change', change).on('blur', change);
81198             var loc = combinedEntityExtent().center();
81199             _isImperial = roadSpeedUnit(loc) === 'mph';
81200             unitInput = wrap.selectAll('input.roadspeed-unit').data([0]);
81201             unitInput = unitInput.enter().append('input').attr('type', 'text').attr('class', 'roadspeed-unit').call(unitCombo).merge(unitInput);
81202             unitInput.on('blur', changeUnits).on('change', changeUnits);
81203
81204             function changeUnits() {
81205               _isImperial = utilGetSetValue(unitInput) === 'mph';
81206               utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
81207               setUnitSuggestions();
81208               change();
81209             }
81210           }
81211
81212           function setUnitSuggestions() {
81213             speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
81214             utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
81215           }
81216
81217           function comboValues(d) {
81218             return {
81219               value: d.toString(),
81220               title: d.toString()
81221             };
81222           }
81223
81224           function change() {
81225             var tag = {};
81226             var value = utilGetSetValue(input).trim(); // don't override multiple values with blank string
81227
81228             if (!value && Array.isArray(_tags[field.key])) return;
81229
81230             if (!value) {
81231               tag[field.key] = undefined;
81232             } else if (isNaN(value) || !_isImperial) {
81233               tag[field.key] = context.cleanTagValue(value);
81234             } else {
81235               tag[field.key] = context.cleanTagValue(value + ' mph');
81236             }
81237
81238             dispatch.call('change', this, tag);
81239           }
81240
81241           roadspeed.tags = function (tags) {
81242             _tags = tags;
81243             var value = tags[field.key];
81244             var isMixed = Array.isArray(value);
81245
81246             if (!isMixed) {
81247               if (value && value.indexOf('mph') >= 0) {
81248                 value = parseInt(value, 10).toString();
81249                 _isImperial = true;
81250               } else if (value) {
81251                 _isImperial = false;
81252               }
81253             }
81254
81255             setUnitSuggestions();
81256             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);
81257           };
81258
81259           roadspeed.focus = function () {
81260             input.node().focus();
81261           };
81262
81263           roadspeed.entityIDs = function (val) {
81264             _entityIDs = val;
81265           };
81266
81267           function combinedEntityExtent() {
81268             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81269           }
81270
81271           return utilRebind(roadspeed, dispatch, 'on');
81272         }
81273
81274         function uiFieldRadio(field, context) {
81275           var dispatch = dispatch$8('change');
81276           var placeholder = select(null);
81277           var wrap = select(null);
81278           var labels = select(null);
81279           var radios = select(null);
81280           var radioData = (field.options || field.keys).slice(); // shallow copy
81281
81282           var typeField;
81283           var layerField;
81284           var _oldType = {};
81285           var _entityIDs = [];
81286
81287           function selectedKey() {
81288             var node = wrap.selectAll('.form-field-input-radio label.active input');
81289             return !node.empty() && node.datum();
81290           }
81291
81292           function radio(selection) {
81293             selection.classed('preset-radio', true);
81294             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81295             var enter = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-radio');
81296             enter.append('span').attr('class', 'placeholder');
81297             wrap = wrap.merge(enter);
81298             placeholder = wrap.selectAll('.placeholder');
81299             labels = wrap.selectAll('label').data(radioData);
81300             enter = labels.enter().append('label');
81301             enter.append('input').attr('type', 'radio').attr('name', field.id).attr('value', function (d) {
81302               return field.t('options.' + d, {
81303                 'default': d
81304               });
81305             }).attr('checked', false);
81306             enter.append('span').html(function (d) {
81307               return field.t.html('options.' + d, {
81308                 'default': d
81309               });
81310             });
81311             labels = labels.merge(enter);
81312             radios = labels.selectAll('input').on('change', changeRadio);
81313           }
81314
81315           function structureExtras(selection, tags) {
81316             var selected = selectedKey() || tags.layer !== undefined;
81317             var type = _mainPresetIndex.field(selected);
81318             var layer = _mainPresetIndex.field('layer');
81319             var showLayer = selected === 'bridge' || selected === 'tunnel' || tags.layer !== undefined;
81320             var extrasWrap = selection.selectAll('.structure-extras-wrap').data(selected ? [0] : []);
81321             extrasWrap.exit().remove();
81322             extrasWrap = extrasWrap.enter().append('div').attr('class', 'structure-extras-wrap').merge(extrasWrap);
81323             var list = extrasWrap.selectAll('ul').data([0]);
81324             list = list.enter().append('ul').attr('class', 'rows').merge(list); // Type
81325
81326             if (type) {
81327               if (!typeField || typeField.id !== selected) {
81328                 typeField = uiField(context, type, _entityIDs, {
81329                   wrap: false
81330                 }).on('change', changeType);
81331               }
81332
81333               typeField.tags(tags);
81334             } else {
81335               typeField = null;
81336             }
81337
81338             var typeItem = list.selectAll('.structure-type-item').data(typeField ? [typeField] : [], function (d) {
81339               return d.id;
81340             }); // Exit
81341
81342             typeItem.exit().remove(); // Enter
81343
81344             var typeEnter = typeItem.enter().insert('li', ':first-child').attr('class', 'labeled-input structure-type-item');
81345             typeEnter.append('span').attr('class', 'label structure-label-type').attr('for', 'preset-input-' + selected).html(_t.html('inspector.radio.structure.type'));
81346             typeEnter.append('div').attr('class', 'structure-input-type-wrap'); // Update
81347
81348             typeItem = typeItem.merge(typeEnter);
81349
81350             if (typeField) {
81351               typeItem.selectAll('.structure-input-type-wrap').call(typeField.render);
81352             } // Layer
81353
81354
81355             if (layer && showLayer) {
81356               if (!layerField) {
81357                 layerField = uiField(context, layer, _entityIDs, {
81358                   wrap: false
81359                 }).on('change', changeLayer);
81360               }
81361
81362               layerField.tags(tags);
81363               field.keys = utilArrayUnion(field.keys, ['layer']);
81364             } else {
81365               layerField = null;
81366               field.keys = field.keys.filter(function (k) {
81367                 return k !== 'layer';
81368               });
81369             }
81370
81371             var layerItem = list.selectAll('.structure-layer-item').data(layerField ? [layerField] : []); // Exit
81372
81373             layerItem.exit().remove(); // Enter
81374
81375             var layerEnter = layerItem.enter().append('li').attr('class', 'labeled-input structure-layer-item');
81376             layerEnter.append('span').attr('class', 'label structure-label-layer').attr('for', 'preset-input-layer').html(_t.html('inspector.radio.structure.layer'));
81377             layerEnter.append('div').attr('class', 'structure-input-layer-wrap'); // Update
81378
81379             layerItem = layerItem.merge(layerEnter);
81380
81381             if (layerField) {
81382               layerItem.selectAll('.structure-input-layer-wrap').call(layerField.render);
81383             }
81384           }
81385
81386           function changeType(t, onInput) {
81387             var key = selectedKey();
81388             if (!key) return;
81389             var val = t[key];
81390
81391             if (val !== 'no') {
81392               _oldType[key] = val;
81393             }
81394
81395             if (field.type === 'structureRadio') {
81396               // remove layer if it should not be set
81397               if (val === 'no' || key !== 'bridge' && key !== 'tunnel' || key === 'tunnel' && val === 'building_passage') {
81398                 t.layer = undefined;
81399               } // add layer if it should be set
81400
81401
81402               if (t.layer === undefined) {
81403                 if (key === 'bridge' && val !== 'no') {
81404                   t.layer = '1';
81405                 }
81406
81407                 if (key === 'tunnel' && val !== 'no' && val !== 'building_passage') {
81408                   t.layer = '-1';
81409                 }
81410               }
81411             }
81412
81413             dispatch.call('change', this, t, onInput);
81414           }
81415
81416           function changeLayer(t, onInput) {
81417             if (t.layer === '0') {
81418               t.layer = undefined;
81419             }
81420
81421             dispatch.call('change', this, t, onInput);
81422           }
81423
81424           function changeRadio() {
81425             var t = {};
81426             var activeKey;
81427
81428             if (field.key) {
81429               t[field.key] = undefined;
81430             }
81431
81432             radios.each(function (d) {
81433               var active = select(this).property('checked');
81434               if (active) activeKey = d;
81435
81436               if (field.key) {
81437                 if (active) t[field.key] = d;
81438               } else {
81439                 var val = _oldType[activeKey] || 'yes';
81440                 t[d] = active ? val : undefined;
81441               }
81442             });
81443
81444             if (field.type === 'structureRadio') {
81445               if (activeKey === 'bridge') {
81446                 t.layer = '1';
81447               } else if (activeKey === 'tunnel' && t.tunnel !== 'building_passage') {
81448                 t.layer = '-1';
81449               } else {
81450                 t.layer = undefined;
81451               }
81452             }
81453
81454             dispatch.call('change', this, t);
81455           }
81456
81457           radio.tags = function (tags) {
81458             radios.property('checked', function (d) {
81459               if (field.key) {
81460                 return tags[field.key] === d;
81461               }
81462
81463               return !!(typeof tags[d] === 'string' && tags[d].toLowerCase() !== 'no');
81464             });
81465
81466             function isMixed(d) {
81467               if (field.key) {
81468                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
81469               }
81470
81471               return Array.isArray(tags[d]);
81472             }
81473
81474             labels.classed('active', function (d) {
81475               if (field.key) {
81476                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
81477               }
81478
81479               return Array.isArray(tags[d]) || !!(tags[d] && tags[d].toLowerCase() !== 'no');
81480             }).classed('mixed', isMixed).attr('title', function (d) {
81481               return isMixed(d) ? _t('inspector.unshared_value_tooltip') : null;
81482             });
81483             var selection = radios.filter(function () {
81484               return this.checked;
81485             });
81486
81487             if (selection.empty()) {
81488               placeholder.html(_t.html('inspector.none'));
81489             } else {
81490               placeholder.html(selection.attr('value'));
81491               _oldType[selection.datum()] = tags[selection.datum()];
81492             }
81493
81494             if (field.type === 'structureRadio') {
81495               // For waterways without a tunnel tag, set 'culvert' as
81496               // the _oldType to default to if the user picks 'tunnel'
81497               if (!!tags.waterway && !_oldType.tunnel) {
81498                 _oldType.tunnel = 'culvert';
81499               }
81500
81501               wrap.call(structureExtras, tags);
81502             }
81503           };
81504
81505           radio.focus = function () {
81506             radios.node().focus();
81507           };
81508
81509           radio.entityIDs = function (val) {
81510             if (!arguments.length) return _entityIDs;
81511             _entityIDs = val;
81512             _oldType = {};
81513             return radio;
81514           };
81515
81516           radio.isAllowed = function () {
81517             return _entityIDs.length === 1;
81518           };
81519
81520           return utilRebind(radio, dispatch, 'on');
81521         }
81522
81523         function uiFieldRestrictions(field, context) {
81524           var dispatch = dispatch$8('change');
81525           var breathe = behaviorBreathe();
81526           corePreferences('turn-restriction-via-way', null); // remove old key
81527
81528           var storedViaWay = corePreferences('turn-restriction-via-way0'); // use new key #6922
81529
81530           var storedDistance = corePreferences('turn-restriction-distance');
81531
81532           var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
81533
81534           var _maxDistance = storedDistance ? +storedDistance : 30;
81535
81536           var _initialized = false;
81537
81538           var _parent = select(null); // the entire field
81539
81540
81541           var _container = select(null); // just the map
81542
81543
81544           var _oldTurns;
81545
81546           var _graph;
81547
81548           var _vertexID;
81549
81550           var _intersection;
81551
81552           var _fromWayID;
81553
81554           var _lastXPos;
81555
81556           function restrictions(selection) {
81557             _parent = selection; // try to reuse the intersection, but always rebuild it if the graph has changed
81558
81559             if (_vertexID && (context.graph() !== _graph || !_intersection)) {
81560               _graph = context.graph();
81561               _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
81562             } // It's possible for there to be no actual intersection here.
81563             // for example, a vertex of two `highway=path`
81564             // In this case, hide the field.
81565
81566
81567             var isOK = _intersection && _intersection.vertices.length && // has vertices
81568             _intersection.vertices // has the vertex that the user selected
81569             .filter(function (vertex) {
81570               return vertex.id === _vertexID;
81571             }).length && _intersection.ways.length > 2 && // has more than 2 ways
81572             _intersection.ways // has more than 1 TO way
81573             .filter(function (way) {
81574               return way.__to;
81575             }).length > 1; // Also hide in the case where
81576
81577             select(selection.node().parentNode).classed('hide', !isOK); // if form field is hidden or has detached from dom, clean up.
81578
81579             if (!isOK || !context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode || !selection.node().parentNode.parentNode) {
81580               selection.call(restrictions.off);
81581               return;
81582             }
81583
81584             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81585             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81586             var container = wrap.selectAll('.restriction-container').data([0]); // enter
81587
81588             var containerEnter = container.enter().append('div').attr('class', 'restriction-container');
81589             containerEnter.append('div').attr('class', 'restriction-help'); // update
81590
81591             _container = containerEnter.merge(container).call(renderViewer);
81592             var controls = wrap.selectAll('.restriction-controls').data([0]); // enter/update
81593
81594             controls.enter().append('div').attr('class', 'restriction-controls-container').append('div').attr('class', 'restriction-controls').merge(controls).call(renderControls);
81595           }
81596
81597           function renderControls(selection) {
81598             var distControl = selection.selectAll('.restriction-distance').data([0]);
81599             distControl.exit().remove();
81600             var distControlEnter = distControl.enter().append('div').attr('class', 'restriction-control restriction-distance');
81601             distControlEnter.append('span').attr('class', 'restriction-control-label restriction-distance-label').html(_t.html('restriction.controls.distance') + ':');
81602             distControlEnter.append('input').attr('class', 'restriction-distance-input').attr('type', 'range').attr('min', '20').attr('max', '50').attr('step', '5');
81603             distControlEnter.append('span').attr('class', 'restriction-distance-text'); // update
81604
81605             selection.selectAll('.restriction-distance-input').property('value', _maxDistance).on('input', function () {
81606               var val = select(this).property('value');
81607               _maxDistance = +val;
81608               _intersection = null;
81609
81610               _container.selectAll('.layer-osm .layer-turns *').remove();
81611
81612               corePreferences('turn-restriction-distance', _maxDistance);
81613
81614               _parent.call(restrictions);
81615             });
81616             selection.selectAll('.restriction-distance-text').html(displayMaxDistance(_maxDistance));
81617             var viaControl = selection.selectAll('.restriction-via-way').data([0]);
81618             viaControl.exit().remove();
81619             var viaControlEnter = viaControl.enter().append('div').attr('class', 'restriction-control restriction-via-way');
81620             viaControlEnter.append('span').attr('class', 'restriction-control-label restriction-via-way-label').html(_t.html('restriction.controls.via') + ':');
81621             viaControlEnter.append('input').attr('class', 'restriction-via-way-input').attr('type', 'range').attr('min', '0').attr('max', '2').attr('step', '1');
81622             viaControlEnter.append('span').attr('class', 'restriction-via-way-text'); // update
81623
81624             selection.selectAll('.restriction-via-way-input').property('value', _maxViaWay).on('input', function () {
81625               var val = select(this).property('value');
81626               _maxViaWay = +val;
81627
81628               _container.selectAll('.layer-osm .layer-turns *').remove();
81629
81630               corePreferences('turn-restriction-via-way0', _maxViaWay);
81631
81632               _parent.call(restrictions);
81633             });
81634             selection.selectAll('.restriction-via-way-text').html(displayMaxVia(_maxViaWay));
81635           }
81636
81637           function renderViewer(selection) {
81638             if (!_intersection) return;
81639             var vgraph = _intersection.graph;
81640             var filter = utilFunctor(true);
81641             var projection = geoRawMercator(); // Reflow warning: `utilGetDimensions` calls `getBoundingClientRect`
81642             // Instead of asking the restriction-container for its dimensions,
81643             //  we can ask the .sidebar, which can have its dimensions cached.
81644             // width: calc as sidebar - padding
81645             // height: hardcoded (from `80_app.css`)
81646             // var d = utilGetDimensions(selection);
81647
81648             var sdims = utilGetDimensions(context.container().select('.sidebar'));
81649             var d = [sdims[0] - 50, 370];
81650             var c = geoVecScale(d, 0.5);
81651             var z = 22;
81652             projection.scale(geoZoomToScale(z)); // Calculate extent of all key vertices
81653
81654             var extent = geoExtent();
81655
81656             for (var i = 0; i < _intersection.vertices.length; i++) {
81657               extent._extend(_intersection.vertices[i].extent());
81658             } // If this is a large intersection, adjust zoom to fit extent
81659
81660
81661             if (_intersection.vertices.length > 1) {
81662               var padding = 180; // in z22 pixels
81663
81664               var tl = projection([extent[0][0], extent[1][1]]);
81665               var br = projection([extent[1][0], extent[0][1]]);
81666               var hFactor = (br[0] - tl[0]) / (d[0] - padding);
81667               var vFactor = (br[1] - tl[1]) / (d[1] - padding);
81668               var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
81669               var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
81670               z = z - Math.max(hZoomDiff, vZoomDiff);
81671               projection.scale(geoZoomToScale(z));
81672             }
81673
81674             var padTop = 35; // reserve top space for hint text
81675
81676             var extentCenter = projection(extent.center());
81677             extentCenter[1] = extentCenter[1] - padTop;
81678             projection.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
81679             var drawLayers = svgLayers(projection, context).only(['osm', 'touch']).dimensions(d);
81680             var drawVertices = svgVertices(projection, context);
81681             var drawLines = svgLines(projection, context);
81682             var drawTurns = svgTurns(projection, context);
81683             var firstTime = selection.selectAll('.surface').empty();
81684             selection.call(drawLayers);
81685             var surface = selection.selectAll('.surface').classed('tr', true);
81686
81687             if (firstTime) {
81688               _initialized = true;
81689               surface.call(breathe);
81690             } // This can happen if we've lowered the detail while a FROM way
81691             // is selected, and that way is no longer part of the intersection.
81692
81693
81694             if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
81695               _fromWayID = null;
81696               _oldTurns = null;
81697             }
81698
81699             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));
81700             surface.on('click.restrictions', click).on('mouseover.restrictions', mouseover);
81701             surface.selectAll('.selected').classed('selected', false);
81702             surface.selectAll('.related').classed('related', false);
81703             var way;
81704
81705             if (_fromWayID) {
81706               way = vgraph.entity(_fromWayID);
81707               surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
81708             }
81709
81710             document.addEventListener('resizeWindow', function () {
81711               utilSetDimensions(_container, null);
81712               redraw(1);
81713             }, false);
81714             updateHints(null);
81715
81716             function click(d3_event) {
81717               surface.call(breathe.off).call(breathe);
81718               var datum = d3_event.target.__data__;
81719               var entity = datum && datum.properties && datum.properties.entity;
81720
81721               if (entity) {
81722                 datum = entity;
81723               }
81724
81725               if (datum instanceof osmWay && (datum.__from || datum.__via)) {
81726                 _fromWayID = datum.id;
81727                 _oldTurns = null;
81728                 redraw();
81729               } else if (datum instanceof osmTurn) {
81730                 var actions, extraActions, turns, i;
81731                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
81732
81733                 if (datum.restrictionID && !datum.direct) {
81734                   return;
81735                 } else if (datum.restrictionID && !datum.only) {
81736                   // NO -> ONLY
81737                   var seen = {};
81738                   var datumOnly = JSON.parse(JSON.stringify(datum)); // deep clone the datum
81739
81740                   datumOnly.only = true; // but change this property
81741
81742                   restrictionType = restrictionType.replace(/^no/, 'only'); // Adding an ONLY restriction should destroy all other direct restrictions from the FROM towards the VIA.
81743                   // We will remember them in _oldTurns, and restore them if the user clicks again.
81744
81745                   turns = _intersection.turns(_fromWayID, 2);
81746                   extraActions = [];
81747                   _oldTurns = [];
81748
81749                   for (i = 0; i < turns.length; i++) {
81750                     var turn = turns[i];
81751                     if (seen[turn.restrictionID]) continue; // avoid deleting the turn twice (#4968, #4928)
81752
81753                     if (turn.direct && turn.path[1] === datum.path[1]) {
81754                       seen[turns[i].restrictionID] = true;
81755                       turn.restrictionType = osmInferRestriction(vgraph, turn, projection);
81756
81757                       _oldTurns.push(turn);
81758
81759                       extraActions.push(actionUnrestrictTurn(turn));
81760                     }
81761                   }
81762
81763                   actions = _intersection.actions.concat(extraActions, [actionRestrictTurn(datumOnly, restrictionType), _t('operations.restriction.annotation.create')]);
81764                 } else if (datum.restrictionID) {
81765                   // ONLY -> Allowed
81766                   // Restore whatever restrictions we might have destroyed by cycling thru the ONLY state.
81767                   // This relies on the assumption that the intersection was already split up when we
81768                   // performed the previous action (NO -> ONLY), so the IDs in _oldTurns shouldn't have changed.
81769                   turns = _oldTurns || [];
81770                   extraActions = [];
81771
81772                   for (i = 0; i < turns.length; i++) {
81773                     if (turns[i].key !== datum.key) {
81774                       extraActions.push(actionRestrictTurn(turns[i], turns[i].restrictionType));
81775                     }
81776                   }
81777
81778                   _oldTurns = null;
81779                   actions = _intersection.actions.concat(extraActions, [actionUnrestrictTurn(datum), _t('operations.restriction.annotation.delete')]);
81780                 } else {
81781                   // Allowed -> NO
81782                   actions = _intersection.actions.concat([actionRestrictTurn(datum, restrictionType), _t('operations.restriction.annotation.create')]);
81783                 }
81784
81785                 context.perform.apply(context, actions); // At this point the datum will be changed, but will have same key..
81786                 // Refresh it and update the help..
81787
81788                 var s = surface.selectAll('.' + datum.key);
81789                 datum = s.empty() ? null : s.datum();
81790                 updateHints(datum);
81791               } else {
81792                 _fromWayID = null;
81793                 _oldTurns = null;
81794                 redraw();
81795               }
81796             }
81797
81798             function mouseover(d3_event) {
81799               var datum = d3_event.target.__data__;
81800               updateHints(datum);
81801             }
81802
81803             _lastXPos = _lastXPos || sdims[0];
81804
81805             function redraw(minChange) {
81806               var xPos = -1;
81807
81808               if (minChange) {
81809                 xPos = utilGetDimensions(context.container().select('.sidebar'))[0];
81810               }
81811
81812               if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
81813                 if (context.hasEntity(_vertexID)) {
81814                   _lastXPos = xPos;
81815
81816                   _container.call(renderViewer);
81817                 }
81818               }
81819             }
81820
81821             function highlightPathsFrom(wayID) {
81822               surface.selectAll('.related').classed('related', false).classed('allow', false).classed('restrict', false).classed('only', false);
81823               surface.selectAll('.' + wayID).classed('related', true);
81824
81825               if (wayID) {
81826                 var turns = _intersection.turns(wayID, _maxViaWay);
81827
81828                 for (var i = 0; i < turns.length; i++) {
81829                   var turn = turns[i];
81830                   var ids = [turn.to.way];
81831                   var klass = turn.no ? 'restrict' : turn.only ? 'only' : 'allow';
81832
81833                   if (turn.only || turns.length === 1) {
81834                     if (turn.via.ways) {
81835                       ids = ids.concat(turn.via.ways);
81836                     }
81837                   } else if (turn.to.way === wayID) {
81838                     continue;
81839                   }
81840
81841                   surface.selectAll(utilEntitySelector(ids)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only');
81842                 }
81843               }
81844             }
81845
81846             function updateHints(datum) {
81847               var help = _container.selectAll('.restriction-help').html('');
81848
81849               var placeholders = {};
81850               ['from', 'via', 'to'].forEach(function (k) {
81851                 placeholders[k] = '<span class="qualifier">' + _t('restriction.help.' + k) + '</span>';
81852               });
81853               var entity = datum && datum.properties && datum.properties.entity;
81854
81855               if (entity) {
81856                 datum = entity;
81857               }
81858
81859               if (_fromWayID) {
81860                 way = vgraph.entity(_fromWayID);
81861                 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
81862               } // Hovering a way
81863
81864
81865               if (datum instanceof osmWay && datum.__from) {
81866                 way = datum;
81867                 highlightPathsFrom(_fromWayID ? null : way.id);
81868                 surface.selectAll('.' + way.id).classed('related', true);
81869                 var clickSelect = !_fromWayID || _fromWayID !== way.id;
81870                 help.append('div') // "Click to select FROM {fromName}." / "FROM {fromName}"
81871                 .html(_t.html('restriction.help.' + (clickSelect ? 'select_from_name' : 'from_name'), {
81872                   from: placeholders.from,
81873                   fromName: displayName(way.id, vgraph)
81874                 })); // Hovering a turn arrow
81875               } else if (datum instanceof osmTurn) {
81876                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
81877                 var turnType = restrictionType.replace(/^(only|no)\_/, '');
81878                 var indirect = datum.direct === false ? _t.html('restriction.help.indirect') : '';
81879                 var klass, turnText, nextText;
81880
81881                 if (datum.no) {
81882                   klass = 'restrict';
81883                   turnText = _t.html('restriction.help.turn.no_' + turnType, {
81884                     indirect: indirect
81885                   });
81886                   nextText = _t.html('restriction.help.turn.only_' + turnType, {
81887                     indirect: ''
81888                   });
81889                 } else if (datum.only) {
81890                   klass = 'only';
81891                   turnText = _t.html('restriction.help.turn.only_' + turnType, {
81892                     indirect: indirect
81893                   });
81894                   nextText = _t.html('restriction.help.turn.allowed_' + turnType, {
81895                     indirect: ''
81896                   });
81897                 } else {
81898                   klass = 'allow';
81899                   turnText = _t.html('restriction.help.turn.allowed_' + turnType, {
81900                     indirect: indirect
81901                   });
81902                   nextText = _t.html('restriction.help.turn.no_' + turnType, {
81903                     indirect: ''
81904                   });
81905                 }
81906
81907                 help.append('div') // "NO Right Turn (indirect)"
81908                 .attr('class', 'qualifier ' + klass).html(turnText);
81909                 help.append('div') // "FROM {fromName} TO {toName}"
81910                 .html(_t.html('restriction.help.from_name_to_name', {
81911                   from: placeholders.from,
81912                   fromName: displayName(datum.from.way, vgraph),
81913                   to: placeholders.to,
81914                   toName: displayName(datum.to.way, vgraph)
81915                 }));
81916
81917                 if (datum.via.ways && datum.via.ways.length) {
81918                   var names = [];
81919
81920                   for (var i = 0; i < datum.via.ways.length; i++) {
81921                     var prev = names[names.length - 1];
81922                     var curr = displayName(datum.via.ways[i], vgraph);
81923
81924                     if (!prev || curr !== prev) {
81925                       // collapse identical names
81926                       names.push(curr);
81927                     }
81928                   }
81929
81930                   help.append('div') // "VIA {viaNames}"
81931                   .html(_t.html('restriction.help.via_names', {
81932                     via: placeholders.via,
81933                     viaNames: names.join(', ')
81934                   }));
81935                 }
81936
81937                 if (!indirect) {
81938                   help.append('div') // Click for "No Right Turn"
81939                   .html(_t.html('restriction.help.toggle', {
81940                     turn: nextText.trim()
81941                   }));
81942                 }
81943
81944                 highlightPathsFrom(null);
81945                 var alongIDs = datum.path.slice();
81946                 surface.selectAll(utilEntitySelector(alongIDs)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only'); // Hovering empty surface
81947               } else {
81948                 highlightPathsFrom(null);
81949
81950                 if (_fromWayID) {
81951                   help.append('div') // "FROM {fromName}"
81952                   .html(_t.html('restriction.help.from_name', {
81953                     from: placeholders.from,
81954                     fromName: displayName(_fromWayID, vgraph)
81955                   }));
81956                 } else {
81957                   help.append('div') // "Click to select a FROM segment."
81958                   .html(_t.html('restriction.help.select_from', {
81959                     from: placeholders.from
81960                   }));
81961                 }
81962               }
81963             }
81964           }
81965
81966           function displayMaxDistance(maxDist) {
81967             var isImperial = !_mainLocalizer.usesMetric();
81968             var opts;
81969
81970             if (isImperial) {
81971               var distToFeet = {
81972                 // imprecise conversion for prettier display
81973                 20: 70,
81974                 25: 85,
81975                 30: 100,
81976                 35: 115,
81977                 40: 130,
81978                 45: 145,
81979                 50: 160
81980               }[maxDist];
81981               opts = {
81982                 distance: _t('units.feet', {
81983                   quantity: distToFeet
81984                 })
81985               };
81986             } else {
81987               opts = {
81988                 distance: _t('units.meters', {
81989                   quantity: maxDist
81990                 })
81991               };
81992             }
81993
81994             return _t.html('restriction.controls.distance_up_to', opts);
81995           }
81996
81997           function displayMaxVia(maxVia) {
81998             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');
81999           }
82000
82001           function displayName(entityID, graph) {
82002             var entity = graph.entity(entityID);
82003             var name = utilDisplayName(entity) || '';
82004             var matched = _mainPresetIndex.match(entity, graph);
82005             var type = matched && matched.name() || utilDisplayType(entity.id);
82006             return name || type;
82007           }
82008
82009           restrictions.entityIDs = function (val) {
82010             _intersection = null;
82011             _fromWayID = null;
82012             _oldTurns = null;
82013             _vertexID = val[0];
82014           };
82015
82016           restrictions.tags = function () {};
82017
82018           restrictions.focus = function () {};
82019
82020           restrictions.off = function (selection) {
82021             if (!_initialized) return;
82022             selection.selectAll('.surface').call(breathe.off).on('click.restrictions', null).on('mouseover.restrictions', null);
82023             select(window).on('resize.restrictions', null);
82024           };
82025
82026           return utilRebind(restrictions, dispatch, 'on');
82027         }
82028         uiFieldRestrictions.supportsMultiselection = false;
82029
82030         function uiFieldTextarea(field, context) {
82031           var dispatch = dispatch$8('change');
82032           var input = select(null);
82033
82034           var _tags;
82035
82036           function textarea(selection) {
82037             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82038             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
82039             input = wrap.selectAll('textarea').data([0]);
82040             input = input.enter().append('textarea').attr('id', field.domId).call(utilNoAuto).on('input', change(true)).on('blur', change()).on('change', change()).merge(input);
82041           }
82042
82043           function change(onInput) {
82044             return function () {
82045               var val = utilGetSetValue(input);
82046               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
82047
82048               if (!val && Array.isArray(_tags[field.key])) return;
82049               var t = {};
82050               t[field.key] = val || undefined;
82051               dispatch.call('change', this, t, onInput);
82052             };
82053           }
82054
82055           textarea.tags = function (tags) {
82056             _tags = tags;
82057             var isMixed = Array.isArray(tags[field.key]);
82058             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);
82059           };
82060
82061           textarea.focus = function () {
82062             input.node().focus();
82063           };
82064
82065           return utilRebind(textarea, dispatch, 'on');
82066         }
82067
82068         var $ = _export;
82069         var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
82070         var toLength = toLength$q;
82071         var notARegExp = notARegexp;
82072         var requireObjectCoercible = requireObjectCoercible$e;
82073         var correctIsRegExpLogic = correctIsRegexpLogic;
82074
82075         // eslint-disable-next-line es/no-string-prototype-endswith -- safe
82076         var $endsWith = ''.endsWith;
82077         var min = Math.min;
82078
82079         var CORRECT_IS_REGEXP_LOGIC = correctIsRegExpLogic('endsWith');
82080         // https://github.com/zloirock/core-js/pull/702
82081         var MDN_POLYFILL_BUG = !CORRECT_IS_REGEXP_LOGIC && !!function () {
82082           var descriptor = getOwnPropertyDescriptor(String.prototype, 'endsWith');
82083           return descriptor && !descriptor.writable;
82084         }();
82085
82086         // `String.prototype.endsWith` method
82087         // https://tc39.es/ecma262/#sec-string.prototype.endswith
82088         $({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
82089           endsWith: function endsWith(searchString /* , endPosition = @length */) {
82090             var that = String(requireObjectCoercible(this));
82091             notARegExp(searchString);
82092             var endPosition = arguments.length > 1 ? arguments[1] : undefined;
82093             var len = toLength(that.length);
82094             var end = endPosition === undefined ? len : min(toLength(endPosition), len);
82095             var search = String(searchString);
82096             return $endsWith
82097               ? $endsWith.call(that, search, end)
82098               : that.slice(end - search.length, end) === search;
82099           }
82100         });
82101
82102         function uiFieldWikidata(field, context) {
82103           var wikidata = services.wikidata;
82104           var dispatch = dispatch$8('change');
82105
82106           var _selection = select(null);
82107
82108           var _searchInput = select(null);
82109
82110           var _qid = null;
82111           var _wikidataEntity = null;
82112           var _wikiURL = '';
82113           var _entityIDs = [];
82114
82115           var _wikipediaKey = field.keys && field.keys.find(function (key) {
82116             return key.includes('wikipedia');
82117           }),
82118               _hintKey = field.key === 'wikidata' ? 'name' : field.key.split(':')[0];
82119
82120           var combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(true).minItems(1);
82121
82122           function wiki(selection) {
82123             _selection = selection;
82124             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82125             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
82126             var list = wrap.selectAll('ul').data([0]);
82127             list = list.enter().append('ul').attr('class', 'rows').merge(list);
82128             var searchRow = list.selectAll('li.wikidata-search').data([0]);
82129             var searchRowEnter = searchRow.enter().append('li').attr('class', 'wikidata-search');
82130             searchRowEnter.append('input').attr('type', 'text').attr('id', field.domId).style('flex', '1').call(utilNoAuto).on('focus', function () {
82131               var node = select(this).node();
82132               node.setSelectionRange(0, node.value.length);
82133             }).on('blur', function () {
82134               setLabelForEntity();
82135             }).call(combobox.fetcher(fetchWikidataItems));
82136             combobox.on('accept', function (d) {
82137               if (d) {
82138                 _qid = d.id;
82139                 change();
82140               }
82141             }).on('cancel', function () {
82142               setLabelForEntity();
82143             });
82144             searchRowEnter.append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
82145               domain: 'wikidata.org'
82146             })).call(svgIcon('#iD-icon-out-link')).on('click', function (d3_event) {
82147               d3_event.preventDefault();
82148               if (_wikiURL) window.open(_wikiURL, '_blank');
82149             });
82150             searchRow = searchRow.merge(searchRowEnter);
82151             _searchInput = searchRow.select('input');
82152             var wikidataProperties = ['description', 'identifier'];
82153             var items = list.selectAll('li.labeled-input').data(wikidataProperties); // Enter
82154
82155             var enter = items.enter().append('li').attr('class', function (d) {
82156               return 'labeled-input preset-wikidata-' + d;
82157             });
82158             enter.append('span').attr('class', 'label').html(function (d) {
82159               return _t.html('wikidata.' + d);
82160             });
82161             enter.append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', 'true').attr('readonly', 'true');
82162             enter.append('button').attr('class', 'form-field-button').attr('title', _t('icons.copy')).call(svgIcon('#iD-operation-copy')).on('click', function (d3_event) {
82163               d3_event.preventDefault();
82164               select(this.parentNode).select('input').node().select();
82165               document.execCommand('copy');
82166             });
82167           }
82168
82169           function fetchWikidataItems(q, callback) {
82170             if (!q && _hintKey) {
82171               // other tags may be good search terms
82172               for (var i in _entityIDs) {
82173                 var entity = context.hasEntity(_entityIDs[i]);
82174
82175                 if (entity.tags[_hintKey]) {
82176                   q = entity.tags[_hintKey];
82177                   break;
82178                 }
82179               }
82180             }
82181
82182             wikidata.itemsForSearchQuery(q, function (err, data) {
82183               if (err) return;
82184
82185               for (var i in data) {
82186                 data[i].value = data[i].label + ' (' + data[i].id + ')';
82187                 data[i].title = data[i].description;
82188               }
82189
82190               if (callback) callback(data);
82191             });
82192           }
82193
82194           function change() {
82195             var syncTags = {};
82196             syncTags[field.key] = _qid;
82197             dispatch.call('change', this, syncTags); // attempt asynchronous update of wikidata tag..
82198
82199             var initGraph = context.graph();
82200             var initEntityIDs = _entityIDs;
82201             wikidata.entityByQID(_qid, function (err, entity) {
82202               if (err) return; // If graph has changed, we can't apply this update.
82203
82204               if (context.graph() !== initGraph) return;
82205               if (!entity.sitelinks) return;
82206               var langs = wikidata.languagesToQuery(); // use the label and description languages as fallbacks
82207
82208               ['labels', 'descriptions'].forEach(function (key) {
82209                 if (!entity[key]) return;
82210                 var valueLangs = Object.keys(entity[key]);
82211                 if (valueLangs.length === 0) return;
82212                 var valueLang = valueLangs[0];
82213
82214                 if (langs.indexOf(valueLang) === -1) {
82215                   langs.push(valueLang);
82216                 }
82217               });
82218               var newWikipediaValue;
82219
82220               if (_wikipediaKey) {
82221                 var foundPreferred;
82222
82223                 for (var i in langs) {
82224                   var lang = langs[i];
82225                   var siteID = lang.replace('-', '_') + 'wiki';
82226
82227                   if (entity.sitelinks[siteID]) {
82228                     foundPreferred = true;
82229                     newWikipediaValue = lang + ':' + entity.sitelinks[siteID].title; // use the first match
82230
82231                     break;
82232                   }
82233                 }
82234
82235                 if (!foundPreferred) {
82236                   // No wikipedia sites available in the user's language or the fallback languages,
82237                   // default to any wikipedia sitelink
82238                   var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function (site) {
82239                     return site.endsWith('wiki');
82240                   });
82241
82242                   if (wikiSiteKeys.length === 0) {
82243                     // if no wikipedia pages are linked to this wikidata entity, delete that tag
82244                     newWikipediaValue = null;
82245                   } else {
82246                     var wikiLang = wikiSiteKeys[0].slice(0, -4).replace('_', '-');
82247                     var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
82248                     newWikipediaValue = wikiLang + ':' + wikiTitle;
82249                   }
82250                 }
82251               }
82252
82253               if (newWikipediaValue) {
82254                 newWikipediaValue = context.cleanTagValue(newWikipediaValue);
82255               }
82256
82257               if (typeof newWikipediaValue === 'undefined') return;
82258               var actions = initEntityIDs.map(function (entityID) {
82259                 var entity = context.hasEntity(entityID);
82260                 if (!entity) return null;
82261                 var currTags = Object.assign({}, entity.tags); // shallow copy
82262
82263                 if (newWikipediaValue === null) {
82264                   if (!currTags[_wikipediaKey]) return null;
82265                   delete currTags[_wikipediaKey];
82266                 } else {
82267                   currTags[_wikipediaKey] = newWikipediaValue;
82268                 }
82269
82270                 return actionChangeTags(entityID, currTags);
82271               }).filter(Boolean);
82272               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
82273
82274               context.overwrite(function actionUpdateWikipediaTags(graph) {
82275                 actions.forEach(function (action) {
82276                   graph = action(graph);
82277                 });
82278                 return graph;
82279               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
82280               // changeTags() is not intended to be called asynchronously
82281             });
82282           }
82283
82284           function setLabelForEntity() {
82285             var label = '';
82286
82287             if (_wikidataEntity) {
82288               label = entityPropertyForDisplay(_wikidataEntity, 'labels');
82289
82290               if (label.length === 0) {
82291                 label = _wikidataEntity.id.toString();
82292               }
82293             }
82294
82295             utilGetSetValue(_searchInput, label);
82296           }
82297
82298           wiki.tags = function (tags) {
82299             var isMixed = Array.isArray(tags[field.key]);
82300
82301             _searchInput.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : '').classed('mixed', isMixed);
82302
82303             _qid = typeof tags[field.key] === 'string' && tags[field.key] || '';
82304
82305             if (!/^Q[0-9]*$/.test(_qid)) {
82306               // not a proper QID
82307               unrecognized();
82308               return;
82309             } // QID value in correct format
82310
82311
82312             _wikiURL = 'https://wikidata.org/wiki/' + _qid;
82313             wikidata.entityByQID(_qid, function (err, entity) {
82314               if (err) {
82315                 unrecognized();
82316                 return;
82317               }
82318
82319               _wikidataEntity = entity;
82320               setLabelForEntity();
82321               var description = entityPropertyForDisplay(entity, 'descriptions');
82322
82323               _selection.select('button.wiki-link').classed('disabled', false);
82324
82325               _selection.select('.preset-wikidata-description').style('display', function () {
82326                 return description.length > 0 ? 'flex' : 'none';
82327               }).select('input').attr('value', description);
82328
82329               _selection.select('.preset-wikidata-identifier').style('display', function () {
82330                 return entity.id ? 'flex' : 'none';
82331               }).select('input').attr('value', entity.id);
82332             }); // not a proper QID
82333
82334             function unrecognized() {
82335               _wikidataEntity = null;
82336               setLabelForEntity();
82337
82338               _selection.select('.preset-wikidata-description').style('display', 'none');
82339
82340               _selection.select('.preset-wikidata-identifier').style('display', 'none');
82341
82342               _selection.select('button.wiki-link').classed('disabled', true);
82343
82344               if (_qid && _qid !== '') {
82345                 _wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + _qid;
82346               } else {
82347                 _wikiURL = '';
82348               }
82349             }
82350           };
82351
82352           function entityPropertyForDisplay(wikidataEntity, propKey) {
82353             if (!wikidataEntity[propKey]) return '';
82354             var propObj = wikidataEntity[propKey];
82355             var langKeys = Object.keys(propObj);
82356             if (langKeys.length === 0) return ''; // sorted by priority, since we want to show the user's language first if possible
82357
82358             var langs = wikidata.languagesToQuery();
82359
82360             for (var i in langs) {
82361               var lang = langs[i];
82362               var valueObj = propObj[lang];
82363               if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
82364             } // default to any available value
82365
82366
82367             return propObj[langKeys[0]].value;
82368           }
82369
82370           wiki.entityIDs = function (val) {
82371             if (!arguments.length) return _entityIDs;
82372             _entityIDs = val;
82373             return wiki;
82374           };
82375
82376           wiki.focus = function () {
82377             _searchInput.node().focus();
82378           };
82379
82380           return utilRebind(wiki, dispatch, 'on');
82381         }
82382
82383         function uiFieldWikipedia(field, context) {
82384           var _arguments = arguments;
82385           var dispatch = dispatch$8('change');
82386           var wikipedia = services.wikipedia;
82387           var wikidata = services.wikidata;
82388
82389           var _langInput = select(null);
82390
82391           var _titleInput = select(null);
82392
82393           var _wikiURL = '';
82394
82395           var _entityIDs;
82396
82397           var _tags;
82398
82399           var _dataWikipedia = [];
82400           _mainFileFetcher.get('wmf_sitematrix').then(function (d) {
82401             _dataWikipedia = d;
82402             if (_tags) updateForTags(_tags);
82403           })["catch"](function () {
82404             /* ignore */
82405           });
82406           var langCombo = uiCombobox(context, 'wikipedia-lang').fetcher(function (value, callback) {
82407             var v = value.toLowerCase();
82408             callback(_dataWikipedia.filter(function (d) {
82409               return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
82410             }).map(function (d) {
82411               return {
82412                 value: d[1]
82413               };
82414             }));
82415           });
82416           var titleCombo = uiCombobox(context, 'wikipedia-title').fetcher(function (value, callback) {
82417             if (!value) {
82418               value = '';
82419
82420               for (var i in _entityIDs) {
82421                 var entity = context.hasEntity(_entityIDs[i]);
82422
82423                 if (entity.tags.name) {
82424                   value = entity.tags.name;
82425                   break;
82426                 }
82427               }
82428             }
82429
82430             var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
82431             searchfn(language()[2], value, function (query, data) {
82432               callback(data.map(function (d) {
82433                 return {
82434                   value: d
82435                 };
82436               }));
82437             });
82438           });
82439
82440           function wiki(selection) {
82441             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82442             wrap = wrap.enter().append('div').attr('class', "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap);
82443             var langContainer = wrap.selectAll('.wiki-lang-container').data([0]);
82444             langContainer = langContainer.enter().append('div').attr('class', 'wiki-lang-container').merge(langContainer);
82445             _langInput = langContainer.selectAll('input.wiki-lang').data([0]);
82446             _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);
82447
82448             _langInput.on('blur', changeLang).on('change', changeLang);
82449
82450             var titleContainer = wrap.selectAll('.wiki-title-container').data([0]);
82451             titleContainer = titleContainer.enter().append('div').attr('class', 'wiki-title-container').merge(titleContainer);
82452             _titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
82453             _titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
82454
82455             _titleInput.on('blur', function () {
82456               change(true);
82457             }).on('change', function () {
82458               change(false);
82459             });
82460
82461             var link = titleContainer.selectAll('.wiki-link').data([0]);
82462             link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
82463               domain: 'wikipedia.org'
82464             })).call(svgIcon('#iD-icon-out-link')).merge(link);
82465             link.on('click', function (d3_event) {
82466               d3_event.preventDefault();
82467               if (_wikiURL) window.open(_wikiURL, '_blank');
82468             });
82469           }
82470
82471           function defaultLanguageInfo(skipEnglishFallback) {
82472             var langCode = _mainLocalizer.languageCode().toLowerCase();
82473
82474             for (var i in _dataWikipedia) {
82475               var d = _dataWikipedia[i]; // default to the language of iD's current locale
82476
82477               if (d[2] === langCode) return d;
82478             } // fallback to English
82479
82480
82481             return skipEnglishFallback ? ['', '', ''] : ['English', 'English', 'en'];
82482           }
82483
82484           function language(skipEnglishFallback) {
82485             var value = utilGetSetValue(_langInput).toLowerCase();
82486
82487             for (var i in _dataWikipedia) {
82488               var d = _dataWikipedia[i]; // return the language already set in the UI, if supported
82489
82490               if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value) return d;
82491             } // fallback to English
82492
82493
82494             return defaultLanguageInfo(skipEnglishFallback);
82495           }
82496
82497           function changeLang() {
82498             utilGetSetValue(_langInput, language()[1]);
82499             change(true);
82500           }
82501
82502           function change(skipWikidata) {
82503             var value = utilGetSetValue(_titleInput);
82504             var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
82505
82506             var langInfo = m && _dataWikipedia.find(function (d) {
82507               return m[1] === d[2];
82508             });
82509
82510             var syncTags = {};
82511
82512             if (langInfo) {
82513               var nativeLangName = langInfo[1]; // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
82514
82515               value = decodeURIComponent(m[2]).replace(/_/g, ' ');
82516
82517               if (m[3]) {
82518                 var anchor; // try {
82519                 // leave this out for now - #6232
82520                 // Best-effort `anchordecode:` implementation
82521                 // anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
82522                 // } catch (e) {
82523
82524                 anchor = decodeURIComponent(m[3]); // }
82525
82526                 value += '#' + anchor.replace(/_/g, ' ');
82527               }
82528
82529               value = value.slice(0, 1).toUpperCase() + value.slice(1);
82530               utilGetSetValue(_langInput, nativeLangName);
82531               utilGetSetValue(_titleInput, value);
82532             }
82533
82534             if (value) {
82535               syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
82536             } else {
82537               syncTags.wikipedia = undefined;
82538             }
82539
82540             dispatch.call('change', this, syncTags);
82541             if (skipWikidata || !value || !language()[2]) return; // attempt asynchronous update of wikidata tag..
82542
82543             var initGraph = context.graph();
82544             var initEntityIDs = _entityIDs;
82545             wikidata.itemsByTitle(language()[2], value, function (err, data) {
82546               if (err || !data || !Object.keys(data).length) return; // If graph has changed, we can't apply this update.
82547
82548               if (context.graph() !== initGraph) return;
82549               var qids = Object.keys(data);
82550               var value = qids && qids.find(function (id) {
82551                 return id.match(/^Q\d+$/);
82552               });
82553               var actions = initEntityIDs.map(function (entityID) {
82554                 var entity = context.entity(entityID).tags;
82555                 var currTags = Object.assign({}, entity); // shallow copy
82556
82557                 if (currTags.wikidata !== value) {
82558                   currTags.wikidata = value;
82559                   return actionChangeTags(entityID, currTags);
82560                 }
82561
82562                 return null;
82563               }).filter(Boolean);
82564               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
82565
82566               context.overwrite(function actionUpdateWikidataTags(graph) {
82567                 actions.forEach(function (action) {
82568                   graph = action(graph);
82569                 });
82570                 return graph;
82571               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
82572               // changeTags() is not intended to be called asynchronously
82573             });
82574           }
82575
82576           wiki.tags = function (tags) {
82577             _tags = tags;
82578             updateForTags(tags);
82579           };
82580
82581           function updateForTags(tags) {
82582             var value = typeof tags[field.key] === 'string' ? tags[field.key] : ''; // Expect tag format of `tagLang:tagArticleTitle`, e.g. `fr:Paris`, with
82583             // optional suffix of `#anchor`
82584
82585             var m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
82586             var tagLang = m && m[1];
82587             var tagArticleTitle = m && m[2];
82588             var anchor = m && m[3];
82589
82590             var tagLangInfo = tagLang && _dataWikipedia.find(function (d) {
82591               return tagLang === d[2];
82592             }); // value in correct format
82593
82594
82595             if (tagLangInfo) {
82596               var nativeLangName = tagLangInfo[1];
82597               utilGetSetValue(_langInput, nativeLangName);
82598               utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? '#' + anchor : ''));
82599
82600               if (anchor) {
82601                 try {
82602                   // Best-effort `anchorencode:` implementation
82603                   anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
82604                 } catch (e) {
82605                   anchor = anchor.replace(/ /g, '_');
82606                 }
82607               }
82608
82609               _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + tagArticleTitle.replace(/ /g, '_') + (anchor ? '#' + anchor : ''); // unrecognized value format
82610             } else {
82611               utilGetSetValue(_titleInput, value);
82612
82613               if (value && value !== '') {
82614                 utilGetSetValue(_langInput, '');
82615                 var defaultLangInfo = defaultLanguageInfo();
82616                 _wikiURL = "https://".concat(defaultLangInfo[2], ".wikipedia.org/w/index.php?fulltext=1&search=").concat(value);
82617               } else {
82618                 var shownOrDefaultLangInfo = language(true
82619                 /* skipEnglishFallback */
82620                 );
82621                 utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
82622                 _wikiURL = '';
82623               }
82624             }
82625           }
82626
82627           wiki.entityIDs = function (val) {
82628             if (!_arguments.length) return _entityIDs;
82629             _entityIDs = val;
82630             return wiki;
82631           };
82632
82633           wiki.focus = function () {
82634             _titleInput.node().focus();
82635           };
82636
82637           return utilRebind(wiki, dispatch, 'on');
82638         }
82639         uiFieldWikipedia.supportsMultiselection = false;
82640
82641         var uiFields = {
82642           access: uiFieldAccess,
82643           address: uiFieldAddress,
82644           check: uiFieldCheck,
82645           combo: uiFieldCombo,
82646           cycleway: uiFieldCycleway,
82647           defaultCheck: uiFieldCheck,
82648           email: uiFieldText,
82649           identifier: uiFieldText,
82650           lanes: uiFieldLanes,
82651           localized: uiFieldLocalized,
82652           roadheight: uiFieldRoadheight,
82653           roadspeed: uiFieldRoadspeed,
82654           manyCombo: uiFieldCombo,
82655           multiCombo: uiFieldCombo,
82656           networkCombo: uiFieldCombo,
82657           number: uiFieldText,
82658           onewayCheck: uiFieldCheck,
82659           radio: uiFieldRadio,
82660           restrictions: uiFieldRestrictions,
82661           semiCombo: uiFieldCombo,
82662           structureRadio: uiFieldRadio,
82663           tel: uiFieldText,
82664           text: uiFieldText,
82665           textarea: uiFieldTextarea,
82666           typeCombo: uiFieldCombo,
82667           url: uiFieldText,
82668           wikidata: uiFieldWikidata,
82669           wikipedia: uiFieldWikipedia
82670         };
82671
82672         function uiField(context, presetField, entityIDs, options) {
82673           options = Object.assign({
82674             show: true,
82675             wrap: true,
82676             remove: true,
82677             revert: true,
82678             info: true
82679           }, options);
82680           var dispatch = dispatch$8('change', 'revert');
82681           var field = Object.assign({}, presetField); // shallow copy
82682
82683           field.domId = utilUniqueDomId('form-field-' + field.safeid);
82684           var _show = options.show;
82685           var _state = '';
82686           var _tags = {};
82687
82688           var _entityExtent;
82689
82690           if (entityIDs && entityIDs.length) {
82691             _entityExtent = entityIDs.reduce(function (extent, entityID) {
82692               var entity = context.graph().entity(entityID);
82693               return extent.extend(entity.extent(context.graph()));
82694             }, geoExtent());
82695           }
82696
82697           var _locked = false;
82698
82699           var _lockedTip = uiTooltip().title(_t.html('inspector.lock.suggestion', {
82700             label: field.label
82701           })).placement('bottom');
82702
82703           field.keys = field.keys || [field.key]; // only create the fields that are actually being shown
82704
82705           if (_show && !field.impl) {
82706             createField();
82707           } // Creates the field.. This is done lazily,
82708           // once we know that the field will be shown.
82709
82710
82711           function createField() {
82712             field.impl = uiFields[field.type](field, context).on('change', function (t, onInput) {
82713               dispatch.call('change', field, t, onInput);
82714             });
82715
82716             if (entityIDs) {
82717               field.entityIDs = entityIDs; // if this field cares about the entities, pass them along
82718
82719               if (field.impl.entityIDs) {
82720                 field.impl.entityIDs(entityIDs);
82721               }
82722             }
82723           }
82724
82725           function isModified() {
82726             if (!entityIDs || !entityIDs.length) return false;
82727             return entityIDs.some(function (entityID) {
82728               var original = context.graph().base().entities[entityID];
82729               var latest = context.graph().entity(entityID);
82730               return field.keys.some(function (key) {
82731                 return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
82732               });
82733             });
82734           }
82735
82736           function tagsContainFieldKey() {
82737             return field.keys.some(function (key) {
82738               if (field.type === 'multiCombo') {
82739                 for (var tagKey in _tags) {
82740                   if (tagKey.indexOf(key) === 0) {
82741                     return true;
82742                   }
82743                 }
82744
82745                 return false;
82746               }
82747
82748               return _tags[key] !== undefined;
82749             });
82750           }
82751
82752           function revert(d3_event, d) {
82753             d3_event.stopPropagation();
82754             d3_event.preventDefault();
82755             if (!entityIDs || _locked) return;
82756             dispatch.call('revert', d, d.keys);
82757           }
82758
82759           function remove(d3_event, d) {
82760             d3_event.stopPropagation();
82761             d3_event.preventDefault();
82762             if (_locked) return;
82763             var t = {};
82764             d.keys.forEach(function (key) {
82765               t[key] = undefined;
82766             });
82767             dispatch.call('change', d, t);
82768           }
82769
82770           field.render = function (selection) {
82771             var container = selection.selectAll('.form-field').data([field]); // Enter
82772
82773             var enter = container.enter().append('div').attr('class', function (d) {
82774               return 'form-field form-field-' + d.safeid;
82775             }).classed('nowrap', !options.wrap);
82776
82777             if (options.wrap) {
82778               var labelEnter = enter.append('label').attr('class', 'field-label').attr('for', function (d) {
82779                 return d.domId;
82780               });
82781               var textEnter = labelEnter.append('span').attr('class', 'label-text');
82782               textEnter.append('span').attr('class', 'label-textvalue').html(function (d) {
82783                 return d.label();
82784               });
82785               textEnter.append('span').attr('class', 'label-textannotation');
82786
82787               if (options.remove) {
82788                 labelEnter.append('button').attr('class', 'remove-icon').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete'));
82789               }
82790
82791               if (options.revert) {
82792                 labelEnter.append('button').attr('class', 'modified-icon').attr('title', _t('icons.undo')).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo'));
82793               }
82794             } // Update
82795
82796
82797             container = container.merge(enter);
82798             container.select('.field-label > .remove-icon') // propagate bound data
82799             .on('click', remove);
82800             container.select('.field-label > .modified-icon') // propagate bound data
82801             .on('click', revert);
82802             container.each(function (d) {
82803               var selection = select(this);
82804
82805               if (!d.impl) {
82806                 createField();
82807               }
82808
82809               var reference, help; // instantiate field help
82810
82811               if (options.wrap && field.type === 'restrictions') {
82812                 help = uiFieldHelp(context, 'restrictions');
82813               } // instantiate tag reference
82814
82815
82816               if (options.wrap && options.info) {
82817                 var referenceKey = d.key || '';
82818
82819                 if (d.type === 'multiCombo') {
82820                   // lookup key without the trailing ':'
82821                   referenceKey = referenceKey.replace(/:$/, '');
82822                 }
82823
82824                 reference = uiTagReference(d.reference || {
82825                   key: referenceKey
82826                 });
82827
82828                 if (_state === 'hover') {
82829                   reference.showing(false);
82830                 }
82831               }
82832
82833               selection.call(d.impl); // add field help components
82834
82835               if (help) {
82836                 selection.call(help.body).select('.field-label').call(help.button);
82837               } // add tag reference components
82838
82839
82840               if (reference) {
82841                 selection.call(reference.body).select('.field-label').call(reference.button);
82842               }
82843
82844               d.impl.tags(_tags);
82845             });
82846             container.classed('locked', _locked).classed('modified', isModified()).classed('present', tagsContainFieldKey()); // show a tip and lock icon if the field is locked
82847
82848             var annotation = container.selectAll('.field-label .label-textannotation');
82849             var icon = annotation.selectAll('.icon').data(_locked ? [0] : []);
82850             icon.exit().remove();
82851             icon.enter().append('svg').attr('class', 'icon').append('use').attr('xlink:href', '#fas-lock');
82852             container.call(_locked ? _lockedTip : _lockedTip.destroy);
82853           };
82854
82855           field.state = function (val) {
82856             if (!arguments.length) return _state;
82857             _state = val;
82858             return field;
82859           };
82860
82861           field.tags = function (val) {
82862             if (!arguments.length) return _tags;
82863             _tags = val;
82864
82865             if (tagsContainFieldKey() && !_show) {
82866               // always show a field if it has a value to display
82867               _show = true;
82868
82869               if (!field.impl) {
82870                 createField();
82871               }
82872             }
82873
82874             return field;
82875           };
82876
82877           field.locked = function (val) {
82878             if (!arguments.length) return _locked;
82879             _locked = val;
82880             return field;
82881           };
82882
82883           field.show = function () {
82884             _show = true;
82885
82886             if (!field.impl) {
82887               createField();
82888             }
82889
82890             if (field["default"] && field.key && _tags[field.key] !== field["default"]) {
82891               var t = {};
82892               t[field.key] = field["default"];
82893               dispatch.call('change', this, t);
82894             }
82895           }; // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
82896
82897
82898           field.isShown = function () {
82899             return _show;
82900           }; // An allowed field can appear in the UI or in the 'Add field' dropdown.
82901           // A non-allowed field is hidden from the user altogether
82902
82903
82904           field.isAllowed = function () {
82905             if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
82906             if (field.geometry && !entityIDs.every(function (entityID) {
82907               return field.matchGeometry(context.graph().geometry(entityID));
82908             })) return false;
82909
82910             if (entityIDs && _entityExtent && field.locationSetID) {
82911               // is field allowed in this location?
82912               var validLocations = _mainLocations.locationsAt(_entityExtent.center());
82913               if (!validLocations[field.locationSetID]) return false;
82914             }
82915
82916             var prerequisiteTag = field.prerequisiteTag;
82917
82918             if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
82919             prerequisiteTag) {
82920               if (!entityIDs.every(function (entityID) {
82921                 var entity = context.graph().entity(entityID);
82922
82923                 if (prerequisiteTag.key) {
82924                   var value = entity.tags[prerequisiteTag.key];
82925                   if (!value) return false;
82926
82927                   if (prerequisiteTag.valueNot) {
82928                     return prerequisiteTag.valueNot !== value;
82929                   }
82930
82931                   if (prerequisiteTag.value) {
82932                     return prerequisiteTag.value === value;
82933                   }
82934                 } else if (prerequisiteTag.keyNot) {
82935                   if (entity.tags[prerequisiteTag.keyNot]) return false;
82936                 }
82937
82938                 return true;
82939               })) return false;
82940             }
82941
82942             return true;
82943           };
82944
82945           field.focus = function () {
82946             if (field.impl) {
82947               field.impl.focus();
82948             }
82949           };
82950
82951           return utilRebind(field, dispatch, 'on');
82952         }
82953
82954         function uiFormFields(context) {
82955           var moreCombo = uiCombobox(context, 'more-fields').minItems(1);
82956           var _fieldsArr = [];
82957           var _lastPlaceholder = '';
82958           var _state = '';
82959           var _klass = '';
82960
82961           function formFields(selection) {
82962             var allowedFields = _fieldsArr.filter(function (field) {
82963               return field.isAllowed();
82964             });
82965
82966             var shown = allowedFields.filter(function (field) {
82967               return field.isShown();
82968             });
82969             var notShown = allowedFields.filter(function (field) {
82970               return !field.isShown();
82971             });
82972             var container = selection.selectAll('.form-fields-container').data([0]);
82973             container = container.enter().append('div').attr('class', 'form-fields-container ' + (_klass || '')).merge(container);
82974             var fields = container.selectAll('.wrap-form-field').data(shown, function (d) {
82975               return d.id + (d.entityIDs ? d.entityIDs.join() : '');
82976             });
82977             fields.exit().remove(); // Enter
82978
82979             var enter = fields.enter().append('div').attr('class', function (d) {
82980               return 'wrap-form-field wrap-form-field-' + d.safeid;
82981             }); // Update
82982
82983             fields = fields.merge(enter);
82984             fields.order().each(function (d) {
82985               select(this).call(d.render);
82986             });
82987             var titles = [];
82988             var moreFields = notShown.map(function (field) {
82989               var title = field.title();
82990               titles.push(title);
82991               var terms = field.terms();
82992               if (field.key) terms.push(field.key);
82993               if (field.keys) terms = terms.concat(field.keys);
82994               return {
82995                 display: field.label(),
82996                 value: title,
82997                 title: title,
82998                 field: field,
82999                 terms: terms
83000               };
83001             });
83002             var placeholder = titles.slice(0, 3).join(', ') + (titles.length > 3 ? '…' : '');
83003             var more = selection.selectAll('.more-fields').data(_state === 'hover' || moreFields.length === 0 ? [] : [0]);
83004             more.exit().remove();
83005             var moreEnter = more.enter().append('div').attr('class', 'more-fields').append('label');
83006             moreEnter.append('span').html(_t.html('inspector.add_fields'));
83007             more = moreEnter.merge(more);
83008             var input = more.selectAll('.value').data([0]);
83009             input.exit().remove();
83010             input = input.enter().append('input').attr('class', 'value').attr('type', 'text').attr('placeholder', placeholder).call(utilNoAuto).merge(input);
83011             input.call(utilGetSetValue, '').call(moreCombo.data(moreFields).on('accept', function (d) {
83012               if (!d) return; // user entered something that was not matched
83013
83014               var field = d.field;
83015               field.show();
83016               selection.call(formFields); // rerender
83017
83018               field.focus();
83019             })); // avoid updating placeholder excessively (triggers style recalc)
83020
83021             if (_lastPlaceholder !== placeholder) {
83022               input.attr('placeholder', placeholder);
83023               _lastPlaceholder = placeholder;
83024             }
83025           }
83026
83027           formFields.fieldsArr = function (val) {
83028             if (!arguments.length) return _fieldsArr;
83029             _fieldsArr = val || [];
83030             return formFields;
83031           };
83032
83033           formFields.state = function (val) {
83034             if (!arguments.length) return _state;
83035             _state = val;
83036             return formFields;
83037           };
83038
83039           formFields.klass = function (val) {
83040             if (!arguments.length) return _klass;
83041             _klass = val;
83042             return formFields;
83043           };
83044
83045           return formFields;
83046         }
83047
83048         function uiSectionPresetFields(context) {
83049           var section = uiSection('preset-fields', context).label(_t.html('inspector.fields')).disclosureContent(renderDisclosureContent);
83050           var dispatch = dispatch$8('change', 'revert');
83051           var formFields = uiFormFields(context);
83052
83053           var _state;
83054
83055           var _fieldsArr;
83056
83057           var _presets = [];
83058
83059           var _tags;
83060
83061           var _entityIDs;
83062
83063           function renderDisclosureContent(selection) {
83064             if (!_fieldsArr) {
83065               var graph = context.graph();
83066               var geometries = Object.keys(_entityIDs.reduce(function (geoms, entityID) {
83067                 geoms[graph.entity(entityID).geometry(graph)] = true;
83068                 return geoms;
83069               }, {}));
83070               var presetsManager = _mainPresetIndex;
83071               var allFields = [];
83072               var allMoreFields = [];
83073               var sharedTotalFields;
83074
83075               _presets.forEach(function (preset) {
83076                 var fields = preset.fields();
83077                 var moreFields = preset.moreFields();
83078                 allFields = utilArrayUnion(allFields, fields);
83079                 allMoreFields = utilArrayUnion(allMoreFields, moreFields);
83080
83081                 if (!sharedTotalFields) {
83082                   sharedTotalFields = utilArrayUnion(fields, moreFields);
83083                 } else {
83084                   sharedTotalFields = sharedTotalFields.filter(function (field) {
83085                     return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
83086                   });
83087                 }
83088               });
83089
83090               var sharedFields = allFields.filter(function (field) {
83091                 return sharedTotalFields.indexOf(field) !== -1;
83092               });
83093               var sharedMoreFields = allMoreFields.filter(function (field) {
83094                 return sharedTotalFields.indexOf(field) !== -1;
83095               });
83096               _fieldsArr = [];
83097               sharedFields.forEach(function (field) {
83098                 if (field.matchAllGeometry(geometries)) {
83099                   _fieldsArr.push(uiField(context, field, _entityIDs));
83100                 }
83101               });
83102               var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
83103
83104               if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field('restrictions')) {
83105                 _fieldsArr.push(uiField(context, presetsManager.field('restrictions'), _entityIDs));
83106               }
83107
83108               var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
83109               additionalFields.sort(function (field1, field2) {
83110                 return field1.label().localeCompare(field2.label(), _mainLocalizer.localeCode());
83111               });
83112               additionalFields.forEach(function (field) {
83113                 if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
83114                   _fieldsArr.push(uiField(context, field, _entityIDs, {
83115                     show: false
83116                   }));
83117                 }
83118               });
83119
83120               _fieldsArr.forEach(function (field) {
83121                 field.on('change', function (t, onInput) {
83122                   dispatch.call('change', field, _entityIDs, t, onInput);
83123                 }).on('revert', function (keys) {
83124                   dispatch.call('revert', field, keys);
83125                 });
83126               });
83127             }
83128
83129             _fieldsArr.forEach(function (field) {
83130               field.state(_state).tags(_tags);
83131             });
83132
83133             selection.call(formFields.fieldsArr(_fieldsArr).state(_state).klass('grouped-items-area'));
83134             selection.selectAll('.wrap-form-field input').on('keydown', function (d3_event) {
83135               // if user presses enter, and combobox is not active, accept edits..
83136               if (d3_event.keyCode === 13 && // ↩ Return
83137               context.container().select('.combobox').empty()) {
83138                 context.enter(modeBrowse(context));
83139               }
83140             });
83141           }
83142
83143           section.presets = function (val) {
83144             if (!arguments.length) return _presets;
83145
83146             if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
83147               _presets = val;
83148               _fieldsArr = null;
83149             }
83150
83151             return section;
83152           };
83153
83154           section.state = function (val) {
83155             if (!arguments.length) return _state;
83156             _state = val;
83157             return section;
83158           };
83159
83160           section.tags = function (val) {
83161             if (!arguments.length) return _tags;
83162             _tags = val; // Don't reset _fieldsArr here.
83163
83164             return section;
83165           };
83166
83167           section.entityIDs = function (val) {
83168             if (!arguments.length) return _entityIDs;
83169
83170             if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
83171               _entityIDs = val;
83172               _fieldsArr = null;
83173             }
83174
83175             return section;
83176           };
83177
83178           return utilRebind(section, dispatch, 'on');
83179         }
83180
83181         function uiSectionRawMemberEditor(context) {
83182           var section = uiSection('raw-member-editor', context).shouldDisplay(function () {
83183             if (!_entityIDs || _entityIDs.length !== 1) return false;
83184             var entity = context.hasEntity(_entityIDs[0]);
83185             return entity && entity.type === 'relation';
83186           }).label(function () {
83187             var entity = context.hasEntity(_entityIDs[0]);
83188             if (!entity) return '';
83189             var gt = entity.members.length > _maxMembers ? '>' : '';
83190             var count = gt + entity.members.slice(0, _maxMembers).length;
83191             return _t('inspector.title_count', {
83192               title: _t.html('inspector.members'),
83193               count: count
83194             });
83195           }).disclosureContent(renderDisclosureContent);
83196           var taginfo = services.taginfo;
83197
83198           var _entityIDs;
83199
83200           var _maxMembers = 1000;
83201
83202           function downloadMember(d3_event, d) {
83203             d3_event.preventDefault(); // display the loading indicator
83204
83205             select(this.parentNode).classed('tag-reference-loading', true);
83206             context.loadEntity(d.id, function () {
83207               section.reRender();
83208             });
83209           }
83210
83211           function zoomToMember(d3_event, d) {
83212             d3_event.preventDefault();
83213             var entity = context.entity(d.id);
83214             context.map().zoomToEase(entity); // highlight the feature in case it wasn't previously on-screen
83215
83216             utilHighlightEntities([d.id], true, context);
83217           }
83218
83219           function selectMember(d3_event, d) {
83220             d3_event.preventDefault(); // remove the hover-highlight styling
83221
83222             utilHighlightEntities([d.id], false, context);
83223             var entity = context.entity(d.id);
83224             var mapExtent = context.map().extent();
83225
83226             if (!entity.intersects(mapExtent, context.graph())) {
83227               // zoom to the entity if its extent is not visible now
83228               context.map().zoomToEase(entity);
83229             }
83230
83231             context.enter(modeSelect(context, [d.id]));
83232           }
83233
83234           function changeRole(d3_event, d) {
83235             var oldRole = d.role;
83236             var newRole = context.cleanRelationRole(select(this).property('value'));
83237
83238             if (oldRole !== newRole) {
83239               var member = {
83240                 id: d.id,
83241                 type: d.type,
83242                 role: newRole
83243               };
83244               context.perform(actionChangeMember(d.relation.id, member, d.index), _t('operations.change_role.annotation', {
83245                 n: 1
83246               }));
83247               context.validator().validate();
83248             }
83249           }
83250
83251           function deleteMember(d3_event, d) {
83252             // remove the hover-highlight styling
83253             utilHighlightEntities([d.id], false, context);
83254             context.perform(actionDeleteMember(d.relation.id, d.index), _t('operations.delete_member.annotation', {
83255               n: 1
83256             }));
83257
83258             if (!context.hasEntity(d.relation.id)) {
83259               // Removing the last member will also delete the relation.
83260               // If this happens we need to exit the selection mode
83261               context.enter(modeBrowse(context));
83262             } else {
83263               // Changing the mode also runs `validate`, but otherwise we need to
83264               // rerun it manually
83265               context.validator().validate();
83266             }
83267           }
83268
83269           function renderDisclosureContent(selection) {
83270             var entityID = _entityIDs[0];
83271             var memberships = [];
83272             var entity = context.entity(entityID);
83273             entity.members.slice(0, _maxMembers).forEach(function (member, index) {
83274               memberships.push({
83275                 index: index,
83276                 id: member.id,
83277                 type: member.type,
83278                 role: member.role,
83279                 relation: entity,
83280                 member: context.hasEntity(member.id),
83281                 domId: utilUniqueDomId(entityID + '-member-' + index)
83282               });
83283             });
83284             var list = selection.selectAll('.member-list').data([0]);
83285             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
83286             var items = list.selectAll('li').data(memberships, function (d) {
83287               return osmEntity.key(d.relation) + ',' + d.index + ',' + (d.member ? osmEntity.key(d.member) : 'incomplete');
83288             });
83289             items.exit().each(unbind).remove();
83290             var itemsEnter = items.enter().append('li').attr('class', 'member-row form-field').classed('member-incomplete', function (d) {
83291               return !d.member;
83292             });
83293             itemsEnter.each(function (d) {
83294               var item = select(this);
83295               var label = item.append('label').attr('class', 'field-label').attr('for', d.domId);
83296
83297               if (d.member) {
83298                 // highlight the member feature in the map while hovering on the list item
83299                 item.on('mouseover', function () {
83300                   utilHighlightEntities([d.id], true, context);
83301                 }).on('mouseout', function () {
83302                   utilHighlightEntities([d.id], false, context);
83303                 });
83304                 var labelLink = label.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectMember);
83305                 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
83306                   var matched = _mainPresetIndex.match(d.member, context.graph());
83307                   return matched && matched.name() || utilDisplayType(d.member.id);
83308                 });
83309                 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
83310                   return utilDisplayName(d.member);
83311                 });
83312                 label.append('button').attr('title', _t('icons.remove')).attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete'));
83313                 label.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToMember);
83314               } else {
83315                 var labelText = label.append('span').attr('class', 'label-text');
83316                 labelText.append('span').attr('class', 'member-entity-type').html(_t.html('inspector.' + d.type, {
83317                   id: d.id
83318                 }));
83319                 labelText.append('span').attr('class', 'member-entity-name').html(_t.html('inspector.incomplete', {
83320                   id: d.id
83321                 }));
83322                 label.append('button').attr('class', 'member-download').attr('title', _t('icons.download')).call(svgIcon('#iD-icon-load')).on('click', downloadMember);
83323               }
83324             });
83325             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
83326             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
83327               return d.domId;
83328             }).property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto);
83329
83330             if (taginfo) {
83331               wrapEnter.each(bindTypeahead);
83332             } // update
83333
83334
83335             items = items.merge(itemsEnter).order();
83336             items.select('input.member-role').property('value', function (d) {
83337               return d.role;
83338             }).on('blur', changeRole).on('change', changeRole);
83339             items.select('button.member-delete').on('click', deleteMember);
83340             var dragOrigin, targetIndex;
83341             items.call(d3_drag().on('start', function (d3_event) {
83342               dragOrigin = {
83343                 x: d3_event.x,
83344                 y: d3_event.y
83345               };
83346               targetIndex = null;
83347             }).on('drag', function (d3_event) {
83348               var x = d3_event.x - dragOrigin.x,
83349                   y = d3_event.y - dragOrigin.y;
83350               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
83351               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
83352               var index = items.nodes().indexOf(this);
83353               select(this).classed('dragging', true);
83354               targetIndex = null;
83355               selection.selectAll('li.member-row').style('transform', function (d2, index2) {
83356                 var node = select(this).node();
83357
83358                 if (index === index2) {
83359                   return 'translate(' + x + 'px, ' + y + 'px)';
83360                 } else if (index2 > index && d3_event.y > node.offsetTop) {
83361                   if (targetIndex === null || index2 > targetIndex) {
83362                     targetIndex = index2;
83363                   }
83364
83365                   return 'translateY(-100%)';
83366                 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
83367                   if (targetIndex === null || index2 < targetIndex) {
83368                     targetIndex = index2;
83369                   }
83370
83371                   return 'translateY(100%)';
83372                 }
83373
83374                 return null;
83375               });
83376             }).on('end', function (d3_event, d) {
83377               if (!select(this).classed('dragging')) return;
83378               var index = items.nodes().indexOf(this);
83379               select(this).classed('dragging', false);
83380               selection.selectAll('li.member-row').style('transform', null);
83381
83382               if (targetIndex !== null) {
83383                 // dragged to a new position, reorder
83384                 context.perform(actionMoveMember(d.relation.id, index, targetIndex), _t('operations.reorder_members.annotation'));
83385                 context.validator().validate();
83386               }
83387             }));
83388
83389             function bindTypeahead(d) {
83390               var row = select(this);
83391               var role = row.selectAll('input.member-role');
83392               var origValue = role.property('value');
83393
83394               function sort(value, data) {
83395                 var sameletter = [];
83396                 var other = [];
83397
83398                 for (var i = 0; i < data.length; i++) {
83399                   if (data[i].value.substring(0, value.length) === value) {
83400                     sameletter.push(data[i]);
83401                   } else {
83402                     other.push(data[i]);
83403                   }
83404                 }
83405
83406                 return sameletter.concat(other);
83407               }
83408
83409               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
83410                 // The `geometry` param is used in the `taginfo.js` interface for
83411                 // filtering results, as a key into the `tag_members_fractions`
83412                 // object.  If we don't know the geometry because the member is
83413                 // not yet downloaded, it's ok to guess based on type.
83414                 var geometry;
83415
83416                 if (d.member) {
83417                   geometry = context.graph().geometry(d.member.id);
83418                 } else if (d.type === 'relation') {
83419                   geometry = 'relation';
83420                 } else if (d.type === 'way') {
83421                   geometry = 'line';
83422                 } else {
83423                   geometry = 'point';
83424                 }
83425
83426                 var rtype = entity.tags.type;
83427                 taginfo.roles({
83428                   debounce: true,
83429                   rtype: rtype || '',
83430                   geometry: geometry,
83431                   query: role
83432                 }, function (err, data) {
83433                   if (!err) callback(sort(role, data));
83434                 });
83435               }).on('cancel', function () {
83436                 role.property('value', origValue);
83437               }));
83438             }
83439
83440             function unbind() {
83441               var row = select(this);
83442               row.selectAll('input.member-role').call(uiCombobox.off, context);
83443             }
83444           }
83445
83446           section.entityIDs = function (val) {
83447             if (!arguments.length) return _entityIDs;
83448             _entityIDs = val;
83449             return section;
83450           };
83451
83452           return section;
83453         }
83454
83455         function actionDeleteMembers(relationId, memberIndexes) {
83456           return function (graph) {
83457             // Remove the members in descending order so removals won't shift what members
83458             // are at the remaining indexes
83459             memberIndexes.sort(function (a, b) {
83460               return b - a;
83461             });
83462
83463             for (var i in memberIndexes) {
83464               graph = actionDeleteMember(relationId, memberIndexes[i])(graph);
83465             }
83466
83467             return graph;
83468           };
83469         }
83470
83471         function uiSectionRawMembershipEditor(context) {
83472           var section = uiSection('raw-membership-editor', context).shouldDisplay(function () {
83473             return _entityIDs && _entityIDs.length;
83474           }).label(function () {
83475             var parents = getSharedParentRelations();
83476             var gt = parents.length > _maxMemberships ? '>' : '';
83477             var count = gt + parents.slice(0, _maxMemberships).length;
83478             return _t('inspector.title_count', {
83479               title: _t.html('inspector.relations'),
83480               count: count
83481             });
83482           }).disclosureContent(renderDisclosureContent);
83483           var taginfo = services.taginfo;
83484           var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d3_event, d) {
83485             if (d.relation) utilHighlightEntities([d.relation.id], true, context);
83486           }).itemsMouseLeave(function (d3_event, d) {
83487             if (d.relation) utilHighlightEntities([d.relation.id], false, context);
83488           });
83489           var _inChange = false;
83490           var _entityIDs = [];
83491
83492           var _showBlank;
83493
83494           var _maxMemberships = 1000;
83495
83496           function getSharedParentRelations() {
83497             var parents = [];
83498
83499             for (var i = 0; i < _entityIDs.length; i++) {
83500               var entity = context.graph().hasEntity(_entityIDs[i]);
83501               if (!entity) continue;
83502
83503               if (i === 0) {
83504                 parents = context.graph().parentRelations(entity);
83505               } else {
83506                 parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
83507               }
83508
83509               if (!parents.length) break;
83510             }
83511
83512             return parents;
83513           }
83514
83515           function getMemberships() {
83516             var memberships = [];
83517             var relations = getSharedParentRelations().slice(0, _maxMemberships);
83518             var isMultiselect = _entityIDs.length > 1;
83519             var i, relation, membership, index, member, indexedMember;
83520
83521             for (i = 0; i < relations.length; i++) {
83522               relation = relations[i];
83523               membership = {
83524                 relation: relation,
83525                 members: [],
83526                 hash: osmEntity.key(relation)
83527               };
83528
83529               for (index = 0; index < relation.members.length; index++) {
83530                 member = relation.members[index];
83531
83532                 if (_entityIDs.indexOf(member.id) !== -1) {
83533                   indexedMember = Object.assign({}, member, {
83534                     index: index
83535                   });
83536                   membership.members.push(indexedMember);
83537                   membership.hash += ',' + index.toString();
83538
83539                   if (!isMultiselect) {
83540                     // For single selections, list one entry per membership per relation.
83541                     // For multiselections, list one entry per relation.
83542                     memberships.push(membership);
83543                     membership = {
83544                       relation: relation,
83545                       members: [],
83546                       hash: osmEntity.key(relation)
83547                     };
83548                   }
83549                 }
83550               }
83551
83552               if (membership.members.length) memberships.push(membership);
83553             }
83554
83555             memberships.forEach(function (membership) {
83556               membership.domId = utilUniqueDomId('membership-' + membership.relation.id);
83557               var roles = [];
83558               membership.members.forEach(function (member) {
83559                 if (roles.indexOf(member.role) === -1) roles.push(member.role);
83560               });
83561               membership.role = roles.length === 1 ? roles[0] : roles;
83562             });
83563             return memberships;
83564           }
83565
83566           function selectRelation(d3_event, d) {
83567             d3_event.preventDefault(); // remove the hover-highlight styling
83568
83569             utilHighlightEntities([d.relation.id], false, context);
83570             context.enter(modeSelect(context, [d.relation.id]));
83571           }
83572
83573           function zoomToRelation(d3_event, d) {
83574             d3_event.preventDefault();
83575             var entity = context.entity(d.relation.id);
83576             context.map().zoomToEase(entity); // highlight the relation in case it wasn't previously on-screen
83577
83578             utilHighlightEntities([d.relation.id], true, context);
83579           }
83580
83581           function changeRole(d3_event, d) {
83582             if (d === 0) return; // called on newrow (shouldn't happen)
83583
83584             if (_inChange) return; // avoid accidental recursive call #5731
83585
83586             var newRole = context.cleanRelationRole(select(this).property('value'));
83587             if (!newRole.trim() && typeof d.role !== 'string') return;
83588             var membersToUpdate = d.members.filter(function (member) {
83589               return member.role !== newRole;
83590             });
83591
83592             if (membersToUpdate.length) {
83593               _inChange = true;
83594               context.perform(function actionChangeMemberRoles(graph) {
83595                 membersToUpdate.forEach(function (member) {
83596                   var newMember = Object.assign({}, member, {
83597                     role: newRole
83598                   });
83599                   delete newMember.index;
83600                   graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
83601                 });
83602                 return graph;
83603               }, _t('operations.change_role.annotation', {
83604                 n: membersToUpdate.length
83605               }));
83606               context.validator().validate();
83607             }
83608
83609             _inChange = false;
83610           }
83611
83612           function addMembership(d, role) {
83613             this.blur(); // avoid keeping focus on the button
83614
83615             _showBlank = false;
83616
83617             function actionAddMembers(relationId, ids, role) {
83618               return function (graph) {
83619                 for (var i in ids) {
83620                   var member = {
83621                     id: ids[i],
83622                     type: graph.entity(ids[i]).type,
83623                     role: role
83624                   };
83625                   graph = actionAddMember(relationId, member)(graph);
83626                 }
83627
83628                 return graph;
83629               };
83630             }
83631
83632             if (d.relation) {
83633               context.perform(actionAddMembers(d.relation.id, _entityIDs, role), _t('operations.add_member.annotation', {
83634                 n: _entityIDs.length
83635               }));
83636               context.validator().validate();
83637             } else {
83638               var relation = osmRelation();
83639               context.perform(actionAddEntity(relation), actionAddMembers(relation.id, _entityIDs, role), _t('operations.add.annotation.relation')); // changing the mode also runs `validate`
83640
83641               context.enter(modeSelect(context, [relation.id]).newFeature(true));
83642             }
83643           }
83644
83645           function deleteMembership(d3_event, d) {
83646             this.blur(); // avoid keeping focus on the button
83647
83648             if (d === 0) return; // called on newrow (shouldn't happen)
83649             // remove the hover-highlight styling
83650
83651             utilHighlightEntities([d.relation.id], false, context);
83652             var indexes = d.members.map(function (member) {
83653               return member.index;
83654             });
83655             context.perform(actionDeleteMembers(d.relation.id, indexes), _t('operations.delete_member.annotation', {
83656               n: _entityIDs.length
83657             }));
83658             context.validator().validate();
83659           }
83660
83661           function fetchNearbyRelations(q, callback) {
83662             var newRelation = {
83663               relation: null,
83664               value: _t('inspector.new_relation'),
83665               display: _t.html('inspector.new_relation')
83666             };
83667             var entityID = _entityIDs[0];
83668             var result = [];
83669             var graph = context.graph();
83670
83671             function baseDisplayLabel(entity) {
83672               var matched = _mainPresetIndex.match(entity, graph);
83673               var presetName = matched && matched.name() || _t('inspector.relation');
83674               var entityName = utilDisplayName(entity) || '';
83675               return presetName + ' ' + entityName;
83676             }
83677
83678             var explicitRelation = q && context.hasEntity(q.toLowerCase());
83679
83680             if (explicitRelation && explicitRelation.type === 'relation' && explicitRelation.id !== entityID) {
83681               // loaded relation is specified explicitly, only show that
83682               result.push({
83683                 relation: explicitRelation,
83684                 value: baseDisplayLabel(explicitRelation) + ' ' + explicitRelation.id
83685               });
83686             } else {
83687               context.history().intersects(context.map().extent()).forEach(function (entity) {
83688                 if (entity.type !== 'relation' || entity.id === entityID) return;
83689                 var value = baseDisplayLabel(entity);
83690                 if (q && (value + ' ' + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1) return;
83691                 result.push({
83692                   relation: entity,
83693                   value: value
83694                 });
83695               });
83696               result.sort(function (a, b) {
83697                 return osmRelation.creationOrder(a.relation, b.relation);
83698               }); // Dedupe identical names by appending relation id - see #2891
83699
83700               var dupeGroups = Object.values(utilArrayGroupBy(result, 'value')).filter(function (v) {
83701                 return v.length > 1;
83702               });
83703               dupeGroups.forEach(function (group) {
83704                 group.forEach(function (obj) {
83705                   obj.value += ' ' + obj.relation.id;
83706                 });
83707               });
83708             }
83709
83710             result.forEach(function (obj) {
83711               obj.title = obj.value;
83712             });
83713             result.unshift(newRelation);
83714             callback(result);
83715           }
83716
83717           function renderDisclosureContent(selection) {
83718             var memberships = getMemberships();
83719             var list = selection.selectAll('.member-list').data([0]);
83720             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
83721             var items = list.selectAll('li.member-row-normal').data(memberships, function (d) {
83722               return d.hash;
83723             });
83724             items.exit().each(unbind).remove(); // Enter
83725
83726             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
83727
83728             itemsEnter.on('mouseover', function (d3_event, d) {
83729               utilHighlightEntities([d.relation.id], true, context);
83730             }).on('mouseout', function (d3_event, d) {
83731               utilHighlightEntities([d.relation.id], false, context);
83732             });
83733             var labelEnter = itemsEnter.append('label').attr('class', 'field-label').attr('for', function (d) {
83734               return d.domId;
83735             });
83736             var labelLink = labelEnter.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectRelation);
83737             labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
83738               var matched = _mainPresetIndex.match(d.relation, context.graph());
83739               return matched && matched.name() || _t('inspector.relation');
83740             });
83741             labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
83742               return utilDisplayName(d.relation);
83743             });
83744             labelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', deleteMembership);
83745             labelEnter.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToRelation);
83746             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
83747             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
83748               return d.domId;
83749             }).property('type', 'text').property('value', function (d) {
83750               return typeof d.role === 'string' ? d.role : '';
83751             }).attr('title', function (d) {
83752               return Array.isArray(d.role) ? d.role.filter(Boolean).join('\n') : d.role;
83753             }).attr('placeholder', function (d) {
83754               return Array.isArray(d.role) ? _t('inspector.multiple_roles') : _t('inspector.role');
83755             }).classed('mixed', function (d) {
83756               return Array.isArray(d.role);
83757             }).call(utilNoAuto).on('blur', changeRole).on('change', changeRole);
83758
83759             if (taginfo) {
83760               wrapEnter.each(bindTypeahead);
83761             }
83762
83763             var newMembership = list.selectAll('.member-row-new').data(_showBlank ? [0] : []); // Exit
83764
83765             newMembership.exit().remove(); // Enter
83766
83767             var newMembershipEnter = newMembership.enter().append('li').attr('class', 'member-row member-row-new form-field');
83768             var newLabelEnter = newMembershipEnter.append('label').attr('class', 'field-label');
83769             newLabelEnter.append('input').attr('placeholder', _t('inspector.choose_relation')).attr('type', 'text').attr('class', 'member-entity-input').call(utilNoAuto);
83770             newLabelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', function () {
83771               list.selectAll('.member-row-new').remove();
83772             });
83773             var newWrapEnter = newMembershipEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
83774             newWrapEnter.append('input').attr('class', 'member-role').property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto); // Update
83775
83776             newMembership = newMembership.merge(newMembershipEnter);
83777             newMembership.selectAll('.member-entity-input').on('blur', cancelEntity) // if it wasn't accepted normally, cancel it
83778             .call(nearbyCombo.on('accept', acceptEntity).on('cancel', cancelEntity)); // Container for the Add button
83779
83780             var addRow = selection.selectAll('.add-row').data([0]); // enter
83781
83782             var addRowEnter = addRow.enter().append('div').attr('class', 'add-row');
83783             var addRelationButton = addRowEnter.append('button').attr('class', 'add-relation');
83784             addRelationButton.call(svgIcon('#iD-icon-plus', 'light'));
83785             addRelationButton.call(uiTooltip().title(_t.html('inspector.add_to_relation')).placement(_mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left'));
83786             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
83787
83788             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
83789             // update
83790
83791             addRow = addRow.merge(addRowEnter);
83792             addRow.select('.add-relation').on('click', function () {
83793               _showBlank = true;
83794               section.reRender();
83795               list.selectAll('.member-entity-input').node().focus();
83796             });
83797
83798             function acceptEntity(d) {
83799               if (!d) {
83800                 cancelEntity();
83801                 return;
83802               } // remove hover-higlighting
83803
83804
83805               if (d.relation) utilHighlightEntities([d.relation.id], false, context);
83806               var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
83807               addMembership(d, role);
83808             }
83809
83810             function cancelEntity() {
83811               var input = newMembership.selectAll('.member-entity-input');
83812               input.property('value', ''); // remove hover-higlighting
83813
83814               context.surface().selectAll('.highlighted').classed('highlighted', false);
83815             }
83816
83817             function bindTypeahead(d) {
83818               var row = select(this);
83819               var role = row.selectAll('input.member-role');
83820               var origValue = role.property('value');
83821
83822               function sort(value, data) {
83823                 var sameletter = [];
83824                 var other = [];
83825
83826                 for (var i = 0; i < data.length; i++) {
83827                   if (data[i].value.substring(0, value.length) === value) {
83828                     sameletter.push(data[i]);
83829                   } else {
83830                     other.push(data[i]);
83831                   }
83832                 }
83833
83834                 return sameletter.concat(other);
83835               }
83836
83837               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
83838                 var rtype = d.relation.tags.type;
83839                 taginfo.roles({
83840                   debounce: true,
83841                   rtype: rtype || '',
83842                   geometry: context.graph().geometry(_entityIDs[0]),
83843                   query: role
83844                 }, function (err, data) {
83845                   if (!err) callback(sort(role, data));
83846                 });
83847               }).on('cancel', function () {
83848                 role.property('value', origValue);
83849               }));
83850             }
83851
83852             function unbind() {
83853               var row = select(this);
83854               row.selectAll('input.member-role').call(uiCombobox.off, context);
83855             }
83856           }
83857
83858           section.entityIDs = function (val) {
83859             if (!arguments.length) return _entityIDs;
83860             _entityIDs = val;
83861             _showBlank = false;
83862             return section;
83863           };
83864
83865           return section;
83866         }
83867
83868         function uiSectionSelectionList(context) {
83869           var _selectedIDs = [];
83870           var section = uiSection('selected-features', context).shouldDisplay(function () {
83871             return _selectedIDs.length > 1;
83872           }).label(function () {
83873             return _t('inspector.title_count', {
83874               title: _t.html('inspector.features'),
83875               count: _selectedIDs.length
83876             });
83877           }).disclosureContent(renderDisclosureContent);
83878           context.history().on('change.selectionList', function (difference) {
83879             if (difference) {
83880               section.reRender();
83881             }
83882           });
83883
83884           section.entityIDs = function (val) {
83885             if (!arguments.length) return _selectedIDs;
83886             _selectedIDs = val;
83887             return section;
83888           };
83889
83890           function selectEntity(d3_event, entity) {
83891             context.enter(modeSelect(context, [entity.id]));
83892           }
83893
83894           function deselectEntity(d3_event, entity) {
83895             var selectedIDs = _selectedIDs.slice();
83896
83897             var index = selectedIDs.indexOf(entity.id);
83898
83899             if (index > -1) {
83900               selectedIDs.splice(index, 1);
83901               context.enter(modeSelect(context, selectedIDs));
83902             }
83903           }
83904
83905           function renderDisclosureContent(selection) {
83906             var list = selection.selectAll('.feature-list').data([0]);
83907             list = list.enter().append('ul').attr('class', 'feature-list').merge(list);
83908
83909             var entities = _selectedIDs.map(function (id) {
83910               return context.hasEntity(id);
83911             }).filter(Boolean);
83912
83913             var items = list.selectAll('.feature-list-item').data(entities, osmEntity.key);
83914             items.exit().remove(); // Enter
83915
83916             var enter = items.enter().append('li').attr('class', 'feature-list-item').each(function (d) {
83917               select(this).on('mouseover', function () {
83918                 utilHighlightEntities([d.id], true, context);
83919               }).on('mouseout', function () {
83920                 utilHighlightEntities([d.id], false, context);
83921               });
83922             });
83923             var label = enter.append('button').attr('class', 'label').on('click', selectEntity);
83924             label.append('span').attr('class', 'entity-geom-icon').call(svgIcon('', 'pre-text'));
83925             label.append('span').attr('class', 'entity-type');
83926             label.append('span').attr('class', 'entity-name');
83927             enter.append('button').attr('class', 'close').attr('title', _t('icons.deselect')).on('click', deselectEntity).call(svgIcon('#iD-icon-close')); // Update
83928
83929             items = items.merge(enter);
83930             items.selectAll('.entity-geom-icon use').attr('href', function () {
83931               var entity = this.parentNode.parentNode.__data__;
83932               return '#iD-icon-' + entity.geometry(context.graph());
83933             });
83934             items.selectAll('.entity-type').html(function (entity) {
83935               return _mainPresetIndex.match(entity, context.graph()).name();
83936             });
83937             items.selectAll('.entity-name').html(function (d) {
83938               // fetch latest entity
83939               var entity = context.entity(d.id);
83940               return utilDisplayName(entity);
83941             });
83942           }
83943
83944           return section;
83945         }
83946
83947         function uiEntityEditor(context) {
83948           var dispatch = dispatch$8('choose');
83949           var _state = 'select';
83950           var _coalesceChanges = false;
83951           var _modified = false;
83952
83953           var _base;
83954
83955           var _entityIDs;
83956
83957           var _activePresets = [];
83958
83959           var _newFeature;
83960
83961           var _sections;
83962
83963           function entityEditor(selection) {
83964             var combinedTags = utilCombinedTags(_entityIDs, context.graph()); // Header
83965
83966             var header = selection.selectAll('.header').data([0]); // Enter
83967
83968             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
83969             headerEnter.append('button').attr('class', 'preset-reset preset-choose').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-forward' : '#iD-icon-backward'));
83970             headerEnter.append('button').attr('class', 'close').on('click', function () {
83971               context.enter(modeBrowse(context));
83972             }).call(svgIcon(_modified ? '#iD-icon-apply' : '#iD-icon-close'));
83973             headerEnter.append('h3'); // Update
83974
83975             header = header.merge(headerEnter);
83976             header.selectAll('h3').html(_entityIDs.length === 1 ? _t.html('inspector.edit') : _t.html('inspector.edit_features'));
83977             header.selectAll('.preset-reset').on('click', function () {
83978               dispatch.call('choose', this, _activePresets);
83979             }); // Body
83980
83981             var body = selection.selectAll('.inspector-body').data([0]); // Enter
83982
83983             var bodyEnter = body.enter().append('div').attr('class', 'entity-editor inspector-body sep-top'); // Update
83984
83985             body = body.merge(bodyEnter);
83986
83987             if (!_sections) {
83988               _sections = [uiSectionSelectionList(context), uiSectionFeatureType(context).on('choose', function (presets) {
83989                 dispatch.call('choose', this, presets);
83990               }), uiSectionEntityIssues(context), uiSectionPresetFields(context).on('change', changeTags).on('revert', revertTags), uiSectionRawTagEditor('raw-tag-editor', context).on('change', changeTags), uiSectionRawMemberEditor(context), uiSectionRawMembershipEditor(context)];
83991             }
83992
83993             _sections.forEach(function (section) {
83994               if (section.entityIDs) {
83995                 section.entityIDs(_entityIDs);
83996               }
83997
83998               if (section.presets) {
83999                 section.presets(_activePresets);
84000               }
84001
84002               if (section.tags) {
84003                 section.tags(combinedTags);
84004               }
84005
84006               if (section.state) {
84007                 section.state(_state);
84008               }
84009
84010               body.call(section.render);
84011             });
84012
84013             context.history().on('change.entity-editor', historyChanged);
84014
84015             function historyChanged(difference) {
84016               if (selection.selectAll('.entity-editor').empty()) return;
84017               if (_state === 'hide') return;
84018               var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
84019               if (!significant) return;
84020               _entityIDs = _entityIDs.filter(context.hasEntity);
84021               if (!_entityIDs.length) return;
84022               var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
84023               loadActivePresets();
84024               var graph = context.graph();
84025               entityEditor.modified(_base !== graph);
84026               entityEditor(selection);
84027
84028               if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
84029                 // flash the button to indicate the preset changed
84030                 context.container().selectAll('.entity-editor button.preset-reset .label').style('background-color', '#fff').transition().duration(750).style('background-color', null);
84031               }
84032             }
84033           } // Tag changes that fire on input can all get coalesced into a single
84034           // history operation when the user leaves the field.  #2342
84035           // Use explicit entityIDs in case the selection changes before the event is fired.
84036
84037
84038           function changeTags(entityIDs, changed, onInput) {
84039             var actions = [];
84040
84041             for (var i in entityIDs) {
84042               var entityID = entityIDs[i];
84043               var entity = context.entity(entityID);
84044               var tags = Object.assign({}, entity.tags); // shallow copy
84045
84046               for (var k in changed) {
84047                 if (!k) continue;
84048                 var v = changed[k];
84049
84050                 if (v !== undefined || tags.hasOwnProperty(k)) {
84051                   tags[k] = v;
84052                 }
84053               }
84054
84055               if (!onInput) {
84056                 tags = utilCleanTags(tags);
84057               }
84058
84059               if (!fastDeepEqual(entity.tags, tags)) {
84060                 actions.push(actionChangeTags(entityID, tags));
84061               }
84062             }
84063
84064             if (actions.length) {
84065               var combinedAction = function combinedAction(graph) {
84066                 actions.forEach(function (action) {
84067                   graph = action(graph);
84068                 });
84069                 return graph;
84070               };
84071
84072               var annotation = _t('operations.change_tags.annotation');
84073
84074               if (_coalesceChanges) {
84075                 context.overwrite(combinedAction, annotation);
84076               } else {
84077                 context.perform(combinedAction, annotation);
84078                 _coalesceChanges = !!onInput;
84079               }
84080             } // if leaving field (blur event), rerun validation
84081
84082
84083             if (!onInput) {
84084               context.validator().validate();
84085             }
84086           }
84087
84088           function revertTags(keys) {
84089             var actions = [];
84090
84091             for (var i in _entityIDs) {
84092               var entityID = _entityIDs[i];
84093               var original = context.graph().base().entities[entityID];
84094               var changed = {};
84095
84096               for (var j in keys) {
84097                 var key = keys[j];
84098                 changed[key] = original ? original.tags[key] : undefined;
84099               }
84100
84101               var entity = context.entity(entityID);
84102               var tags = Object.assign({}, entity.tags); // shallow copy
84103
84104               for (var k in changed) {
84105                 if (!k) continue;
84106                 var v = changed[k];
84107
84108                 if (v !== undefined || tags.hasOwnProperty(k)) {
84109                   tags[k] = v;
84110                 }
84111               }
84112
84113               tags = utilCleanTags(tags);
84114
84115               if (!fastDeepEqual(entity.tags, tags)) {
84116                 actions.push(actionChangeTags(entityID, tags));
84117               }
84118             }
84119
84120             if (actions.length) {
84121               var combinedAction = function combinedAction(graph) {
84122                 actions.forEach(function (action) {
84123                   graph = action(graph);
84124                 });
84125                 return graph;
84126               };
84127
84128               var annotation = _t('operations.change_tags.annotation');
84129
84130               if (_coalesceChanges) {
84131                 context.overwrite(combinedAction, annotation);
84132               } else {
84133                 context.perform(combinedAction, annotation);
84134                 _coalesceChanges = false;
84135               }
84136             }
84137
84138             context.validator().validate();
84139           }
84140
84141           entityEditor.modified = function (val) {
84142             if (!arguments.length) return _modified;
84143             _modified = val;
84144             return entityEditor;
84145           };
84146
84147           entityEditor.state = function (val) {
84148             if (!arguments.length) return _state;
84149             _state = val;
84150             return entityEditor;
84151           };
84152
84153           entityEditor.entityIDs = function (val) {
84154             if (!arguments.length) return _entityIDs; // always reload these even if the entityIDs are unchanged, since we
84155             // could be reselecting after something like dragging a node
84156
84157             _base = context.graph();
84158             _coalesceChanges = false;
84159             if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor; // exit early if no change
84160
84161             _entityIDs = val;
84162             loadActivePresets(true);
84163             return entityEditor.modified(false);
84164           };
84165
84166           entityEditor.newFeature = function (val) {
84167             if (!arguments.length) return _newFeature;
84168             _newFeature = val;
84169             return entityEditor;
84170           };
84171
84172           function loadActivePresets(isForNewSelection) {
84173             var graph = context.graph();
84174             var counts = {};
84175
84176             for (var i in _entityIDs) {
84177               var entity = graph.hasEntity(_entityIDs[i]);
84178               if (!entity) return;
84179               var match = _mainPresetIndex.match(entity, graph);
84180               if (!counts[match.id]) counts[match.id] = 0;
84181               counts[match.id] += 1;
84182             }
84183
84184             var matches = Object.keys(counts).sort(function (p1, p2) {
84185               return counts[p2] - counts[p1];
84186             }).map(function (pID) {
84187               return _mainPresetIndex.item(pID);
84188             });
84189
84190             if (!isForNewSelection) {
84191               // A "weak" preset doesn't set any tags. (e.g. "Address")
84192               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")
84193
84194               if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
84195             }
84196
84197             entityEditor.presets(matches);
84198           }
84199
84200           entityEditor.presets = function (val) {
84201             if (!arguments.length) return _activePresets; // don't reload the same preset
84202
84203             if (!utilArrayIdentical(val, _activePresets)) {
84204               _activePresets = val;
84205             }
84206
84207             return entityEditor;
84208           };
84209
84210           return utilRebind(entityEditor, dispatch, 'on');
84211         }
84212
84213         function uiPresetList(context) {
84214           var dispatch = dispatch$8('cancel', 'choose');
84215
84216           var _entityIDs;
84217
84218           var _currLoc;
84219
84220           var _currentPresets;
84221
84222           var _autofocus = false;
84223
84224           function presetList(selection) {
84225             if (!_entityIDs) return;
84226             var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
84227             selection.html('');
84228             var messagewrap = selection.append('div').attr('class', 'header fillL');
84229             var message = messagewrap.append('h3').html(_t.html('inspector.choose'));
84230             messagewrap.append('button').attr('class', 'preset-choose').on('click', function () {
84231               dispatch.call('cancel', this);
84232             }).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'));
84233
84234             function initialKeydown(d3_event) {
84235               // hack to let delete shortcut work when search is autofocused
84236               if (search.property('value').length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
84237                 d3_event.preventDefault();
84238                 d3_event.stopPropagation();
84239                 operationDelete(context, _entityIDs)(); // hack to let undo work when search is autofocused
84240               } else if (search.property('value').length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
84241                 d3_event.preventDefault();
84242                 d3_event.stopPropagation();
84243                 context.undo();
84244               } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
84245                 // don't check for delete/undo hack on future keydown events
84246                 select(this).on('keydown', keydown);
84247                 keydown.call(this, d3_event);
84248               }
84249             }
84250
84251             function keydown(d3_event) {
84252               // down arrow
84253               if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] && // if insertion point is at the end of the string
84254               search.node().selectionStart === search.property('value').length) {
84255                 d3_event.preventDefault();
84256                 d3_event.stopPropagation(); // move focus to the first item in the preset list
84257
84258                 var buttons = list.selectAll('.preset-list-button');
84259                 if (!buttons.empty()) buttons.nodes()[0].focus();
84260               }
84261             }
84262
84263             function keypress(d3_event) {
84264               // enter
84265               var value = search.property('value');
84266
84267               if (d3_event.keyCode === 13 && // ↩ Return
84268               value.length) {
84269                 list.selectAll('.preset-list-item:first-child').each(function (d) {
84270                   d.choose.call(this);
84271                 });
84272               }
84273             }
84274
84275             function inputevent() {
84276               var value = search.property('value');
84277               list.classed('filtered', value.length);
84278               var results, messageText;
84279
84280               if (value.length) {
84281                 results = presets.search(value, entityGeometries()[0], _currLoc);
84282                 messageText = _t('inspector.results', {
84283                   n: results.collection.length,
84284                   search: value
84285                 });
84286               } else {
84287                 results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc);
84288                 messageText = _t('inspector.choose');
84289               }
84290
84291               list.call(drawList, results);
84292               message.html(messageText);
84293             }
84294
84295             var searchWrap = selection.append('div').attr('class', 'search-header');
84296             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
84297             var search = searchWrap.append('input').attr('class', 'preset-search-input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keydown', initialKeydown).on('keypress', keypress).on('input', debounce(inputevent));
84298
84299             if (_autofocus) {
84300               search.node().focus(); // Safari 14 doesn't always like to focus immediately,
84301               // so try again on the next pass
84302
84303               setTimeout(function () {
84304                 search.node().focus();
84305               }, 0);
84306             }
84307
84308             var listWrap = selection.append('div').attr('class', 'inspector-body');
84309             var list = listWrap.append('div').attr('class', 'preset-list').call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc));
84310             context.features().on('change.preset-list', updateForFeatureHiddenState);
84311           }
84312
84313           function drawList(list, presets) {
84314             presets = presets.matchAllGeometry(entityGeometries());
84315             var collection = presets.collection.reduce(function (collection, preset) {
84316               if (!preset) return collection;
84317
84318               if (preset.members) {
84319                 if (preset.members.collection.filter(function (preset) {
84320                   return preset.addable();
84321                 }).length > 1) {
84322                   collection.push(CategoryItem(preset));
84323                 }
84324               } else if (preset.addable()) {
84325                 collection.push(PresetItem(preset));
84326               }
84327
84328               return collection;
84329             }, []);
84330             var items = list.selectAll('.preset-list-item').data(collection, function (d) {
84331               return d.preset.id;
84332             });
84333             items.order();
84334             items.exit().remove();
84335             items.enter().append('div').attr('class', function (item) {
84336               return 'preset-list-item preset-' + item.preset.id.replace('/', '-');
84337             }).classed('current', function (item) {
84338               return _currentPresets.indexOf(item.preset) !== -1;
84339             }).each(function (item) {
84340               select(this).call(item);
84341             }).style('opacity', 0).transition().style('opacity', 1);
84342             updateForFeatureHiddenState();
84343           }
84344
84345           function itemKeydown(d3_event) {
84346             // the actively focused item
84347             var item = select(this.closest('.preset-list-item'));
84348             var parentItem = select(item.node().parentNode.closest('.preset-list-item')); // arrow down, move focus to the next, lower item
84349
84350             if (d3_event.keyCode === utilKeybinding.keyCodes['↓']) {
84351               d3_event.preventDefault();
84352               d3_event.stopPropagation(); // the next item in the list at the same level
84353
84354               var nextItem = select(item.node().nextElementSibling); // if there is no next item in this list
84355
84356               if (nextItem.empty()) {
84357                 // if there is a parent item
84358                 if (!parentItem.empty()) {
84359                   // the item is the last item of a sublist,
84360                   // select the next item at the parent level
84361                   nextItem = select(parentItem.node().nextElementSibling);
84362                 } // if the focused item is expanded
84363
84364               } else if (select(this).classed('expanded')) {
84365                 // select the first subitem instead
84366                 nextItem = item.select('.subgrid .preset-list-item:first-child');
84367               }
84368
84369               if (!nextItem.empty()) {
84370                 // focus on the next item
84371                 nextItem.select('.preset-list-button').node().focus();
84372               } // arrow up, move focus to the previous, higher item
84373
84374             } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑']) {
84375               d3_event.preventDefault();
84376               d3_event.stopPropagation(); // the previous item in the list at the same level
84377
84378               var previousItem = select(item.node().previousElementSibling); // if there is no previous item in this list
84379
84380               if (previousItem.empty()) {
84381                 // if there is a parent item
84382                 if (!parentItem.empty()) {
84383                   // the item is the first subitem of a sublist select the parent item
84384                   previousItem = parentItem;
84385                 } // if the previous item is expanded
84386
84387               } else if (previousItem.select('.preset-list-button').classed('expanded')) {
84388                 // select the last subitem of the sublist of the previous item
84389                 previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
84390               }
84391
84392               if (!previousItem.empty()) {
84393                 // focus on the previous item
84394                 previousItem.select('.preset-list-button').node().focus();
84395               } else {
84396                 // the focus is at the top of the list, move focus back to the search field
84397                 var search = select(this.closest('.preset-list-pane')).select('.preset-search-input');
84398                 search.node().focus();
84399               } // arrow left, move focus to the parent item if there is one
84400
84401             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
84402               d3_event.preventDefault();
84403               d3_event.stopPropagation(); // if there is a parent item, focus on the parent item
84404
84405               if (!parentItem.empty()) {
84406                 parentItem.select('.preset-list-button').node().focus();
84407               } // arrow right, choose this item
84408
84409             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
84410               d3_event.preventDefault();
84411               d3_event.stopPropagation();
84412               item.datum().choose.call(select(this).node());
84413             }
84414           }
84415
84416           function CategoryItem(preset) {
84417             var box,
84418                 sublist,
84419                 shown = false;
84420
84421             function item(selection) {
84422               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap category');
84423
84424               function click() {
84425                 var isExpanded = select(this).classed('expanded');
84426                 var iconName = isExpanded ? _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward' : '#iD-icon-down';
84427                 select(this).classed('expanded', !isExpanded);
84428                 select(this).selectAll('div.label-inner svg.icon use').attr('href', iconName);
84429                 item.choose();
84430               }
84431
84432               var geometries = entityGeometries();
84433               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) {
84434                 // right arrow, expand the focused item
84435                 if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
84436                   d3_event.preventDefault();
84437                   d3_event.stopPropagation(); // if the item isn't expanded
84438
84439                   if (!select(this).classed('expanded')) {
84440                     // toggle expansion (expand the item)
84441                     click.call(this, d3_event);
84442                   } // left arrow, collapse the focused item
84443
84444                 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
84445                   d3_event.preventDefault();
84446                   d3_event.stopPropagation(); // if the item is expanded
84447
84448                   if (select(this).classed('expanded')) {
84449                     // toggle expansion (collapse the item)
84450                     click.call(this, d3_event);
84451                   }
84452                 } else {
84453                   itemKeydown.call(this, d3_event);
84454                 }
84455               });
84456               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
84457               label.append('div').attr('class', 'namepart').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline')).append('span').html(function () {
84458                 return preset.nameLabel() + '&hellip;';
84459               });
84460               box = selection.append('div').attr('class', 'subgrid').style('max-height', '0px').style('opacity', 0);
84461               box.append('div').attr('class', 'arrow');
84462               sublist = box.append('div').attr('class', 'preset-list fillL3');
84463             }
84464
84465             item.choose = function () {
84466               if (!box || !sublist) return;
84467
84468               if (shown) {
84469                 shown = false;
84470                 box.transition().duration(200).style('opacity', '0').style('max-height', '0px').style('padding-bottom', '0px');
84471               } else {
84472                 shown = true;
84473                 var members = preset.members.matchAllGeometry(entityGeometries());
84474                 sublist.call(drawList, members);
84475                 box.transition().duration(200).style('opacity', '1').style('max-height', 200 + members.collection.length * 190 + 'px').style('padding-bottom', '10px');
84476               }
84477             };
84478
84479             item.preset = preset;
84480             return item;
84481           }
84482
84483           function PresetItem(preset) {
84484             function item(selection) {
84485               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap');
84486               var geometries = entityGeometries();
84487               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);
84488               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
84489               var nameparts = [preset.nameLabel(), preset.subtitleLabel()].filter(Boolean);
84490               label.selectAll('.namepart').data(nameparts).enter().append('div').attr('class', 'namepart').html(function (d) {
84491                 return d;
84492               });
84493               wrap.call(item.reference.button);
84494               selection.call(item.reference.body);
84495             }
84496
84497             item.choose = function () {
84498               if (select(this).classed('disabled')) return;
84499
84500               if (!context.inIntro()) {
84501                 _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
84502               }
84503
84504               context.perform(function (graph) {
84505                 for (var i in _entityIDs) {
84506                   var entityID = _entityIDs[i];
84507                   var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
84508                   graph = actionChangePreset(entityID, oldPreset, preset)(graph);
84509                 }
84510
84511                 return graph;
84512               }, _t('operations.change_tags.annotation'));
84513               context.validator().validate(); // rerun validation
84514
84515               dispatch.call('choose', this, preset);
84516             };
84517
84518             item.help = function (d3_event) {
84519               d3_event.stopPropagation();
84520               item.reference.toggle();
84521             };
84522
84523             item.preset = preset;
84524             item.reference = uiTagReference(preset.reference());
84525             return item;
84526           }
84527
84528           function updateForFeatureHiddenState() {
84529             if (!_entityIDs.every(context.hasEntity)) return;
84530             var geometries = entityGeometries();
84531             var button = context.container().selectAll('.preset-list .preset-list-button'); // remove existing tooltips
84532
84533             button.call(uiTooltip().destroyAny);
84534             button.each(function (item, index) {
84535               var hiddenPresetFeaturesId;
84536
84537               for (var i in geometries) {
84538                 hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i]);
84539                 if (hiddenPresetFeaturesId) break;
84540               }
84541
84542               var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
84543               select(this).classed('disabled', isHiddenPreset);
84544
84545               if (isHiddenPreset) {
84546                 var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
84547                 select(this).call(uiTooltip().title(_t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), {
84548                   features: _t.html('feature.' + hiddenPresetFeaturesId + '.description')
84549                 })).placement(index < 2 ? 'bottom' : 'top'));
84550               }
84551             });
84552           }
84553
84554           presetList.autofocus = function (val) {
84555             if (!arguments.length) return _autofocus;
84556             _autofocus = val;
84557             return presetList;
84558           };
84559
84560           presetList.entityIDs = function (val) {
84561             if (!arguments.length) return _entityIDs;
84562             _entityIDs = val;
84563             _currLoc = null;
84564
84565             if (_entityIDs && _entityIDs.length) {
84566               // calculate current location
84567               var extent = _entityIDs.reduce(function (extent, entityID) {
84568                 var entity = context.graph().entity(entityID);
84569                 return extent.extend(entity.extent(context.graph()));
84570               }, geoExtent());
84571
84572               _currLoc = extent.center(); // match presets
84573
84574               var presets = _entityIDs.map(function (entityID) {
84575                 return _mainPresetIndex.match(context.entity(entityID), context.graph());
84576               });
84577
84578               presetList.presets(presets);
84579             }
84580
84581             return presetList;
84582           };
84583
84584           presetList.presets = function (val) {
84585             if (!arguments.length) return _currentPresets;
84586             _currentPresets = val;
84587             return presetList;
84588           };
84589
84590           function entityGeometries() {
84591             var counts = {};
84592
84593             for (var i in _entityIDs) {
84594               var entityID = _entityIDs[i];
84595               var entity = context.entity(entityID);
84596               var geometry = entity.geometry(context.graph()); // Treat entities on addr:interpolation lines as points, not vertices (#3241)
84597
84598               if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
84599                 geometry = 'point';
84600               }
84601
84602               if (!counts[geometry]) counts[geometry] = 0;
84603               counts[geometry] += 1;
84604             }
84605
84606             return Object.keys(counts).sort(function (geom1, geom2) {
84607               return counts[geom2] - counts[geom1];
84608             });
84609           }
84610
84611           return utilRebind(presetList, dispatch, 'on');
84612         }
84613
84614         function uiViewOnOSM(context) {
84615           var _what; // an osmEntity or osmNote
84616
84617
84618           function viewOnOSM(selection) {
84619             var url;
84620
84621             if (_what instanceof osmEntity) {
84622               url = context.connection().entityURL(_what);
84623             } else if (_what instanceof osmNote) {
84624               url = context.connection().noteURL(_what);
84625             }
84626
84627             var data = !_what || _what.isNew() ? [] : [_what];
84628             var link = selection.selectAll('.view-on-osm').data(data, function (d) {
84629               return d.id;
84630             }); // exit
84631
84632             link.exit().remove(); // enter
84633
84634             var linkEnter = link.enter().append('a').attr('class', 'view-on-osm').attr('target', '_blank').attr('href', url).call(svgIcon('#iD-icon-out-link', 'inline'));
84635             linkEnter.append('span').html(_t.html('inspector.view_on_osm'));
84636           }
84637
84638           viewOnOSM.what = function (_) {
84639             if (!arguments.length) return _what;
84640             _what = _;
84641             return viewOnOSM;
84642           };
84643
84644           return viewOnOSM;
84645         }
84646
84647         function uiInspector(context) {
84648           var presetList = uiPresetList(context);
84649           var entityEditor = uiEntityEditor(context);
84650           var wrap = select(null),
84651               presetPane = select(null),
84652               editorPane = select(null);
84653           var _state = 'select';
84654
84655           var _entityIDs;
84656
84657           var _newFeature = false;
84658
84659           function inspector(selection) {
84660             presetList.entityIDs(_entityIDs).autofocus(_newFeature).on('choose', inspector.setPreset).on('cancel', function () {
84661               inspector.setPreset();
84662             });
84663             entityEditor.state(_state).entityIDs(_entityIDs).on('choose', inspector.showList);
84664             wrap = selection.selectAll('.panewrap').data([0]);
84665             var enter = wrap.enter().append('div').attr('class', 'panewrap');
84666             enter.append('div').attr('class', 'preset-list-pane pane');
84667             enter.append('div').attr('class', 'entity-editor-pane pane');
84668             wrap = wrap.merge(enter);
84669             presetPane = wrap.selectAll('.preset-list-pane');
84670             editorPane = wrap.selectAll('.entity-editor-pane');
84671
84672             function shouldDefaultToPresetList() {
84673               // always show the inspector on hover
84674               if (_state !== 'select') return false; // can only change preset on single selection
84675
84676               if (_entityIDs.length !== 1) return false;
84677               var entityID = _entityIDs[0];
84678               var entity = context.hasEntity(entityID);
84679               if (!entity) return false; // default to inspector if there are already tags
84680
84681               if (entity.hasNonGeometryTags()) return false; // prompt to select preset if feature is new and untagged
84682
84683               if (_newFeature) return true; // all existing features except vertices should default to inspector
84684
84685               if (entity.geometry(context.graph()) !== 'vertex') return false; // show vertex relations if any
84686
84687               if (context.graph().parentRelations(entity).length) return false; // show vertex issues if there are any
84688
84689               if (context.validator().getEntityIssues(entityID).length) return false; // show turn retriction editor for junction vertices
84690
84691               if (entity.isHighwayIntersection(context.graph())) return false; // otherwise show preset list for uninteresting vertices
84692
84693               return true;
84694             }
84695
84696             if (shouldDefaultToPresetList()) {
84697               wrap.style('right', '-100%');
84698               editorPane.classed('hide', true);
84699               presetPane.classed('hide', false).call(presetList);
84700             } else {
84701               wrap.style('right', '0%');
84702               presetPane.classed('hide', true);
84703               editorPane.classed('hide', false).call(entityEditor);
84704             }
84705
84706             var footer = selection.selectAll('.footer').data([0]);
84707             footer = footer.enter().append('div').attr('class', 'footer').merge(footer);
84708             footer.call(uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0])));
84709           }
84710
84711           inspector.showList = function (presets) {
84712             presetPane.classed('hide', false);
84713             wrap.transition().styleTween('right', function () {
84714               return interpolate$1('0%', '-100%');
84715             }).on('end', function () {
84716               editorPane.classed('hide', true);
84717             });
84718
84719             if (presets) {
84720               presetList.presets(presets);
84721             }
84722
84723             presetPane.call(presetList.autofocus(true));
84724           };
84725
84726           inspector.setPreset = function (preset) {
84727             // upon setting multipolygon, go to the area preset list instead of the editor
84728             if (preset && preset.id === 'type/multipolygon') {
84729               presetPane.call(presetList.autofocus(true));
84730             } else {
84731               editorPane.classed('hide', false);
84732               wrap.transition().styleTween('right', function () {
84733                 return interpolate$1('-100%', '0%');
84734               }).on('end', function () {
84735                 presetPane.classed('hide', true);
84736               });
84737
84738               if (preset) {
84739                 entityEditor.presets([preset]);
84740               }
84741
84742               editorPane.call(entityEditor);
84743             }
84744           };
84745
84746           inspector.state = function (val) {
84747             if (!arguments.length) return _state;
84748             _state = val;
84749             entityEditor.state(_state); // remove any old field help overlay that might have gotten attached to the inspector
84750
84751             context.container().selectAll('.field-help-body').remove();
84752             return inspector;
84753           };
84754
84755           inspector.entityIDs = function (val) {
84756             if (!arguments.length) return _entityIDs;
84757             _entityIDs = val;
84758             return inspector;
84759           };
84760
84761           inspector.newFeature = function (val) {
84762             if (!arguments.length) return _newFeature;
84763             _newFeature = val;
84764             return inspector;
84765           };
84766
84767           return inspector;
84768         }
84769
84770         function uiImproveOsmComments() {
84771           var _qaItem;
84772
84773           function issueComments(selection) {
84774             // make the div immediately so it appears above the buttons
84775             var comments = selection.selectAll('.comments-container').data([0]);
84776             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments); // must retrieve comments from API before they can be displayed
84777
84778             services.improveOSM.getComments(_qaItem).then(function (d) {
84779               if (!d.comments) return; // nothing to do here
84780
84781               var commentEnter = comments.selectAll('.comment').data(d.comments).enter().append('div').attr('class', 'comment');
84782               commentEnter.append('div').attr('class', 'comment-avatar').call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
84783               var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
84784               var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
84785               metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
84786                 var osm = services.osm;
84787                 var selection = select(this);
84788
84789                 if (osm && d.username) {
84790                   selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.username)).attr('target', '_blank');
84791                 }
84792
84793                 selection.html(function (d) {
84794                   return d.username;
84795                 });
84796               });
84797               metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
84798                 return _t.html('note.status.commented', {
84799                   when: localeDateString(d.timestamp)
84800                 });
84801               });
84802               mainEnter.append('div').attr('class', 'comment-text').append('p').html(function (d) {
84803                 return d.text;
84804               });
84805             })["catch"](function (err) {
84806               console.log(err); // eslint-disable-line no-console
84807             });
84808           }
84809
84810           function localeDateString(s) {
84811             if (!s) return null;
84812             var options = {
84813               day: 'numeric',
84814               month: 'short',
84815               year: 'numeric'
84816             };
84817             var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
84818
84819             if (isNaN(d.getTime())) return null;
84820             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
84821           }
84822
84823           issueComments.issue = function (val) {
84824             if (!arguments.length) return _qaItem;
84825             _qaItem = val;
84826             return issueComments;
84827           };
84828
84829           return issueComments;
84830         }
84831
84832         function uiImproveOsmDetails(context) {
84833           var _qaItem;
84834
84835           function issueDetail(d) {
84836             if (d.desc) return d.desc;
84837             var issueKey = d.issueKey;
84838             d.replacements = d.replacements || {};
84839             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
84840
84841             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d.replacements);
84842           }
84843
84844           function improveOsmDetails(selection) {
84845             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
84846               return "".concat(d.id, "-").concat(d.status || 0);
84847             });
84848             details.exit().remove();
84849             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
84850
84851             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
84852             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
84853             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
84854
84855             var relatedEntities = [];
84856             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
84857               var link = select(this);
84858               var isObjectLink = link.classed('error_object_link');
84859               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
84860               var entity = context.hasEntity(entityID);
84861               relatedEntities.push(entityID); // Add click handler
84862
84863               link.on('mouseenter', function () {
84864                 utilHighlightEntities([entityID], true, context);
84865               }).on('mouseleave', function () {
84866                 utilHighlightEntities([entityID], false, context);
84867               }).on('click', function (d3_event) {
84868                 d3_event.preventDefault();
84869                 utilHighlightEntities([entityID], false, context);
84870                 var osmlayer = context.layers().layer('osm');
84871
84872                 if (!osmlayer.enabled()) {
84873                   osmlayer.enabled(true);
84874                 }
84875
84876                 context.map().centerZoom(_qaItem.loc, 20);
84877
84878                 if (entity) {
84879                   context.enter(modeSelect(context, [entityID]));
84880                 } else {
84881                   context.loadEntity(entityID, function (err, result) {
84882                     if (err) return;
84883                     var entity = result.data.find(function (e) {
84884                       return e.id === entityID;
84885                     });
84886                     if (entity) context.enter(modeSelect(context, [entityID]));
84887                   });
84888                 }
84889               }); // Replace with friendly name if possible
84890               // (The entity may not yet be loaded into the graph)
84891
84892               if (entity) {
84893                 var name = utilDisplayName(entity); // try to use common name
84894
84895                 if (!name && !isObjectLink) {
84896                   var preset = _mainPresetIndex.match(entity, context.graph());
84897                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
84898                 }
84899
84900                 if (name) {
84901                   this.innerText = name;
84902                 }
84903               }
84904             }); // Don't hide entities related to this error - #5880
84905
84906             context.features().forceVisible(relatedEntities);
84907             context.map().pan([0, 0]); // trigger a redraw
84908           }
84909
84910           improveOsmDetails.issue = function (val) {
84911             if (!arguments.length) return _qaItem;
84912             _qaItem = val;
84913             return improveOsmDetails;
84914           };
84915
84916           return improveOsmDetails;
84917         }
84918
84919         function uiImproveOsmHeader() {
84920           var _qaItem;
84921
84922           function issueTitle(d) {
84923             var issueKey = d.issueKey;
84924             d.replacements = d.replacements || {};
84925             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
84926
84927             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d.replacements);
84928           }
84929
84930           function improveOsmHeader(selection) {
84931             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
84932               return "".concat(d.id, "-").concat(d.status || 0);
84933             });
84934             header.exit().remove();
84935             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
84936             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
84937               return d.id < 0;
84938             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
84939               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
84940             });
84941             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');
84942             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
84943               var picon = d.icon;
84944
84945               if (!picon) {
84946                 return '';
84947               } else {
84948                 var isMaki = /^maki-/.test(picon);
84949                 return "#".concat(picon).concat(isMaki ? '-11' : '');
84950               }
84951             });
84952             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
84953           }
84954
84955           improveOsmHeader.issue = function (val) {
84956             if (!arguments.length) return _qaItem;
84957             _qaItem = val;
84958             return improveOsmHeader;
84959           };
84960
84961           return improveOsmHeader;
84962         }
84963
84964         function uiImproveOsmEditor(context) {
84965           var dispatch = dispatch$8('change');
84966           var qaDetails = uiImproveOsmDetails(context);
84967           var qaComments = uiImproveOsmComments();
84968           var qaHeader = uiImproveOsmHeader();
84969
84970           var _qaItem;
84971
84972           function improveOsmEditor(selection) {
84973             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
84974             headerEnter.append('button').attr('class', 'close').on('click', function () {
84975               return context.enter(modeBrowse(context));
84976             }).call(svgIcon('#iD-icon-close'));
84977             headerEnter.append('h3').html(_t.html('QA.improveOSM.title'));
84978             var body = selection.selectAll('.body').data([0]);
84979             body = body.enter().append('div').attr('class', 'body').merge(body);
84980             var editor = body.selectAll('.qa-editor').data([0]);
84981             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);
84982           }
84983
84984           function improveOsmSaveSection(selection) {
84985             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
84986
84987             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
84988             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
84989               return "".concat(d.id, "-").concat(d.status || 0);
84990             }); // exit
84991
84992             saveSection.exit().remove(); // enter
84993
84994             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
84995             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('note.newComment'));
84996             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
84997               return d.newComment;
84998             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
84999
85000             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
85001
85002             function changeInput() {
85003               var input = select(this);
85004               var val = input.property('value').trim();
85005
85006               if (val === '') {
85007                 val = undefined;
85008               } // store the unsaved comment with the issue itself
85009
85010
85011               _qaItem = _qaItem.update({
85012                 newComment: val
85013               });
85014               var qaService = services.improveOSM;
85015
85016               if (qaService) {
85017                 qaService.replaceItem(_qaItem);
85018               }
85019
85020               saveSection.call(qaSaveButtons);
85021             }
85022           }
85023
85024           function qaSaveButtons(selection) {
85025             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85026
85027             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
85028               return d.status + d.id;
85029             }); // exit
85030
85031             buttonSection.exit().remove(); // enter
85032
85033             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
85034             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
85035             buttonEnter.append('button').attr('class', 'button close-button action');
85036             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
85037
85038             buttonSection = buttonSection.merge(buttonEnter);
85039             buttonSection.select('.comment-button').attr('disabled', function (d) {
85040               return d.newComment ? null : true;
85041             }).on('click.comment', function (d3_event, d) {
85042               this.blur(); // avoid keeping focus on the button - #4641
85043
85044               var qaService = services.improveOSM;
85045
85046               if (qaService) {
85047                 qaService.postUpdate(d, function (err, item) {
85048                   return dispatch.call('change', item);
85049                 });
85050               }
85051             });
85052             buttonSection.select('.close-button').html(function (d) {
85053               var andComment = d.newComment ? '_comment' : '';
85054               return _t.html("QA.keepRight.close".concat(andComment));
85055             }).on('click.close', function (d3_event, d) {
85056               this.blur(); // avoid keeping focus on the button - #4641
85057
85058               var qaService = services.improveOSM;
85059
85060               if (qaService) {
85061                 d.newStatus = 'SOLVED';
85062                 qaService.postUpdate(d, function (err, item) {
85063                   return dispatch.call('change', item);
85064                 });
85065               }
85066             });
85067             buttonSection.select('.ignore-button').html(function (d) {
85068               var andComment = d.newComment ? '_comment' : '';
85069               return _t.html("QA.keepRight.ignore".concat(andComment));
85070             }).on('click.ignore', function (d3_event, d) {
85071               this.blur(); // avoid keeping focus on the button - #4641
85072
85073               var qaService = services.improveOSM;
85074
85075               if (qaService) {
85076                 d.newStatus = 'INVALID';
85077                 qaService.postUpdate(d, function (err, item) {
85078                   return dispatch.call('change', item);
85079                 });
85080               }
85081             });
85082           } // NOTE: Don't change method name until UI v3 is merged
85083
85084
85085           improveOsmEditor.error = function (val) {
85086             if (!arguments.length) return _qaItem;
85087             _qaItem = val;
85088             return improveOsmEditor;
85089           };
85090
85091           return utilRebind(improveOsmEditor, dispatch, 'on');
85092         }
85093
85094         function uiKeepRightDetails(context) {
85095           var _qaItem;
85096
85097           function issueDetail(d) {
85098             var itemType = d.itemType,
85099                 parentIssueType = d.parentIssueType;
85100             var unknown = _t.html('inspector.unknown');
85101             var replacements = d.replacements || {};
85102             replacements["default"] = unknown; // special key `default` works as a fallback string
85103
85104             var detail = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
85105
85106             if (detail === unknown) {
85107               detail = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
85108             }
85109
85110             return detail;
85111           }
85112
85113           function keepRightDetails(selection) {
85114             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
85115               return "".concat(d.id, "-").concat(d.status || 0);
85116             });
85117             details.exit().remove();
85118             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
85119
85120             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85121             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
85122             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
85123
85124             var relatedEntities = [];
85125             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
85126               var link = select(this);
85127               var isObjectLink = link.classed('error_object_link');
85128               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
85129               var entity = context.hasEntity(entityID);
85130               relatedEntities.push(entityID); // Add click handler
85131
85132               link.on('mouseenter', function () {
85133                 utilHighlightEntities([entityID], true, context);
85134               }).on('mouseleave', function () {
85135                 utilHighlightEntities([entityID], false, context);
85136               }).on('click', function (d3_event) {
85137                 d3_event.preventDefault();
85138                 utilHighlightEntities([entityID], false, context);
85139                 var osmlayer = context.layers().layer('osm');
85140
85141                 if (!osmlayer.enabled()) {
85142                   osmlayer.enabled(true);
85143                 }
85144
85145                 context.map().centerZoomEase(_qaItem.loc, 20);
85146
85147                 if (entity) {
85148                   context.enter(modeSelect(context, [entityID]));
85149                 } else {
85150                   context.loadEntity(entityID, function (err, result) {
85151                     if (err) return;
85152                     var entity = result.data.find(function (e) {
85153                       return e.id === entityID;
85154                     });
85155                     if (entity) context.enter(modeSelect(context, [entityID]));
85156                   });
85157                 }
85158               }); // Replace with friendly name if possible
85159               // (The entity may not yet be loaded into the graph)
85160
85161               if (entity) {
85162                 var name = utilDisplayName(entity); // try to use common name
85163
85164                 if (!name && !isObjectLink) {
85165                   var preset = _mainPresetIndex.match(entity, context.graph());
85166                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
85167                 }
85168
85169                 if (name) {
85170                   this.innerText = name;
85171                 }
85172               }
85173             }); // Don't hide entities related to this issue - #5880
85174
85175             context.features().forceVisible(relatedEntities);
85176             context.map().pan([0, 0]); // trigger a redraw
85177           }
85178
85179           keepRightDetails.issue = function (val) {
85180             if (!arguments.length) return _qaItem;
85181             _qaItem = val;
85182             return keepRightDetails;
85183           };
85184
85185           return keepRightDetails;
85186         }
85187
85188         function uiKeepRightHeader() {
85189           var _qaItem;
85190
85191           function issueTitle(d) {
85192             var itemType = d.itemType,
85193                 parentIssueType = d.parentIssueType;
85194             var unknown = _t.html('inspector.unknown');
85195             var replacements = d.replacements || {};
85196             replacements["default"] = unknown; // special key `default` works as a fallback string
85197
85198             var title = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
85199
85200             if (title === unknown) {
85201               title = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
85202             }
85203
85204             return title;
85205           }
85206
85207           function keepRightHeader(selection) {
85208             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
85209               return "".concat(d.id, "-").concat(d.status || 0);
85210             });
85211             header.exit().remove();
85212             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
85213             var iconEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
85214               return d.id < 0;
85215             });
85216             iconEnter.append('div').attr('class', function (d) {
85217               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
85218             }).call(svgIcon('#iD-icon-bolt', 'qaItem-fill'));
85219             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
85220           }
85221
85222           keepRightHeader.issue = function (val) {
85223             if (!arguments.length) return _qaItem;
85224             _qaItem = val;
85225             return keepRightHeader;
85226           };
85227
85228           return keepRightHeader;
85229         }
85230
85231         function uiViewOnKeepRight() {
85232           var _qaItem;
85233
85234           function viewOnKeepRight(selection) {
85235             var url;
85236
85237             if (services.keepRight && _qaItem instanceof QAItem) {
85238               url = services.keepRight.issueURL(_qaItem);
85239             }
85240
85241             var link = selection.selectAll('.view-on-keepRight').data(url ? [url] : []); // exit
85242
85243             link.exit().remove(); // enter
85244
85245             var linkEnter = link.enter().append('a').attr('class', 'view-on-keepRight').attr('target', '_blank').attr('rel', 'noopener') // security measure
85246             .attr('href', function (d) {
85247               return d;
85248             }).call(svgIcon('#iD-icon-out-link', 'inline'));
85249             linkEnter.append('span').html(_t.html('inspector.view_on_keepRight'));
85250           }
85251
85252           viewOnKeepRight.what = function (val) {
85253             if (!arguments.length) return _qaItem;
85254             _qaItem = val;
85255             return viewOnKeepRight;
85256           };
85257
85258           return viewOnKeepRight;
85259         }
85260
85261         function uiKeepRightEditor(context) {
85262           var dispatch = dispatch$8('change');
85263           var qaDetails = uiKeepRightDetails(context);
85264           var qaHeader = uiKeepRightHeader();
85265
85266           var _qaItem;
85267
85268           function keepRightEditor(selection) {
85269             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
85270             headerEnter.append('button').attr('class', 'close').on('click', function () {
85271               return context.enter(modeBrowse(context));
85272             }).call(svgIcon('#iD-icon-close'));
85273             headerEnter.append('h3').html(_t.html('QA.keepRight.title'));
85274             var body = selection.selectAll('.body').data([0]);
85275             body = body.enter().append('div').attr('class', 'body').merge(body);
85276             var editor = body.selectAll('.qa-editor').data([0]);
85277             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
85278             var footer = selection.selectAll('.footer').data([0]);
85279             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnKeepRight().what(_qaItem));
85280           }
85281
85282           function keepRightSaveSection(selection) {
85283             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85284
85285             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
85286             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
85287               return "".concat(d.id, "-").concat(d.status || 0);
85288             }); // exit
85289
85290             saveSection.exit().remove(); // enter
85291
85292             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
85293             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('QA.keepRight.comment'));
85294             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
85295               return d.newComment || d.comment;
85296             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
85297
85298             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
85299
85300             function changeInput() {
85301               var input = select(this);
85302               var val = input.property('value').trim();
85303
85304               if (val === _qaItem.comment) {
85305                 val = undefined;
85306               } // store the unsaved comment with the issue itself
85307
85308
85309               _qaItem = _qaItem.update({
85310                 newComment: val
85311               });
85312               var qaService = services.keepRight;
85313
85314               if (qaService) {
85315                 qaService.replaceItem(_qaItem); // update keepright cache
85316               }
85317
85318               saveSection.call(qaSaveButtons);
85319             }
85320           }
85321
85322           function qaSaveButtons(selection) {
85323             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85324
85325             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
85326               return d.status + d.id;
85327             }); // exit
85328
85329             buttonSection.exit().remove(); // enter
85330
85331             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
85332             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
85333             buttonEnter.append('button').attr('class', 'button close-button action');
85334             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
85335
85336             buttonSection = buttonSection.merge(buttonEnter);
85337             buttonSection.select('.comment-button') // select and propagate data
85338             .attr('disabled', function (d) {
85339               return d.newComment ? null : true;
85340             }).on('click.comment', function (d3_event, d) {
85341               this.blur(); // avoid keeping focus on the button - #4641
85342
85343               var qaService = services.keepRight;
85344
85345               if (qaService) {
85346                 qaService.postUpdate(d, function (err, item) {
85347                   return dispatch.call('change', item);
85348                 });
85349               }
85350             });
85351             buttonSection.select('.close-button') // select and propagate data
85352             .html(function (d) {
85353               var andComment = d.newComment ? '_comment' : '';
85354               return _t.html("QA.keepRight.close".concat(andComment));
85355             }).on('click.close', function (d3_event, d) {
85356               this.blur(); // avoid keeping focus on the button - #4641
85357
85358               var qaService = services.keepRight;
85359
85360               if (qaService) {
85361                 d.newStatus = 'ignore_t'; // ignore temporarily (item fixed)
85362
85363                 qaService.postUpdate(d, function (err, item) {
85364                   return dispatch.call('change', item);
85365                 });
85366               }
85367             });
85368             buttonSection.select('.ignore-button') // select and propagate data
85369             .html(function (d) {
85370               var andComment = d.newComment ? '_comment' : '';
85371               return _t.html("QA.keepRight.ignore".concat(andComment));
85372             }).on('click.ignore', function (d3_event, d) {
85373               this.blur(); // avoid keeping focus on the button - #4641
85374
85375               var qaService = services.keepRight;
85376
85377               if (qaService) {
85378                 d.newStatus = 'ignore'; // ignore permanently (false positive)
85379
85380                 qaService.postUpdate(d, function (err, item) {
85381                   return dispatch.call('change', item);
85382                 });
85383               }
85384             });
85385           } // NOTE: Don't change method name until UI v3 is merged
85386
85387
85388           keepRightEditor.error = function (val) {
85389             if (!arguments.length) return _qaItem;
85390             _qaItem = val;
85391             return keepRightEditor;
85392           };
85393
85394           return utilRebind(keepRightEditor, dispatch, 'on');
85395         }
85396
85397         function uiOsmoseDetails(context) {
85398           var _qaItem;
85399
85400           function issueString(d, type) {
85401             if (!d) return ''; // Issue strings are cached from Osmose API
85402
85403             var s = services.osmose.getStrings(d.itemType);
85404             return type in s ? s[type] : '';
85405           }
85406
85407           function osmoseDetails(selection) {
85408             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
85409               return "".concat(d.id, "-").concat(d.status || 0);
85410             });
85411             details.exit().remove();
85412             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // Description
85413
85414             if (issueString(_qaItem, 'detail')) {
85415               var div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85416               div.append('h4').html(_t.html('QA.keepRight.detail_description'));
85417               div.append('p').attr('class', 'qa-details-description-text').html(function (d) {
85418                 return issueString(d, 'detail');
85419               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85420             } // Elements (populated later as data is requested)
85421
85422
85423             var detailsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85424             var elemsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection'); // Suggested Fix (mustn't exist for every issue type)
85425
85426             if (issueString(_qaItem, 'fix')) {
85427               var _div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85428
85429               _div.append('h4').html(_t.html('QA.osmose.fix_title'));
85430
85431               _div.append('p').html(function (d) {
85432                 return issueString(d, 'fix');
85433               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85434             } // Common Pitfalls (mustn't exist for every issue type)
85435
85436
85437             if (issueString(_qaItem, 'trap')) {
85438               var _div2 = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85439
85440               _div2.append('h4').html(_t.html('QA.osmose.trap_title'));
85441
85442               _div2.append('p').html(function (d) {
85443                 return issueString(d, 'trap');
85444               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85445             } // Save current item to check if UI changed by time request resolves
85446
85447
85448             var thisItem = _qaItem;
85449             services.osmose.loadIssueDetail(_qaItem).then(function (d) {
85450               // No details to add if there are no associated issue elements
85451               if (!d.elems || d.elems.length === 0) return; // Do nothing if UI has moved on by the time this resolves
85452
85453               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
85454
85455               if (d.detail) {
85456                 detailsDiv.append('h4').html(_t.html('QA.osmose.detail_title'));
85457                 detailsDiv.append('p').html(function (d) {
85458                   return d.detail;
85459                 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85460               } // Create list of linked issue elements
85461
85462
85463               elemsDiv.append('h4').html(_t.html('QA.osmose.elems_title'));
85464               elemsDiv.append('ul').selectAll('li').data(d.elems).enter().append('li').append('a').attr('href', '#').attr('class', 'error_entity_link').html(function (d) {
85465                 return d;
85466               }).each(function () {
85467                 var link = select(this);
85468                 var entityID = this.textContent;
85469                 var entity = context.hasEntity(entityID); // Add click handler
85470
85471                 link.on('mouseenter', function () {
85472                   utilHighlightEntities([entityID], true, context);
85473                 }).on('mouseleave', function () {
85474                   utilHighlightEntities([entityID], false, context);
85475                 }).on('click', function (d3_event) {
85476                   d3_event.preventDefault();
85477                   utilHighlightEntities([entityID], false, context);
85478                   var osmlayer = context.layers().layer('osm');
85479
85480                   if (!osmlayer.enabled()) {
85481                     osmlayer.enabled(true);
85482                   }
85483
85484                   context.map().centerZoom(d.loc, 20);
85485
85486                   if (entity) {
85487                     context.enter(modeSelect(context, [entityID]));
85488                   } else {
85489                     context.loadEntity(entityID, function (err, result) {
85490                       if (err) return;
85491                       var entity = result.data.find(function (e) {
85492                         return e.id === entityID;
85493                       });
85494                       if (entity) context.enter(modeSelect(context, [entityID]));
85495                     });
85496                   }
85497                 }); // Replace with friendly name if possible
85498                 // (The entity may not yet be loaded into the graph)
85499
85500                 if (entity) {
85501                   var name = utilDisplayName(entity); // try to use common name
85502
85503                   if (!name) {
85504                     var preset = _mainPresetIndex.match(entity, context.graph());
85505                     name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
85506                   }
85507
85508                   if (name) {
85509                     this.innerText = name;
85510                   }
85511                 }
85512               }); // Don't hide entities related to this issue - #5880
85513
85514               context.features().forceVisible(d.elems);
85515               context.map().pan([0, 0]); // trigger a redraw
85516             })["catch"](function (err) {
85517               console.log(err); // eslint-disable-line no-console
85518             });
85519           }
85520
85521           osmoseDetails.issue = function (val) {
85522             if (!arguments.length) return _qaItem;
85523             _qaItem = val;
85524             return osmoseDetails;
85525           };
85526
85527           return osmoseDetails;
85528         }
85529
85530         function uiOsmoseHeader() {
85531           var _qaItem;
85532
85533           function issueTitle(d) {
85534             var unknown = _t('inspector.unknown');
85535             if (!d) return unknown; // Issue titles supplied by Osmose
85536
85537             var s = services.osmose.getStrings(d.itemType);
85538             return 'title' in s ? s.title : unknown;
85539           }
85540
85541           function osmoseHeader(selection) {
85542             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
85543               return "".concat(d.id, "-").concat(d.status || 0);
85544             });
85545             header.exit().remove();
85546             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
85547             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
85548               return d.id < 0;
85549             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
85550               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
85551             });
85552             svgEnter.append('polygon').attr('fill', function (d) {
85553               return services.osmose.getColor(d.item);
85554             }).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');
85555             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
85556               var picon = d.icon;
85557
85558               if (!picon) {
85559                 return '';
85560               } else {
85561                 var isMaki = /^maki-/.test(picon);
85562                 return "#".concat(picon).concat(isMaki ? '-11' : '');
85563               }
85564             });
85565             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
85566           }
85567
85568           osmoseHeader.issue = function (val) {
85569             if (!arguments.length) return _qaItem;
85570             _qaItem = val;
85571             return osmoseHeader;
85572           };
85573
85574           return osmoseHeader;
85575         }
85576
85577         function uiViewOnOsmose() {
85578           var _qaItem;
85579
85580           function viewOnOsmose(selection) {
85581             var url;
85582
85583             if (services.osmose && _qaItem instanceof QAItem) {
85584               url = services.osmose.itemURL(_qaItem);
85585             }
85586
85587             var link = selection.selectAll('.view-on-osmose').data(url ? [url] : []); // exit
85588
85589             link.exit().remove(); // enter
85590
85591             var linkEnter = link.enter().append('a').attr('class', 'view-on-osmose').attr('target', '_blank').attr('rel', 'noopener') // security measure
85592             .attr('href', function (d) {
85593               return d;
85594             }).call(svgIcon('#iD-icon-out-link', 'inline'));
85595             linkEnter.append('span').html(_t.html('inspector.view_on_osmose'));
85596           }
85597
85598           viewOnOsmose.what = function (val) {
85599             if (!arguments.length) return _qaItem;
85600             _qaItem = val;
85601             return viewOnOsmose;
85602           };
85603
85604           return viewOnOsmose;
85605         }
85606
85607         function uiOsmoseEditor(context) {
85608           var dispatch = dispatch$8('change');
85609           var qaDetails = uiOsmoseDetails(context);
85610           var qaHeader = uiOsmoseHeader();
85611
85612           var _qaItem;
85613
85614           function osmoseEditor(selection) {
85615             var header = selection.selectAll('.header').data([0]);
85616             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
85617             headerEnter.append('button').attr('class', 'close').on('click', function () {
85618               return context.enter(modeBrowse(context));
85619             }).call(svgIcon('#iD-icon-close'));
85620             headerEnter.append('h3').html(_t.html('QA.osmose.title'));
85621             var body = selection.selectAll('.body').data([0]);
85622             body = body.enter().append('div').attr('class', 'body').merge(body);
85623             var editor = body.selectAll('.qa-editor').data([0]);
85624             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
85625             var footer = selection.selectAll('.footer').data([0]);
85626             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOsmose().what(_qaItem));
85627           }
85628
85629           function osmoseSaveSection(selection) {
85630             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85631
85632             var isShown = _qaItem && isSelected;
85633             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
85634               return "".concat(d.id, "-").concat(d.status || 0);
85635             }); // exit
85636
85637             saveSection.exit().remove(); // enter
85638
85639             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf'); // update
85640
85641             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
85642           }
85643
85644           function qaSaveButtons(selection) {
85645             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85646
85647             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
85648               return d.status + d.id;
85649             }); // exit
85650
85651             buttonSection.exit().remove(); // enter
85652
85653             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
85654             buttonEnter.append('button').attr('class', 'button close-button action');
85655             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
85656
85657             buttonSection = buttonSection.merge(buttonEnter);
85658             buttonSection.select('.close-button').html(_t.html('QA.keepRight.close')).on('click.close', function (d3_event, d) {
85659               this.blur(); // avoid keeping focus on the button - #4641
85660
85661               var qaService = services.osmose;
85662
85663               if (qaService) {
85664                 d.newStatus = 'done';
85665                 qaService.postUpdate(d, function (err, item) {
85666                   return dispatch.call('change', item);
85667                 });
85668               }
85669             });
85670             buttonSection.select('.ignore-button').html(_t.html('QA.keepRight.ignore')).on('click.ignore', function (d3_event, d) {
85671               this.blur(); // avoid keeping focus on the button - #4641
85672
85673               var qaService = services.osmose;
85674
85675               if (qaService) {
85676                 d.newStatus = 'false';
85677                 qaService.postUpdate(d, function (err, item) {
85678                   return dispatch.call('change', item);
85679                 });
85680               }
85681             });
85682           } // NOTE: Don't change method name until UI v3 is merged
85683
85684
85685           osmoseEditor.error = function (val) {
85686             if (!arguments.length) return _qaItem;
85687             _qaItem = val;
85688             return osmoseEditor;
85689           };
85690
85691           return utilRebind(osmoseEditor, dispatch, 'on');
85692         }
85693
85694         function uiNoteComments() {
85695           var _note;
85696
85697           function noteComments(selection) {
85698             if (_note.isNew()) return; // don't draw .comments-container
85699
85700             var comments = selection.selectAll('.comments-container').data([0]);
85701             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments);
85702             var commentEnter = comments.selectAll('.comment').data(_note.comments).enter().append('div').attr('class', 'comment');
85703             commentEnter.append('div').attr('class', function (d) {
85704               return 'comment-avatar user-' + d.uid;
85705             }).call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
85706             var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
85707             var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
85708             metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
85709               var selection = select(this);
85710               var osm = services.osm;
85711
85712               if (osm && d.user) {
85713                 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.user)).attr('target', '_blank');
85714               }
85715
85716               selection.html(function (d) {
85717                 return d.user || _t.html('note.anonymous');
85718               });
85719             });
85720             metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
85721               return _t('note.status.' + d.action, {
85722                 when: localeDateString(d.date)
85723               });
85724             });
85725             mainEnter.append('div').attr('class', 'comment-text').html(function (d) {
85726               return d.html;
85727             }).selectAll('a').attr('rel', 'noopener nofollow').attr('target', '_blank');
85728             comments.call(replaceAvatars);
85729           }
85730
85731           function replaceAvatars(selection) {
85732             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
85733             var osm = services.osm;
85734             if (showThirdPartyIcons !== 'true' || !osm) return;
85735             var uids = {}; // gather uids in the comment thread
85736
85737             _note.comments.forEach(function (d) {
85738               if (d.uid) uids[d.uid] = true;
85739             });
85740
85741             Object.keys(uids).forEach(function (uid) {
85742               osm.loadUser(uid, function (err, user) {
85743                 if (!user || !user.image_url) return;
85744                 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);
85745               });
85746             });
85747           }
85748
85749           function localeDateString(s) {
85750             if (!s) return null;
85751             var options = {
85752               day: 'numeric',
85753               month: 'short',
85754               year: 'numeric'
85755             };
85756             s = s.replace(/-/g, '/'); // fix browser-specific Date() issues
85757
85758             var d = new Date(s);
85759             if (isNaN(d.getTime())) return null;
85760             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
85761           }
85762
85763           noteComments.note = function (val) {
85764             if (!arguments.length) return _note;
85765             _note = val;
85766             return noteComments;
85767           };
85768
85769           return noteComments;
85770         }
85771
85772         function uiNoteHeader() {
85773           var _note;
85774
85775           function noteHeader(selection) {
85776             var header = selection.selectAll('.note-header').data(_note ? [_note] : [], function (d) {
85777               return d.status + d.id;
85778             });
85779             header.exit().remove();
85780             var headerEnter = header.enter().append('div').attr('class', 'note-header');
85781             var iconEnter = headerEnter.append('div').attr('class', function (d) {
85782               return 'note-header-icon ' + d.status;
85783             }).classed('new', function (d) {
85784               return d.id < 0;
85785             });
85786             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-note', 'note-fill'));
85787             iconEnter.each(function (d) {
85788               var statusIcon;
85789
85790               if (d.id < 0) {
85791                 statusIcon = '#iD-icon-plus';
85792               } else if (d.status === 'open') {
85793                 statusIcon = '#iD-icon-close';
85794               } else {
85795                 statusIcon = '#iD-icon-apply';
85796               }
85797
85798               iconEnter.append('div').attr('class', 'note-icon-annotation').call(svgIcon(statusIcon, 'icon-annotation'));
85799             });
85800             headerEnter.append('div').attr('class', 'note-header-label').html(function (d) {
85801               if (_note.isNew()) {
85802                 return _t('note.new');
85803               }
85804
85805               return _t('note.note') + ' ' + d.id + ' ' + (d.status === 'closed' ? _t('note.closed') : '');
85806             });
85807           }
85808
85809           noteHeader.note = function (val) {
85810             if (!arguments.length) return _note;
85811             _note = val;
85812             return noteHeader;
85813           };
85814
85815           return noteHeader;
85816         }
85817
85818         function uiNoteReport() {
85819           var _note;
85820
85821           function noteReport(selection) {
85822             var url;
85823
85824             if (services.osm && _note instanceof osmNote && !_note.isNew()) {
85825               url = services.osm.noteReportURL(_note);
85826             }
85827
85828             var link = selection.selectAll('.note-report').data(url ? [url] : []); // exit
85829
85830             link.exit().remove(); // enter
85831
85832             var linkEnter = link.enter().append('a').attr('class', 'note-report').attr('target', '_blank').attr('href', function (d) {
85833               return d;
85834             }).call(svgIcon('#iD-icon-out-link', 'inline'));
85835             linkEnter.append('span').html(_t.html('note.report'));
85836           }
85837
85838           noteReport.note = function (val) {
85839             if (!arguments.length) return _note;
85840             _note = val;
85841             return noteReport;
85842           };
85843
85844           return noteReport;
85845         }
85846
85847         function uiNoteEditor(context) {
85848           var dispatch = dispatch$8('change');
85849           var noteComments = uiNoteComments();
85850           var noteHeader = uiNoteHeader(); // var formFields = uiFormFields(context);
85851
85852           var _note;
85853
85854           var _newNote; // var _fieldsArr;
85855
85856
85857           function noteEditor(selection) {
85858             var header = selection.selectAll('.header').data([0]);
85859             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
85860             headerEnter.append('button').attr('class', 'close').on('click', function () {
85861               context.enter(modeBrowse(context));
85862             }).call(svgIcon('#iD-icon-close'));
85863             headerEnter.append('h3').html(_t.html('note.title'));
85864             var body = selection.selectAll('.body').data([0]);
85865             body = body.enter().append('div').attr('class', 'body').merge(body);
85866             var editor = body.selectAll('.note-editor').data([0]);
85867             editor.enter().append('div').attr('class', 'modal-section note-editor').merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
85868             var footer = selection.selectAll('.footer').data([0]);
85869             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
85870
85871             var osm = services.osm;
85872
85873             if (osm) {
85874               osm.on('change.note-save', function () {
85875                 selection.call(noteEditor);
85876               });
85877             }
85878           }
85879
85880           function noteSaveSection(selection) {
85881             var isSelected = _note && _note.id === context.selectedNoteID();
85882
85883             var noteSave = selection.selectAll('.note-save').data(isSelected ? [_note] : [], function (d) {
85884               return d.status + d.id;
85885             }); // exit
85886
85887             noteSave.exit().remove(); // enter
85888
85889             var noteSaveEnter = noteSave.enter().append('div').attr('class', 'note-save save-section cf'); // // if new note, show categories to pick from
85890             // if (_note.isNew()) {
85891             //     var presets = presetManager;
85892             //     // NOTE: this key isn't a age and therefore there is no documentation (yet)
85893             //     _fieldsArr = [
85894             //         uiField(context, presets.field('category'), null, { show: true, revert: false }),
85895             //     ];
85896             //     _fieldsArr.forEach(function(field) {
85897             //         field
85898             //             .on('change', changeCategory);
85899             //     });
85900             //     noteSaveEnter
85901             //         .append('div')
85902             //         .attr('class', 'note-category')
85903             //         .call(formFields.fieldsArr(_fieldsArr));
85904             // }
85905             // function changeCategory() {
85906             //     // NOTE: perhaps there is a better way to get value
85907             //     var val = context.container().select('input[name=\'category\']:checked').property('__data__') || undefined;
85908             //     // store the unsaved category with the note itself
85909             //     _note = _note.update({ newCategory: val });
85910             //     var osm = services.osm;
85911             //     if (osm) {
85912             //         osm.replaceNote(_note);  // update note cache
85913             //     }
85914             //     noteSave
85915             //         .call(noteSaveButtons);
85916             // }
85917
85918             noteSaveEnter.append('h4').attr('class', '.note-save-header').html(function () {
85919               return _note.isNew() ? _t('note.newDescription') : _t('note.newComment');
85920             });
85921             var commentTextarea = noteSaveEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('note.inputPlaceholder')).attr('maxlength', 1000).property('value', function (d) {
85922               return d.newComment;
85923             }).call(utilNoAuto).on('keydown.note-input', keydown).on('input.note-input', changeInput).on('blur.note-input', changeInput);
85924
85925             if (!commentTextarea.empty() && _newNote) {
85926               // autofocus the comment field for new notes
85927               commentTextarea.node().focus();
85928             } // update
85929
85930
85931             noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons); // fast submit if user presses cmd+enter
85932
85933             function keydown(d3_event) {
85934               if (!(d3_event.keyCode === 13 && // ↩ Return
85935               d3_event.metaKey)) return;
85936               var osm = services.osm;
85937               if (!osm) return;
85938               var hasAuth = osm.authenticated();
85939               if (!hasAuth) return;
85940               if (!_note.newComment) return;
85941               d3_event.preventDefault();
85942               select(this).on('keydown.note-input', null); // focus on button and submit
85943
85944               window.setTimeout(function () {
85945                 if (_note.isNew()) {
85946                   noteSave.selectAll('.save-button').node().focus();
85947                   clickSave();
85948                 } else {
85949                   noteSave.selectAll('.comment-button').node().focus();
85950                   clickComment();
85951                 }
85952               }, 10);
85953             }
85954
85955             function changeInput() {
85956               var input = select(this);
85957               var val = input.property('value').trim() || undefined; // store the unsaved comment with the note itself
85958
85959               _note = _note.update({
85960                 newComment: val
85961               });
85962               var osm = services.osm;
85963
85964               if (osm) {
85965                 osm.replaceNote(_note); // update note cache
85966               }
85967
85968               noteSave.call(noteSaveButtons);
85969             }
85970           }
85971
85972           function userDetails(selection) {
85973             var detailSection = selection.selectAll('.detail-section').data([0]);
85974             detailSection = detailSection.enter().append('div').attr('class', 'detail-section').merge(detailSection);
85975             var osm = services.osm;
85976             if (!osm) return; // Add warning if user is not logged in
85977
85978             var hasAuth = osm.authenticated();
85979             var authWarning = detailSection.selectAll('.auth-warning').data(hasAuth ? [] : [0]);
85980             authWarning.exit().transition().duration(200).style('opacity', 0).remove();
85981             var authEnter = authWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning auth-warning').style('opacity', 0);
85982             authEnter.call(svgIcon('#iD-icon-alert', 'inline'));
85983             authEnter.append('span').html(_t.html('note.login'));
85984             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) {
85985               d3_event.preventDefault();
85986               osm.authenticate();
85987             });
85988             authEnter.transition().duration(200).style('opacity', 1);
85989             var prose = detailSection.selectAll('.note-save-prose').data(hasAuth ? [0] : []);
85990             prose.exit().remove();
85991             prose = prose.enter().append('p').attr('class', 'note-save-prose').html(_t.html('note.upload_explanation')).merge(prose);
85992             osm.userDetails(function (err, user) {
85993               if (err) return;
85994               var userLink = select(document.createElement('div'));
85995
85996               if (user.image_url) {
85997                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
85998               }
85999
86000               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
86001               prose.html(_t.html('note.upload_explanation_with_user', {
86002                 user: userLink.html()
86003               }));
86004             });
86005           }
86006
86007           function noteSaveButtons(selection) {
86008             var osm = services.osm;
86009             var hasAuth = osm && osm.authenticated();
86010
86011             var isSelected = _note && _note.id === context.selectedNoteID();
86012
86013             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_note] : [], function (d) {
86014               return d.status + d.id;
86015             }); // exit
86016
86017             buttonSection.exit().remove(); // enter
86018
86019             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
86020
86021             if (_note.isNew()) {
86022               buttonEnter.append('button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
86023               buttonEnter.append('button').attr('class', 'button save-button action').html(_t.html('note.save'));
86024             } else {
86025               buttonEnter.append('button').attr('class', 'button status-button action');
86026               buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('note.comment'));
86027             } // update
86028
86029
86030             buttonSection = buttonSection.merge(buttonEnter);
86031             buttonSection.select('.cancel-button') // select and propagate data
86032             .on('click.cancel', clickCancel);
86033             buttonSection.select('.save-button') // select and propagate data
86034             .attr('disabled', isSaveDisabled).on('click.save', clickSave);
86035             buttonSection.select('.status-button') // select and propagate data
86036             .attr('disabled', hasAuth ? null : true).html(function (d) {
86037               var action = d.status === 'open' ? 'close' : 'open';
86038               var andComment = d.newComment ? '_comment' : '';
86039               return _t('note.' + action + andComment);
86040             }).on('click.status', clickStatus);
86041             buttonSection.select('.comment-button') // select and propagate data
86042             .attr('disabled', isSaveDisabled).on('click.comment', clickComment);
86043
86044             function isSaveDisabled(d) {
86045               return hasAuth && d.status === 'open' && d.newComment ? null : true;
86046             }
86047           }
86048
86049           function clickCancel(d3_event, d) {
86050             this.blur(); // avoid keeping focus on the button - #4641
86051
86052             var osm = services.osm;
86053
86054             if (osm) {
86055               osm.removeNote(d);
86056             }
86057
86058             context.enter(modeBrowse(context));
86059             dispatch.call('change');
86060           }
86061
86062           function clickSave(d3_event, d) {
86063             this.blur(); // avoid keeping focus on the button - #4641
86064
86065             var osm = services.osm;
86066
86067             if (osm) {
86068               osm.postNoteCreate(d, function (err, note) {
86069                 dispatch.call('change', note);
86070               });
86071             }
86072           }
86073
86074           function clickStatus(d3_event, d) {
86075             this.blur(); // avoid keeping focus on the button - #4641
86076
86077             var osm = services.osm;
86078
86079             if (osm) {
86080               var setStatus = d.status === 'open' ? 'closed' : 'open';
86081               osm.postNoteUpdate(d, setStatus, function (err, note) {
86082                 dispatch.call('change', note);
86083               });
86084             }
86085           }
86086
86087           function clickComment(d3_event, d) {
86088             this.blur(); // avoid keeping focus on the button - #4641
86089
86090             var osm = services.osm;
86091
86092             if (osm) {
86093               osm.postNoteUpdate(d, d.status, function (err, note) {
86094                 dispatch.call('change', note);
86095               });
86096             }
86097           }
86098
86099           noteEditor.note = function (val) {
86100             if (!arguments.length) return _note;
86101             _note = val;
86102             return noteEditor;
86103           };
86104
86105           noteEditor.newNote = function (val) {
86106             if (!arguments.length) return _newNote;
86107             _newNote = val;
86108             return noteEditor;
86109           };
86110
86111           return utilRebind(noteEditor, dispatch, 'on');
86112         }
86113
86114         function uiSidebar(context) {
86115           var inspector = uiInspector(context);
86116           var dataEditor = uiDataEditor(context);
86117           var noteEditor = uiNoteEditor(context);
86118           var improveOsmEditor = uiImproveOsmEditor(context);
86119           var keepRightEditor = uiKeepRightEditor(context);
86120           var osmoseEditor = uiOsmoseEditor(context);
86121
86122           var _current;
86123
86124           var _wasData = false;
86125           var _wasNote = false;
86126           var _wasQaItem = false; // use pointer events on supported platforms; fallback to mouse events
86127
86128           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
86129
86130           function sidebar(selection) {
86131             var container = context.container();
86132             var minWidth = 240;
86133             var sidebarWidth;
86134             var containerWidth;
86135             var dragOffset; // Set the initial width constraints
86136
86137             selection.style('min-width', minWidth + 'px').style('max-width', '400px').style('width', '33.3333%');
86138             var resizer = selection.append('div').attr('class', 'sidebar-resizer').on(_pointerPrefix + 'down.sidebar-resizer', pointerdown);
86139             var downPointerId, lastClientX, containerLocGetter;
86140
86141             function pointerdown(d3_event) {
86142               if (downPointerId) return;
86143               if ('button' in d3_event && d3_event.button !== 0) return;
86144               downPointerId = d3_event.pointerId || 'mouse';
86145               lastClientX = d3_event.clientX;
86146               containerLocGetter = utilFastMouse(container.node()); // offset from edge of sidebar-resizer
86147
86148               dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
86149               sidebarWidth = selection.node().getBoundingClientRect().width;
86150               containerWidth = container.node().getBoundingClientRect().width;
86151               var widthPct = sidebarWidth / containerWidth * 100;
86152               selection.style('width', widthPct + '%') // lock in current width
86153               .style('max-width', '85%'); // but allow larger widths
86154
86155               resizer.classed('dragging', true);
86156               select(window).on('touchmove.sidebar-resizer', function (d3_event) {
86157                 // disable page scrolling while resizing on touch input
86158                 d3_event.preventDefault();
86159               }, {
86160                 passive: false
86161               }).on(_pointerPrefix + 'move.sidebar-resizer', pointermove).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', pointerup);
86162             }
86163
86164             function pointermove(d3_event) {
86165               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
86166               d3_event.preventDefault();
86167               var dx = d3_event.clientX - lastClientX;
86168               lastClientX = d3_event.clientX;
86169               var isRTL = _mainLocalizer.textDirection() === 'rtl';
86170               var scaleX = isRTL ? 0 : 1;
86171               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
86172               var x = containerLocGetter(d3_event)[0] - dragOffset;
86173               sidebarWidth = isRTL ? containerWidth - x : x;
86174               var isCollapsed = selection.classed('collapsed');
86175               var shouldCollapse = sidebarWidth < minWidth;
86176               selection.classed('collapsed', shouldCollapse);
86177
86178               if (shouldCollapse) {
86179                 if (!isCollapsed) {
86180                   selection.style(xMarginProperty, '-400px').style('width', '400px');
86181                   context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
86182                 }
86183               } else {
86184                 var widthPct = sidebarWidth / containerWidth * 100;
86185                 selection.style(xMarginProperty, null).style('width', widthPct + '%');
86186
86187                 if (isCollapsed) {
86188                   context.ui().onResize([-sidebarWidth * scaleX, 0]);
86189                 } else {
86190                   context.ui().onResize([-dx * scaleX, 0]);
86191                 }
86192               }
86193             }
86194
86195             function pointerup(d3_event) {
86196               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
86197               downPointerId = null;
86198               resizer.classed('dragging', false);
86199               select(window).on('touchmove.sidebar-resizer', null).on(_pointerPrefix + 'move.sidebar-resizer', null).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', null);
86200             }
86201
86202             var featureListWrap = selection.append('div').attr('class', 'feature-list-pane').call(uiFeatureList(context));
86203             var inspectorWrap = selection.append('div').attr('class', 'inspector-hidden inspector-wrap');
86204
86205             var hoverModeSelect = function hoverModeSelect(targets) {
86206               context.container().selectAll('.feature-list-item button').classed('hover', false);
86207
86208               if (context.selectedIDs().length > 1 && targets && targets.length) {
86209                 var elements = context.container().selectAll('.feature-list-item button').filter(function (node) {
86210                   return targets.indexOf(node) !== -1;
86211                 });
86212
86213                 if (!elements.empty()) {
86214                   elements.classed('hover', true);
86215                 }
86216               }
86217             };
86218
86219             sidebar.hoverModeSelect = throttle(hoverModeSelect, 200);
86220
86221             function hover(targets) {
86222               var datum = targets && targets.length && targets[0];
86223
86224               if (datum && datum.__featurehash__) {
86225                 // hovering on data
86226                 _wasData = true;
86227                 sidebar.show(dataEditor.datum(datum));
86228                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
86229               } else if (datum instanceof osmNote) {
86230                 if (context.mode().id === 'drag-note') return;
86231                 _wasNote = true;
86232                 var osm = services.osm;
86233
86234                 if (osm) {
86235                   datum = osm.getNote(datum.id); // marker may contain stale data - get latest
86236                 }
86237
86238                 sidebar.show(noteEditor.note(datum));
86239                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
86240               } else if (datum instanceof QAItem) {
86241                 _wasQaItem = true;
86242                 var errService = services[datum.service];
86243
86244                 if (errService) {
86245                   // marker may contain stale data - get latest
86246                   datum = errService.getError(datum.id);
86247                 } // Currently only three possible services
86248
86249
86250                 var errEditor;
86251
86252                 if (datum.service === 'keepRight') {
86253                   errEditor = keepRightEditor;
86254                 } else if (datum.service === 'osmose') {
86255                   errEditor = osmoseEditor;
86256                 } else {
86257                   errEditor = improveOsmEditor;
86258                 }
86259
86260                 context.container().selectAll('.qaItem.' + datum.service).classed('hover', function (d) {
86261                   return d.id === datum.id;
86262                 });
86263                 sidebar.show(errEditor.error(datum));
86264                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
86265               } else if (!_current && datum instanceof osmEntity) {
86266                 featureListWrap.classed('inspector-hidden', true);
86267                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', true);
86268
86269                 if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum.id]) || inspector.state() !== 'hover') {
86270                   inspector.state('hover').entityIDs([datum.id]).newFeature(false);
86271                   inspectorWrap.call(inspector);
86272                 }
86273               } else if (!_current) {
86274                 featureListWrap.classed('inspector-hidden', false);
86275                 inspectorWrap.classed('inspector-hidden', true);
86276                 inspector.state('hide');
86277               } else if (_wasData || _wasNote || _wasQaItem) {
86278                 _wasNote = false;
86279                 _wasData = false;
86280                 _wasQaItem = false;
86281                 context.container().selectAll('.note').classed('hover', false);
86282                 context.container().selectAll('.qaItem').classed('hover', false);
86283                 sidebar.hide();
86284               }
86285             }
86286
86287             sidebar.hover = throttle(hover, 200);
86288
86289             sidebar.intersects = function (extent) {
86290               var rect = selection.node().getBoundingClientRect();
86291               return extent.intersects([context.projection.invert([0, rect.height]), context.projection.invert([rect.width, 0])]);
86292             };
86293
86294             sidebar.select = function (ids, newFeature) {
86295               sidebar.hide();
86296
86297               if (ids && ids.length) {
86298                 var entity = ids.length === 1 && context.entity(ids[0]);
86299
86300                 if (entity && newFeature && selection.classed('collapsed')) {
86301                   // uncollapse the sidebar
86302                   var extent = entity.extent(context.graph());
86303                   sidebar.expand(sidebar.intersects(extent));
86304                 }
86305
86306                 featureListWrap.classed('inspector-hidden', true);
86307                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', false); // reload the UI even if the ids are the same since the entities
86308                 // themselves may have changed
86309
86310                 inspector.state('select').entityIDs(ids).newFeature(newFeature);
86311                 inspectorWrap.call(inspector);
86312               } else {
86313                 inspector.state('hide');
86314               }
86315             };
86316
86317             sidebar.showPresetList = function () {
86318               inspector.showList();
86319             };
86320
86321             sidebar.show = function (component, element) {
86322               featureListWrap.classed('inspector-hidden', true);
86323               inspectorWrap.classed('inspector-hidden', true);
86324               if (_current) _current.remove();
86325               _current = selection.append('div').attr('class', 'sidebar-component').call(component, element);
86326             };
86327
86328             sidebar.hide = function () {
86329               featureListWrap.classed('inspector-hidden', false);
86330               inspectorWrap.classed('inspector-hidden', true);
86331               if (_current) _current.remove();
86332               _current = null;
86333             };
86334
86335             sidebar.expand = function (moveMap) {
86336               if (selection.classed('collapsed')) {
86337                 sidebar.toggle(moveMap);
86338               }
86339             };
86340
86341             sidebar.collapse = function (moveMap) {
86342               if (!selection.classed('collapsed')) {
86343                 sidebar.toggle(moveMap);
86344               }
86345             };
86346
86347             sidebar.toggle = function (moveMap) {
86348               // Don't allow sidebar to toggle when the user is in the walkthrough.
86349               if (context.inIntro()) return;
86350               var isCollapsed = selection.classed('collapsed');
86351               var isCollapsing = !isCollapsed;
86352               var isRTL = _mainLocalizer.textDirection() === 'rtl';
86353               var scaleX = isRTL ? 0 : 1;
86354               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
86355               sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px
86356
86357               selection.style('width', sidebarWidth + 'px');
86358               var startMargin, endMargin, lastMargin;
86359
86360               if (isCollapsing) {
86361                 startMargin = lastMargin = 0;
86362                 endMargin = -sidebarWidth;
86363               } else {
86364                 startMargin = lastMargin = -sidebarWidth;
86365                 endMargin = 0;
86366               }
86367
86368               if (!isCollapsing) {
86369                 // unhide the sidebar's content before it transitions onscreen
86370                 selection.classed('collapsed', isCollapsing);
86371               }
86372
86373               selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
86374                 var i = d3_interpolateNumber(startMargin, endMargin);
86375                 return function (t) {
86376                   var dx = lastMargin - Math.round(i(t));
86377                   lastMargin = lastMargin - dx;
86378                   context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
86379                 };
86380               }).on('end', function () {
86381                 if (isCollapsing) {
86382                   // hide the sidebar's content after it transitions offscreen
86383                   selection.classed('collapsed', isCollapsing);
86384                 } // switch back from px to %
86385
86386
86387                 if (!isCollapsing) {
86388                   var containerWidth = container.node().getBoundingClientRect().width;
86389                   var widthPct = sidebarWidth / containerWidth * 100;
86390                   selection.style(xMarginProperty, null).style('width', widthPct + '%');
86391                 }
86392               });
86393             }; // toggle the sidebar collapse when double-clicking the resizer
86394
86395
86396             resizer.on('dblclick', function (d3_event) {
86397               d3_event.preventDefault();
86398
86399               if (d3_event.sourceEvent) {
86400                 d3_event.sourceEvent.preventDefault();
86401               }
86402
86403               sidebar.toggle();
86404             }); // ensure hover sidebar is closed when zooming out beyond editable zoom
86405
86406             context.map().on('crossEditableZoom.sidebar', function (within) {
86407               if (!within && !selection.select('.inspector-hover').empty()) {
86408                 hover([]);
86409               }
86410             });
86411           }
86412
86413           sidebar.showPresetList = function () {};
86414
86415           sidebar.hover = function () {};
86416
86417           sidebar.hover.cancel = function () {};
86418
86419           sidebar.intersects = function () {};
86420
86421           sidebar.select = function () {};
86422
86423           sidebar.show = function () {};
86424
86425           sidebar.hide = function () {};
86426
86427           sidebar.expand = function () {};
86428
86429           sidebar.collapse = function () {};
86430
86431           sidebar.toggle = function () {};
86432
86433           return sidebar;
86434         }
86435
86436         function uiSourceSwitch(context) {
86437           var keys;
86438
86439           function click(d3_event) {
86440             d3_event.preventDefault();
86441             var osm = context.connection();
86442             if (!osm) return;
86443             if (context.inIntro()) return;
86444             if (context.history().hasChanges() && !window.confirm(_t('source_switch.lose_changes'))) return;
86445             var isLive = select(this).classed('live');
86446             isLive = !isLive;
86447             context.enter(modeBrowse(context));
86448             context.history().clearSaved(); // remove saved history
86449
86450             context.flush(); // remove stored data
86451
86452             select(this).html(isLive ? _t.html('source_switch.live') : _t.html('source_switch.dev')).classed('live', isLive).classed('chip', isLive);
86453             osm["switch"](isLive ? keys[0] : keys[1]); // switch connection (warning: dispatches 'change' event)
86454           }
86455
86456           var sourceSwitch = function sourceSwitch(selection) {
86457             selection.append('a').attr('href', '#').html(_t.html('source_switch.live')).attr('class', 'live chip').on('click', click);
86458           };
86459
86460           sourceSwitch.keys = function (_) {
86461             if (!arguments.length) return keys;
86462             keys = _;
86463             return sourceSwitch;
86464           };
86465
86466           return sourceSwitch;
86467         }
86468
86469         function uiSpinner(context) {
86470           var osm = context.connection();
86471           return function (selection) {
86472             var img = selection.append('img').attr('src', context.imagePath('loader-black.gif')).style('opacity', 0);
86473
86474             if (osm) {
86475               osm.on('loading.spinner', function () {
86476                 img.transition().style('opacity', 1);
86477               }).on('loaded.spinner', function () {
86478                 img.transition().style('opacity', 0);
86479               });
86480             }
86481           };
86482         }
86483
86484         function uiSplash(context) {
86485           return function (selection) {
86486             // Exception - if there are restorable changes, skip this splash screen.
86487             // This is because we currently only support one `uiModal` at a time
86488             //  and we need to show them `uiRestore`` instead of this one.
86489             if (context.history().hasRestorableChanges()) return; // If user has not seen this version of the privacy policy, show the splash again.
86490
86491             var updateMessage = '';
86492             var sawPrivacyVersion = corePreferences('sawPrivacyVersion');
86493             var showSplash = !corePreferences('sawSplash');
86494
86495             if (sawPrivacyVersion !== context.privacyVersion) {
86496               updateMessage = _t('splash.privacy_update');
86497               showSplash = true;
86498             }
86499
86500             if (!showSplash) return;
86501             corePreferences('sawSplash', true);
86502             corePreferences('sawPrivacyVersion', context.privacyVersion); // fetch intro graph data now, while user is looking at the splash screen
86503
86504             _mainFileFetcher.get('intro_graph');
86505             var modalSelection = uiModal(selection);
86506             modalSelection.select('.modal').attr('class', 'modal-splash modal');
86507             var introModal = modalSelection.select('.content').append('div').attr('class', 'fillL');
86508             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('splash.welcome'));
86509             var modalSection = introModal.append('div').attr('class', 'modal-section');
86510             modalSection.append('p').html(_t.html('splash.text', {
86511               version: context.version,
86512               website: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">changelog</a>',
86513               github: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>'
86514             }));
86515             modalSection.append('p').html(_t.html('splash.privacy', {
86516               updateMessage: updateMessage,
86517               privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t('splash.privacy_policy') + '</a>'
86518             }));
86519             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
86520             var walkthrough = buttonWrap.append('button').attr('class', 'walkthrough').on('click', function () {
86521               context.container().call(uiIntro(context));
86522               modalSelection.close();
86523             });
86524             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
86525             walkthrough.append('div').html(_t.html('splash.walkthrough'));
86526             var startEditing = buttonWrap.append('button').attr('class', 'start-editing').on('click', modalSelection.close);
86527             startEditing.append('svg').attr('class', 'logo logo-features').append('use').attr('xlink:href', '#iD-logo-features');
86528             startEditing.append('div').html(_t.html('splash.start'));
86529             modalSelection.select('button.close').attr('class', 'hide');
86530           };
86531         }
86532
86533         function uiStatus(context) {
86534           var osm = context.connection();
86535           return function (selection) {
86536             if (!osm) return;
86537
86538             function update(err, apiStatus) {
86539               selection.html('');
86540
86541               if (err) {
86542                 if (apiStatus === 'connectionSwitched') {
86543                   // if the connection was just switched, we can't rely on
86544                   // the status (we're getting the status of the previous api)
86545                   return;
86546                 } else if (apiStatus === 'rateLimited') {
86547                   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) {
86548                     d3_event.preventDefault();
86549                     osm.authenticate();
86550                   });
86551                 } else {
86552                   // don't allow retrying too rapidly
86553                   var throttledRetry = throttle(function () {
86554                     // try loading the visible tiles
86555                     context.loadTiles(context.projection); // manually reload the status too in case all visible tiles were already loaded
86556
86557                     osm.reloadApiStatus();
86558                   }, 2000); // eslint-disable-next-line no-warning-comments
86559                   // TODO: nice messages for different error types
86560
86561
86562                   selection.html(_t.html('osm_api_status.message.error') + ' ').append('a').attr('href', '#') // let the user manually retry their connection directly
86563                   .html(_t.html('osm_api_status.retry')).on('click.retry', function (d3_event) {
86564                     d3_event.preventDefault();
86565                     throttledRetry();
86566                   });
86567                 }
86568               } else if (apiStatus === 'readonly') {
86569                 selection.html(_t.html('osm_api_status.message.readonly'));
86570               } else if (apiStatus === 'offline') {
86571                 selection.html(_t.html('osm_api_status.message.offline'));
86572               }
86573
86574               selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
86575             }
86576
86577             osm.on('apiStatusChange.uiStatus', update);
86578             context.history().on('storage_error', function () {
86579               selection.html(_t.html('osm_api_status.message.local_storage_full'));
86580               selection.attr('class', 'api-status error');
86581             }); // reload the status periodically regardless of other factors
86582
86583             window.setInterval(function () {
86584               osm.reloadApiStatus();
86585             }, 90000); // load the initial status in case no OSM data was loaded yet
86586
86587             osm.reloadApiStatus();
86588           };
86589         }
86590
86591         function modeDrawArea(context, wayID, startGraph, button) {
86592           var mode = {
86593             button: button,
86594             id: 'draw-area'
86595           };
86596           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawArea', function () {
86597             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.areas'))();
86598           });
86599           mode.wayID = wayID;
86600
86601           mode.enter = function () {
86602             context.install(behavior);
86603           };
86604
86605           mode.exit = function () {
86606             context.uninstall(behavior);
86607           };
86608
86609           mode.selectedIDs = function () {
86610             return [wayID];
86611           };
86612
86613           mode.activeID = function () {
86614             return behavior && behavior.activeID() || [];
86615           };
86616
86617           return mode;
86618         }
86619
86620         function modeAddArea(context, mode) {
86621           mode.id = 'add-area';
86622           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
86623           var defaultTags = {
86624             area: 'yes'
86625           };
86626           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
86627
86628           function actionClose(wayId) {
86629             return function (graph) {
86630               return graph.replace(graph.entity(wayId).close());
86631             };
86632           }
86633
86634           function start(loc) {
86635             var startGraph = context.graph();
86636             var node = osmNode({
86637               loc: loc
86638             });
86639             var way = osmWay({
86640               tags: defaultTags
86641             });
86642             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
86643             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
86644           }
86645
86646           function startFromWay(loc, edge) {
86647             var startGraph = context.graph();
86648             var node = osmNode({
86649               loc: loc
86650             });
86651             var way = osmWay({
86652               tags: defaultTags
86653             });
86654             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id), actionAddMidpoint({
86655               loc: loc,
86656               edge: edge
86657             }, node));
86658             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
86659           }
86660
86661           function startFromNode(node) {
86662             var startGraph = context.graph();
86663             var way = osmWay({
86664               tags: defaultTags
86665             });
86666             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
86667             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
86668           }
86669
86670           mode.enter = function () {
86671             context.install(behavior);
86672           };
86673
86674           mode.exit = function () {
86675             context.uninstall(behavior);
86676           };
86677
86678           return mode;
86679         }
86680
86681         function modeAddLine(context, mode) {
86682           mode.id = 'add-line';
86683           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
86684           var defaultTags = {};
86685           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
86686
86687           function start(loc) {
86688             var startGraph = context.graph();
86689             var node = osmNode({
86690               loc: loc
86691             });
86692             var way = osmWay({
86693               tags: defaultTags
86694             });
86695             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id));
86696             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
86697           }
86698
86699           function startFromWay(loc, edge) {
86700             var startGraph = context.graph();
86701             var node = osmNode({
86702               loc: loc
86703             });
86704             var way = osmWay({
86705               tags: defaultTags
86706             });
86707             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionAddMidpoint({
86708               loc: loc,
86709               edge: edge
86710             }, node));
86711             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
86712           }
86713
86714           function startFromNode(node) {
86715             var startGraph = context.graph();
86716             var way = osmWay({
86717               tags: defaultTags
86718             });
86719             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id));
86720             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
86721           }
86722
86723           mode.enter = function () {
86724             context.install(behavior);
86725           };
86726
86727           mode.exit = function () {
86728             context.uninstall(behavior);
86729           };
86730
86731           return mode;
86732         }
86733
86734         function modeAddPoint(context, mode) {
86735           mode.id = 'add-point';
86736           var behavior = behaviorDraw(context).on('click', add).on('clickWay', addWay).on('clickNode', addNode).on('cancel', cancel).on('finish', cancel);
86737           var defaultTags = {};
86738           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
86739
86740           function add(loc) {
86741             var node = osmNode({
86742               loc: loc,
86743               tags: defaultTags
86744             });
86745             context.perform(actionAddEntity(node), _t('operations.add.annotation.point'));
86746             enterSelectMode(node);
86747           }
86748
86749           function addWay(loc, edge) {
86750             var node = osmNode({
86751               tags: defaultTags
86752             });
86753             context.perform(actionAddMidpoint({
86754               loc: loc,
86755               edge: edge
86756             }, node), _t('operations.add.annotation.vertex'));
86757             enterSelectMode(node);
86758           }
86759
86760           function enterSelectMode(node) {
86761             context.enter(modeSelect(context, [node.id]).newFeature(true));
86762           }
86763
86764           function addNode(node) {
86765             if (Object.keys(defaultTags).length === 0) {
86766               enterSelectMode(node);
86767               return;
86768             }
86769
86770             var tags = Object.assign({}, node.tags); // shallow copy
86771
86772             for (var key in defaultTags) {
86773               tags[key] = defaultTags[key];
86774             }
86775
86776             context.perform(actionChangeTags(node.id, tags), _t('operations.add.annotation.point'));
86777             enterSelectMode(node);
86778           }
86779
86780           function cancel() {
86781             context.enter(modeBrowse(context));
86782           }
86783
86784           mode.enter = function () {
86785             context.install(behavior);
86786           };
86787
86788           mode.exit = function () {
86789             context.uninstall(behavior);
86790           };
86791
86792           return mode;
86793         }
86794
86795         function modeSelectNote(context, selectedNoteID) {
86796           var mode = {
86797             id: 'select-note',
86798             button: 'browse'
86799           };
86800
86801           var _keybinding = utilKeybinding('select-note');
86802
86803           var _noteEditor = uiNoteEditor(context).on('change', function () {
86804             context.map().pan([0, 0]); // trigger a redraw
86805
86806             var note = checkSelectedID();
86807             if (!note) return;
86808             context.ui().sidebar.show(_noteEditor.note(note));
86809           });
86810
86811           var _behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
86812           var _newFeature = false;
86813
86814           function checkSelectedID() {
86815             if (!services.osm) return;
86816             var note = services.osm.getNote(selectedNoteID);
86817
86818             if (!note) {
86819               context.enter(modeBrowse(context));
86820             }
86821
86822             return note;
86823           } // class the note as selected, or return to browse mode if the note is gone
86824
86825
86826           function selectNote(d3_event, drawn) {
86827             if (!checkSelectedID()) return;
86828             var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID);
86829
86830             if (selection.empty()) {
86831               // Return to browse mode if selected DOM elements have
86832               // disappeared because the user moved them out of view..
86833               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
86834
86835               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
86836                 context.enter(modeBrowse(context));
86837               }
86838             } else {
86839               selection.classed('selected', true);
86840               context.selectedNoteID(selectedNoteID);
86841             }
86842           }
86843
86844           function esc() {
86845             if (context.container().select('.combobox').size()) return;
86846             context.enter(modeBrowse(context));
86847           }
86848
86849           mode.zoomToSelected = function () {
86850             if (!services.osm) return;
86851             var note = services.osm.getNote(selectedNoteID);
86852
86853             if (note) {
86854               context.map().centerZoomEase(note.loc, 20);
86855             }
86856           };
86857
86858           mode.newFeature = function (val) {
86859             if (!arguments.length) return _newFeature;
86860             _newFeature = val;
86861             return mode;
86862           };
86863
86864           mode.enter = function () {
86865             var note = checkSelectedID();
86866             if (!note) return;
86867
86868             _behaviors.forEach(context.install);
86869
86870             _keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
86871
86872             select(document).call(_keybinding);
86873             selectNote();
86874             var sidebar = context.ui().sidebar;
86875             sidebar.show(_noteEditor.note(note).newNote(_newFeature)); // expand the sidebar, avoid obscuring the note if needed
86876
86877             sidebar.expand(sidebar.intersects(note.extent()));
86878             context.map().on('drawn.select', selectNote);
86879           };
86880
86881           mode.exit = function () {
86882             _behaviors.forEach(context.uninstall);
86883
86884             select(document).call(_keybinding.unbind);
86885             context.surface().selectAll('.layer-notes .selected').classed('selected hover', false);
86886             context.map().on('drawn.select', null);
86887             context.ui().sidebar.hide();
86888             context.selectedNoteID(null);
86889           };
86890
86891           return mode;
86892         }
86893
86894         function modeAddNote(context) {
86895           var mode = {
86896             id: 'add-note',
86897             button: 'note',
86898             description: _t.html('modes.add_note.description'),
86899             key: _t('modes.add_note.key')
86900           };
86901           var behavior = behaviorDraw(context).on('click', add).on('cancel', cancel).on('finish', cancel);
86902
86903           function add(loc) {
86904             var osm = services.osm;
86905             if (!osm) return;
86906             var note = osmNote({
86907               loc: loc,
86908               status: 'open',
86909               comments: []
86910             });
86911             osm.replaceNote(note); // force a reraw (there is no history change that would otherwise do this)
86912
86913             context.map().pan([0, 0]);
86914             context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
86915           }
86916
86917           function cancel() {
86918             context.enter(modeBrowse(context));
86919           }
86920
86921           mode.enter = function () {
86922             context.install(behavior);
86923           };
86924
86925           mode.exit = function () {
86926             context.uninstall(behavior);
86927           };
86928
86929           return mode;
86930         }
86931
86932         var JXON = new function () {
86933           var sValueProp = 'keyValue',
86934               sAttributesProp = 'keyAttributes',
86935               sAttrPref = '@',
86936
86937           /* you can customize these values */
86938           aCache = [],
86939               rIsNull = /^\s*$/,
86940               rIsBool = /^(?:true|false)$/i;
86941
86942           function parseText(sValue) {
86943             if (rIsNull.test(sValue)) {
86944               return null;
86945             }
86946
86947             if (rIsBool.test(sValue)) {
86948               return sValue.toLowerCase() === 'true';
86949             }
86950
86951             if (isFinite(sValue)) {
86952               return parseFloat(sValue);
86953             }
86954
86955             if (isFinite(Date.parse(sValue))) {
86956               return new Date(sValue);
86957             }
86958
86959             return sValue;
86960           }
86961
86962           function EmptyTree() {}
86963
86964           EmptyTree.prototype.toString = function () {
86965             return 'null';
86966           };
86967
86968           EmptyTree.prototype.valueOf = function () {
86969             return null;
86970           };
86971
86972           function objectify(vValue) {
86973             return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
86974           }
86975
86976           function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
86977             var nLevelStart = aCache.length,
86978                 bChildren = oParentNode.hasChildNodes(),
86979                 bAttributes = oParentNode.hasAttributes(),
86980                 bHighVerb = Boolean(nVerb & 2);
86981             var sProp,
86982                 vContent,
86983                 nLength = 0,
86984                 sCollectedTxt = '',
86985                 vResult = bHighVerb ? {} :
86986             /* put here the default value for empty nodes: */
86987             true;
86988
86989             if (bChildren) {
86990               for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
86991                 oNode = oParentNode.childNodes.item(nItem);
86992
86993                 if (oNode.nodeType === 4) {
86994                   /* nodeType is 'CDATASection' (4) */
86995                   sCollectedTxt += oNode.nodeValue;
86996                 } else if (oNode.nodeType === 3) {
86997                   /* nodeType is 'Text' (3) */
86998                   sCollectedTxt += oNode.nodeValue.trim();
86999                 } else if (oNode.nodeType === 1 && !oNode.prefix) {
87000                   /* nodeType is 'Element' (1) */
87001                   aCache.push(oNode);
87002                 }
87003               }
87004             }
87005
87006             var nLevelEnd = aCache.length,
87007                 vBuiltVal = parseText(sCollectedTxt);
87008
87009             if (!bHighVerb && (bChildren || bAttributes)) {
87010               vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
87011             }
87012
87013             for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
87014               sProp = aCache[nElId].nodeName.toLowerCase();
87015               vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
87016
87017               if (vResult.hasOwnProperty(sProp)) {
87018                 if (vResult[sProp].constructor !== Array) {
87019                   vResult[sProp] = [vResult[sProp]];
87020                 }
87021
87022                 vResult[sProp].push(vContent);
87023               } else {
87024                 vResult[sProp] = vContent;
87025                 nLength++;
87026               }
87027             }
87028
87029             if (bAttributes) {
87030               var nAttrLen = oParentNode.attributes.length,
87031                   sAPrefix = bNesteAttr ? '' : sAttrPref,
87032                   oAttrParent = bNesteAttr ? {} : vResult;
87033
87034               for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
87035                 oAttrib = oParentNode.attributes.item(nAttrib);
87036                 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
87037               }
87038
87039               if (bNesteAttr) {
87040                 if (bFreeze) {
87041                   Object.freeze(oAttrParent);
87042                 }
87043
87044                 vResult[sAttributesProp] = oAttrParent;
87045                 nLength -= nAttrLen - 1;
87046               }
87047             }
87048
87049             if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
87050               vResult[sValueProp] = vBuiltVal;
87051             } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
87052               vResult = vBuiltVal;
87053             }
87054
87055             if (bFreeze && (bHighVerb || nLength > 0)) {
87056               Object.freeze(vResult);
87057             }
87058
87059             aCache.length = nLevelStart;
87060             return vResult;
87061           }
87062
87063           function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
87064             var vValue, oChild;
87065
87066             if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
87067               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
87068               /* verbosity level is 0 */
87069             } else if (oParentObj.constructor === Date) {
87070               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
87071             }
87072
87073             for (var sName in oParentObj) {
87074               vValue = oParentObj[sName];
87075
87076               if (isFinite(sName) || vValue instanceof Function) {
87077                 continue;
87078               }
87079               /* verbosity level is 0 */
87080
87081
87082               if (sName === sValueProp) {
87083                 if (vValue !== null && vValue !== true) {
87084                   oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
87085                 }
87086               } else if (sName === sAttributesProp) {
87087                 /* verbosity level is 3 */
87088                 for (var sAttrib in vValue) {
87089                   oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
87090                 }
87091               } else if (sName.charAt(0) === sAttrPref) {
87092                 oParentEl.setAttribute(sName.slice(1), vValue);
87093               } else if (vValue.constructor === Array) {
87094                 for (var nItem = 0; nItem < vValue.length; nItem++) {
87095                   oChild = oXMLDoc.createElement(sName);
87096                   loadObjTree(oXMLDoc, oChild, vValue[nItem]);
87097                   oParentEl.appendChild(oChild);
87098                 }
87099               } else {
87100                 oChild = oXMLDoc.createElement(sName);
87101
87102                 if (vValue instanceof Object) {
87103                   loadObjTree(oXMLDoc, oChild, vValue);
87104                 } else if (vValue !== null && vValue !== true) {
87105                   oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
87106                 }
87107
87108                 oParentEl.appendChild(oChild);
87109               }
87110             }
87111           }
87112
87113           this.build = function (oXMLParent, nVerbosity
87114           /* optional */
87115           , bFreeze
87116           /* optional */
87117           , bNesteAttributes
87118           /* optional */
87119           ) {
87120             var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 :
87121             /* put here the default verbosity level: */
87122             1;
87123
87124             return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
87125           };
87126
87127           this.unbuild = function (oObjTree) {
87128             var oNewDoc = document.implementation.createDocument('', '', null);
87129             loadObjTree(oNewDoc, oNewDoc, oObjTree);
87130             return oNewDoc;
87131           };
87132
87133           this.stringify = function (oObjTree) {
87134             return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
87135           };
87136         }(); // var myObject = JXON.build(doc);
87137         // we got our javascript object! try: alert(JSON.stringify(myObject));
87138         // var newDoc = JXON.unbuild(myObject);
87139         // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
87140
87141         function uiConflicts(context) {
87142           var dispatch = dispatch$8('cancel', 'save');
87143           var keybinding = utilKeybinding('conflicts');
87144
87145           var _origChanges;
87146
87147           var _conflictList;
87148
87149           var _shownConflictIndex;
87150
87151           function keybindingOn() {
87152             select(document).call(keybinding.on('⎋', cancel, true));
87153           }
87154
87155           function keybindingOff() {
87156             select(document).call(keybinding.unbind);
87157           }
87158
87159           function tryAgain() {
87160             keybindingOff();
87161             dispatch.call('save');
87162           }
87163
87164           function cancel() {
87165             keybindingOff();
87166             dispatch.call('cancel');
87167           }
87168
87169           function conflicts(selection) {
87170             keybindingOn();
87171             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
87172             headerEnter.append('button').attr('class', 'fr').on('click', cancel).call(svgIcon('#iD-icon-close'));
87173             headerEnter.append('h3').html(_t.html('save.conflict.header'));
87174             var bodyEnter = selection.selectAll('.body').data([0]).enter().append('div').attr('class', 'body fillL');
87175             var conflictsHelpEnter = bodyEnter.append('div').attr('class', 'conflicts-help').html(_t.html('save.conflict.help')); // Download changes link
87176
87177             var detected = utilDetect();
87178             var changeset = new osmChangeset();
87179             delete changeset.id; // Export without changeset_id
87180
87181             var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
87182             var blob = new Blob([data], {
87183               type: 'text/xml;charset=utf-8;'
87184             });
87185             var fileName = 'changes.osc';
87186             var linkEnter = conflictsHelpEnter.selectAll('.download-changes').append('a').attr('class', 'download-changes');
87187
87188             if (detected.download) {
87189               // All except IE11 and Edge
87190               linkEnter // download the data as a file
87191               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
87192             } else {
87193               // IE11 and Edge
87194               linkEnter // open data uri in a new tab
87195               .attr('target', '_blank').on('click.download', function () {
87196                 navigator.msSaveBlob(blob, fileName);
87197               });
87198             }
87199
87200             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('save.conflict.download_changes'));
87201             bodyEnter.append('div').attr('class', 'conflict-container fillL3').call(showConflict, 0);
87202             bodyEnter.append('div').attr('class', 'conflicts-done').attr('opacity', 0).style('display', 'none').html(_t.html('save.conflict.done'));
87203             var buttonsEnter = bodyEnter.append('div').attr('class', 'buttons col12 joined conflicts-buttons');
87204             buttonsEnter.append('button').attr('disabled', _conflictList.length > 1).attr('class', 'action conflicts-button col6').html(_t.html('save.title')).on('click.try_again', tryAgain);
87205             buttonsEnter.append('button').attr('class', 'secondary-action conflicts-button col6').html(_t.html('confirm.cancel')).on('click.cancel', cancel);
87206           }
87207
87208           function showConflict(selection, index) {
87209             index = utilWrap(index, _conflictList.length);
87210             _shownConflictIndex = index;
87211             var parent = select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed..
87212
87213             if (index === _conflictList.length - 1) {
87214               window.setTimeout(function () {
87215                 parent.select('.conflicts-button').attr('disabled', null);
87216                 parent.select('.conflicts-done').transition().attr('opacity', 1).style('display', 'block');
87217               }, 250);
87218             }
87219
87220             var conflict = selection.selectAll('.conflict').data([_conflictList[index]]);
87221             conflict.exit().remove();
87222             var conflictEnter = conflict.enter().append('div').attr('class', 'conflict');
87223             conflictEnter.append('h4').attr('class', 'conflict-count').html(_t.html('save.conflict.count', {
87224               num: index + 1,
87225               total: _conflictList.length
87226             }));
87227             conflictEnter.append('a').attr('class', 'conflict-description').attr('href', '#').html(function (d) {
87228               return d.name;
87229             }).on('click', function (d3_event, d) {
87230               d3_event.preventDefault();
87231               zoomToEntity(d.id);
87232             });
87233             var details = conflictEnter.append('div').attr('class', 'conflict-detail-container');
87234             details.append('ul').attr('class', 'conflict-detail-list').selectAll('li').data(function (d) {
87235               return d.details || [];
87236             }).enter().append('li').attr('class', 'conflict-detail-item').html(function (d) {
87237               return d;
87238             });
87239             details.append('div').attr('class', 'conflict-choices').call(addChoices);
87240             details.append('div').attr('class', 'conflict-nav-buttons joined cf').selectAll('button').data(['previous', 'next']).enter().append('button').html(function (d) {
87241               return _t.html('save.conflict.' + d);
87242             }).attr('class', 'conflict-nav-button action col6').attr('disabled', function (d, i) {
87243               return i === 0 && index === 0 || i === 1 && index === _conflictList.length - 1 || null;
87244             }).on('click', function (d3_event, d) {
87245               d3_event.preventDefault();
87246               var container = parent.selectAll('.conflict-container');
87247               var sign = d === 'previous' ? -1 : 1;
87248               container.selectAll('.conflict').remove();
87249               container.call(showConflict, index + sign);
87250             });
87251           }
87252
87253           function addChoices(selection) {
87254             var choices = selection.append('ul').attr('class', 'layer-list').selectAll('li').data(function (d) {
87255               return d.choices || [];
87256             }); // enter
87257
87258             var choicesEnter = choices.enter().append('li').attr('class', 'layer');
87259             var labelEnter = choicesEnter.append('label');
87260             labelEnter.append('input').attr('type', 'radio').attr('name', function (d) {
87261               return d.id;
87262             }).on('change', function (d3_event, d) {
87263               var ul = this.parentNode.parentNode.parentNode;
87264               ul.__data__.chosen = d.id;
87265               choose(d3_event, ul, d);
87266             });
87267             labelEnter.append('span').html(function (d) {
87268               return d.text;
87269             }); // update
87270
87271             choicesEnter.merge(choices).each(function (d) {
87272               var ul = this.parentNode;
87273
87274               if (ul.__data__.chosen === d.id) {
87275                 choose(null, ul, d);
87276               }
87277             });
87278           }
87279
87280           function choose(d3_event, ul, datum) {
87281             if (d3_event) d3_event.preventDefault();
87282             select(ul).selectAll('li').classed('active', function (d) {
87283               return d === datum;
87284             }).selectAll('input').property('checked', function (d) {
87285               return d === datum;
87286             });
87287             var extent = geoExtent();
87288             var entity;
87289             entity = context.graph().hasEntity(datum.id);
87290             if (entity) extent._extend(entity.extent(context.graph()));
87291             datum.action();
87292             entity = context.graph().hasEntity(datum.id);
87293             if (entity) extent._extend(entity.extent(context.graph()));
87294             zoomToEntity(datum.id, extent);
87295           }
87296
87297           function zoomToEntity(id, extent) {
87298             context.surface().selectAll('.hover').classed('hover', false);
87299             var entity = context.graph().hasEntity(id);
87300
87301             if (entity) {
87302               if (extent) {
87303                 context.map().trimmedExtent(extent);
87304               } else {
87305                 context.map().zoomToEase(entity);
87306               }
87307
87308               context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
87309             }
87310           } // The conflict list should be an array of objects like:
87311           // {
87312           //     id: id,
87313           //     name: entityName(local),
87314           //     details: merge.conflicts(),
87315           //     chosen: 1,
87316           //     choices: [
87317           //         choice(id, keepMine, forceLocal),
87318           //         choice(id, keepTheirs, forceRemote)
87319           //     ]
87320           // }
87321
87322
87323           conflicts.conflictList = function (_) {
87324             if (!arguments.length) return _conflictList;
87325             _conflictList = _;
87326             return conflicts;
87327           };
87328
87329           conflicts.origChanges = function (_) {
87330             if (!arguments.length) return _origChanges;
87331             _origChanges = _;
87332             return conflicts;
87333           };
87334
87335           conflicts.shownEntityIds = function () {
87336             if (_conflictList && typeof _shownConflictIndex === 'number') {
87337               return [_conflictList[_shownConflictIndex].id];
87338             }
87339
87340             return [];
87341           };
87342
87343           return utilRebind(conflicts, dispatch, 'on');
87344         }
87345
87346         function uiConfirm(selection) {
87347           var modalSelection = uiModal(selection);
87348           modalSelection.select('.modal').classed('modal-alert', true);
87349           var section = modalSelection.select('.content');
87350           section.append('div').attr('class', 'modal-section header');
87351           section.append('div').attr('class', 'modal-section message-text');
87352           var buttons = section.append('div').attr('class', 'modal-section buttons cf');
87353
87354           modalSelection.okButton = function () {
87355             buttons.append('button').attr('class', 'button ok-button action').on('click.confirm', function () {
87356               modalSelection.remove();
87357             }).html(_t.html('confirm.okay')).node().focus();
87358             return modalSelection;
87359           };
87360
87361           return modalSelection;
87362         }
87363
87364         function uiChangesetEditor(context) {
87365           var dispatch = dispatch$8('change');
87366           var formFields = uiFormFields(context);
87367           var commentCombo = uiCombobox(context, 'comment').caseSensitive(true);
87368
87369           var _fieldsArr;
87370
87371           var _tags;
87372
87373           var _changesetID;
87374
87375           function changesetEditor(selection) {
87376             render(selection);
87377           }
87378
87379           function render(selection) {
87380             var initial = false;
87381
87382             if (!_fieldsArr) {
87383               initial = true;
87384               var presets = _mainPresetIndex;
87385               _fieldsArr = [uiField(context, presets.field('comment'), null, {
87386                 show: true,
87387                 revert: false
87388               }), uiField(context, presets.field('source'), null, {
87389                 show: false,
87390                 revert: false
87391               }), uiField(context, presets.field('hashtags'), null, {
87392                 show: false,
87393                 revert: false
87394               })];
87395
87396               _fieldsArr.forEach(function (field) {
87397                 field.on('change', function (t, onInput) {
87398                   dispatch.call('change', field, undefined, t, onInput);
87399                 });
87400               });
87401             }
87402
87403             _fieldsArr.forEach(function (field) {
87404               field.tags(_tags);
87405             });
87406
87407             selection.call(formFields.fieldsArr(_fieldsArr));
87408
87409             if (initial) {
87410               var commentField = selection.select('.form-field-comment textarea');
87411               var commentNode = commentField.node();
87412
87413               if (commentNode) {
87414                 commentNode.focus();
87415                 commentNode.select();
87416               } // trigger a 'blur' event so that comment field can be cleaned
87417               // and checked for hashtags, even if retrieved from localstorage
87418
87419
87420               utilTriggerEvent(commentField, 'blur');
87421               var osm = context.connection();
87422
87423               if (osm) {
87424                 osm.userChangesets(function (err, changesets) {
87425                   if (err) return;
87426                   var comments = changesets.map(function (changeset) {
87427                     var comment = changeset.tags.comment;
87428                     return comment ? {
87429                       title: comment,
87430                       value: comment
87431                     } : null;
87432                   }).filter(Boolean);
87433                   commentField.call(commentCombo.data(utilArrayUniqBy(comments, 'title')));
87434                 });
87435               }
87436             } // Add warning if comment mentions Google
87437
87438
87439             var hasGoogle = _tags.comment.match(/google/i);
87440
87441             var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning').data(hasGoogle ? [0] : []);
87442             commentWarning.exit().transition().duration(200).style('opacity', 0).remove();
87443             var commentEnter = commentWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning comment-warning').style('opacity', 0);
87444             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'));
87445             commentEnter.transition().duration(200).style('opacity', 1);
87446           }
87447
87448           changesetEditor.tags = function (_) {
87449             if (!arguments.length) return _tags;
87450             _tags = _; // Don't reset _fieldsArr here.
87451
87452             return changesetEditor;
87453           };
87454
87455           changesetEditor.changesetID = function (_) {
87456             if (!arguments.length) return _changesetID;
87457             if (_changesetID === _) return changesetEditor;
87458             _changesetID = _;
87459             _fieldsArr = null;
87460             return changesetEditor;
87461           };
87462
87463           return utilRebind(changesetEditor, dispatch, 'on');
87464         }
87465
87466         function uiSectionChanges(context) {
87467           var detected = utilDetect();
87468           var _discardTags = {};
87469           _mainFileFetcher.get('discarded').then(function (d) {
87470             _discardTags = d;
87471           })["catch"](function () {
87472             /* ignore */
87473           });
87474           var section = uiSection('changes-list', context).label(function () {
87475             var history = context.history();
87476             var summary = history.difference().summary();
87477             return _t('inspector.title_count', {
87478               title: _t.html('commit.changes'),
87479               count: summary.length
87480             });
87481           }).disclosureContent(renderDisclosureContent);
87482
87483           function renderDisclosureContent(selection) {
87484             var history = context.history();
87485             var summary = history.difference().summary();
87486             var container = selection.selectAll('.commit-section').data([0]);
87487             var containerEnter = container.enter().append('div').attr('class', 'commit-section');
87488             containerEnter.append('ul').attr('class', 'changeset-list');
87489             container = containerEnter.merge(container);
87490             var items = container.select('ul').selectAll('li').data(summary);
87491             var itemsEnter = items.enter().append('li').attr('class', 'change-item');
87492             var buttons = itemsEnter.append('button').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
87493             buttons.each(function (d) {
87494               select(this).call(svgIcon('#iD-icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
87495             });
87496             buttons.append('span').attr('class', 'change-type').html(function (d) {
87497               return _t.html('commit.' + d.changeType) + ' ';
87498             });
87499             buttons.append('strong').attr('class', 'entity-type').html(function (d) {
87500               var matched = _mainPresetIndex.match(d.entity, d.graph);
87501               return matched && matched.name() || utilDisplayType(d.entity.id);
87502             });
87503             buttons.append('span').attr('class', 'entity-name').html(function (d) {
87504               var name = utilDisplayName(d.entity) || '',
87505                   string = '';
87506
87507               if (name !== '') {
87508                 string += ':';
87509               }
87510
87511               return string += ' ' + name;
87512             });
87513             items = itemsEnter.merge(items); // Download changeset link
87514
87515             var changeset = new osmChangeset().update({
87516               id: undefined
87517             });
87518             var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
87519             delete changeset.id; // Export without chnageset_id
87520
87521             var data = JXON.stringify(changeset.osmChangeJXON(changes));
87522             var blob = new Blob([data], {
87523               type: 'text/xml;charset=utf-8;'
87524             });
87525             var fileName = 'changes.osc';
87526             var linkEnter = container.selectAll('.download-changes').data([0]).enter().append('a').attr('class', 'download-changes');
87527
87528             if (detected.download) {
87529               // All except IE11 and Edge
87530               linkEnter // download the data as a file
87531               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
87532             } else {
87533               // IE11 and Edge
87534               linkEnter // open data uri in a new tab
87535               .attr('target', '_blank').on('click.download', function () {
87536                 navigator.msSaveBlob(blob, fileName);
87537               });
87538             }
87539
87540             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('commit.download_changes'));
87541
87542             function mouseover(d) {
87543               if (d.entity) {
87544                 context.surface().selectAll(utilEntityOrMemberSelector([d.entity.id], context.graph())).classed('hover', true);
87545               }
87546             }
87547
87548             function mouseout() {
87549               context.surface().selectAll('.hover').classed('hover', false);
87550             }
87551
87552             function click(d3_event, change) {
87553               if (change.changeType !== 'deleted') {
87554                 var entity = change.entity;
87555                 context.map().zoomToEase(entity);
87556                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
87557               }
87558             }
87559           }
87560
87561           return section;
87562         }
87563
87564         function uiCommitWarnings(context) {
87565           function commitWarnings(selection) {
87566             var issuesBySeverity = context.validator().getIssuesBySeverity({
87567               what: 'edited',
87568               where: 'all',
87569               includeDisabledRules: true
87570             });
87571
87572             for (var severity in issuesBySeverity) {
87573               var issues = issuesBySeverity[severity];
87574
87575               if (severity !== 'error') {
87576                 // exclude 'fixme' and similar - #8603
87577                 issues = issues.filter(function (issue) {
87578                   return issue.type !== 'help_request';
87579                 });
87580               }
87581
87582               var section = severity + '-section';
87583               var issueItem = severity + '-item';
87584               var container = selection.selectAll('.' + section).data(issues.length ? [0] : []);
87585               container.exit().remove();
87586               var containerEnter = container.enter().append('div').attr('class', 'modal-section ' + section + ' fillL2');
87587               containerEnter.append('h3').html(severity === 'warning' ? _t.html('commit.warnings') : _t.html('commit.errors'));
87588               containerEnter.append('ul').attr('class', 'changeset-list');
87589               container = containerEnter.merge(container);
87590               var items = container.select('ul').selectAll('li').data(issues, function (d) {
87591                 return d.key;
87592               });
87593               items.exit().remove();
87594               var itemsEnter = items.enter().append('li').attr('class', issueItem);
87595               var buttons = itemsEnter.append('button').on('mouseover', function (d3_event, d) {
87596                 if (d.entityIds) {
87597                   context.surface().selectAll(utilEntityOrMemberSelector(d.entityIds, context.graph())).classed('hover', true);
87598                 }
87599               }).on('mouseout', function () {
87600                 context.surface().selectAll('.hover').classed('hover', false);
87601               }).on('click', function (d3_event, d) {
87602                 context.validator().focusIssue(d);
87603               });
87604               buttons.call(svgIcon('#iD-icon-alert', 'pre-text'));
87605               buttons.append('strong').attr('class', 'issue-message');
87606               buttons.filter(function (d) {
87607                 return d.tooltip;
87608               }).call(uiTooltip().title(function (d) {
87609                 return d.tooltip;
87610               }).placement('top'));
87611               items = itemsEnter.merge(items);
87612               items.selectAll('.issue-message').html(function (d) {
87613                 return d.message(context);
87614               });
87615             }
87616           }
87617
87618           return commitWarnings;
87619         }
87620
87621         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
87622         // from https://stackoverflow.com/a/25575009
87623
87624         var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
87625         function uiCommit(context) {
87626           var dispatch = dispatch$8('cancel');
87627
87628           var _userDetails;
87629
87630           var _selection;
87631
87632           var changesetEditor = uiChangesetEditor(context).on('change', changeTags);
87633           var rawTagEditor = uiSectionRawTagEditor('changeset-tag-editor', context).on('change', changeTags).readOnlyTags(readOnlyTags);
87634           var commitChanges = uiSectionChanges(context);
87635           var commitWarnings = uiCommitWarnings(context);
87636
87637           function commit(selection) {
87638             _selection = selection; // Initialize changeset if one does not exist yet.
87639
87640             if (!context.changeset) initChangeset();
87641             loadDerivedChangesetTags();
87642             selection.call(render);
87643           }
87644
87645           function initChangeset() {
87646             // expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
87647             var commentDate = +corePreferences('commentDate') || 0;
87648             var currDate = Date.now();
87649             var cutoff = 2 * 86400 * 1000; // 2 days
87650
87651             if (commentDate > currDate || currDate - commentDate > cutoff) {
87652               corePreferences('comment', null);
87653               corePreferences('hashtags', null);
87654               corePreferences('source', null);
87655             } // load in explicitly-set values, if any
87656
87657
87658             if (context.defaultChangesetComment()) {
87659               corePreferences('comment', context.defaultChangesetComment());
87660               corePreferences('commentDate', Date.now());
87661             }
87662
87663             if (context.defaultChangesetSource()) {
87664               corePreferences('source', context.defaultChangesetSource());
87665               corePreferences('commentDate', Date.now());
87666             }
87667
87668             if (context.defaultChangesetHashtags()) {
87669               corePreferences('hashtags', context.defaultChangesetHashtags());
87670               corePreferences('commentDate', Date.now());
87671             }
87672
87673             var detected = utilDetect();
87674             var tags = {
87675               comment: corePreferences('comment') || '',
87676               created_by: context.cleanTagValue('iD ' + context.version),
87677               host: context.cleanTagValue(detected.host),
87678               locale: context.cleanTagValue(_mainLocalizer.localeCode())
87679             }; // call findHashtags initially - this will remove stored
87680             // hashtags if any hashtags are found in the comment - #4304
87681
87682             findHashtags(tags, true);
87683             var hashtags = corePreferences('hashtags');
87684
87685             if (hashtags) {
87686               tags.hashtags = hashtags;
87687             }
87688
87689             var source = corePreferences('source');
87690
87691             if (source) {
87692               tags.source = source;
87693             }
87694
87695             var photoOverlaysUsed = context.history().photoOverlaysUsed();
87696
87697             if (photoOverlaysUsed.length) {
87698               var sources = (tags.source || '').split(';'); // include this tag for any photo layer
87699
87700               if (sources.indexOf('streetlevel imagery') === -1) {
87701                 sources.push('streetlevel imagery');
87702               } // add the photo overlays used during editing as sources
87703
87704
87705               photoOverlaysUsed.forEach(function (photoOverlay) {
87706                 if (sources.indexOf(photoOverlay) === -1) {
87707                   sources.push(photoOverlay);
87708                 }
87709               });
87710               tags.source = context.cleanTagValue(sources.join(';'));
87711             }
87712
87713             context.changeset = new osmChangeset({
87714               tags: tags
87715             });
87716           } // Calculates read-only metadata tags based on the user's editing session and applies
87717           // them to the changeset.
87718
87719
87720           function loadDerivedChangesetTags() {
87721             var osm = context.connection();
87722             if (!osm) return;
87723             var tags = Object.assign({}, context.changeset.tags); // shallow copy
87724             // assign tags for imagery used
87725
87726             var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
87727             tags.imagery_used = imageryUsed || 'None'; // assign tags for closed issues and notes
87728
87729             var osmClosed = osm.getClosedIDs();
87730             var itemType;
87731
87732             if (osmClosed.length) {
87733               tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
87734             }
87735
87736             if (services.keepRight) {
87737               var krClosed = services.keepRight.getClosedIDs();
87738
87739               if (krClosed.length) {
87740                 tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
87741               }
87742             }
87743
87744             if (services.improveOSM) {
87745               var iOsmClosed = services.improveOSM.getClosedCounts();
87746
87747               for (itemType in iOsmClosed) {
87748                 tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
87749               }
87750             }
87751
87752             if (services.osmose) {
87753               var osmoseClosed = services.osmose.getClosedCounts();
87754
87755               for (itemType in osmoseClosed) {
87756                 tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
87757               }
87758             } // remove existing issue counts
87759
87760
87761             for (var key in tags) {
87762               if (key.match(/(^warnings:)|(^resolved:)/)) {
87763                 delete tags[key];
87764               }
87765             }
87766
87767             function addIssueCounts(issues, prefix) {
87768               var issuesByType = utilArrayGroupBy(issues, 'type');
87769
87770               for (var issueType in issuesByType) {
87771                 var issuesOfType = issuesByType[issueType];
87772
87773                 if (issuesOfType[0].subtype) {
87774                   var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
87775
87776                   for (var issueSubtype in issuesBySubtype) {
87777                     var issuesOfSubtype = issuesBySubtype[issueSubtype];
87778                     tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
87779                   }
87780                 } else {
87781                   tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
87782                 }
87783               }
87784             } // add counts of warnings generated by the user's edits
87785
87786
87787             var warnings = context.validator().getIssuesBySeverity({
87788               what: 'edited',
87789               where: 'all',
87790               includeIgnored: true,
87791               includeDisabledRules: true
87792             }).warning.filter(function (issue) {
87793               return issue.type !== 'help_request';
87794             }); // exclude 'fixme' and similar - #8603
87795
87796             addIssueCounts(warnings, 'warnings'); // add counts of issues resolved by the user's edits
87797
87798             var resolvedIssues = context.validator().getResolvedIssues();
87799             addIssueCounts(resolvedIssues, 'resolved');
87800             context.changeset = context.changeset.update({
87801               tags: tags
87802             });
87803           }
87804
87805           function render(selection) {
87806             var osm = context.connection();
87807             if (!osm) return;
87808             var header = selection.selectAll('.header').data([0]);
87809             var headerTitle = header.enter().append('div').attr('class', 'header fillL');
87810             headerTitle.append('div').append('h3').html(_t.html('commit.title'));
87811             headerTitle.append('button').attr('class', 'close').on('click', function () {
87812               dispatch.call('cancel', this);
87813             }).call(svgIcon('#iD-icon-close'));
87814             var body = selection.selectAll('.body').data([0]);
87815             body = body.enter().append('div').attr('class', 'body').merge(body); // Changeset Section
87816
87817             var changesetSection = body.selectAll('.changeset-editor').data([0]);
87818             changesetSection = changesetSection.enter().append('div').attr('class', 'modal-section changeset-editor').merge(changesetSection);
87819             changesetSection.call(changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)); // Warnings
87820
87821             body.call(commitWarnings); // Upload Explanation
87822
87823             var saveSection = body.selectAll('.save-section').data([0]);
87824             saveSection = saveSection.enter().append('div').attr('class', 'modal-section save-section fillL').merge(saveSection);
87825             var prose = saveSection.selectAll('.commit-info').data([0]);
87826
87827             if (prose.enter().size()) {
87828               // first time, make sure to update user details in prose
87829               _userDetails = null;
87830             }
87831
87832             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()
87833             // if needed, because it can trigger a style recalculation
87834
87835             osm.userDetails(function (err, user) {
87836               if (err) return;
87837               if (_userDetails === user) return; // no change
87838
87839               _userDetails = user;
87840               var userLink = select(document.createElement('div'));
87841
87842               if (user.image_url) {
87843                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
87844               }
87845
87846               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
87847               prose.html(_t.html('commit.upload_explanation_with_user', {
87848                 user: userLink.html()
87849               }));
87850             }); // Request Review
87851
87852             var requestReview = saveSection.selectAll('.request-review').data([0]); // Enter
87853
87854             var requestReviewEnter = requestReview.enter().append('div').attr('class', 'request-review');
87855             var requestReviewDomId = utilUniqueDomId('commit-input-request-review');
87856             var labelEnter = requestReviewEnter.append('label').attr('for', requestReviewDomId);
87857
87858             if (!labelEnter.empty()) {
87859               labelEnter.call(uiTooltip().title(_t.html('commit.request_review_info')).placement('top'));
87860             }
87861
87862             labelEnter.append('input').attr('type', 'checkbox').attr('id', requestReviewDomId);
87863             labelEnter.append('span').html(_t.html('commit.request_review')); // Update
87864
87865             requestReview = requestReview.merge(requestReviewEnter);
87866             var requestReviewInput = requestReview.selectAll('input').property('checked', isReviewRequested(context.changeset.tags)).on('change', toggleRequestReview); // Buttons
87867
87868             var buttonSection = saveSection.selectAll('.buttons').data([0]); // enter
87869
87870             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons fillL');
87871             buttonEnter.append('button').attr('class', 'secondary-action button cancel-button').append('span').attr('class', 'label').html(_t.html('commit.cancel'));
87872             var uploadButton = buttonEnter.append('button').attr('class', 'action button save-button');
87873             uploadButton.append('span').attr('class', 'label').html(_t.html('commit.save'));
87874             var uploadBlockerTooltipText = getUploadBlockerMessage(); // update
87875
87876             buttonSection = buttonSection.merge(buttonEnter);
87877             buttonSection.selectAll('.cancel-button').on('click.cancel', function () {
87878               dispatch.call('cancel', this);
87879             });
87880             buttonSection.selectAll('.save-button').classed('disabled', uploadBlockerTooltipText !== null).on('click.save', function () {
87881               if (!select(this).classed('disabled')) {
87882                 this.blur(); // avoid keeping focus on the button - #4641
87883
87884                 for (var key in context.changeset.tags) {
87885                   // remove any empty keys before upload
87886                   if (!key) delete context.changeset.tags[key];
87887                 }
87888
87889                 context.uploader().save(context.changeset);
87890               }
87891             }); // remove any existing tooltip
87892
87893             uiTooltip().destroyAny(buttonSection.selectAll('.save-button'));
87894
87895             if (uploadBlockerTooltipText) {
87896               buttonSection.selectAll('.save-button').call(uiTooltip().title(uploadBlockerTooltipText).placement('top'));
87897             } // Raw Tag Editor
87898
87899
87900             var tagSection = body.selectAll('.tag-section.raw-tag-editor').data([0]);
87901             tagSection = tagSection.enter().append('div').attr('class', 'modal-section tag-section raw-tag-editor').merge(tagSection);
87902             tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
87903             .render);
87904             var changesSection = body.selectAll('.commit-changes-section').data([0]);
87905             changesSection = changesSection.enter().append('div').attr('class', 'modal-section commit-changes-section').merge(changesSection); // Change summary
87906
87907             changesSection.call(commitChanges.render);
87908
87909             function toggleRequestReview() {
87910               var rr = requestReviewInput.property('checked');
87911               updateChangeset({
87912                 review_requested: rr ? 'yes' : undefined
87913               });
87914               tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
87915               .render);
87916             }
87917           }
87918
87919           function getUploadBlockerMessage() {
87920             var errors = context.validator().getIssuesBySeverity({
87921               what: 'edited',
87922               where: 'all'
87923             }).error;
87924
87925             if (errors.length) {
87926               return _t('commit.outstanding_errors_message', {
87927                 count: errors.length
87928               });
87929             } else {
87930               var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
87931
87932               if (!hasChangesetComment) {
87933                 return _t('commit.comment_needed_message');
87934               }
87935             }
87936
87937             return null;
87938           }
87939
87940           function changeTags(_, changed, onInput) {
87941             if (changed.hasOwnProperty('comment')) {
87942               if (changed.comment === undefined) {
87943                 changed.comment = '';
87944               }
87945
87946               if (!onInput) {
87947                 corePreferences('comment', changed.comment);
87948                 corePreferences('commentDate', Date.now());
87949               }
87950             }
87951
87952             if (changed.hasOwnProperty('source')) {
87953               if (changed.source === undefined) {
87954                 corePreferences('source', null);
87955               } else if (!onInput) {
87956                 corePreferences('source', changed.source);
87957                 corePreferences('commentDate', Date.now());
87958               }
87959             } // no need to update `prefs` for `hashtags` here since it's done in `updateChangeset`
87960
87961
87962             updateChangeset(changed, onInput);
87963
87964             if (_selection) {
87965               _selection.call(render);
87966             }
87967           }
87968
87969           function findHashtags(tags, commentOnly) {
87970             var detectedHashtags = commentHashtags();
87971
87972             if (detectedHashtags.length) {
87973               // always remove stored hashtags if there are hashtags in the comment - #4304
87974               corePreferences('hashtags', null);
87975             }
87976
87977             if (!detectedHashtags.length || !commentOnly) {
87978               detectedHashtags = detectedHashtags.concat(hashtagHashtags());
87979             }
87980
87981             var allLowerCase = new Set();
87982             return detectedHashtags.filter(function (hashtag) {
87983               // Compare tags as lowercase strings, but keep original case tags
87984               var lowerCase = hashtag.toLowerCase();
87985
87986               if (!allLowerCase.has(lowerCase)) {
87987                 allLowerCase.add(lowerCase);
87988                 return true;
87989               }
87990
87991               return false;
87992             }); // Extract hashtags from `comment`
87993
87994             function commentHashtags() {
87995               var matches = (tags.comment || '').replace(/http\S*/g, '') // drop anything that looks like a URL - #4289
87996               .match(hashtagRegex);
87997               return matches || [];
87998             } // Extract and clean hashtags from `hashtags`
87999
88000
88001             function hashtagHashtags() {
88002               var matches = (tags.hashtags || '').split(/[,;\s]+/).map(function (s) {
88003                 if (s[0] !== '#') {
88004                   s = '#' + s;
88005                 } // prepend '#'
88006
88007
88008                 var matched = s.match(hashtagRegex);
88009                 return matched && matched[0];
88010               }).filter(Boolean); // exclude falsy
88011
88012               return matches || [];
88013             }
88014           }
88015
88016           function isReviewRequested(tags) {
88017             var rr = tags.review_requested;
88018             if (rr === undefined) return false;
88019             rr = rr.trim().toLowerCase();
88020             return !(rr === '' || rr === 'no');
88021           }
88022
88023           function updateChangeset(changed, onInput) {
88024             var tags = Object.assign({}, context.changeset.tags); // shallow copy
88025
88026             Object.keys(changed).forEach(function (k) {
88027               var v = changed[k];
88028               k = context.cleanTagKey(k);
88029               if (readOnlyTags.indexOf(k) !== -1) return;
88030
88031               if (v === undefined) {
88032                 delete tags[k];
88033               } else if (onInput) {
88034                 tags[k] = v;
88035               } else {
88036                 tags[k] = context.cleanTagValue(v);
88037               }
88038             });
88039
88040             if (!onInput) {
88041               // when changing the comment, override hashtags with any found in comment.
88042               var commentOnly = changed.hasOwnProperty('comment') && changed.comment !== '';
88043               var arr = findHashtags(tags, commentOnly);
88044
88045               if (arr.length) {
88046                 tags.hashtags = context.cleanTagValue(arr.join(';'));
88047                 corePreferences('hashtags', tags.hashtags);
88048               } else {
88049                 delete tags.hashtags;
88050                 corePreferences('hashtags', null);
88051               }
88052             } // always update userdetails, just in case user reauthenticates as someone else
88053
88054
88055             if (_userDetails && _userDetails.changesets_count !== undefined) {
88056               var changesetsCount = parseInt(_userDetails.changesets_count, 10) + 1; // #4283
88057
88058               tags.changesets_count = String(changesetsCount); // first 100 edits - new user
88059
88060               if (changesetsCount <= 100) {
88061                 var s;
88062                 s = corePreferences('walkthrough_completed');
88063
88064                 if (s) {
88065                   tags['ideditor:walkthrough_completed'] = s;
88066                 }
88067
88068                 s = corePreferences('walkthrough_progress');
88069
88070                 if (s) {
88071                   tags['ideditor:walkthrough_progress'] = s;
88072                 }
88073
88074                 s = corePreferences('walkthrough_started');
88075
88076                 if (s) {
88077                   tags['ideditor:walkthrough_started'] = s;
88078                 }
88079               }
88080             } else {
88081               delete tags.changesets_count;
88082             }
88083
88084             if (!fastDeepEqual(context.changeset.tags, tags)) {
88085               context.changeset = context.changeset.update({
88086                 tags: tags
88087               });
88088             }
88089           }
88090
88091           commit.reset = function () {
88092             context.changeset = null;
88093           };
88094
88095           return utilRebind(commit, dispatch, 'on');
88096         }
88097
88098         // for punction see https://stackoverflow.com/a/21224179
88099
88100         function simplify(str) {
88101           if (typeof str !== 'string') return '';
88102           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());
88103         }
88104
88105         // `resolveStrings`
88106         // Resolves the text strings for a given community index item
88107         //
88108         // Arguments
88109         //   `item`:  Object containing the community index item
88110         //   `defaults`: Object containing the community index default strings
88111         //   `localizerFn?`: optional function we will call to do the localization.
88112         //      This function should be like the iD `t()` function that
88113         //      accepts a `stringID` and returns a localized string
88114         //
88115         // Returns
88116         //   An Object containing all the resolved strings:
88117         //   {
88118         //     name:                     'talk-ru Mailing List',
88119         //     url:                      'https://lists.openstreetmap.org/listinfo/talk-ru',
88120         //     signupUrl:                'https://example.url/signup',
88121         //     description:              'A one line description',
88122         //     extendedDescription:      'Extended description',
88123         //     nameHTML:                 '<a href="the url">the name</a>',
88124         //     urlHTML:                  '<a href="the url">the url</a>',
88125         //     signupUrlHTML:            '<a href="the signupUrl">the signupUrl</a>',
88126         //     descriptionHTML:          the description, with urls and signupUrls linkified,
88127         //     extendedDescriptionHTML:  the extendedDescription with urls and signupUrls linkified
88128         //   }
88129         //
88130
88131         function resolveStrings(item, defaults, localizerFn) {
88132           var itemStrings = Object.assign({}, item.strings); // shallow clone
88133
88134           var defaultStrings = Object.assign({}, defaults[item.type]); // shallow clone
88135
88136           var anyToken = new RegExp(/(\{\w+\})/, 'gi'); // Pre-localize the item and default strings
88137
88138           if (localizerFn) {
88139             if (itemStrings.community) {
88140               var communityID = simplify(itemStrings.community);
88141               itemStrings.community = localizerFn("_communities.".concat(communityID));
88142             }
88143
88144             ['name', 'description', 'extendedDescription'].forEach(function (prop) {
88145               if (defaultStrings[prop]) defaultStrings[prop] = localizerFn("_defaults.".concat(item.type, ".").concat(prop));
88146               if (itemStrings[prop]) itemStrings[prop] = localizerFn("".concat(item.id, ".").concat(prop));
88147             });
88148           }
88149
88150           var replacements = {
88151             account: item.account,
88152             community: itemStrings.community,
88153             signupUrl: itemStrings.signupUrl,
88154             url: itemStrings.url
88155           }; // Resolve URLs first (which may refer to {account})
88156
88157           if (!replacements.signupUrl) {
88158             replacements.signupUrl = resolve(itemStrings.signupUrl || defaultStrings.signupUrl);
88159           }
88160
88161           if (!replacements.url) {
88162             replacements.url = resolve(itemStrings.url || defaultStrings.url);
88163           }
88164
88165           var resolved = {
88166             name: resolve(itemStrings.name || defaultStrings.name),
88167             url: resolve(itemStrings.url || defaultStrings.url),
88168             signupUrl: resolve(itemStrings.signupUrl || defaultStrings.signupUrl),
88169             description: resolve(itemStrings.description || defaultStrings.description),
88170             extendedDescription: resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription)
88171           }; // Generate linkified strings
88172
88173           resolved.nameHTML = linkify(resolved.url, resolved.name);
88174           resolved.urlHTML = linkify(resolved.url);
88175           resolved.signupUrlHTML = linkify(resolved.signupUrl);
88176           resolved.descriptionHTML = resolve(itemStrings.description || defaultStrings.description, true);
88177           resolved.extendedDescriptionHTML = resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription, true);
88178           return resolved;
88179
88180           function resolve(s, addLinks) {
88181             if (!s) return undefined;
88182             var result = s;
88183
88184             for (var key in replacements) {
88185               var token = "{".concat(key, "}");
88186               var regex = new RegExp(token, 'g');
88187
88188               if (regex.test(result)) {
88189                 var replacement = replacements[key];
88190
88191                 if (!replacement) {
88192                   throw new Error("Cannot resolve token: ".concat(token));
88193                 } else {
88194                   if (addLinks && (key === 'signupUrl' || key === 'url')) {
88195                     replacement = linkify(replacement);
88196                   }
88197
88198                   result = result.replace(regex, replacement);
88199                 }
88200               }
88201             } // There shouldn't be any leftover tokens in a resolved string
88202
88203
88204             var leftovers = result.match(anyToken);
88205
88206             if (leftovers) {
88207               throw new Error("Cannot resolve tokens: ".concat(leftovers));
88208             } // Linkify subreddits like `/r/openstreetmap`
88209             // https://github.com/osmlab/osm-community-index/issues/82
88210             // https://github.com/openstreetmap/iD/issues/4997
88211
88212
88213             if (addLinks && item.type === 'reddit') {
88214               result = result.replace(/(\/r\/\w+\/*)/i, function (match) {
88215                 return linkify(resolved.url, match);
88216               });
88217             }
88218
88219             return result;
88220           }
88221
88222           function linkify(url, text) {
88223             if (!url) return undefined;
88224             text = text || url;
88225             return "<a target=\"_blank\" href=\"".concat(url, "\">").concat(text, "</a>");
88226           }
88227         }
88228
88229         var _oci = null;
88230         function uiSuccess(context) {
88231           var MAXEVENTS = 2;
88232           var dispatch = dispatch$8('cancel');
88233
88234           var _changeset;
88235
88236           var _location;
88237
88238           ensureOSMCommunityIndex(); // start fetching the data
88239
88240           function ensureOSMCommunityIndex() {
88241             var data = _mainFileFetcher;
88242             return Promise.all([data.get('oci_features'), data.get('oci_resources'), data.get('oci_defaults')]).then(function (vals) {
88243               if (_oci) return _oci; // Merge Custom Features
88244
88245               if (vals[0] && Array.isArray(vals[0].features)) {
88246                 _mainLocations.mergeCustomGeoJSON(vals[0]);
88247               }
88248
88249               var ociResources = Object.values(vals[1].resources);
88250
88251               if (ociResources.length) {
88252                 // Resolve all locationSet features.
88253                 return _mainLocations.mergeLocationSets(ociResources).then(function () {
88254                   _oci = {
88255                     resources: ociResources,
88256                     defaults: vals[2].defaults
88257                   };
88258                   return _oci;
88259                 });
88260               } else {
88261                 _oci = {
88262                   resources: [],
88263                   // no resources?
88264                   defaults: vals[2].defaults
88265                 };
88266                 return _oci;
88267               }
88268             });
88269           } // string-to-date parsing in JavaScript is weird
88270
88271
88272           function parseEventDate(when) {
88273             if (!when) return;
88274             var raw = when.trim();
88275             if (!raw) return;
88276
88277             if (!/Z$/.test(raw)) {
88278               // if no trailing 'Z', add one
88279               raw += 'Z'; // this forces date to be parsed as a UTC date
88280             }
88281
88282             var parsed = new Date(raw);
88283             return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone
88284           }
88285
88286           function success(selection) {
88287             var header = selection.append('div').attr('class', 'header fillL');
88288             header.append('h3').html(_t.html('success.just_edited'));
88289             header.append('button').attr('class', 'close').on('click', function () {
88290               return dispatch.call('cancel');
88291             }).call(svgIcon('#iD-icon-close'));
88292             var body = selection.append('div').attr('class', 'body save-success fillL');
88293             var summary = body.append('div').attr('class', 'save-summary');
88294             summary.append('h3').html(_t.html('success.thank_you' + (_location ? '_location' : ''), {
88295               where: _location
88296             }));
88297             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'));
88298             var osm = context.connection();
88299             if (!osm) return;
88300             var changesetURL = osm.changesetURL(_changeset.id);
88301             var table = summary.append('table').attr('class', 'summary-table');
88302             var row = table.append('tr').attr('class', 'summary-row');
88303             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');
88304             var summaryDetail = row.append('td').attr('class', 'cell-detail summary-detail');
88305             summaryDetail.append('a').attr('class', 'cell-detail summary-view-on-osm').attr('target', '_blank').attr('href', changesetURL).html(_t.html('success.view_on_osm'));
88306             summaryDetail.append('div').html(_t.html('success.changeset_id', {
88307               changeset_id: "<a href=\"".concat(changesetURL, "\" target=\"_blank\">").concat(_changeset.id, "</a>")
88308             })); // Get OSM community index features intersecting the map..
88309
88310             ensureOSMCommunityIndex().then(function (oci) {
88311               var loc = context.map().center();
88312               var validLocations = _mainLocations.locationsAt(loc); // Gather the communities
88313
88314               var communities = [];
88315               oci.resources.forEach(function (resource) {
88316                 var area = validLocations[resource.locationSetID];
88317                 if (!area) return; // Resolve strings
88318
88319                 var localizer = function localizer(stringID) {
88320                   return _t.html("community.".concat(stringID));
88321                 };
88322
88323                 resource.resolved = resolveStrings(resource, oci.defaults, localizer);
88324                 communities.push({
88325                   area: area,
88326                   order: resource.order || 0,
88327                   resource: resource
88328                 });
88329               }); // sort communities by feature area ascending, community order descending
88330
88331               communities.sort(function (a, b) {
88332                 return a.area - b.area || b.order - a.order;
88333               });
88334               body.call(showCommunityLinks, communities.map(function (c) {
88335                 return c.resource;
88336               }));
88337             });
88338           }
88339
88340           function showCommunityLinks(selection, resources) {
88341             var communityLinks = selection.append('div').attr('class', 'save-communityLinks');
88342             communityLinks.append('h3').html(_t.html('success.like_osm'));
88343             var table = communityLinks.append('table').attr('class', 'community-table');
88344             var row = table.selectAll('.community-row').data(resources);
88345             var rowEnter = row.enter().append('tr').attr('class', 'community-row');
88346             rowEnter.append('td').attr('class', 'cell-icon community-icon').append('a').attr('target', '_blank').attr('href', function (d) {
88347               return d.resolved.url;
88348             }).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', function (d) {
88349               return "#community-".concat(d.type);
88350             });
88351             var communityDetail = rowEnter.append('td').attr('class', 'cell-detail community-detail');
88352             communityDetail.each(showCommunityDetails);
88353             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'));
88354           }
88355
88356           function showCommunityDetails(d) {
88357             var selection = select(this);
88358             var communityID = d.id;
88359             selection.append('div').attr('class', 'community-name').html(d.resolved.nameHTML);
88360             selection.append('div').attr('class', 'community-description').html(d.resolved.descriptionHTML); // Create an expanding section if any of these are present..
88361
88362             if (d.resolved.extendedDescriptionHTML || d.languageCodes && d.languageCodes.length) {
88363               selection.append('div').call(uiDisclosure(context, "community-more-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.more')).content(showMore));
88364             }
88365
88366             var nextEvents = (d.events || []).map(function (event) {
88367               event.date = parseEventDate(event.when);
88368               return event;
88369             }).filter(function (event) {
88370               // date is valid and future (or today)
88371               var t = event.date.getTime();
88372               var now = new Date().setHours(0, 0, 0, 0);
88373               return !isNaN(t) && t >= now;
88374             }).sort(function (a, b) {
88375               // sort by date ascending
88376               return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
88377             }).slice(0, MAXEVENTS); // limit number of events shown
88378
88379             if (nextEvents.length) {
88380               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);
88381             }
88382
88383             function showMore(selection) {
88384               var more = selection.selectAll('.community-more').data([0]);
88385               var moreEnter = more.enter().append('div').attr('class', 'community-more');
88386
88387               if (d.resolved.extendedDescriptionHTML) {
88388                 moreEnter.append('div').attr('class', 'community-extended-description').html(d.resolved.extendedDescriptionHTML);
88389               }
88390
88391               if (d.languageCodes && d.languageCodes.length) {
88392                 var languageList = d.languageCodes.map(function (code) {
88393                   return _mainLocalizer.languageName(code);
88394                 }).join(', ');
88395                 moreEnter.append('div').attr('class', 'community-languages').html(_t.html('success.languages', {
88396                   languages: languageList
88397                 }));
88398               }
88399             }
88400
88401             function showNextEvents(selection) {
88402               var events = selection.append('div').attr('class', 'community-events');
88403               var item = events.selectAll('.community-event').data(nextEvents);
88404               var itemEnter = item.enter().append('div').attr('class', 'community-event');
88405               itemEnter.append('div').attr('class', 'community-event-name').append('a').attr('target', '_blank').attr('href', function (d) {
88406                 return d.url;
88407               }).html(function (d) {
88408                 var name = d.name;
88409
88410                 if (d.i18n && d.id) {
88411                   name = _t("community.".concat(communityID, ".events.").concat(d.id, ".name"), {
88412                     "default": name
88413                   });
88414                 }
88415
88416                 return name;
88417               });
88418               itemEnter.append('div').attr('class', 'community-event-when').html(function (d) {
88419                 var options = {
88420                   weekday: 'short',
88421                   day: 'numeric',
88422                   month: 'short',
88423                   year: 'numeric'
88424                 };
88425
88426                 if (d.date.getHours() || d.date.getMinutes()) {
88427                   // include time if it has one
88428                   options.hour = 'numeric';
88429                   options.minute = 'numeric';
88430                 }
88431
88432                 return d.date.toLocaleString(_mainLocalizer.localeCode(), options);
88433               });
88434               itemEnter.append('div').attr('class', 'community-event-where').html(function (d) {
88435                 var where = d.where;
88436
88437                 if (d.i18n && d.id) {
88438                   where = _t("community.".concat(communityID, ".events.").concat(d.id, ".where"), {
88439                     "default": where
88440                   });
88441                 }
88442
88443                 return where;
88444               });
88445               itemEnter.append('div').attr('class', 'community-event-description').html(function (d) {
88446                 var description = d.description;
88447
88448                 if (d.i18n && d.id) {
88449                   description = _t("community.".concat(communityID, ".events.").concat(d.id, ".description"), {
88450                     "default": description
88451                   });
88452                 }
88453
88454                 return description;
88455               });
88456             }
88457           }
88458
88459           success.changeset = function (val) {
88460             if (!arguments.length) return _changeset;
88461             _changeset = val;
88462             return success;
88463           };
88464
88465           success.location = function (val) {
88466             if (!arguments.length) return _location;
88467             _location = val;
88468             return success;
88469           };
88470
88471           return utilRebind(success, dispatch, 'on');
88472         }
88473
88474         function modeSave(context) {
88475           var mode = {
88476             id: 'save'
88477           };
88478           var keybinding = utilKeybinding('modeSave');
88479           var commit = uiCommit(context).on('cancel', cancel);
88480
88481           var _conflictsUi; // uiConflicts
88482
88483
88484           var _location;
88485
88486           var _success;
88487
88488           var uploader = context.uploader().on('saveStarted.modeSave', function () {
88489             keybindingOff();
88490           }) // fire off some async work that we want to be ready later
88491           .on('willAttemptUpload.modeSave', prepareForSuccess).on('progressChanged.modeSave', showProgress).on('resultNoChanges.modeSave', function () {
88492             cancel();
88493           }).on('resultErrors.modeSave', showErrors).on('resultConflicts.modeSave', showConflicts).on('resultSuccess.modeSave', showSuccess);
88494
88495           function cancel() {
88496             context.enter(modeBrowse(context));
88497           }
88498
88499           function showProgress(num, total) {
88500             var modal = context.container().select('.loading-modal .modal-section');
88501             var progress = modal.selectAll('.progress').data([0]); // enter/update
88502
88503             progress.enter().append('div').attr('class', 'progress').merge(progress).text(_t('save.conflict_progress', {
88504               num: num,
88505               total: total
88506             }));
88507           }
88508
88509           function showConflicts(changeset, conflicts, origChanges) {
88510             var selection = context.container().select('.sidebar').append('div').attr('class', 'sidebar-component');
88511             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
88512             _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on('cancel', function () {
88513               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
88514               selection.remove();
88515               keybindingOn();
88516               uploader.cancelConflictResolution();
88517             }).on('save', function () {
88518               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
88519               selection.remove();
88520               uploader.processResolvedConflicts(changeset);
88521             });
88522             selection.call(_conflictsUi);
88523           }
88524
88525           function showErrors(errors) {
88526             keybindingOn();
88527             var selection = uiConfirm(context.container());
88528             selection.select('.modal-section.header').append('h3').text(_t('save.error'));
88529             addErrors(selection, errors);
88530             selection.okButton();
88531           }
88532
88533           function addErrors(selection, data) {
88534             var message = selection.select('.modal-section.message-text');
88535             var items = message.selectAll('.error-container').data(data);
88536             var enter = items.enter().append('div').attr('class', 'error-container');
88537             enter.append('a').attr('class', 'error-description').attr('href', '#').classed('hide-toggle', true).text(function (d) {
88538               return d.msg || _t('save.unknown_error_details');
88539             }).on('click', function (d3_event) {
88540               d3_event.preventDefault();
88541               var error = select(this);
88542               var detail = select(this.nextElementSibling);
88543               var exp = error.classed('expanded');
88544               detail.style('display', exp ? 'none' : 'block');
88545               error.classed('expanded', !exp);
88546             });
88547             var details = enter.append('div').attr('class', 'error-detail-container').style('display', 'none');
88548             details.append('ul').attr('class', 'error-detail-list').selectAll('li').data(function (d) {
88549               return d.details || [];
88550             }).enter().append('li').attr('class', 'error-detail-item').text(function (d) {
88551               return d;
88552             });
88553             items.exit().remove();
88554           }
88555
88556           function showSuccess(changeset) {
88557             commit.reset();
88558
88559             var ui = _success.changeset(changeset).location(_location).on('cancel', function () {
88560               context.ui().sidebar.hide();
88561             });
88562
88563             context.enter(modeBrowse(context).sidebar(ui));
88564           }
88565
88566           function keybindingOn() {
88567             select(document).call(keybinding.on('⎋', cancel, true));
88568           }
88569
88570           function keybindingOff() {
88571             select(document).call(keybinding.unbind);
88572           } // Reverse geocode current map location so we can display a message on
88573           // the success screen like "Thank you for editing around place, region."
88574
88575
88576           function prepareForSuccess() {
88577             _success = uiSuccess(context);
88578             _location = null;
88579             if (!services.geocoder) return;
88580             services.geocoder.reverse(context.map().center(), function (err, result) {
88581               if (err || !result || !result.address) return;
88582               var addr = result.address;
88583               var place = addr && (addr.town || addr.city || addr.county) || '';
88584               var region = addr && (addr.state || addr.country) || '';
88585               var separator = place && region ? _t('success.thank_you_where.separator') : '';
88586               _location = _t('success.thank_you_where.format', {
88587                 place: place,
88588                 separator: separator,
88589                 region: region
88590               });
88591             });
88592           }
88593
88594           mode.selectedIDs = function () {
88595             return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
88596           };
88597
88598           mode.enter = function () {
88599             // Show sidebar
88600             context.ui().sidebar.expand();
88601
88602             function done() {
88603               context.ui().sidebar.show(commit);
88604             }
88605
88606             keybindingOn();
88607             context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
88608             var osm = context.connection();
88609
88610             if (!osm) {
88611               cancel();
88612               return;
88613             }
88614
88615             if (osm.authenticated()) {
88616               done();
88617             } else {
88618               osm.authenticate(function (err) {
88619                 if (err) {
88620                   cancel();
88621                 } else {
88622                   done();
88623                 }
88624               });
88625             }
88626           };
88627
88628           mode.exit = function () {
88629             keybindingOff();
88630             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
88631             context.ui().sidebar.hide();
88632           };
88633
88634           return mode;
88635         }
88636
88637         function modeSelectError(context, selectedErrorID, selectedErrorService) {
88638           var mode = {
88639             id: 'select-error',
88640             button: 'browse'
88641           };
88642           var keybinding = utilKeybinding('select-error');
88643           var errorService = services[selectedErrorService];
88644           var errorEditor;
88645
88646           switch (selectedErrorService) {
88647             case 'improveOSM':
88648               errorEditor = uiImproveOsmEditor(context).on('change', function () {
88649                 context.map().pan([0, 0]); // trigger a redraw
88650
88651                 var error = checkSelectedID();
88652                 if (!error) return;
88653                 context.ui().sidebar.show(errorEditor.error(error));
88654               });
88655               break;
88656
88657             case 'keepRight':
88658               errorEditor = uiKeepRightEditor(context).on('change', function () {
88659                 context.map().pan([0, 0]); // trigger a redraw
88660
88661                 var error = checkSelectedID();
88662                 if (!error) return;
88663                 context.ui().sidebar.show(errorEditor.error(error));
88664               });
88665               break;
88666
88667             case 'osmose':
88668               errorEditor = uiOsmoseEditor(context).on('change', function () {
88669                 context.map().pan([0, 0]); // trigger a redraw
88670
88671                 var error = checkSelectedID();
88672                 if (!error) return;
88673                 context.ui().sidebar.show(errorEditor.error(error));
88674               });
88675               break;
88676           }
88677
88678           var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
88679
88680           function checkSelectedID() {
88681             if (!errorService) return;
88682             var error = errorService.getError(selectedErrorID);
88683
88684             if (!error) {
88685               context.enter(modeBrowse(context));
88686             }
88687
88688             return error;
88689           }
88690
88691           mode.zoomToSelected = function () {
88692             if (!errorService) return;
88693             var error = errorService.getError(selectedErrorID);
88694
88695             if (error) {
88696               context.map().centerZoomEase(error.loc, 20);
88697             }
88698           };
88699
88700           mode.enter = function () {
88701             var error = checkSelectedID();
88702             if (!error) return;
88703             behaviors.forEach(context.install);
88704             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
88705             select(document).call(keybinding);
88706             selectError();
88707             var sidebar = context.ui().sidebar;
88708             sidebar.show(errorEditor.error(error));
88709             context.map().on('drawn.select-error', selectError); // class the error as selected, or return to browse mode if the error is gone
88710
88711             function selectError(d3_event, drawn) {
88712               if (!checkSelectedID()) return;
88713               var selection = context.surface().selectAll('.itemId-' + selectedErrorID + '.' + selectedErrorService);
88714
88715               if (selection.empty()) {
88716                 // Return to browse mode if selected DOM elements have
88717                 // disappeared because the user moved them out of view..
88718                 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
88719
88720                 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
88721                   context.enter(modeBrowse(context));
88722                 }
88723               } else {
88724                 selection.classed('selected', true);
88725                 context.selectedErrorID(selectedErrorID);
88726               }
88727             }
88728
88729             function esc() {
88730               if (context.container().select('.combobox').size()) return;
88731               context.enter(modeBrowse(context));
88732             }
88733           };
88734
88735           mode.exit = function () {
88736             behaviors.forEach(context.uninstall);
88737             select(document).call(keybinding.unbind);
88738             context.surface().selectAll('.qaItem.selected').classed('selected hover', false);
88739             context.map().on('drawn.select-error', null);
88740             context.ui().sidebar.hide();
88741             context.selectedErrorID(null);
88742             context.features().forceVisible([]);
88743           };
88744
88745           return mode;
88746         }
88747
88748         function uiToolOldDrawModes(context) {
88749           var tool = {
88750             id: 'old_modes',
88751             label: _t.html('toolbar.add_feature')
88752           };
88753           var modes = [modeAddPoint(context, {
88754             title: _t.html('modes.add_point.title'),
88755             button: 'point',
88756             description: _t.html('modes.add_point.description'),
88757             preset: _mainPresetIndex.item('point'),
88758             key: '1'
88759           }), modeAddLine(context, {
88760             title: _t.html('modes.add_line.title'),
88761             button: 'line',
88762             description: _t.html('modes.add_line.description'),
88763             preset: _mainPresetIndex.item('line'),
88764             key: '2'
88765           }), modeAddArea(context, {
88766             title: _t.html('modes.add_area.title'),
88767             button: 'area',
88768             description: _t.html('modes.add_area.description'),
88769             preset: _mainPresetIndex.item('area'),
88770             key: '3'
88771           })];
88772
88773           function enabled() {
88774             return osmEditable();
88775           }
88776
88777           function osmEditable() {
88778             return context.editable();
88779           }
88780
88781           modes.forEach(function (mode) {
88782             context.keybinding().on(mode.key, function () {
88783               if (!enabled()) return;
88784
88785               if (mode.id === context.mode().id) {
88786                 context.enter(modeBrowse(context));
88787               } else {
88788                 context.enter(mode);
88789               }
88790             });
88791           });
88792
88793           tool.render = function (selection) {
88794             var wrap = selection.append('div').attr('class', 'joined').style('display', 'flex');
88795
88796             var debouncedUpdate = debounce(update, 500, {
88797               leading: true,
88798               trailing: true
88799             });
88800
88801             context.map().on('move.modes', debouncedUpdate).on('drawn.modes', debouncedUpdate);
88802             context.on('enter.modes', update);
88803             update();
88804
88805             function update() {
88806               var buttons = wrap.selectAll('button.add-button').data(modes, function (d) {
88807                 return d.id;
88808               }); // exit
88809
88810               buttons.exit().remove(); // enter
88811
88812               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
88813                 return d.id + ' add-button bar-button';
88814               }).on('click.mode-buttons', function (d3_event, d) {
88815                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
88816
88817                 var currMode = context.mode().id;
88818                 if (/^draw/.test(currMode)) return;
88819
88820                 if (d.id === currMode) {
88821                   context.enter(modeBrowse(context));
88822                 } else {
88823                   context.enter(d);
88824                 }
88825               }).call(uiTooltip().placement('bottom').title(function (d) {
88826                 return d.description;
88827               }).keys(function (d) {
88828                 return [d.key];
88829               }).scrollContainer(context.container().select('.top-toolbar')));
88830               buttonsEnter.each(function (d) {
88831                 select(this).call(svgIcon('#iD-icon-' + d.button));
88832               });
88833               buttonsEnter.append('span').attr('class', 'label').html(function (mode) {
88834                 return mode.title;
88835               }); // if we are adding/removing the buttons, check if toolbar has overflowed
88836
88837               if (buttons.enter().size() || buttons.exit().size()) {
88838                 context.ui().checkOverflow('.top-toolbar', true);
88839               } // update
88840
88841
88842               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
88843                 return !enabled();
88844               }).classed('active', function (d) {
88845                 return context.mode() && context.mode().button === d.button;
88846               });
88847             }
88848           };
88849
88850           return tool;
88851         }
88852
88853         function uiToolNotes(context) {
88854           var tool = {
88855             id: 'notes',
88856             label: _t.html('modes.add_note.label')
88857           };
88858           var mode = modeAddNote(context);
88859
88860           function enabled() {
88861             return notesEnabled() && notesEditable();
88862           }
88863
88864           function notesEnabled() {
88865             var noteLayer = context.layers().layer('notes');
88866             return noteLayer && noteLayer.enabled();
88867           }
88868
88869           function notesEditable() {
88870             var mode = context.mode();
88871             return context.map().notesEditable() && mode && mode.id !== 'save';
88872           }
88873
88874           context.keybinding().on(mode.key, function () {
88875             if (!enabled()) return;
88876
88877             if (mode.id === context.mode().id) {
88878               context.enter(modeBrowse(context));
88879             } else {
88880               context.enter(mode);
88881             }
88882           });
88883
88884           tool.render = function (selection) {
88885             var debouncedUpdate = debounce(update, 500, {
88886               leading: true,
88887               trailing: true
88888             });
88889
88890             context.map().on('move.notes', debouncedUpdate).on('drawn.notes', debouncedUpdate);
88891             context.on('enter.notes', update);
88892             update();
88893
88894             function update() {
88895               var showNotes = notesEnabled();
88896               var data = showNotes ? [mode] : [];
88897               var buttons = selection.selectAll('button.add-button').data(data, function (d) {
88898                 return d.id;
88899               }); // exit
88900
88901               buttons.exit().remove(); // enter
88902
88903               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
88904                 return d.id + ' add-button bar-button';
88905               }).on('click.notes', function (d3_event, d) {
88906                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
88907
88908                 var currMode = context.mode().id;
88909                 if (/^draw/.test(currMode)) return;
88910
88911                 if (d.id === currMode) {
88912                   context.enter(modeBrowse(context));
88913                 } else {
88914                   context.enter(d);
88915                 }
88916               }).call(uiTooltip().placement('bottom').title(function (d) {
88917                 return d.description;
88918               }).keys(function (d) {
88919                 return [d.key];
88920               }).scrollContainer(context.container().select('.top-toolbar')));
88921               buttonsEnter.each(function (d) {
88922                 select(this).call(svgIcon(d.icon || '#iD-icon-' + d.button));
88923               }); // if we are adding/removing the buttons, check if toolbar has overflowed
88924
88925               if (buttons.enter().size() || buttons.exit().size()) {
88926                 context.ui().checkOverflow('.top-toolbar', true);
88927               } // update
88928
88929
88930               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
88931                 return !enabled();
88932               }).classed('active', function (d) {
88933                 return context.mode() && context.mode().button === d.button;
88934               });
88935             }
88936           };
88937
88938           tool.uninstall = function () {
88939             context.on('enter.editor.notes', null).on('exit.editor.notes', null).on('enter.notes', null);
88940             context.map().on('move.notes', null).on('drawn.notes', null);
88941           };
88942
88943           return tool;
88944         }
88945
88946         function uiToolSave(context) {
88947           var tool = {
88948             id: 'save',
88949             label: _t.html('save.title')
88950           };
88951           var button = null;
88952           var tooltipBehavior = null;
88953           var history = context.history();
88954           var key = uiCmd('⌘S');
88955           var _numChanges = 0;
88956
88957           function isSaving() {
88958             var mode = context.mode();
88959             return mode && mode.id === 'save';
88960           }
88961
88962           function isDisabled() {
88963             return _numChanges === 0 || isSaving();
88964           }
88965
88966           function save(d3_event) {
88967             d3_event.preventDefault();
88968
88969             if (!context.inIntro() && !isSaving() && history.hasChanges()) {
88970               context.enter(modeSave(context));
88971             }
88972           }
88973
88974           function bgColor() {
88975             var step;
88976
88977             if (_numChanges === 0) {
88978               return null;
88979             } else if (_numChanges <= 50) {
88980               step = _numChanges / 50;
88981               return d3_interpolateRgb('#fff', '#ff8')(step); // white -> yellow
88982             } else {
88983               step = Math.min((_numChanges - 50) / 50, 1.0);
88984               return d3_interpolateRgb('#ff8', '#f88')(step); // yellow -> red
88985             }
88986           }
88987
88988           function updateCount() {
88989             var val = history.difference().summary().length;
88990             if (val === _numChanges) return;
88991             _numChanges = val;
88992
88993             if (tooltipBehavior) {
88994               tooltipBehavior.title(_t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')).keys([key]);
88995             }
88996
88997             if (button) {
88998               button.classed('disabled', isDisabled()).style('background', bgColor());
88999               button.select('span.count').html(_numChanges);
89000             }
89001           }
89002
89003           tool.render = function (selection) {
89004             tooltipBehavior = uiTooltip().placement('bottom').title(_t.html('save.no_changes')).keys([key]).scrollContainer(context.container().select('.top-toolbar'));
89005             var lastPointerUpType;
89006             button = selection.append('button').attr('class', 'save disabled bar-button').on('pointerup', function (d3_event) {
89007               lastPointerUpType = d3_event.pointerType;
89008             }).on('click', function (d3_event) {
89009               save(d3_event);
89010
89011               if (_numChanges === 0 && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
89012                 // there are no tooltips for touch interactions so flash feedback instead
89013                 context.ui().flash.duration(2000).iconName('#iD-icon-save').iconClass('disabled').label(_t.html('save.no_changes'))();
89014               }
89015
89016               lastPointerUpType = null;
89017             }).call(tooltipBehavior);
89018             button.call(svgIcon('#iD-icon-save'));
89019             button.append('span').attr('class', 'count').attr('aria-hidden', 'true').html('0');
89020             updateCount();
89021             context.keybinding().on(key, save, true);
89022             context.history().on('change.save', updateCount);
89023             context.on('enter.save', function () {
89024               if (button) {
89025                 button.classed('disabled', isDisabled());
89026
89027                 if (isSaving()) {
89028                   button.call(tooltipBehavior.hide);
89029                 }
89030               }
89031             });
89032           };
89033
89034           tool.uninstall = function () {
89035             context.keybinding().off(key, true);
89036             context.history().on('change.save', null);
89037             context.on('enter.save', null);
89038             button = null;
89039             tooltipBehavior = null;
89040           };
89041
89042           return tool;
89043         }
89044
89045         function uiToolSidebarToggle(context) {
89046           var tool = {
89047             id: 'sidebar_toggle',
89048             label: _t.html('toolbar.inspect')
89049           };
89050
89051           tool.render = function (selection) {
89052             selection.append('button').attr('class', 'bar-button').on('click', function () {
89053               context.ui().sidebar.toggle();
89054             }).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')));
89055           };
89056
89057           return tool;
89058         }
89059
89060         function uiToolUndoRedo(context) {
89061           var tool = {
89062             id: 'undo_redo',
89063             label: _t.html('toolbar.undo_redo')
89064           };
89065           var commands = [{
89066             id: 'undo',
89067             cmd: uiCmd('⌘Z'),
89068             action: function action() {
89069               context.undo();
89070             },
89071             annotation: function annotation() {
89072               return context.history().undoAnnotation();
89073             },
89074             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')
89075           }, {
89076             id: 'redo',
89077             cmd: uiCmd('⌘⇧Z'),
89078             action: function action() {
89079               context.redo();
89080             },
89081             annotation: function annotation() {
89082               return context.history().redoAnnotation();
89083             },
89084             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'undo' : 'redo')
89085           }];
89086
89087           function editable() {
89088             return context.mode() && context.mode().id !== 'save' && context.map().editableDataEnabled(true
89089             /* ignore min zoom */
89090             );
89091           }
89092
89093           tool.render = function (selection) {
89094             var tooltipBehavior = uiTooltip().placement('bottom').title(function (d) {
89095               return d.annotation() ? _t.html(d.id + '.tooltip', {
89096                 action: d.annotation()
89097               }) : _t.html(d.id + '.nothing');
89098             }).keys(function (d) {
89099               return [d.cmd];
89100             }).scrollContainer(context.container().select('.top-toolbar'));
89101             var lastPointerUpType;
89102             var buttons = selection.selectAll('button').data(commands).enter().append('button').attr('class', function (d) {
89103               return 'disabled ' + d.id + '-button bar-button';
89104             }).on('pointerup', function (d3_event) {
89105               // `pointerup` is always called before `click`
89106               lastPointerUpType = d3_event.pointerType;
89107             }).on('click', function (d3_event, d) {
89108               d3_event.preventDefault();
89109               var annotation = d.annotation();
89110
89111               if (editable() && annotation) {
89112                 d.action();
89113               }
89114
89115               if (editable() && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
89116                 // there are no tooltips for touch interactions so flash feedback instead
89117                 var text = annotation ? _t(d.id + '.tooltip', {
89118                   action: annotation
89119                 }) : _t(d.id + '.nothing');
89120                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass(annotation ? '' : 'disabled').label(text)();
89121               }
89122
89123               lastPointerUpType = null;
89124             }).call(tooltipBehavior);
89125             buttons.each(function (d) {
89126               select(this).call(svgIcon('#' + d.icon));
89127             });
89128             context.keybinding().on(commands[0].cmd, function (d3_event) {
89129               d3_event.preventDefault();
89130               if (editable()) commands[0].action();
89131             }).on(commands[1].cmd, function (d3_event) {
89132               d3_event.preventDefault();
89133               if (editable()) commands[1].action();
89134             });
89135
89136             var debouncedUpdate = debounce(update, 500, {
89137               leading: true,
89138               trailing: true
89139             });
89140
89141             context.map().on('move.undo_redo', debouncedUpdate).on('drawn.undo_redo', debouncedUpdate);
89142             context.history().on('change.undo_redo', function (difference) {
89143               if (difference) update();
89144             });
89145             context.on('enter.undo_redo', update);
89146
89147             function update() {
89148               buttons.classed('disabled', function (d) {
89149                 return !editable() || !d.annotation();
89150               }).each(function () {
89151                 var selection = select(this);
89152
89153                 if (!selection.select('.tooltip.in').empty()) {
89154                   selection.call(tooltipBehavior.updateContent);
89155                 }
89156               });
89157             }
89158           };
89159
89160           tool.uninstall = function () {
89161             context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
89162             context.map().on('move.undo_redo', null).on('drawn.undo_redo', null);
89163             context.history().on('change.undo_redo', null);
89164             context.on('enter.undo_redo', null);
89165           };
89166
89167           return tool;
89168         }
89169
89170         function uiTopToolbar(context) {
89171           var sidebarToggle = uiToolSidebarToggle(context),
89172               modes = uiToolOldDrawModes(context),
89173               notes = uiToolNotes(context),
89174               undoRedo = uiToolUndoRedo(context),
89175               save = uiToolSave(context);
89176
89177           function notesEnabled() {
89178             var noteLayer = context.layers().layer('notes');
89179             return noteLayer && noteLayer.enabled();
89180           }
89181
89182           function topToolbar(bar) {
89183             bar.on('wheel.topToolbar', function (d3_event) {
89184               if (!d3_event.deltaX) {
89185                 // translate vertical scrolling into horizontal scrolling in case
89186                 // the user doesn't have an input device that can scroll horizontally
89187                 bar.node().scrollLeft += d3_event.deltaY;
89188               }
89189             });
89190
89191             var debouncedUpdate = debounce(update, 500, {
89192               leading: true,
89193               trailing: true
89194             });
89195
89196             context.layers().on('change.topToolbar', debouncedUpdate);
89197             update();
89198
89199             function update() {
89200               var tools = [sidebarToggle, 'spacer', modes];
89201               tools.push('spacer');
89202
89203               if (notesEnabled()) {
89204                 tools = tools.concat([notes, 'spacer']);
89205               }
89206
89207               tools = tools.concat([undoRedo, save]);
89208               var toolbarItems = bar.selectAll('.toolbar-item').data(tools, function (d) {
89209                 return d.id || d;
89210               });
89211               toolbarItems.exit().each(function (d) {
89212                 if (d.uninstall) {
89213                   d.uninstall();
89214                 }
89215               }).remove();
89216               var itemsEnter = toolbarItems.enter().append('div').attr('class', function (d) {
89217                 var classes = 'toolbar-item ' + (d.id || d).replace('_', '-');
89218                 if (d.klass) classes += ' ' + d.klass;
89219                 return classes;
89220               });
89221               var actionableItems = itemsEnter.filter(function (d) {
89222                 return d !== 'spacer';
89223               });
89224               actionableItems.append('div').attr('class', 'item-content').each(function (d) {
89225                 select(this).call(d.render, bar);
89226               });
89227               actionableItems.append('div').attr('class', 'item-label').html(function (d) {
89228                 return d.label;
89229               });
89230             }
89231           }
89232
89233           return topToolbar;
89234         }
89235
89236         var sawVersion = null;
89237         var isNewVersion = false;
89238         var isNewUser = false;
89239         function uiVersion(context) {
89240           var currVersion = context.version;
89241           var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
89242
89243           if (sawVersion === null && matchedVersion !== null) {
89244             if (corePreferences('sawVersion')) {
89245               isNewUser = false;
89246               isNewVersion = corePreferences('sawVersion') !== currVersion && currVersion.indexOf('-') === -1;
89247             } else {
89248               isNewUser = true;
89249               isNewVersion = true;
89250             }
89251
89252             corePreferences('sawVersion', currVersion);
89253             sawVersion = currVersion;
89254           }
89255
89256           return function (selection) {
89257             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
89258
89259             if (isNewVersion && !isNewUser) {
89260               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', {
89261                 version: currVersion
89262               })).placement('top').scrollContainer(context.container().select('.main-footer-wrap')));
89263             }
89264           };
89265         }
89266
89267         function uiZoom(context) {
89268           var zooms = [{
89269             id: 'zoom-in',
89270             icon: 'iD-icon-plus',
89271             title: _t.html('zoom.in'),
89272             action: zoomIn,
89273             disabled: function disabled() {
89274               return !context.map().canZoomIn();
89275             },
89276             disabledTitle: _t.html('zoom.disabled.in'),
89277             key: '+'
89278           }, {
89279             id: 'zoom-out',
89280             icon: 'iD-icon-minus',
89281             title: _t.html('zoom.out'),
89282             action: zoomOut,
89283             disabled: function disabled() {
89284               return !context.map().canZoomOut();
89285             },
89286             disabledTitle: _t.html('zoom.disabled.out'),
89287             key: '-'
89288           }];
89289
89290           function zoomIn(d3_event) {
89291             if (d3_event.shiftKey) return;
89292             d3_event.preventDefault();
89293             context.map().zoomIn();
89294           }
89295
89296           function zoomOut(d3_event) {
89297             if (d3_event.shiftKey) return;
89298             d3_event.preventDefault();
89299             context.map().zoomOut();
89300           }
89301
89302           function zoomInFurther(d3_event) {
89303             if (d3_event.shiftKey) return;
89304             d3_event.preventDefault();
89305             context.map().zoomInFurther();
89306           }
89307
89308           function zoomOutFurther(d3_event) {
89309             if (d3_event.shiftKey) return;
89310             d3_event.preventDefault();
89311             context.map().zoomOutFurther();
89312           }
89313
89314           return function (selection) {
89315             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function (d) {
89316               if (d.disabled()) {
89317                 return d.disabledTitle;
89318               }
89319
89320               return d.title;
89321             }).keys(function (d) {
89322               return [d.key];
89323             });
89324             var lastPointerUpType;
89325             var buttons = selection.selectAll('button').data(zooms).enter().append('button').attr('class', function (d) {
89326               return d.id;
89327             }).on('pointerup.editor', function (d3_event) {
89328               lastPointerUpType = d3_event.pointerType;
89329             }).on('click.editor', function (d3_event, d) {
89330               if (!d.disabled()) {
89331                 d.action(d3_event);
89332               } else if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
89333                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass('disabled').label(d.disabledTitle)();
89334               }
89335
89336               lastPointerUpType = null;
89337             }).call(tooltipBehavior);
89338             buttons.each(function (d) {
89339               select(this).call(svgIcon('#' + d.icon, 'light'));
89340             });
89341             utilKeybinding.plusKeys.forEach(function (key) {
89342               context.keybinding().on([key], zoomIn);
89343               context.keybinding().on([uiCmd('⌥' + key)], zoomInFurther);
89344             });
89345             utilKeybinding.minusKeys.forEach(function (key) {
89346               context.keybinding().on([key], zoomOut);
89347               context.keybinding().on([uiCmd('⌥' + key)], zoomOutFurther);
89348             });
89349
89350             function updateButtonStates() {
89351               buttons.classed('disabled', function (d) {
89352                 return d.disabled();
89353               }).each(function () {
89354                 var selection = select(this);
89355
89356                 if (!selection.select('.tooltip.in').empty()) {
89357                   selection.call(tooltipBehavior.updateContent);
89358                 }
89359               });
89360             }
89361
89362             updateButtonStates();
89363             context.map().on('move.uiZoom', updateButtonStates);
89364           };
89365         }
89366
89367         function uiZoomToSelection(context) {
89368           function isDisabled() {
89369             var mode = context.mode();
89370             return !mode || !mode.zoomToSelected;
89371           }
89372
89373           var _lastPointerUpType;
89374
89375           function pointerup(d3_event) {
89376             _lastPointerUpType = d3_event.pointerType;
89377           }
89378
89379           function click(d3_event) {
89380             d3_event.preventDefault();
89381
89382             if (isDisabled()) {
89383               if (_lastPointerUpType === 'touch' || _lastPointerUpType === 'pen') {
89384                 context.ui().flash.duration(2000).iconName('#iD-icon-framed-dot').iconClass('disabled').label(_t.html('inspector.zoom_to.no_selection'))();
89385               }
89386             } else {
89387               var mode = context.mode();
89388
89389               if (mode && mode.zoomToSelected) {
89390                 mode.zoomToSelected();
89391               }
89392             }
89393
89394             _lastPointerUpType = null;
89395           }
89396
89397           return function (selection) {
89398             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function () {
89399               if (isDisabled()) {
89400                 return _t.html('inspector.zoom_to.no_selection');
89401               }
89402
89403               return _t.html('inspector.zoom_to.title');
89404             }).keys([_t('inspector.zoom_to.key')]);
89405             var button = selection.append('button').on('pointerup', pointerup).on('click', click).call(svgIcon('#iD-icon-framed-dot', 'light')).call(tooltipBehavior);
89406
89407             function setEnabledState() {
89408               button.classed('disabled', isDisabled());
89409
89410               if (!button.select('.tooltip.in').empty()) {
89411                 button.call(tooltipBehavior.updateContent);
89412               }
89413             }
89414
89415             context.on('enter.uiZoomToSelection', setEnabledState);
89416             setEnabledState();
89417           };
89418         }
89419
89420         function uiPane(id, context) {
89421           var _key;
89422
89423           var _label = '';
89424           var _description = '';
89425           var _iconName = '';
89426
89427           var _sections; // array of uiSection objects
89428
89429
89430           var _paneSelection = select(null);
89431
89432           var _paneTooltip;
89433
89434           var pane = {
89435             id: id
89436           };
89437
89438           pane.label = function (val) {
89439             if (!arguments.length) return _label;
89440             _label = val;
89441             return pane;
89442           };
89443
89444           pane.key = function (val) {
89445             if (!arguments.length) return _key;
89446             _key = val;
89447             return pane;
89448           };
89449
89450           pane.description = function (val) {
89451             if (!arguments.length) return _description;
89452             _description = val;
89453             return pane;
89454           };
89455
89456           pane.iconName = function (val) {
89457             if (!arguments.length) return _iconName;
89458             _iconName = val;
89459             return pane;
89460           };
89461
89462           pane.sections = function (val) {
89463             if (!arguments.length) return _sections;
89464             _sections = val;
89465             return pane;
89466           };
89467
89468           pane.selection = function () {
89469             return _paneSelection;
89470           };
89471
89472           function hidePane() {
89473             context.ui().togglePanes();
89474           }
89475
89476           pane.togglePane = function (d3_event) {
89477             if (d3_event) d3_event.preventDefault();
89478
89479             _paneTooltip.hide();
89480
89481             context.ui().togglePanes(!_paneSelection.classed('shown') ? _paneSelection : undefined);
89482           };
89483
89484           pane.renderToggleButton = function (selection) {
89485             if (!_paneTooltip) {
89486               _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_description).keys([_key]);
89487             }
89488
89489             selection.append('button').on('click', pane.togglePane).call(svgIcon('#' + _iconName, 'light')).call(_paneTooltip);
89490           };
89491
89492           pane.renderContent = function (selection) {
89493             // override to fully customize content
89494             if (_sections) {
89495               _sections.forEach(function (section) {
89496                 selection.call(section.render);
89497               });
89498             }
89499           };
89500
89501           pane.renderPane = function (selection) {
89502             _paneSelection = selection.append('div').attr('class', 'fillL map-pane hide ' + id + '-pane').attr('pane', id);
89503
89504             var heading = _paneSelection.append('div').attr('class', 'pane-heading');
89505
89506             heading.append('h2').html(_label);
89507             heading.append('button').on('click', hidePane).call(svgIcon('#iD-icon-close'));
89508
89509             _paneSelection.append('div').attr('class', 'pane-content').call(pane.renderContent);
89510
89511             if (_key) {
89512               context.keybinding().on(_key, pane.togglePane);
89513             }
89514           };
89515
89516           return pane;
89517         }
89518
89519         function uiSectionBackgroundDisplayOptions(context) {
89520           var section = uiSection('background-display-options', context).label(_t.html('background.display_options')).disclosureContent(renderDisclosureContent);
89521
89522           var _detected = utilDetect();
89523
89524           var _storedOpacity = corePreferences('background-opacity');
89525
89526           var _minVal = 0;
89527
89528           var _maxVal = _detected.cssfilters ? 3 : 1;
89529
89530           var _sliders = _detected.cssfilters ? ['brightness', 'contrast', 'saturation', 'sharpness'] : ['brightness'];
89531
89532           var _options = {
89533             brightness: _storedOpacity !== null ? +_storedOpacity : 1,
89534             contrast: 1,
89535             saturation: 1,
89536             sharpness: 1
89537           };
89538
89539           function clamp(x, min, max) {
89540             return Math.max(min, Math.min(x, max));
89541           }
89542
89543           function updateValue(d, val) {
89544             val = clamp(val, _minVal, _maxVal);
89545             _options[d] = val;
89546             context.background()[d](val);
89547
89548             if (d === 'brightness') {
89549               corePreferences('background-opacity', val);
89550             }
89551
89552             section.reRender();
89553           }
89554
89555           function renderDisclosureContent(selection) {
89556             var container = selection.selectAll('.display-options-container').data([0]);
89557             var containerEnter = container.enter().append('div').attr('class', 'display-options-container controls-list'); // add slider controls
89558
89559             var slidersEnter = containerEnter.selectAll('.display-control').data(_sliders).enter().append('div').attr('class', function (d) {
89560               return 'display-control display-control-' + d;
89561             });
89562             slidersEnter.append('h5').html(function (d) {
89563               return _t.html('background.' + d);
89564             }).append('span').attr('class', function (d) {
89565               return 'display-option-value display-option-value-' + d;
89566             });
89567             var sildersControlEnter = slidersEnter.append('div').attr('class', 'control-wrap');
89568             sildersControlEnter.append('input').attr('class', function (d) {
89569               return 'display-option-input display-option-input-' + d;
89570             }).attr('type', 'range').attr('min', _minVal).attr('max', _maxVal).attr('step', '0.05').on('input', function (d3_event, d) {
89571               var val = select(this).property('value');
89572
89573               if (!val && d3_event && d3_event.target) {
89574                 val = d3_event.target.value;
89575               }
89576
89577               updateValue(d, val);
89578             });
89579             sildersControlEnter.append('button').attr('title', _t('background.reset')).attr('class', function (d) {
89580               return 'display-option-reset display-option-reset-' + d;
89581             }).on('click', function (d3_event, d) {
89582               if (d3_event.button !== 0) return;
89583               updateValue(d, 1);
89584             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo'))); // reset all button
89585
89586             containerEnter.append('a').attr('class', 'display-option-resetlink').attr('href', '#').html(_t.html('background.reset_all')).on('click', function (d3_event) {
89587               d3_event.preventDefault();
89588
89589               for (var i = 0; i < _sliders.length; i++) {
89590                 updateValue(_sliders[i], 1);
89591               }
89592             }); // update
89593
89594             container = containerEnter.merge(container);
89595             container.selectAll('.display-option-input').property('value', function (d) {
89596               return _options[d];
89597             });
89598             container.selectAll('.display-option-value').html(function (d) {
89599               return Math.floor(_options[d] * 100) + '%';
89600             });
89601             container.selectAll('.display-option-reset').classed('disabled', function (d) {
89602               return _options[d] === 1;
89603             }); // first time only, set brightness if needed
89604
89605             if (containerEnter.size() && _options.brightness !== 1) {
89606               context.background().brightness(_options.brightness);
89607             }
89608           }
89609
89610           return section;
89611         }
89612
89613         function uiSettingsCustomBackground() {
89614           var dispatch = dispatch$8('change');
89615
89616           function render(selection) {
89617             // keep separate copies of original and current settings
89618             var _origSettings = {
89619               template: corePreferences('background-custom-template')
89620             };
89621             var _currSettings = {
89622               template: corePreferences('background-custom-template')
89623             };
89624             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
89625             var modal = uiConfirm(selection).okButton();
89626             modal.classed('settings-modal settings-custom-background', true);
89627             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_background.header'));
89628             var textSection = modal.select('.modal-section.message-text');
89629             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, "`");
89630             textSection.append('div').attr('class', 'instructions-template').html(marked_1(instructions));
89631             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
89632
89633             var buttonSection = modal.select('.modal-section.buttons');
89634             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
89635             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
89636             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
89637
89638             function isSaveDisabled() {
89639               return null;
89640             } // restore the original template
89641
89642
89643             function clickCancel() {
89644               textSection.select('.field-template').property('value', _origSettings.template);
89645               corePreferences('background-custom-template', _origSettings.template);
89646               this.blur();
89647               modal.close();
89648             } // accept the current template
89649
89650
89651             function clickSave() {
89652               _currSettings.template = textSection.select('.field-template').property('value');
89653               corePreferences('background-custom-template', _currSettings.template);
89654               this.blur();
89655               modal.close();
89656               dispatch.call('change', this, _currSettings);
89657             }
89658           }
89659
89660           return utilRebind(render, dispatch, 'on');
89661         }
89662
89663         function uiSectionBackgroundList(context) {
89664           var _backgroundList = select(null);
89665
89666           var _customSource = context.background().findSource('custom');
89667
89668           var _settingsCustomBackground = uiSettingsCustomBackground().on('change', customChanged);
89669
89670           var section = uiSection('background-list', context).label(_t.html('background.backgrounds')).disclosureContent(renderDisclosureContent);
89671
89672           function previousBackgroundID() {
89673             return corePreferences('background-last-used-toggle');
89674           }
89675
89676           function renderDisclosureContent(selection) {
89677             // the background list
89678             var container = selection.selectAll('.layer-background-list').data([0]);
89679             _backgroundList = container.enter().append('ul').attr('class', 'layer-list layer-background-list').attr('dir', 'auto').merge(container); // add minimap toggle below list
89680
89681             var bgExtrasListEnter = selection.selectAll('.bg-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list bg-extras-list');
89682             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'));
89683             minimapLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
89684               d3_event.preventDefault();
89685               uiMapInMap.toggle();
89686             });
89687             minimapLabelEnter.append('span').html(_t.html('background.minimap.description'));
89688             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'));
89689             panelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
89690               d3_event.preventDefault();
89691               context.ui().info.toggle('background');
89692             });
89693             panelLabelEnter.append('span').html(_t.html('background.panel.description'));
89694             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'));
89695             locPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
89696               d3_event.preventDefault();
89697               context.ui().info.toggle('location');
89698             });
89699             locPanelLabelEnter.append('span').html(_t.html('background.location_panel.description')); // "Info / Report a Problem" link
89700
89701             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'));
89702
89703             _backgroundList.call(drawListItems, 'radio', function (d3_event, d) {
89704               chooseBackground(d);
89705             }, function (d) {
89706               return !d.isHidden() && !d.overlay;
89707             });
89708           }
89709
89710           function setTooltips(selection) {
89711             selection.each(function (d, i, nodes) {
89712               var item = select(this).select('label');
89713               var span = item.select('span');
89714               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
89715               var description = d.description();
89716               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
89717               item.call(uiTooltip().destroyAny);
89718
89719               if (d.id === previousBackgroundID()) {
89720                 item.call(uiTooltip().placement(placement).title('<div>' + _t.html('background.switch') + '</div>').keys([uiCmd('⌘' + _t('background.key'))]));
89721               } else if (description || isOverflowing) {
89722                 item.call(uiTooltip().placement(placement).title(description || d.label()));
89723               }
89724             });
89725           }
89726
89727           function drawListItems(layerList, type, change, filter) {
89728             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter).sort(function (a, b) {
89729               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
89730             });
89731             var layerLinks = layerList.selectAll('li') // We have to be a bit inefficient about reordering the list since
89732             // arrow key navigation of radio values likes to work in the order
89733             // they were added, not the display document order.
89734             .data(sources, function (d, i) {
89735               return d.id + '---' + i;
89736             });
89737             layerLinks.exit().remove();
89738             var enter = layerLinks.enter().append('li').classed('layer-custom', function (d) {
89739               return d.id === 'custom';
89740             }).classed('best', function (d) {
89741               return d.best();
89742             });
89743             var label = enter.append('label');
89744             label.append('input').attr('type', type).attr('name', 'background-layer').attr('value', function (d) {
89745               return d.id;
89746             }).on('change', change);
89747             label.append('span').html(function (d) {
89748               return d.label();
89749             });
89750             enter.filter(function (d) {
89751               return d.id === 'custom';
89752             }).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) {
89753               d3_event.preventDefault();
89754               editCustom();
89755             }).call(svgIcon('#iD-icon-more'));
89756             enter.filter(function (d) {
89757               return d.best();
89758             }).append('div').attr('class', 'best').call(uiTooltip().title(_t.html('background.best_imagery')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).append('span').html('&#9733;');
89759             layerList.call(updateLayerSelections);
89760           }
89761
89762           function updateLayerSelections(selection) {
89763             function active(d) {
89764               return context.background().showsLayer(d);
89765             }
89766
89767             selection.selectAll('li').classed('active', active).classed('switch', function (d) {
89768               return d.id === previousBackgroundID();
89769             }).call(setTooltips).selectAll('input').property('checked', active);
89770           }
89771
89772           function chooseBackground(d) {
89773             if (d.id === 'custom' && !d.template()) {
89774               return editCustom();
89775             }
89776
89777             var previousBackground = context.background().baseLayerSource();
89778             corePreferences('background-last-used-toggle', previousBackground.id);
89779             corePreferences('background-last-used', d.id);
89780             context.background().baseLayerSource(d);
89781           }
89782
89783           function customChanged(d) {
89784             if (d && d.template) {
89785               _customSource.template(d.template);
89786
89787               chooseBackground(_customSource);
89788             } else {
89789               _customSource.template('');
89790
89791               chooseBackground(context.background().findSource('none'));
89792             }
89793           }
89794
89795           function editCustom() {
89796             context.container().call(_settingsCustomBackground);
89797           }
89798
89799           context.background().on('change.background_list', function () {
89800             _backgroundList.call(updateLayerSelections);
89801           });
89802           context.map().on('move.background_list', debounce(function () {
89803             // layers in-view may have changed due to map move
89804             window.requestIdleCallback(section.reRender);
89805           }, 1000));
89806           return section;
89807         }
89808
89809         function uiSectionBackgroundOffset(context) {
89810           var section = uiSection('background-offset', context).label(_t.html('background.fix_misalignment')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
89811
89812           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
89813
89814           var _directions = [['top', [0, -0.5]], ['left', [-0.5, 0]], ['right', [0.5, 0]], ['bottom', [0, 0.5]]];
89815
89816           function updateValue() {
89817             var meters = geoOffsetToMeters(context.background().offset());
89818             var x = +meters[0].toFixed(2);
89819             var y = +meters[1].toFixed(2);
89820             context.container().selectAll('.nudge-inner-rect').select('input').classed('error', false).property('value', x + ', ' + y);
89821             context.container().selectAll('.nudge-reset').classed('disabled', function () {
89822               return x === 0 && y === 0;
89823             });
89824           }
89825
89826           function resetOffset() {
89827             context.background().offset([0, 0]);
89828             updateValue();
89829           }
89830
89831           function nudge(d) {
89832             context.background().nudge(d, context.map().zoom());
89833             updateValue();
89834           }
89835
89836           function inputOffset() {
89837             var input = select(this);
89838             var d = input.node().value;
89839             if (d === '') return resetOffset();
89840             d = d.replace(/;/g, ',').split(',').map(function (n) {
89841               // if n is NaN, it will always get mapped to false.
89842               return !isNaN(n) && n;
89843             });
89844
89845             if (d.length !== 2 || !d[0] || !d[1]) {
89846               input.classed('error', true);
89847               return;
89848             }
89849
89850             context.background().offset(geoMetersToOffset(d));
89851             updateValue();
89852           }
89853
89854           function dragOffset(d3_event) {
89855             if (d3_event.button !== 0) return;
89856             var origin = [d3_event.clientX, d3_event.clientY];
89857             var pointerId = d3_event.pointerId || 'mouse';
89858             context.container().append('div').attr('class', 'nudge-surface');
89859             select(window).on(_pointerPrefix + 'move.drag-bg-offset', pointermove).on(_pointerPrefix + 'up.drag-bg-offset', pointerup);
89860
89861             if (_pointerPrefix === 'pointer') {
89862               select(window).on('pointercancel.drag-bg-offset', pointerup);
89863             }
89864
89865             function pointermove(d3_event) {
89866               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
89867               var latest = [d3_event.clientX, d3_event.clientY];
89868               var d = [-(origin[0] - latest[0]) / 4, -(origin[1] - latest[1]) / 4];
89869               origin = latest;
89870               nudge(d);
89871             }
89872
89873             function pointerup(d3_event) {
89874               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
89875               if (d3_event.button !== 0) return;
89876               context.container().selectAll('.nudge-surface').remove();
89877               select(window).on('.drag-bg-offset', null);
89878             }
89879           }
89880
89881           function renderDisclosureContent(selection) {
89882             var container = selection.selectAll('.nudge-container').data([0]);
89883             var containerEnter = container.enter().append('div').attr('class', 'nudge-container');
89884             containerEnter.append('div').attr('class', 'nudge-instructions').html(_t.html('background.offset'));
89885             var nudgeWrapEnter = containerEnter.append('div').attr('class', 'nudge-controls-wrap');
89886             var nudgeEnter = nudgeWrapEnter.append('div').attr('class', 'nudge-outer-rect').on(_pointerPrefix + 'down', dragOffset);
89887             nudgeEnter.append('div').attr('class', 'nudge-inner-rect').append('input').attr('type', 'text').on('change', inputOffset);
89888             nudgeWrapEnter.append('div').selectAll('button').data(_directions).enter().append('button').attr('class', function (d) {
89889               return d[0] + ' nudge';
89890             }).on('click', function (d3_event, d) {
89891               nudge(d[1]);
89892             });
89893             nudgeWrapEnter.append('button').attr('title', _t('background.reset')).attr('class', 'nudge-reset disabled').on('click', function (d3_event) {
89894               d3_event.preventDefault();
89895               resetOffset();
89896             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')));
89897             updateValue();
89898           }
89899
89900           context.background().on('change.backgroundOffset-update', updateValue);
89901           return section;
89902         }
89903
89904         function uiSectionOverlayList(context) {
89905           var section = uiSection('overlay-list', context).label(_t.html('background.overlays')).disclosureContent(renderDisclosureContent);
89906
89907           var _overlayList = select(null);
89908
89909           function setTooltips(selection) {
89910             selection.each(function (d, i, nodes) {
89911               var item = select(this).select('label');
89912               var span = item.select('span');
89913               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
89914               var description = d.description();
89915               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
89916               item.call(uiTooltip().destroyAny);
89917
89918               if (description || isOverflowing) {
89919                 item.call(uiTooltip().placement(placement).title(description || d.name()));
89920               }
89921             });
89922           }
89923
89924           function updateLayerSelections(selection) {
89925             function active(d) {
89926               return context.background().showsLayer(d);
89927             }
89928
89929             selection.selectAll('li').classed('active', active).call(setTooltips).selectAll('input').property('checked', active);
89930           }
89931
89932           function chooseOverlay(d3_event, d) {
89933             d3_event.preventDefault();
89934             context.background().toggleOverlayLayer(d);
89935
89936             _overlayList.call(updateLayerSelections);
89937
89938             document.activeElement.blur();
89939           }
89940
89941           function drawListItems(layerList, type, change, filter) {
89942             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter);
89943             var layerLinks = layerList.selectAll('li').data(sources, function (d) {
89944               return d.name();
89945             });
89946             layerLinks.exit().remove();
89947             var enter = layerLinks.enter().append('li');
89948             var label = enter.append('label');
89949             label.append('input').attr('type', type).attr('name', 'layers').on('change', change);
89950             label.append('span').html(function (d) {
89951               return d.label();
89952             });
89953             layerList.selectAll('li').sort(sortSources);
89954             layerList.call(updateLayerSelections);
89955
89956             function sortSources(a, b) {
89957               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
89958             }
89959           }
89960
89961           function renderDisclosureContent(selection) {
89962             var container = selection.selectAll('.layer-overlay-list').data([0]);
89963             _overlayList = container.enter().append('ul').attr('class', 'layer-list layer-overlay-list').attr('dir', 'auto').merge(container);
89964
89965             _overlayList.call(drawListItems, 'checkbox', chooseOverlay, function (d) {
89966               return !d.isHidden() && d.overlay;
89967             });
89968           }
89969
89970           context.map().on('move.overlay_list', debounce(function () {
89971             // layers in-view may have changed due to map move
89972             window.requestIdleCallback(section.reRender);
89973           }, 1000));
89974           return section;
89975         }
89976
89977         function uiPaneBackground(context) {
89978           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)]);
89979           return backgroundPane;
89980         }
89981
89982         function uiPaneHelp(context) {
89983           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']]];
89984           var headings = {
89985             'help.help.open_data_h': 3,
89986             'help.help.before_start_h': 3,
89987             'help.help.open_source_h': 3,
89988             'help.overview.navigation_h': 3,
89989             'help.overview.features_h': 3,
89990             'help.editing.select_h': 3,
89991             'help.editing.multiselect_h': 3,
89992             'help.editing.undo_redo_h': 3,
89993             'help.editing.save_h': 3,
89994             'help.editing.upload_h': 3,
89995             'help.editing.backups_h': 3,
89996             'help.editing.keyboard_h': 3,
89997             'help.feature_editor.type_h': 3,
89998             'help.feature_editor.fields_h': 3,
89999             'help.feature_editor.tags_h': 3,
90000             'help.points.add_point_h': 3,
90001             'help.points.move_point_h': 3,
90002             'help.points.delete_point_h': 3,
90003             'help.lines.add_line_h': 3,
90004             'help.lines.modify_line_h': 3,
90005             'help.lines.connect_line_h': 3,
90006             'help.lines.disconnect_line_h': 3,
90007             'help.lines.move_line_h': 3,
90008             'help.lines.delete_line_h': 3,
90009             'help.areas.point_or_area_h': 3,
90010             'help.areas.add_area_h': 3,
90011             'help.areas.square_area_h': 3,
90012             'help.areas.modify_area_h': 3,
90013             'help.areas.delete_area_h': 3,
90014             'help.relations.edit_relation_h': 3,
90015             'help.relations.maintain_relation_h': 3,
90016             'help.relations.relation_types_h': 2,
90017             'help.relations.multipolygon_h': 3,
90018             'help.relations.turn_restriction_h': 3,
90019             'help.relations.route_h': 3,
90020             'help.relations.boundary_h': 3,
90021             'help.notes.add_note_h': 3,
90022             'help.notes.update_note_h': 3,
90023             'help.notes.save_note_h': 3,
90024             'help.imagery.sources_h': 3,
90025             'help.imagery.offsets_h': 3,
90026             'help.streetlevel.using_h': 3,
90027             'help.gps.using_h': 3,
90028             'help.qa.tools_h': 3,
90029             'help.qa.issues_h': 3
90030           }; // For each section, squash all the texts into a single markdown document
90031
90032           var docs = docKeys.map(function (key) {
90033             var helpkey = 'help.' + key[0];
90034             var helpPaneReplacements = {
90035               version: context.version
90036             };
90037             var text = key[1].reduce(function (all, part) {
90038               var subkey = helpkey + '.' + part;
90039               var depth = headings[subkey]; // is this subkey a heading?
90040
90041               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
90042
90043               return all + hhh + helpHtml(subkey, helpPaneReplacements) + '\n\n';
90044             }, '');
90045             return {
90046               title: _t.html(helpkey + '.title'),
90047               content: marked_1(text.trim()) // use keyboard key styling for shortcuts
90048               .replace(/<code>/g, '<kbd>').replace(/<\/code>/g, '<\/kbd>')
90049             };
90050           });
90051           var helpPane = uiPane('help', context).key(_t('help.key')).label(_t.html('help.title')).description(_t.html('help.title')).iconName('iD-icon-help');
90052
90053           helpPane.renderContent = function (content) {
90054             function clickHelp(d, i) {
90055               var rtl = _mainLocalizer.textDirection() === 'rtl';
90056               content.property('scrollTop', 0);
90057               helpPane.selection().select('.pane-heading h2').html(d.title);
90058               body.html(d.content);
90059               body.selectAll('a').attr('target', '_blank');
90060               menuItems.classed('selected', function (m) {
90061                 return m.title === d.title;
90062               });
90063               nav.html('');
90064
90065               if (rtl) {
90066                 nav.call(drawNext).call(drawPrevious);
90067               } else {
90068                 nav.call(drawPrevious).call(drawNext);
90069               }
90070
90071               function drawNext(selection) {
90072                 if (i < docs.length - 1) {
90073                   var nextLink = selection.append('a').attr('href', '#').attr('class', 'next').on('click', function (d3_event) {
90074                     d3_event.preventDefault();
90075                     clickHelp(docs[i + 1], i + 1);
90076                   });
90077                   nextLink.append('span').html(docs[i + 1].title).call(svgIcon(rtl ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
90078                 }
90079               }
90080
90081               function drawPrevious(selection) {
90082                 if (i > 0) {
90083                   var prevLink = selection.append('a').attr('href', '#').attr('class', 'previous').on('click', function (d3_event) {
90084                     d3_event.preventDefault();
90085                     clickHelp(docs[i - 1], i - 1);
90086                   });
90087                   prevLink.call(svgIcon(rtl ? '#iD-icon-forward' : '#iD-icon-backward', 'inline')).append('span').html(docs[i - 1].title);
90088                 }
90089               }
90090             }
90091
90092             function clickWalkthrough(d3_event) {
90093               d3_event.preventDefault();
90094               if (context.inIntro()) return;
90095               context.container().call(uiIntro(context));
90096               context.ui().togglePanes();
90097             }
90098
90099             function clickShortcuts(d3_event) {
90100               d3_event.preventDefault();
90101               context.container().call(context.ui().shortcuts, true);
90102             }
90103
90104             var toc = content.append('ul').attr('class', 'toc');
90105             var menuItems = toc.selectAll('li').data(docs).enter().append('li').append('a').attr('href', '#').html(function (d) {
90106               return d.title;
90107             }).on('click', function (d3_event, d) {
90108               d3_event.preventDefault();
90109               clickHelp(d, docs.indexOf(d));
90110             });
90111             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);
90112             shortcuts.append('div').html(_t.html('shortcuts.title'));
90113             var walkthrough = toc.append('li').attr('class', 'walkthrough').append('a').attr('href', '#').on('click', clickWalkthrough);
90114             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
90115             walkthrough.append('div').html(_t.html('splash.walkthrough'));
90116             var helpContent = content.append('div').attr('class', 'left-content');
90117             var body = helpContent.append('div').attr('class', 'body');
90118             var nav = helpContent.append('div').attr('class', 'nav');
90119             clickHelp(docs[0], 0);
90120           };
90121
90122           return helpPane;
90123         }
90124
90125         function uiSectionValidationIssues(id, severity, context) {
90126           var _issues = [];
90127           var section = uiSection(id, context).label(function () {
90128             if (!_issues) return '';
90129             var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
90130             return _t('inspector.title_count', {
90131               title: _t.html('issues.' + severity + 's.list_title'),
90132               count: issueCountText
90133             });
90134           }).disclosureContent(renderDisclosureContent).shouldDisplay(function () {
90135             return _issues && _issues.length;
90136           });
90137
90138           function getOptions() {
90139             return {
90140               what: corePreferences('validate-what') || 'edited',
90141               where: corePreferences('validate-where') || 'all'
90142             };
90143           } // get and cache the issues to display, unordered
90144
90145
90146           function reloadIssues() {
90147             _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
90148           }
90149
90150           function renderDisclosureContent(selection) {
90151             var center = context.map().center();
90152             var graph = context.graph(); // sort issues by distance away from the center of the map
90153
90154             var issues = _issues.map(function withDistance(issue) {
90155               var extent = issue.extent(graph);
90156               var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
90157               return Object.assign(issue, {
90158                 dist: dist
90159               });
90160             }).sort(function byDistance(a, b) {
90161               return a.dist - b.dist;
90162             }); // cut off at 1000
90163
90164
90165             issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection);
90166
90167             selection.call(drawIssuesList, issues);
90168           }
90169
90170           function drawIssuesList(selection, issues) {
90171             var list = selection.selectAll('.issues-list').data([0]);
90172             list = list.enter().append('ul').attr('class', 'layer-list issues-list ' + severity + 's-list').merge(list);
90173             var items = list.selectAll('li').data(issues, function (d) {
90174               return d.key;
90175             }); // Exit
90176
90177             items.exit().remove(); // Enter
90178
90179             var itemsEnter = items.enter().append('li').attr('class', function (d) {
90180               return 'issue severity-' + d.severity;
90181             });
90182             var labelsEnter = itemsEnter.append('button').attr('class', 'issue-label').on('click', function (d3_event, d) {
90183               context.validator().focusIssue(d);
90184             }).on('mouseover', function (d3_event, d) {
90185               utilHighlightEntities(d.entityIds, true, context);
90186             }).on('mouseout', function (d3_event, d) {
90187               utilHighlightEntities(d.entityIds, false, context);
90188             });
90189             var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
90190             textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
90191               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
90192               select(this).call(svgIcon(iconName));
90193             });
90194             textEnter.append('span').attr('class', 'issue-message');
90195             /*
90196             labelsEnter
90197                 .append('span')
90198                 .attr('class', 'issue-autofix')
90199                 .each(function(d) {
90200                     if (!d.autoFix) return;
90201                      d3_select(this)
90202                         .append('button')
90203                         .attr('title', t('issues.fix_one.title'))
90204                         .datum(d.autoFix)  // set button datum to the autofix
90205                         .attr('class', 'autofix action')
90206                         .on('click', function(d3_event, d) {
90207                             d3_event.preventDefault();
90208                             d3_event.stopPropagation();
90209                              var issuesEntityIDs = d.issue.entityIds;
90210                             utilHighlightEntities(issuesEntityIDs.concat(d.entityIds), false, context);
90211                              context.perform.apply(context, d.autoArgs);
90212                             context.validator().validate();
90213                         })
90214                         .call(svgIcon('#iD-icon-wrench'));
90215                 });
90216             */
90217             // Update
90218
90219             items = items.merge(itemsEnter).order();
90220             items.selectAll('.issue-message').html(function (d) {
90221               return d.message(context);
90222             });
90223             /*
90224             // autofix
90225             var canAutoFix = issues.filter(function(issue) { return issue.autoFix; });
90226              var autoFixAll = selection.selectAll('.autofix-all')
90227                 .data(canAutoFix.length ? [0] : []);
90228              // exit
90229             autoFixAll.exit()
90230                 .remove();
90231              // enter
90232             var autoFixAllEnter = autoFixAll.enter()
90233                 .insert('div', '.issues-list')
90234                 .attr('class', 'autofix-all');
90235              var linkEnter = autoFixAllEnter
90236                 .append('a')
90237                 .attr('class', 'autofix-all-link')
90238                 .attr('href', '#');
90239              linkEnter
90240                 .append('span')
90241                 .attr('class', 'autofix-all-link-text')
90242                 .html(t.html('issues.fix_all.title'));
90243              linkEnter
90244                 .append('span')
90245                 .attr('class', 'autofix-all-link-icon')
90246                 .call(svgIcon('#iD-icon-wrench'));
90247              if (severity === 'warning') {
90248                 renderIgnoredIssuesReset(selection);
90249             }
90250              // update
90251             autoFixAll = autoFixAll
90252                 .merge(autoFixAllEnter);
90253              autoFixAll.selectAll('.autofix-all-link')
90254                 .on('click', function() {
90255                     context.pauseChangeDispatch();
90256                     context.perform(actionNoop());
90257                     canAutoFix.forEach(function(issue) {
90258                         var args = issue.autoFix.autoArgs.slice();  // copy
90259                         if (typeof args[args.length - 1] !== 'function') {
90260                             args.pop();
90261                         }
90262                         args.push(t('issues.fix_all.annotation'));
90263                         context.replace.apply(context, args);
90264                     });
90265                     context.resumeChangeDispatch();
90266                     context.validator().validate();
90267                 });
90268             */
90269           }
90270
90271           context.validator().on('validated.uiSectionValidationIssues' + id, function () {
90272             window.requestIdleCallback(function () {
90273               reloadIssues();
90274               section.reRender();
90275             });
90276           });
90277           context.map().on('move.uiSectionValidationIssues' + id, debounce(function () {
90278             window.requestIdleCallback(function () {
90279               if (getOptions().where === 'visible') {
90280                 // must refetch issues if they are viewport-dependent
90281                 reloadIssues();
90282               } // always reload list to re-sort-by-distance
90283
90284
90285               section.reRender();
90286             });
90287           }, 1000));
90288           return section;
90289         }
90290
90291         function uiSectionValidationOptions(context) {
90292           var section = uiSection('issues-options', context).content(renderContent);
90293
90294           function renderContent(selection) {
90295             var container = selection.selectAll('.issues-options-container').data([0]);
90296             container = container.enter().append('div').attr('class', 'issues-options-container').merge(container);
90297             var data = [{
90298               key: 'what',
90299               values: ['edited', 'all']
90300             }, {
90301               key: 'where',
90302               values: ['visible', 'all']
90303             }];
90304             var options = container.selectAll('.issues-option').data(data, function (d) {
90305               return d.key;
90306             });
90307             var optionsEnter = options.enter().append('div').attr('class', function (d) {
90308               return 'issues-option issues-option-' + d.key;
90309             });
90310             optionsEnter.append('div').attr('class', 'issues-option-title').html(function (d) {
90311               return _t.html('issues.options.' + d.key + '.title');
90312             });
90313             var valuesEnter = optionsEnter.selectAll('label').data(function (d) {
90314               return d.values.map(function (val) {
90315                 return {
90316                   value: val,
90317                   key: d.key
90318                 };
90319               });
90320             }).enter().append('label');
90321             valuesEnter.append('input').attr('type', 'radio').attr('name', function (d) {
90322               return 'issues-option-' + d.key;
90323             }).attr('value', function (d) {
90324               return d.value;
90325             }).property('checked', function (d) {
90326               return getOptions()[d.key] === d.value;
90327             }).on('change', function (d3_event, d) {
90328               updateOptionValue(d3_event, d.key, d.value);
90329             });
90330             valuesEnter.append('span').html(function (d) {
90331               return _t.html('issues.options.' + d.key + '.' + d.value);
90332             });
90333           }
90334
90335           function getOptions() {
90336             return {
90337               what: corePreferences('validate-what') || 'edited',
90338               // 'all', 'edited'
90339               where: corePreferences('validate-where') || 'all' // 'all', 'visible'
90340
90341             };
90342           }
90343
90344           function updateOptionValue(d3_event, d, val) {
90345             if (!val && d3_event && d3_event.target) {
90346               val = d3_event.target.value;
90347             }
90348
90349             corePreferences('validate-' + d, val);
90350             context.validator().validate();
90351           }
90352
90353           return section;
90354         }
90355
90356         function uiSectionValidationRules(context) {
90357           var MINSQUARE = 0;
90358           var MAXSQUARE = 20;
90359           var DEFAULTSQUARE = 5; // see also unsquare_way.js
90360
90361           var section = uiSection('issues-rules', context).disclosureContent(renderDisclosureContent).label(_t.html('issues.rules.title'));
90362
90363           var _ruleKeys = context.validator().getRuleKeys().filter(function (key) {
90364             return key !== 'maprules';
90365           }).sort(function (key1, key2) {
90366             // alphabetize by localized title
90367             return _t('issues.' + key1 + '.title') < _t('issues.' + key2 + '.title') ? -1 : 1;
90368           });
90369
90370           function renderDisclosureContent(selection) {
90371             var container = selection.selectAll('.issues-rulelist-container').data([0]);
90372             var containerEnter = container.enter().append('div').attr('class', 'issues-rulelist-container');
90373             containerEnter.append('ul').attr('class', 'layer-list issue-rules-list');
90374             var ruleLinks = containerEnter.append('div').attr('class', 'issue-rules-links section-footer');
90375             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
90376               d3_event.preventDefault();
90377               context.validator().disableRules(_ruleKeys);
90378             });
90379             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
90380               d3_event.preventDefault();
90381               context.validator().disableRules([]);
90382             }); // Update
90383
90384             container = container.merge(containerEnter);
90385             container.selectAll('.issue-rules-list').call(drawListItems, _ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
90386           }
90387
90388           function drawListItems(selection, data, type, name, change, active) {
90389             var items = selection.selectAll('li').data(data); // Exit
90390
90391             items.exit().remove(); // Enter
90392
90393             var enter = items.enter().append('li');
90394
90395             if (name === 'rule') {
90396               enter.call(uiTooltip().title(function (d) {
90397                 return _t.html('issues.' + d + '.tip');
90398               }).placement('top'));
90399             }
90400
90401             var label = enter.append('label');
90402             label.append('input').attr('type', type).attr('name', name).on('change', change);
90403             label.append('span').html(function (d) {
90404               var params = {};
90405
90406               if (d === 'unsquare_way') {
90407                 params.val = '<span class="square-degrees"></span>';
90408               }
90409
90410               return _t.html('issues.' + d + '.title', params);
90411             }); // Update
90412
90413             items = items.merge(enter);
90414             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false); // user-configurable square threshold
90415
90416             var degStr = corePreferences('validate-square-degrees');
90417
90418             if (degStr === null) {
90419               degStr = DEFAULTSQUARE.toString();
90420             }
90421
90422             var span = items.selectAll('.square-degrees');
90423             var input = span.selectAll('.square-degrees-input').data([0]); // enter / update
90424
90425             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) {
90426               d3_event.preventDefault();
90427               d3_event.stopPropagation();
90428               this.select();
90429             }).on('keyup', function (d3_event) {
90430               if (d3_event.keyCode === 13) {
90431                 // ↩ Return
90432                 this.blur();
90433                 this.select();
90434               }
90435             }).on('blur', changeSquare).merge(input).property('value', degStr);
90436           }
90437
90438           function changeSquare() {
90439             var input = select(this);
90440             var degStr = utilGetSetValue(input).trim();
90441             var degNum = parseFloat(degStr, 10);
90442
90443             if (!isFinite(degNum)) {
90444               degNum = DEFAULTSQUARE;
90445             } else if (degNum > MAXSQUARE) {
90446               degNum = MAXSQUARE;
90447             } else if (degNum < MINSQUARE) {
90448               degNum = MINSQUARE;
90449             }
90450
90451             degNum = Math.round(degNum * 10) / 10; // round to 1 decimal
90452
90453             degStr = degNum.toString();
90454             input.property('value', degStr);
90455             corePreferences('validate-square-degrees', degStr);
90456             context.validator().revalidateUnsquare();
90457           }
90458
90459           function isRuleEnabled(d) {
90460             return context.validator().isRuleEnabled(d);
90461           }
90462
90463           function toggleRule(d3_event, d) {
90464             context.validator().toggleRule(d);
90465           }
90466
90467           context.validator().on('validated.uiSectionValidationRules', function () {
90468             window.requestIdleCallback(section.reRender);
90469           });
90470           return section;
90471         }
90472
90473         function uiSectionValidationStatus(context) {
90474           var section = uiSection('issues-status', context).content(renderContent).shouldDisplay(function () {
90475             var issues = context.validator().getIssues(getOptions());
90476             return issues.length === 0;
90477           });
90478
90479           function getOptions() {
90480             return {
90481               what: corePreferences('validate-what') || 'edited',
90482               where: corePreferences('validate-where') || 'all'
90483             };
90484           }
90485
90486           function renderContent(selection) {
90487             var box = selection.selectAll('.box').data([0]);
90488             var boxEnter = box.enter().append('div').attr('class', 'box');
90489             boxEnter.append('div').call(svgIcon('#iD-icon-apply', 'pre-text'));
90490             var noIssuesMessage = boxEnter.append('span');
90491             noIssuesMessage.append('strong').attr('class', 'message');
90492             noIssuesMessage.append('br');
90493             noIssuesMessage.append('span').attr('class', 'details');
90494             renderIgnoredIssuesReset(selection);
90495             setNoIssuesText(selection);
90496           }
90497
90498           function renderIgnoredIssuesReset(selection) {
90499             var ignoredIssues = context.validator().getIssues({
90500               what: 'all',
90501               where: 'all',
90502               includeDisabledRules: true,
90503               includeIgnored: 'only'
90504             });
90505             var resetIgnored = selection.selectAll('.reset-ignored').data(ignoredIssues.length ? [0] : []); // exit
90506
90507             resetIgnored.exit().remove(); // enter
90508
90509             var resetIgnoredEnter = resetIgnored.enter().append('div').attr('class', 'reset-ignored section-footer');
90510             resetIgnoredEnter.append('a').attr('href', '#'); // update
90511
90512             resetIgnored = resetIgnored.merge(resetIgnoredEnter);
90513             resetIgnored.select('a').html(_t('inspector.title_count', {
90514               title: _t.html('issues.reset_ignored'),
90515               count: ignoredIssues.length
90516             }));
90517             resetIgnored.on('click', function (d3_event) {
90518               d3_event.preventDefault();
90519               context.validator().resetIgnoredIssues();
90520             });
90521           }
90522
90523           function setNoIssuesText(selection) {
90524             var opts = getOptions();
90525
90526             function checkForHiddenIssues(cases) {
90527               for (var type in cases) {
90528                 var hiddenOpts = cases[type];
90529                 var hiddenIssues = context.validator().getIssues(hiddenOpts);
90530
90531                 if (hiddenIssues.length) {
90532                   selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.' + type, {
90533                     count: hiddenIssues.length.toString()
90534                   }));
90535                   return;
90536                 }
90537               }
90538
90539               selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.none'));
90540             }
90541
90542             var messageType;
90543
90544             if (opts.what === 'edited' && opts.where === 'visible') {
90545               messageType = 'edits_in_view';
90546               checkForHiddenIssues({
90547                 elsewhere: {
90548                   what: 'edited',
90549                   where: 'all'
90550                 },
90551                 everything_else: {
90552                   what: 'all',
90553                   where: 'visible'
90554                 },
90555                 disabled_rules: {
90556                   what: 'edited',
90557                   where: 'visible',
90558                   includeDisabledRules: 'only'
90559                 },
90560                 everything_else_elsewhere: {
90561                   what: 'all',
90562                   where: 'all'
90563                 },
90564                 disabled_rules_elsewhere: {
90565                   what: 'edited',
90566                   where: 'all',
90567                   includeDisabledRules: 'only'
90568                 },
90569                 ignored_issues: {
90570                   what: 'edited',
90571                   where: 'visible',
90572                   includeIgnored: 'only'
90573                 },
90574                 ignored_issues_elsewhere: {
90575                   what: 'edited',
90576                   where: 'all',
90577                   includeIgnored: 'only'
90578                 }
90579               });
90580             } else if (opts.what === 'edited' && opts.where === 'all') {
90581               messageType = 'edits';
90582               checkForHiddenIssues({
90583                 everything_else: {
90584                   what: 'all',
90585                   where: 'all'
90586                 },
90587                 disabled_rules: {
90588                   what: 'edited',
90589                   where: 'all',
90590                   includeDisabledRules: 'only'
90591                 },
90592                 ignored_issues: {
90593                   what: 'edited',
90594                   where: 'all',
90595                   includeIgnored: 'only'
90596                 }
90597               });
90598             } else if (opts.what === 'all' && opts.where === 'visible') {
90599               messageType = 'everything_in_view';
90600               checkForHiddenIssues({
90601                 elsewhere: {
90602                   what: 'all',
90603                   where: 'all'
90604                 },
90605                 disabled_rules: {
90606                   what: 'all',
90607                   where: 'visible',
90608                   includeDisabledRules: 'only'
90609                 },
90610                 disabled_rules_elsewhere: {
90611                   what: 'all',
90612                   where: 'all',
90613                   includeDisabledRules: 'only'
90614                 },
90615                 ignored_issues: {
90616                   what: 'all',
90617                   where: 'visible',
90618                   includeIgnored: 'only'
90619                 },
90620                 ignored_issues_elsewhere: {
90621                   what: 'all',
90622                   where: 'all',
90623                   includeIgnored: 'only'
90624                 }
90625               });
90626             } else if (opts.what === 'all' && opts.where === 'all') {
90627               messageType = 'everything';
90628               checkForHiddenIssues({
90629                 disabled_rules: {
90630                   what: 'all',
90631                   where: 'all',
90632                   includeDisabledRules: 'only'
90633                 },
90634                 ignored_issues: {
90635                   what: 'all',
90636                   where: 'all',
90637                   includeIgnored: 'only'
90638                 }
90639               });
90640             }
90641
90642             if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
90643               messageType = 'no_edits';
90644             }
90645
90646             selection.select('.box .message').html(_t.html('issues.no_issues.message.' + messageType));
90647           }
90648
90649           context.validator().on('validated.uiSectionValidationStatus', function () {
90650             window.requestIdleCallback(section.reRender);
90651           });
90652           context.map().on('move.uiSectionValidationStatus', debounce(function () {
90653             window.requestIdleCallback(section.reRender);
90654           }, 1000));
90655           return section;
90656         }
90657
90658         function uiPaneIssues(context) {
90659           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)]);
90660           return issuesPane;
90661         }
90662
90663         function uiSettingsCustomData(context) {
90664           var dispatch = dispatch$8('change');
90665
90666           function render(selection) {
90667             var dataLayer = context.layers().layer('data'); // keep separate copies of original and current settings
90668
90669             var _origSettings = {
90670               fileList: dataLayer && dataLayer.fileList() || null,
90671               url: corePreferences('settings-custom-data-url')
90672             };
90673             var _currSettings = {
90674               fileList: dataLayer && dataLayer.fileList() || null,
90675               url: corePreferences('settings-custom-data-url')
90676             }; // var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
90677
90678             var modal = uiConfirm(selection).okButton();
90679             modal.classed('settings-modal settings-custom-data', true);
90680             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_data.header'));
90681             var textSection = modal.select('.modal-section.message-text');
90682             textSection.append('pre').attr('class', 'instructions-file').html(_t.html('settings.custom_data.file.instructions'));
90683             textSection.append('input').attr('class', 'field-file').attr('type', 'file').property('files', _currSettings.fileList) // works for all except IE11
90684             .on('change', function (d3_event) {
90685               var files = d3_event.target.files;
90686
90687               if (files && files.length) {
90688                 _currSettings.url = '';
90689                 textSection.select('.field-url').property('value', '');
90690                 _currSettings.fileList = files;
90691               } else {
90692                 _currSettings.fileList = null;
90693               }
90694             });
90695             textSection.append('h4').html(_t.html('settings.custom_data.or'));
90696             textSection.append('pre').attr('class', 'instructions-url').html(_t.html('settings.custom_data.url.instructions'));
90697             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
90698
90699             var buttonSection = modal.select('.modal-section.buttons');
90700             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
90701             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
90702             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
90703
90704             function isSaveDisabled() {
90705               return null;
90706             } // restore the original url
90707
90708
90709             function clickCancel() {
90710               textSection.select('.field-url').property('value', _origSettings.url);
90711               corePreferences('settings-custom-data-url', _origSettings.url);
90712               this.blur();
90713               modal.close();
90714             } // accept the current url
90715
90716
90717             function clickSave() {
90718               _currSettings.url = textSection.select('.field-url').property('value').trim(); // one or the other but not both
90719
90720               if (_currSettings.url) {
90721                 _currSettings.fileList = null;
90722               }
90723
90724               if (_currSettings.fileList) {
90725                 _currSettings.url = '';
90726               }
90727
90728               corePreferences('settings-custom-data-url', _currSettings.url);
90729               this.blur();
90730               modal.close();
90731               dispatch.call('change', this, _currSettings);
90732             }
90733           }
90734
90735           return utilRebind(render, dispatch, 'on');
90736         }
90737
90738         function uiSectionDataLayers(context) {
90739           var settingsCustomData = uiSettingsCustomData(context).on('change', customChanged);
90740           var layers = context.layers();
90741           var section = uiSection('data-layers', context).label(_t.html('map_data.data_layers')).disclosureContent(renderDisclosureContent);
90742
90743           function renderDisclosureContent(selection) {
90744             var container = selection.selectAll('.data-layer-container').data([0]);
90745             container.enter().append('div').attr('class', 'data-layer-container').merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems) // Beta - Detroit mapping challenge
90746             .call(drawPanelItems);
90747           }
90748
90749           function showsLayer(which) {
90750             var layer = layers.layer(which);
90751
90752             if (layer) {
90753               return layer.enabled();
90754             }
90755
90756             return false;
90757           }
90758
90759           function setLayer(which, enabled) {
90760             // Don't allow layer changes while drawing - #6584
90761             var mode = context.mode();
90762             if (mode && /^draw/.test(mode.id)) return;
90763             var layer = layers.layer(which);
90764
90765             if (layer) {
90766               layer.enabled(enabled);
90767
90768               if (!enabled && (which === 'osm' || which === 'notes')) {
90769                 context.enter(modeBrowse(context));
90770               }
90771             }
90772           }
90773
90774           function toggleLayer(which) {
90775             setLayer(which, !showsLayer(which));
90776           }
90777
90778           function drawOsmItems(selection) {
90779             var osmKeys = ['osm', 'notes'];
90780             var osmLayers = layers.all().filter(function (obj) {
90781               return osmKeys.indexOf(obj.id) !== -1;
90782             });
90783             var ul = selection.selectAll('.layer-list-osm').data([0]);
90784             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-osm').merge(ul);
90785             var li = ul.selectAll('.list-item').data(osmLayers);
90786             li.exit().remove();
90787             var liEnter = li.enter().append('li').attr('class', function (d) {
90788               return 'list-item list-item-' + d.id;
90789             });
90790             var labelEnter = liEnter.append('label').each(function (d) {
90791               if (d.id === 'osm') {
90792                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).keys([uiCmd('⌥' + _t('area_fill.wireframe.key'))]).placement('bottom'));
90793               } else {
90794                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
90795               }
90796             });
90797             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
90798               toggleLayer(d.id);
90799             });
90800             labelEnter.append('span').html(function (d) {
90801               return _t.html('map_data.layers.' + d.id + '.title');
90802             }); // Update
90803
90804             li.merge(liEnter).classed('active', function (d) {
90805               return d.layer.enabled();
90806             }).selectAll('input').property('checked', function (d) {
90807               return d.layer.enabled();
90808             });
90809           }
90810
90811           function drawQAItems(selection) {
90812             var qaKeys = ['keepRight', 'improveOSM', 'osmose'];
90813             var qaLayers = layers.all().filter(function (obj) {
90814               return qaKeys.indexOf(obj.id) !== -1;
90815             });
90816             var ul = selection.selectAll('.layer-list-qa').data([0]);
90817             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-qa').merge(ul);
90818             var li = ul.selectAll('.list-item').data(qaLayers);
90819             li.exit().remove();
90820             var liEnter = li.enter().append('li').attr('class', function (d) {
90821               return 'list-item list-item-' + d.id;
90822             });
90823             var labelEnter = liEnter.append('label').each(function (d) {
90824               select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
90825             });
90826             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
90827               toggleLayer(d.id);
90828             });
90829             labelEnter.append('span').html(function (d) {
90830               return _t.html('map_data.layers.' + d.id + '.title');
90831             }); // Update
90832
90833             li.merge(liEnter).classed('active', function (d) {
90834               return d.layer.enabled();
90835             }).selectAll('input').property('checked', function (d) {
90836               return d.layer.enabled();
90837             });
90838           } // Beta feature - sample vector layers to support Detroit Mapping Challenge
90839           // https://github.com/osmus/detroit-mapping-challenge
90840
90841
90842           function drawVectorItems(selection) {
90843             var dataLayer = layers.layer('data');
90844             var vtData = [{
90845               name: 'Detroit Neighborhoods/Parks',
90846               src: 'neighborhoods-parks',
90847               tooltip: 'Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.',
90848               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'
90849             }, {
90850               name: 'Detroit Composite POIs',
90851               src: 'composite-poi',
90852               tooltip: 'Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.',
90853               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'
90854             }, {
90855               name: 'Detroit All-The-Places POIs',
90856               src: 'alltheplaces-poi',
90857               tooltip: 'Public domain business location data created by web scrapers.',
90858               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'
90859             }]; // Only show this if the map is around Detroit..
90860
90861             var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
90862             var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
90863             var container = selection.selectAll('.vectortile-container').data(showVectorItems ? [0] : []);
90864             container.exit().remove();
90865             var containerEnter = container.enter().append('div').attr('class', 'vectortile-container');
90866             containerEnter.append('h4').attr('class', 'vectortile-header').html('Detroit Vector Tiles (Beta)');
90867             containerEnter.append('ul').attr('class', 'layer-list layer-list-vectortile');
90868             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');
90869             container = container.merge(containerEnter);
90870             var ul = container.selectAll('.layer-list-vectortile');
90871             var li = ul.selectAll('.list-item').data(vtData);
90872             li.exit().remove();
90873             var liEnter = li.enter().append('li').attr('class', function (d) {
90874               return 'list-item list-item-' + d.src;
90875             });
90876             var labelEnter = liEnter.append('label').each(function (d) {
90877               select(this).call(uiTooltip().title(d.tooltip).placement('top'));
90878             });
90879             labelEnter.append('input').attr('type', 'radio').attr('name', 'vectortile').on('change', selectVTLayer);
90880             labelEnter.append('span').html(function (d) {
90881               return d.name;
90882             }); // Update
90883
90884             li.merge(liEnter).classed('active', isVTLayerSelected).selectAll('input').property('checked', isVTLayerSelected);
90885
90886             function isVTLayerSelected(d) {
90887               return dataLayer && dataLayer.template() === d.template;
90888             }
90889
90890             function selectVTLayer(d3_event, d) {
90891               corePreferences('settings-custom-data-url', d.template);
90892
90893               if (dataLayer) {
90894                 dataLayer.template(d.template, d.src);
90895                 dataLayer.enabled(true);
90896               }
90897             }
90898           }
90899
90900           function drawCustomDataItems(selection) {
90901             var dataLayer = layers.layer('data');
90902             var hasData = dataLayer && dataLayer.hasData();
90903             var showsData = hasData && dataLayer.enabled();
90904             var ul = selection.selectAll('.layer-list-data').data(dataLayer ? [0] : []); // Exit
90905
90906             ul.exit().remove(); // Enter
90907
90908             var ulEnter = ul.enter().append('ul').attr('class', 'layer-list layer-list-data');
90909             var liEnter = ulEnter.append('li').attr('class', 'list-item-data');
90910             var labelEnter = liEnter.append('label').call(uiTooltip().title(_t.html('map_data.layers.custom.tooltip')).placement('top'));
90911             labelEnter.append('input').attr('type', 'checkbox').on('change', function () {
90912               toggleLayer('data');
90913             });
90914             labelEnter.append('span').html(_t.html('map_data.layers.custom.title'));
90915             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) {
90916               d3_event.preventDefault();
90917               editCustom();
90918             }).call(svgIcon('#iD-icon-more'));
90919             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) {
90920               if (select(this).classed('disabled')) return;
90921               d3_event.preventDefault();
90922               d3_event.stopPropagation();
90923               dataLayer.fitZoom();
90924             }).call(svgIcon('#iD-icon-framed-dot', 'monochrome')); // Update
90925
90926             ul = ul.merge(ulEnter);
90927             ul.selectAll('.list-item-data').classed('active', showsData).selectAll('label').classed('deemphasize', !hasData).selectAll('input').property('disabled', !hasData).property('checked', showsData);
90928             ul.selectAll('button.zoom-to-data').classed('disabled', !hasData);
90929           }
90930
90931           function editCustom() {
90932             context.container().call(settingsCustomData);
90933           }
90934
90935           function customChanged(d) {
90936             var dataLayer = layers.layer('data');
90937
90938             if (d && d.url) {
90939               dataLayer.url(d.url);
90940             } else if (d && d.fileList) {
90941               dataLayer.fileList(d.fileList);
90942             }
90943           }
90944
90945           function drawPanelItems(selection) {
90946             var panelsListEnter = selection.selectAll('.md-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list md-extras-list');
90947             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'));
90948             historyPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
90949               d3_event.preventDefault();
90950               context.ui().info.toggle('history');
90951             });
90952             historyPanelLabelEnter.append('span').html(_t.html('map_data.history_panel.title'));
90953             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'));
90954             measurementPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
90955               d3_event.preventDefault();
90956               context.ui().info.toggle('measurement');
90957             });
90958             measurementPanelLabelEnter.append('span').html(_t.html('map_data.measurement_panel.title'));
90959           }
90960
90961           context.layers().on('change.uiSectionDataLayers', section.reRender);
90962           context.map().on('move.uiSectionDataLayers', debounce(function () {
90963             // Detroit layers may have moved in or out of view
90964             window.requestIdleCallback(section.reRender);
90965           }, 1000));
90966           return section;
90967         }
90968
90969         function uiSectionMapFeatures(context) {
90970           var _features = context.features().keys();
90971
90972           var section = uiSection('map-features', context).label(_t.html('map_data.map_features')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
90973
90974           function renderDisclosureContent(selection) {
90975             var container = selection.selectAll('.layer-feature-list-container').data([0]);
90976             var containerEnter = container.enter().append('div').attr('class', 'layer-feature-list-container');
90977             containerEnter.append('ul').attr('class', 'layer-list layer-feature-list');
90978             var footer = containerEnter.append('div').attr('class', 'feature-list-links section-footer');
90979             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
90980               d3_event.preventDefault();
90981               context.features().disableAll();
90982             });
90983             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
90984               d3_event.preventDefault();
90985               context.features().enableAll();
90986             }); // Update
90987
90988             container = container.merge(containerEnter);
90989             container.selectAll('.layer-feature-list').call(drawListItems, _features, 'checkbox', 'feature', clickFeature, showsFeature);
90990           }
90991
90992           function drawListItems(selection, data, type, name, change, active) {
90993             var items = selection.selectAll('li').data(data); // Exit
90994
90995             items.exit().remove(); // Enter
90996
90997             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
90998               var tip = _t.html(name + '.' + d + '.tooltip');
90999
91000               if (autoHiddenFeature(d)) {
91001                 var msg = showsLayer('osm') ? _t.html('map_data.autohidden') : _t.html('map_data.osmhidden');
91002                 tip += '<div>' + msg + '</div>';
91003               }
91004
91005               return tip;
91006             }).placement('top'));
91007             var label = enter.append('label');
91008             label.append('input').attr('type', type).attr('name', name).on('change', change);
91009             label.append('span').html(function (d) {
91010               return _t.html(name + '.' + d + '.description');
91011             }); // Update
91012
91013             items = items.merge(enter);
91014             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', autoHiddenFeature);
91015           }
91016
91017           function autoHiddenFeature(d) {
91018             return context.features().autoHidden(d);
91019           }
91020
91021           function showsFeature(d) {
91022             return context.features().enabled(d);
91023           }
91024
91025           function clickFeature(d3_event, d) {
91026             context.features().toggle(d);
91027           }
91028
91029           function showsLayer(id) {
91030             var layer = context.layers().layer(id);
91031             return layer && layer.enabled();
91032           } // add listeners
91033
91034
91035           context.features().on('change.map_features', section.reRender);
91036           return section;
91037         }
91038
91039         function uiSectionMapStyleOptions(context) {
91040           var section = uiSection('fill-area', context).label(_t.html('map_data.style_options')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
91041
91042           function renderDisclosureContent(selection) {
91043             var container = selection.selectAll('.layer-fill-list').data([0]);
91044             container.enter().append('ul').attr('class', 'layer-list layer-fill-list').merge(container).call(drawListItems, context.map().areaFillOptions, 'radio', 'area_fill', setFill, isActiveFill);
91045             var container2 = selection.selectAll('.layer-visual-diff-list').data([0]);
91046             container2.enter().append('ul').attr('class', 'layer-list layer-visual-diff-list').merge(container2).call(drawListItems, ['highlight_edits'], 'checkbox', 'visual_diff', toggleHighlightEdited, function () {
91047               return context.surface().classed('highlight-edited');
91048             });
91049           }
91050
91051           function drawListItems(selection, data, type, name, change, active) {
91052             var items = selection.selectAll('li').data(data); // Exit
91053
91054             items.exit().remove(); // Enter
91055
91056             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
91057               return _t.html(name + '.' + d + '.tooltip');
91058             }).keys(function (d) {
91059               var key = d === 'wireframe' ? _t('area_fill.wireframe.key') : null;
91060               if (d === 'highlight_edits') key = _t('map_data.highlight_edits.key');
91061               return key ? [key] : null;
91062             }).placement('top'));
91063             var label = enter.append('label');
91064             label.append('input').attr('type', type).attr('name', name).on('change', change);
91065             label.append('span').html(function (d) {
91066               return _t.html(name + '.' + d + '.description');
91067             }); // Update
91068
91069             items = items.merge(enter);
91070             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false);
91071           }
91072
91073           function isActiveFill(d) {
91074             return context.map().activeAreaFill() === d;
91075           }
91076
91077           function toggleHighlightEdited(d3_event) {
91078             d3_event.preventDefault();
91079             context.map().toggleHighlightEdited();
91080           }
91081
91082           function setFill(d3_event, d) {
91083             context.map().activeAreaFill(d);
91084           }
91085
91086           context.map().on('changeHighlighting.ui_style, changeAreaFill.ui_style', section.reRender);
91087           return section;
91088         }
91089
91090         function uiSectionPhotoOverlays(context) {
91091           var layers = context.layers();
91092           var section = uiSection('photo-overlays', context).label(_t.html('photo_overlays.title')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
91093
91094           function renderDisclosureContent(selection) {
91095             var container = selection.selectAll('.photo-overlay-container').data([0]);
91096             container.enter().append('div').attr('class', 'photo-overlay-container').merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter);
91097           }
91098
91099           function drawPhotoItems(selection) {
91100             var photoKeys = context.photos().overlayLayerIDs();
91101             var photoLayers = layers.all().filter(function (obj) {
91102               return photoKeys.indexOf(obj.id) !== -1;
91103             });
91104             var data = photoLayers.filter(function (obj) {
91105               return obj.layer.supported();
91106             });
91107
91108             function layerSupported(d) {
91109               return d.layer && d.layer.supported();
91110             }
91111
91112             function layerEnabled(d) {
91113               return layerSupported(d) && d.layer.enabled();
91114             }
91115
91116             var ul = selection.selectAll('.layer-list-photos').data([0]);
91117             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photos').merge(ul);
91118             var li = ul.selectAll('.list-item-photos').data(data);
91119             li.exit().remove();
91120             var liEnter = li.enter().append('li').attr('class', function (d) {
91121               var classes = 'list-item-photos list-item-' + d.id;
91122
91123               if (d.id === 'mapillary-signs' || d.id === 'mapillary-map-features') {
91124                 classes += ' indented';
91125               }
91126
91127               return classes;
91128             });
91129             var labelEnter = liEnter.append('label').each(function (d) {
91130               var titleID;
91131               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';
91132               select(this).call(uiTooltip().title(_t.html(titleID)).placement('top'));
91133             });
91134             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
91135               toggleLayer(d.id);
91136             });
91137             labelEnter.append('span').html(function (d) {
91138               var id = d.id;
91139               if (id === 'mapillary-signs') id = 'photo_overlays.traffic_signs';
91140               return _t.html(id.replace(/-/g, '_') + '.title');
91141             }); // Update
91142
91143             li.merge(liEnter).classed('active', layerEnabled).selectAll('input').property('checked', layerEnabled);
91144           }
91145
91146           function drawPhotoTypeItems(selection) {
91147             var data = context.photos().allPhotoTypes();
91148
91149             function typeEnabled(d) {
91150               return context.photos().showsPhotoType(d);
91151             }
91152
91153             var ul = selection.selectAll('.layer-list-photo-types').data([0]);
91154             ul.exit().remove();
91155             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photo-types').merge(ul);
91156             var li = ul.selectAll('.list-item-photo-types').data(context.photos().shouldFilterByPhotoType() ? data : []);
91157             li.exit().remove();
91158             var liEnter = li.enter().append('li').attr('class', function (d) {
91159               return 'list-item-photo-types list-item-' + d;
91160             });
91161             var labelEnter = liEnter.append('label').each(function (d) {
91162               select(this).call(uiTooltip().title(_t.html('photo_overlays.photo_type.' + d + '.tooltip')).placement('top'));
91163             });
91164             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
91165               context.photos().togglePhotoType(d);
91166             });
91167             labelEnter.append('span').html(function (d) {
91168               return _t.html('photo_overlays.photo_type.' + d + '.title');
91169             }); // Update
91170
91171             li.merge(liEnter).classed('active', typeEnabled).selectAll('input').property('checked', typeEnabled);
91172           }
91173
91174           function drawDateFilter(selection) {
91175             var data = context.photos().dateFilters();
91176
91177             function filterEnabled(d) {
91178               return context.photos().dateFilterValue(d);
91179             }
91180
91181             var ul = selection.selectAll('.layer-list-date-filter').data([0]);
91182             ul.exit().remove();
91183             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-date-filter').merge(ul);
91184             var li = ul.selectAll('.list-item-date-filter').data(context.photos().shouldFilterByDate() ? data : []);
91185             li.exit().remove();
91186             var liEnter = li.enter().append('li').attr('class', 'list-item-date-filter');
91187             var labelEnter = liEnter.append('label').each(function (d) {
91188               select(this).call(uiTooltip().title(_t.html('photo_overlays.date_filter.' + d + '.tooltip')).placement('top'));
91189             });
91190             labelEnter.append('span').html(function (d) {
91191               return _t.html('photo_overlays.date_filter.' + d + '.title');
91192             });
91193             labelEnter.append('input').attr('type', 'date').attr('class', 'list-item-input').attr('placeholder', _t('units.year_month_day')).call(utilNoAuto).each(function (d) {
91194               utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
91195             }).on('change', function (d3_event, d) {
91196               var value = utilGetSetValue(select(this)).trim();
91197               context.photos().setDateFilter(d, value, true); // reload the displayed dates
91198
91199               li.selectAll('input').each(function (d) {
91200                 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
91201               });
91202             });
91203             li = li.merge(liEnter).classed('active', filterEnabled);
91204           }
91205
91206           function drawUsernameFilter(selection) {
91207             function filterEnabled() {
91208               return context.photos().usernames();
91209             }
91210
91211             var ul = selection.selectAll('.layer-list-username-filter').data([0]);
91212             ul.exit().remove();
91213             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-username-filter').merge(ul);
91214             var li = ul.selectAll('.list-item-username-filter').data(context.photos().shouldFilterByUsername() ? ['username-filter'] : []);
91215             li.exit().remove();
91216             var liEnter = li.enter().append('li').attr('class', 'list-item-username-filter');
91217             var labelEnter = liEnter.append('label').each(function () {
91218               select(this).call(uiTooltip().title(_t.html('photo_overlays.username_filter.tooltip')).placement('top'));
91219             });
91220             labelEnter.append('span').html(_t.html('photo_overlays.username_filter.title'));
91221             labelEnter.append('input').attr('type', 'text').attr('class', 'list-item-input').call(utilNoAuto).property('value', usernameValue).on('change', function () {
91222               var value = select(this).property('value');
91223               context.photos().setUsernameFilter(value, true);
91224               select(this).property('value', usernameValue);
91225             });
91226             li.merge(liEnter).classed('active', filterEnabled);
91227
91228             function usernameValue() {
91229               var usernames = context.photos().usernames();
91230               if (usernames) return usernames.join('; ');
91231               return usernames;
91232             }
91233           }
91234
91235           function toggleLayer(which) {
91236             setLayer(which, !showsLayer(which));
91237           }
91238
91239           function showsLayer(which) {
91240             var layer = layers.layer(which);
91241
91242             if (layer) {
91243               return layer.enabled();
91244             }
91245
91246             return false;
91247           }
91248
91249           function setLayer(which, enabled) {
91250             var layer = layers.layer(which);
91251
91252             if (layer) {
91253               layer.enabled(enabled);
91254             }
91255           }
91256
91257           context.layers().on('change.uiSectionPhotoOverlays', section.reRender);
91258           context.photos().on('change.uiSectionPhotoOverlays', section.reRender);
91259           return section;
91260         }
91261
91262         function uiPaneMapData(context) {
91263           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)]);
91264           return mapDataPane;
91265         }
91266
91267         function uiSectionPrivacy(context) {
91268           var section = uiSection('preferences-third-party', context).label(_t.html('preferences.privacy.title')).disclosureContent(renderDisclosureContent);
91269
91270           var _showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
91271
91272           function renderDisclosureContent(selection) {
91273             // enter
91274             var privacyOptionsListEnter = selection.selectAll('.privacy-options-list').data([0]).enter().append('ul').attr('class', 'layer-list privacy-options-list');
91275             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'));
91276             thirdPartyIconsEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
91277               d3_event.preventDefault();
91278               _showThirdPartyIcons = _showThirdPartyIcons === 'true' ? 'false' : 'true';
91279               corePreferences('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
91280               update();
91281             });
91282             thirdPartyIconsEnter.append('span').html(_t.html('preferences.privacy.third_party_icons.description')); // Privacy Policy link
91283
91284             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'));
91285             update();
91286
91287             function update() {
91288               selection.selectAll('.privacy-third-party-icons-item').classed('active', _showThirdPartyIcons === 'true').select('input').property('checked', _showThirdPartyIcons === 'true');
91289             }
91290           }
91291
91292           return section;
91293         }
91294
91295         function uiPanePreferences(context) {
91296           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)]);
91297           return preferencesPane;
91298         }
91299
91300         function uiInit(context) {
91301           var _initCounter = 0;
91302           var _needWidth = {};
91303
91304           var _lastPointerType;
91305
91306           function render(container) {
91307             container.on('click.ui', function (d3_event) {
91308               // we're only concerned with the primary mouse button
91309               if (d3_event.button !== 0) return;
91310               if (!d3_event.composedPath) return; // some targets have default click events we don't want to override
91311
91312               var isOkayTarget = d3_event.composedPath().some(function (node) {
91313                 // we only care about element nodes
91314                 return node.nodeType === 1 && ( // clicking <input> focuses it and/or changes a value
91315                 node.nodeName === 'INPUT' || // clicking <label> affects its <input> by default
91316                 node.nodeName === 'LABEL' || // clicking <a> opens a hyperlink by default
91317                 node.nodeName === 'A');
91318               });
91319               if (isOkayTarget) return; // disable double-tap-to-zoom on touchscreens
91320
91321               d3_event.preventDefault();
91322             });
91323             var detected = utilDetect(); // only WebKit supports gesture events
91324
91325             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
91326             // but we only need to do this on desktop Safari anyway. – #7694
91327             !detected.isMobileWebKit) {
91328               // On iOS we disable pinch-to-zoom of the UI via the `touch-action`
91329               // CSS property, but on desktop Safari we need to manually cancel the
91330               // default gesture events.
91331               container.on('gesturestart.ui gesturechange.ui gestureend.ui', function (d3_event) {
91332                 // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari
91333                 d3_event.preventDefault();
91334               });
91335             }
91336
91337             if ('PointerEvent' in window) {
91338               select(window).on('pointerdown.ui pointerup.ui', function (d3_event) {
91339                 var pointerType = d3_event.pointerType || 'mouse';
91340
91341                 if (_lastPointerType !== pointerType) {
91342                   _lastPointerType = pointerType;
91343                   container.attr('pointer', pointerType);
91344                 }
91345               }, true);
91346             } else {
91347               _lastPointerType = 'mouse';
91348               container.attr('pointer', 'mouse');
91349             }
91350
91351             container.attr('lang', _mainLocalizer.localeCode()).attr('dir', _mainLocalizer.textDirection()); // setup fullscreen keybindings (no button shown at this time)
91352
91353             container.call(uiFullScreen(context));
91354             var map = context.map();
91355             map.redrawEnable(false); // don't draw until we've set zoom/lat/long
91356
91357             map.on('hitMinZoom.ui', function () {
91358               ui.flash.iconName('#iD-icon-no').label(_t.html('cannot_zoom'))();
91359             });
91360             container.append('svg').attr('id', 'ideditor-defs').call(ui.svgDefs);
91361             container.append('div').attr('class', 'sidebar').call(ui.sidebar);
91362             var content = container.append('div').attr('class', 'main-content active'); // Top toolbar
91363
91364             content.append('div').attr('class', 'top-toolbar-wrap').append('div').attr('class', 'top-toolbar fillD').call(uiTopToolbar(context));
91365             content.append('div').attr('class', 'main-map').attr('dir', 'ltr').call(map);
91366             var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
91367             // pressing, even if it's not targeted. This conflicts with long-pressing
91368             // to show the edit menu. We add a selectable offscreen element as the first
91369             // child to trick Safari into not showing the selection UI.
91370
91371             overMap.append('div').attr('class', 'select-trap').text('t');
91372             overMap.call(uiMapInMap(context)).call(uiNotice(context));
91373             overMap.append('div').attr('class', 'spinner').call(uiSpinner(context)); // Map controls
91374
91375             var controls = overMap.append('div').attr('class', 'map-controls');
91376             controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
91377             controls.append('div').attr('class', 'map-control zoom-to-selection-control').call(uiZoomToSelection(context));
91378             controls.append('div').attr('class', 'map-control geolocate-control').call(uiGeolocate(context));
91379             controls.on('wheel.mapControls', function (d3_event) {
91380               if (!d3_event.deltaX) {
91381                 controls.node().scrollTop += d3_event.deltaY;
91382               }
91383             }); // Add panes
91384             // This should happen after map is initialized, as some require surface()
91385
91386             var panes = overMap.append('div').attr('class', 'map-panes');
91387             var uiPanes = [uiPaneBackground(context), uiPaneMapData(context), uiPaneIssues(context), uiPanePreferences(context), uiPaneHelp(context)];
91388             uiPanes.forEach(function (pane) {
91389               controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
91390               panes.call(pane.renderPane);
91391             });
91392             ui.info = uiInfo(context);
91393             overMap.call(ui.info);
91394             overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left,  'ar'=right
91395             .classed('hide', true).call(ui.photoviewer);
91396             overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Add footer
91397
91398             var about = content.append('div').attr('class', 'map-footer');
91399             about.append('div').attr('class', 'api-status').call(uiStatus(context));
91400             var footer = about.append('div').attr('class', 'map-footer-bar fillD');
91401             footer.append('div').attr('class', 'flash-wrap footer-hide');
91402             var footerWrap = footer.append('div').attr('class', 'main-footer-wrap footer-show');
91403             footerWrap.append('div').attr('class', 'scale-block').call(uiScale(context));
91404             var aboutList = footerWrap.append('div').attr('class', 'info-block').append('ul').attr('class', 'map-footer-list');
91405             aboutList.append('li').attr('class', 'user-list').call(uiContributors(context));
91406             var apiConnections = context.apiConnections();
91407
91408             if (apiConnections && apiConnections.length > 1) {
91409               aboutList.append('li').attr('class', 'source-switch').call(uiSourceSwitch(context).keys(apiConnections));
91410             }
91411
91412             aboutList.append('li').attr('class', 'issues-info').call(uiIssuesInfo(context));
91413             aboutList.append('li').attr('class', 'feature-warning').call(uiFeatureInfo(context));
91414             var issueLinks = aboutList.append('li');
91415             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'));
91416             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'));
91417             aboutList.append('li').attr('class', 'version').call(uiVersion(context));
91418
91419             if (!context.embed()) {
91420               aboutList.call(uiAccount(context));
91421             } // Setup map dimensions and move map to initial center/zoom.
91422             // This should happen after .main-content and toolbars exist.
91423
91424
91425             ui.onResize();
91426             map.redrawEnable(true);
91427             ui.hash = behaviorHash(context);
91428             ui.hash();
91429
91430             if (!ui.hash.hadHash) {
91431               map.centerZoom([0, 0], 2);
91432             } // Bind events
91433
91434
91435             window.onbeforeunload = function () {
91436               return context.save();
91437             };
91438
91439             window.onunload = function () {
91440               context.history().unlock();
91441             };
91442
91443             select(window).on('resize.editor', function () {
91444               ui.onResize();
91445             });
91446             var panPixels = 80;
91447             context.keybinding().on('⌫', function (d3_event) {
91448               d3_event.preventDefault();
91449             }).on([_t('sidebar.key'), '`', '²', '@'], ui.sidebar.toggle) // #5663, #6864 - common QWERTY, AZERTY
91450             .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) {
91451               if (d3_event) {
91452                 d3_event.stopImmediatePropagation();
91453                 d3_event.preventDefault();
91454               }
91455
91456               var previousBackground = context.background().findSource(corePreferences('background-last-used-toggle'));
91457
91458               if (previousBackground) {
91459                 var currentBackground = context.background().baseLayerSource();
91460                 corePreferences('background-last-used-toggle', currentBackground.id);
91461                 corePreferences('background-last-used', previousBackground.id);
91462                 context.background().baseLayerSource(previousBackground);
91463               }
91464             }).on(_t('area_fill.wireframe.key'), function toggleWireframe(d3_event) {
91465               d3_event.preventDefault();
91466               d3_event.stopPropagation();
91467               context.map().toggleWireframe();
91468             }).on(uiCmd('⌥' + _t('area_fill.wireframe.key')), function toggleOsmData(d3_event) {
91469               d3_event.preventDefault();
91470               d3_event.stopPropagation(); // Don't allow layer changes while drawing - #6584
91471
91472               var mode = context.mode();
91473               if (mode && /^draw/.test(mode.id)) return;
91474               var layer = context.layers().layer('osm');
91475
91476               if (layer) {
91477                 layer.enabled(!layer.enabled());
91478
91479                 if (!layer.enabled()) {
91480                   context.enter(modeBrowse(context));
91481                 }
91482               }
91483             }).on(_t('map_data.highlight_edits.key'), function toggleHighlightEdited(d3_event) {
91484               d3_event.preventDefault();
91485               context.map().toggleHighlightEdited();
91486             });
91487             context.on('enter.editor', function (entered) {
91488               container.classed('mode-' + entered.id, true);
91489             }).on('exit.editor', function (exited) {
91490               container.classed('mode-' + exited.id, false);
91491             });
91492             context.enter(modeBrowse(context));
91493
91494             if (!_initCounter++) {
91495               if (!ui.hash.startWalkthrough) {
91496                 context.container().call(uiSplash(context)).call(uiRestore(context));
91497               }
91498
91499               context.container().call(ui.shortcuts);
91500             }
91501
91502             var osm = context.connection();
91503             var auth = uiLoading(context).message(_t.html('loading_auth')).blocking(true);
91504
91505             if (osm && auth) {
91506               osm.on('authLoading.ui', function () {
91507                 context.container().call(auth);
91508               }).on('authDone.ui', function () {
91509                 auth.close();
91510               });
91511             }
91512
91513             _initCounter++;
91514
91515             if (ui.hash.startWalkthrough) {
91516               ui.hash.startWalkthrough = false;
91517               context.container().call(uiIntro(context));
91518             }
91519
91520             function pan(d) {
91521               return function (d3_event) {
91522                 if (d3_event.shiftKey) return;
91523                 if (context.container().select('.combobox').size()) return;
91524                 d3_event.preventDefault();
91525                 context.map().pan(d, 100);
91526               };
91527             }
91528           }
91529
91530           var ui = {};
91531
91532           var _loadPromise; // renders the iD interface into the container node
91533
91534
91535           ui.ensureLoaded = function () {
91536             if (_loadPromise) return _loadPromise;
91537             return _loadPromise = Promise.all([// must have strings and presets before loading the UI
91538             _mainLocalizer.ensureLoaded(), _mainPresetIndex.ensureLoaded()]).then(function () {
91539               if (!context.container().empty()) render(context.container());
91540             })["catch"](function (err) {
91541               return console.error(err);
91542             }); // eslint-disable-line
91543           }; // `ui.restart()` will destroy and rebuild the entire iD interface,
91544           // for example to switch the locale while iD is running.
91545
91546
91547           ui.restart = function () {
91548             context.keybinding().clear();
91549             _loadPromise = null;
91550             context.container().selectAll('*').remove();
91551             ui.ensureLoaded();
91552           };
91553
91554           ui.lastPointerType = function () {
91555             return _lastPointerType;
91556           };
91557
91558           ui.svgDefs = svgDefs(context);
91559           ui.flash = uiFlash(context);
91560           ui.sidebar = uiSidebar(context);
91561           ui.photoviewer = uiPhotoviewer(context);
91562           ui.shortcuts = uiShortcuts(context);
91563
91564           ui.onResize = function (withPan) {
91565             var map = context.map(); // Recalc dimensions of map and sidebar.. (`true` = force recalc)
91566             // This will call `getBoundingClientRect` and trigger reflow,
91567             //  but the values will be cached for later use.
91568
91569             var mapDimensions = utilGetDimensions(context.container().select('.main-content'), true);
91570             utilGetDimensions(context.container().select('.sidebar'), true);
91571
91572             if (withPan !== undefined) {
91573               map.redrawEnable(false);
91574               map.pan(withPan);
91575               map.redrawEnable(true);
91576             }
91577
91578             map.dimensions(mapDimensions);
91579             ui.photoviewer.onMapResize(); // check if header or footer have overflowed
91580
91581             ui.checkOverflow('.top-toolbar');
91582             ui.checkOverflow('.map-footer-bar'); // Use outdated code so it works on Explorer
91583
91584             var resizeWindowEvent = document.createEvent('Event');
91585             resizeWindowEvent.initEvent('resizeWindow', true, true);
91586             document.dispatchEvent(resizeWindowEvent);
91587           }; // Call checkOverflow when resizing or whenever the contents change.
91588
91589
91590           ui.checkOverflow = function (selector, reset) {
91591             if (reset) {
91592               delete _needWidth[selector];
91593             }
91594
91595             var selection = context.container().select(selector);
91596             if (selection.empty()) return;
91597             var scrollWidth = selection.property('scrollWidth');
91598             var clientWidth = selection.property('clientWidth');
91599             var needed = _needWidth[selector] || scrollWidth;
91600
91601             if (scrollWidth > clientWidth) {
91602               // overflow happening
91603               selection.classed('narrow', true);
91604
91605               if (!_needWidth[selector]) {
91606                 _needWidth[selector] = scrollWidth;
91607               }
91608             } else if (scrollWidth >= needed) {
91609               selection.classed('narrow', false);
91610             }
91611           };
91612
91613           ui.togglePanes = function (showPane) {
91614             var hidePanes = context.container().selectAll('.map-pane.shown');
91615             var side = _mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left';
91616             hidePanes.classed('shown', false).classed('hide', true);
91617             context.container().selectAll('.map-pane-control button').classed('active', false);
91618
91619             if (showPane) {
91620               hidePanes.classed('shown', false).classed('hide', true).style(side, '-500px');
91621               context.container().selectAll('.' + showPane.attr('pane') + '-control button').classed('active', true);
91622               showPane.classed('shown', true).classed('hide', false);
91623
91624               if (hidePanes.empty()) {
91625                 showPane.style(side, '-500px').transition().duration(200).style(side, '0px');
91626               } else {
91627                 showPane.style(side, '0px');
91628               }
91629             } else {
91630               hidePanes.classed('shown', true).classed('hide', false).style(side, '0px').transition().duration(200).style(side, '-500px').on('end', function () {
91631                 select(this).classed('shown', false).classed('hide', true);
91632               });
91633             }
91634           };
91635
91636           var _editMenu = uiEditMenu(context);
91637
91638           ui.editMenu = function () {
91639             return _editMenu;
91640           };
91641
91642           ui.showEditMenu = function (anchorPoint, triggerType, operations) {
91643             // remove any displayed menu
91644             ui.closeEditMenu();
91645             if (!operations && context.mode().operations) operations = context.mode().operations();
91646             if (!operations || !operations.length) return; // disable menu if in wide selection, for example
91647
91648             if (!context.map().editableDataEnabled()) return;
91649             var surfaceNode = context.surface().node();
91650
91651             if (surfaceNode.focus) {
91652               // FF doesn't support it
91653               // focus the surface or else clicking off the menu may not trigger modeBrowse
91654               surfaceNode.focus();
91655             }
91656
91657             operations.forEach(function (operation) {
91658               if (operation.point) operation.point(anchorPoint);
91659             });
91660
91661             _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations); // render the menu
91662
91663
91664             context.map().supersurface.call(_editMenu);
91665           };
91666
91667           ui.closeEditMenu = function () {
91668             // remove any existing menu no matter how it was added
91669             context.map().supersurface.select('.edit-menu').remove();
91670           };
91671
91672           var _saveLoading = select(null);
91673
91674           context.uploader().on('saveStarted.ui', function () {
91675             _saveLoading = uiLoading(context).message(_t.html('save.uploading')).blocking(true);
91676             context.container().call(_saveLoading); // block input during upload
91677           }).on('saveEnded.ui', function () {
91678             _saveLoading.close();
91679
91680             _saveLoading = select(null);
91681           });
91682           return ui;
91683         }
91684
91685         function coreContext() {
91686           var _this = this;
91687
91688           var dispatch = dispatch$8('enter', 'exit', 'change');
91689           var context = utilRebind({}, dispatch, 'on');
91690
91691           var _deferred = new Set();
91692
91693           context.version = '2.20.2';
91694           context.privacyVersion = '20201202'; // iD will alter the hash so cache the parameters intended to setup the session
91695
91696           context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
91697           context.isFirstSession = !corePreferences('sawSplash') && !corePreferences('sawPrivacyVersion');
91698           /* Changeset */
91699           // An osmChangeset object. Not loaded until needed.
91700
91701           context.changeset = null;
91702           var _defaultChangesetComment = context.initialHashParams.comment;
91703           var _defaultChangesetSource = context.initialHashParams.source;
91704           var _defaultChangesetHashtags = context.initialHashParams.hashtags;
91705
91706           context.defaultChangesetComment = function (val) {
91707             if (!arguments.length) return _defaultChangesetComment;
91708             _defaultChangesetComment = val;
91709             return context;
91710           };
91711
91712           context.defaultChangesetSource = function (val) {
91713             if (!arguments.length) return _defaultChangesetSource;
91714             _defaultChangesetSource = val;
91715             return context;
91716           };
91717
91718           context.defaultChangesetHashtags = function (val) {
91719             if (!arguments.length) return _defaultChangesetHashtags;
91720             _defaultChangesetHashtags = val;
91721             return context;
91722           };
91723           /* Document title */
91724
91725           /* (typically shown as the label for the browser window/tab) */
91726           // If true, iD will update the title based on what the user is doing
91727
91728
91729           var _setsDocumentTitle = true;
91730
91731           context.setsDocumentTitle = function (val) {
91732             if (!arguments.length) return _setsDocumentTitle;
91733             _setsDocumentTitle = val;
91734             return context;
91735           }; // The part of the title that is always the same
91736
91737
91738           var _documentTitleBase = document.title;
91739
91740           context.documentTitleBase = function (val) {
91741             if (!arguments.length) return _documentTitleBase;
91742             _documentTitleBase = val;
91743             return context;
91744           };
91745           /* User interface and keybinding */
91746
91747
91748           var _ui;
91749
91750           context.ui = function () {
91751             return _ui;
91752           };
91753
91754           context.lastPointerType = function () {
91755             return _ui.lastPointerType();
91756           };
91757
91758           var _keybinding = utilKeybinding('context');
91759
91760           context.keybinding = function () {
91761             return _keybinding;
91762           };
91763
91764           select(document).call(_keybinding);
91765           /* Straight accessors. Avoid using these if you can. */
91766           // Instantiate the connection here because it doesn't require passing in
91767           // `context` and it's needed for pre-init calls like `preauth`
91768
91769           var _connection = services.osm;
91770
91771           var _history;
91772
91773           var _validator;
91774
91775           var _uploader;
91776
91777           context.connection = function () {
91778             return _connection;
91779           };
91780
91781           context.history = function () {
91782             return _history;
91783           };
91784
91785           context.validator = function () {
91786             return _validator;
91787           };
91788
91789           context.uploader = function () {
91790             return _uploader;
91791           };
91792           /* Connection */
91793
91794
91795           context.preauth = function (options) {
91796             if (_connection) {
91797               _connection["switch"](options);
91798             }
91799
91800             return context;
91801           };
91802           /* connection options for source switcher (optional) */
91803
91804
91805           var _apiConnections;
91806
91807           context.apiConnections = function (val) {
91808             if (!arguments.length) return _apiConnections;
91809             _apiConnections = val;
91810             return context;
91811           }; // A string or array or locale codes to prefer over the browser's settings
91812
91813
91814           context.locale = function (locale) {
91815             if (!arguments.length) return _mainLocalizer.localeCode();
91816             _mainLocalizer.preferredLocaleCodes(locale);
91817             return context;
91818           };
91819
91820           function afterLoad(cid, callback) {
91821             return function (err, result) {
91822               if (err) {
91823                 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
91824                 if (err.status === 400 || err.status === 401 || err.status === 403) {
91825                   if (_connection) {
91826                     _connection.logout();
91827                   }
91828                 }
91829
91830                 if (typeof callback === 'function') {
91831                   callback(err);
91832                 }
91833
91834                 return;
91835               } else if (_connection && _connection.getConnectionId() !== cid) {
91836                 if (typeof callback === 'function') {
91837                   callback({
91838                     message: 'Connection Switched',
91839                     status: -1
91840                   });
91841                 }
91842
91843                 return;
91844               } else {
91845                 _history.merge(result.data, result.extent);
91846
91847                 if (typeof callback === 'function') {
91848                   callback(err, result);
91849                 }
91850
91851                 return;
91852               }
91853             };
91854           }
91855
91856           context.loadTiles = function (projection, callback) {
91857             var handle = window.requestIdleCallback(function () {
91858               _deferred["delete"](handle);
91859
91860               if (_connection && context.editableDataEnabled()) {
91861                 var cid = _connection.getConnectionId();
91862
91863                 _connection.loadTiles(projection, afterLoad(cid, callback));
91864               }
91865             });
91866
91867             _deferred.add(handle);
91868           };
91869
91870           context.loadTileAtLoc = function (loc, callback) {
91871             var handle = window.requestIdleCallback(function () {
91872               _deferred["delete"](handle);
91873
91874               if (_connection && context.editableDataEnabled()) {
91875                 var cid = _connection.getConnectionId();
91876
91877                 _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
91878               }
91879             });
91880
91881             _deferred.add(handle);
91882           }; // Download the full entity and its parent relations. The callback may be called multiple times.
91883
91884
91885           context.loadEntity = function (entityID, callback) {
91886             if (_connection) {
91887               var cid = _connection.getConnectionId();
91888
91889               _connection.loadEntity(entityID, afterLoad(cid, callback)); // We need to fetch the parent relations separately.
91890
91891
91892               _connection.loadEntityRelations(entityID, afterLoad(cid, callback));
91893             }
91894           };
91895
91896           context.zoomToEntity = function (entityID, zoomTo) {
91897             // be sure to load the entity even if we're not going to zoom to it
91898             context.loadEntity(entityID, function (err, result) {
91899               if (err) return;
91900
91901               if (zoomTo !== false) {
91902                 var entity = result.data.find(function (e) {
91903                   return e.id === entityID;
91904                 });
91905
91906                 if (entity) {
91907                   _map.zoomTo(entity);
91908                 }
91909               }
91910             });
91911
91912             _map.on('drawn.zoomToEntity', function () {
91913               if (!context.hasEntity(entityID)) return;
91914
91915               _map.on('drawn.zoomToEntity', null);
91916
91917               context.on('enter.zoomToEntity', null);
91918               context.enter(modeSelect(context, [entityID]));
91919             });
91920
91921             context.on('enter.zoomToEntity', function () {
91922               if (_mode.id !== 'browse') {
91923                 _map.on('drawn.zoomToEntity', null);
91924
91925                 context.on('enter.zoomToEntity', null);
91926               }
91927             });
91928           };
91929
91930           var _minEditableZoom = 16;
91931
91932           context.minEditableZoom = function (val) {
91933             if (!arguments.length) return _minEditableZoom;
91934             _minEditableZoom = val;
91935
91936             if (_connection) {
91937               _connection.tileZoom(val);
91938             }
91939
91940             return context;
91941           }; // String length limits in Unicode characters, not JavaScript UTF-16 code units
91942
91943
91944           context.maxCharsForTagKey = function () {
91945             return 255;
91946           };
91947
91948           context.maxCharsForTagValue = function () {
91949             return 255;
91950           };
91951
91952           context.maxCharsForRelationRole = function () {
91953             return 255;
91954           };
91955
91956           function cleanOsmString(val, maxChars) {
91957             // be lenient with input
91958             if (val === undefined || val === null) {
91959               val = '';
91960             } else {
91961               val = val.toString();
91962             } // remove whitespace
91963
91964
91965             val = val.trim(); // use the canonical form of the string
91966
91967             if (val.normalize) val = val.normalize('NFC'); // trim to the number of allowed characters
91968
91969             return utilUnicodeCharsTruncated(val, maxChars);
91970           }
91971
91972           context.cleanTagKey = function (val) {
91973             return cleanOsmString(val, context.maxCharsForTagKey());
91974           };
91975
91976           context.cleanTagValue = function (val) {
91977             return cleanOsmString(val, context.maxCharsForTagValue());
91978           };
91979
91980           context.cleanRelationRole = function (val) {
91981             return cleanOsmString(val, context.maxCharsForRelationRole());
91982           };
91983           /* History */
91984
91985
91986           var _inIntro = false;
91987
91988           context.inIntro = function (val) {
91989             if (!arguments.length) return _inIntro;
91990             _inIntro = val;
91991             return context;
91992           }; // Immediately save the user's history to localstorage, if possible
91993           // This is called someteimes, but also on the `window.onbeforeunload` handler
91994
91995
91996           context.save = function () {
91997             // no history save, no message onbeforeunload
91998             if (_inIntro || context.container().select('.modal').size()) return;
91999             var canSave;
92000
92001             if (_mode && _mode.id === 'save') {
92002               canSave = false; // Attempt to prevent user from creating duplicate changes - see #5200
92003
92004               if (services.osm && services.osm.isChangesetInflight()) {
92005                 _history.clearSaved();
92006
92007                 return;
92008               }
92009             } else {
92010               canSave = context.selectedIDs().every(function (id) {
92011                 var entity = context.hasEntity(id);
92012                 return entity && !entity.isDegenerate();
92013               });
92014             }
92015
92016             if (canSave) {
92017               _history.save();
92018             }
92019
92020             if (_history.hasChanges()) {
92021               return _t('save.unsaved_changes');
92022             }
92023           }; // Debounce save, since it's a synchronous localStorage write,
92024           // and history changes can happen frequently (e.g. when dragging).
92025
92026
92027           context.debouncedSave = debounce(context.save, 350);
92028
92029           function withDebouncedSave(fn) {
92030             return function () {
92031               var result = fn.apply(_history, arguments);
92032               context.debouncedSave();
92033               return result;
92034             };
92035           }
92036           /* Graph */
92037
92038
92039           context.hasEntity = function (id) {
92040             return _history.graph().hasEntity(id);
92041           };
92042
92043           context.entity = function (id) {
92044             return _history.graph().entity(id);
92045           };
92046           /* Modes */
92047
92048
92049           var _mode;
92050
92051           context.mode = function () {
92052             return _mode;
92053           };
92054
92055           context.enter = function (newMode) {
92056             if (_mode) {
92057               _mode.exit();
92058
92059               dispatch.call('exit', _this, _mode);
92060             }
92061
92062             _mode = newMode;
92063
92064             _mode.enter();
92065
92066             dispatch.call('enter', _this, _mode);
92067           };
92068
92069           context.selectedIDs = function () {
92070             return _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
92071           };
92072
92073           context.activeID = function () {
92074             return _mode && _mode.activeID && _mode.activeID();
92075           };
92076
92077           var _selectedNoteID;
92078
92079           context.selectedNoteID = function (noteID) {
92080             if (!arguments.length) return _selectedNoteID;
92081             _selectedNoteID = noteID;
92082             return context;
92083           }; // NOTE: Don't change the name of this until UI v3 is merged
92084
92085
92086           var _selectedErrorID;
92087
92088           context.selectedErrorID = function (errorID) {
92089             if (!arguments.length) return _selectedErrorID;
92090             _selectedErrorID = errorID;
92091             return context;
92092           };
92093           /* Behaviors */
92094
92095
92096           context.install = function (behavior) {
92097             return context.surface().call(behavior);
92098           };
92099
92100           context.uninstall = function (behavior) {
92101             return context.surface().call(behavior.off);
92102           };
92103           /* Copy/Paste */
92104
92105
92106           var _copyGraph;
92107
92108           context.copyGraph = function () {
92109             return _copyGraph;
92110           };
92111
92112           var _copyIDs = [];
92113
92114           context.copyIDs = function (val) {
92115             if (!arguments.length) return _copyIDs;
92116             _copyIDs = val;
92117             _copyGraph = _history.graph();
92118             return context;
92119           };
92120
92121           var _copyLonLat;
92122
92123           context.copyLonLat = function (val) {
92124             if (!arguments.length) return _copyLonLat;
92125             _copyLonLat = val;
92126             return context;
92127           };
92128           /* Background */
92129
92130
92131           var _background;
92132
92133           context.background = function () {
92134             return _background;
92135           };
92136           /* Features */
92137
92138
92139           var _features;
92140
92141           context.features = function () {
92142             return _features;
92143           };
92144
92145           context.hasHiddenConnections = function (id) {
92146             var graph = _history.graph();
92147
92148             var entity = graph.entity(id);
92149             return _features.hasHiddenConnections(entity, graph);
92150           };
92151           /* Photos */
92152
92153
92154           var _photos;
92155
92156           context.photos = function () {
92157             return _photos;
92158           };
92159           /* Map */
92160
92161
92162           var _map;
92163
92164           context.map = function () {
92165             return _map;
92166           };
92167
92168           context.layers = function () {
92169             return _map.layers();
92170           };
92171
92172           context.surface = function () {
92173             return _map.surface;
92174           };
92175
92176           context.editableDataEnabled = function () {
92177             return _map.editableDataEnabled();
92178           };
92179
92180           context.surfaceRect = function () {
92181             return _map.surface.node().getBoundingClientRect();
92182           };
92183
92184           context.editable = function () {
92185             // don't allow editing during save
92186             var mode = context.mode();
92187             if (!mode || mode.id === 'save') return false;
92188             return _map.editableDataEnabled();
92189           };
92190           /* Debug */
92191
92192
92193           var _debugFlags = {
92194             tile: false,
92195             // tile boundaries
92196             collision: false,
92197             // label collision bounding boxes
92198             imagery: false,
92199             // imagery bounding polygons
92200             target: false,
92201             // touch targets
92202             downloaded: false // downloaded data from osm
92203
92204           };
92205
92206           context.debugFlags = function () {
92207             return _debugFlags;
92208           };
92209
92210           context.getDebug = function (flag) {
92211             return flag && _debugFlags[flag];
92212           };
92213
92214           context.setDebug = function (flag, val) {
92215             if (arguments.length === 1) val = true;
92216             _debugFlags[flag] = val;
92217             dispatch.call('change');
92218             return context;
92219           };
92220           /* Container */
92221
92222
92223           var _container = select(null);
92224
92225           context.container = function (val) {
92226             if (!arguments.length) return _container;
92227             _container = val;
92228
92229             _container.classed('ideditor', true);
92230
92231             return context;
92232           };
92233
92234           context.containerNode = function (val) {
92235             if (!arguments.length) return context.container().node();
92236             context.container(select(val));
92237             return context;
92238           };
92239
92240           var _embed;
92241
92242           context.embed = function (val) {
92243             if (!arguments.length) return _embed;
92244             _embed = val;
92245             return context;
92246           };
92247           /* Assets */
92248
92249
92250           var _assetPath = '';
92251
92252           context.assetPath = function (val) {
92253             if (!arguments.length) return _assetPath;
92254             _assetPath = val;
92255             _mainFileFetcher.assetPath(val);
92256             return context;
92257           };
92258
92259           var _assetMap = {};
92260
92261           context.assetMap = function (val) {
92262             if (!arguments.length) return _assetMap;
92263             _assetMap = val;
92264             _mainFileFetcher.assetMap(val);
92265             return context;
92266           };
92267
92268           context.asset = function (val) {
92269             if (/^http(s)?:\/\//i.test(val)) return val;
92270             var filename = _assetPath + val;
92271             return _assetMap[filename] || filename;
92272           };
92273
92274           context.imagePath = function (val) {
92275             return context.asset("img/".concat(val));
92276           };
92277           /* reset (aka flush) */
92278
92279
92280           context.reset = context.flush = function () {
92281             context.debouncedSave.cancel();
92282             Array.from(_deferred).forEach(function (handle) {
92283               window.cancelIdleCallback(handle);
92284
92285               _deferred["delete"](handle);
92286             });
92287             Object.values(services).forEach(function (service) {
92288               if (service && typeof service.reset === 'function') {
92289                 service.reset(context);
92290               }
92291             });
92292             context.changeset = null;
92293
92294             _validator.reset();
92295
92296             _features.reset();
92297
92298             _history.reset();
92299
92300             _uploader.reset(); // don't leave stale state in the inspector
92301
92302
92303             context.container().select('.inspector-wrap *').remove();
92304             return context;
92305           };
92306           /* Projections */
92307
92308
92309           context.projection = geoRawMercator();
92310           context.curtainProjection = geoRawMercator();
92311           /* Init */
92312
92313           context.init = function () {
92314             instantiateInternal();
92315             initializeDependents();
92316             return context; // Load variables and properties. No property of `context` should be accessed
92317             // until this is complete since load statuses are indeterminate. The order
92318             // of instantiation shouldn't matter.
92319
92320             function instantiateInternal() {
92321               _history = coreHistory(context);
92322               context.graph = _history.graph;
92323               context.pauseChangeDispatch = _history.pauseChangeDispatch;
92324               context.resumeChangeDispatch = _history.resumeChangeDispatch;
92325               context.perform = withDebouncedSave(_history.perform);
92326               context.replace = withDebouncedSave(_history.replace);
92327               context.pop = withDebouncedSave(_history.pop);
92328               context.overwrite = withDebouncedSave(_history.overwrite);
92329               context.undo = withDebouncedSave(_history.undo);
92330               context.redo = withDebouncedSave(_history.redo);
92331               _validator = coreValidator(context);
92332               _uploader = coreUploader(context);
92333               _background = rendererBackground(context);
92334               _features = rendererFeatures(context);
92335               _map = rendererMap(context);
92336               _photos = rendererPhotos(context);
92337               _ui = uiInit(context);
92338             } // Set up objects that might need to access properties of `context`. The order
92339             // might matter if dependents make calls to each other. Be wary of async calls.
92340
92341
92342             function initializeDependents() {
92343               if (context.initialHashParams.presets) {
92344                 _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(',')));
92345               }
92346
92347               if (context.initialHashParams.locale) {
92348                 _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
92349               } // kick off some async work
92350
92351
92352               _mainLocalizer.ensureLoaded();
92353
92354               _background.ensureLoaded();
92355
92356               _mainPresetIndex.ensureLoaded();
92357               Object.values(services).forEach(function (service) {
92358                 if (service && typeof service.init === 'function') {
92359                   service.init();
92360                 }
92361               });
92362
92363               _map.init();
92364
92365               _validator.init();
92366
92367               _features.init();
92368
92369               if (services.maprules && context.initialHashParams.maprules) {
92370                 d3_json(context.initialHashParams.maprules).then(function (mapcss) {
92371                   services.maprules.init();
92372                   mapcss.forEach(function (mapcssSelector) {
92373                     return services.maprules.addRule(mapcssSelector);
92374                   });
92375                 })["catch"](function () {
92376                   /* ignore */
92377                 });
92378               } // if the container isn't available, e.g. when testing, don't load the UI
92379
92380
92381               if (!context.container().empty()) {
92382                 _ui.ensureLoaded().then(function () {
92383                   _photos.init();
92384                 });
92385               }
92386             }
92387           };
92388
92389           return context;
92390         }
92391
92392         // NSI contains the most correct tagging for many commonly mapped features.
92393         // See https://github.com/osmlab/name-suggestion-index  and  https://nsi.guide
92394         // DATA
92395
92396         var _nsiStatus = 'loading'; // 'loading', 'ok', 'failed'
92397
92398         var _nsi = {}; // Sometimes we can upgrade a feature tagged like `building=yes` to a better tag.
92399
92400         var buildingPreset = {
92401           'building/commercial': true,
92402           'building/government': true,
92403           'building/hotel': true,
92404           'building/retail': true,
92405           'building/office': true,
92406           'building/supermarket': true,
92407           'building/yes': true
92408         }; // Exceptions to the namelike regexes.
92409         // Usually a tag suffix contains a language code like `name:en`, `name:ru`
92410         // but we want to exclude things like `operator:type`, `name:etymology`, etc..
92411
92412         var notNames = /:(colou?r|type|forward|backward|left|right|etymology|pronunciation|wikipedia)$/i; // Exceptions to the branchlike regexes
92413
92414         var notBranches = /(coop|express|wireless|factory|outlet)/i; // PRIVATE FUNCTIONS
92415         // `setNsiSources()`
92416         // Adds the sources to iD's filemap so we can start downloading data.
92417         //
92418
92419         function setNsiSources() {
92420           var nsiVersion = packageJSON.devDependencies['name-suggestion-index'];
92421           var v = parseVersion(nsiVersion);
92422           var vMinor = "".concat(v.major, ".").concat(v.minor);
92423           var sources = {
92424             'nsi_data': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/nsi.min.json"),
92425             'nsi_dissolved': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/dissolved.min.json"),
92426             'nsi_features': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/featureCollection.min.json"),
92427             'nsi_generics': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/genericWords.min.json"),
92428             'nsi_presets': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/presets/nsi-id-presets.min.json"),
92429             'nsi_replacements': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/replacements.min.json"),
92430             'nsi_trees': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/trees.min.json")
92431           };
92432           var fileMap = _mainFileFetcher.fileMap();
92433
92434           for (var k in sources) {
92435             if (!fileMap[k]) fileMap[k] = sources[k];
92436           }
92437         } // `loadNsiPresets()`
92438         //  Returns a Promise fulfilled when the presets have been downloaded and merged into iD.
92439         //
92440
92441
92442         function loadNsiPresets() {
92443           return Promise.all([_mainFileFetcher.get('nsi_presets'), _mainFileFetcher.get('nsi_features')]).then(function (vals) {
92444             // Add `suggestion=true` to all the nsi presets
92445             // The preset json schema doesn't include it, but the iD code still uses it
92446             Object.values(vals[0].presets).forEach(function (preset) {
92447               return preset.suggestion = true;
92448             });
92449             _mainPresetIndex.merge({
92450               presets: vals[0].presets,
92451               featureCollection: vals[1]
92452             });
92453           });
92454         } // `loadNsiData()`
92455         //  Returns a Promise fulfilled when the other data have been downloaded and processed
92456         //
92457
92458
92459         function loadNsiData() {
92460           return Promise.all([_mainFileFetcher.get('nsi_data'), _mainFileFetcher.get('nsi_dissolved'), _mainFileFetcher.get('nsi_replacements'), _mainFileFetcher.get('nsi_trees')]).then(function (vals) {
92461             _nsi = {
92462               data: vals[0].nsi,
92463               // the raw name-suggestion-index data
92464               dissolved: vals[1].dissolved,
92465               // list of dissolved items
92466               replacements: vals[2].replacements,
92467               // trivial old->new qid replacements
92468               trees: vals[3].trees,
92469               // metadata about trees, main tags
92470               kvt: new Map(),
92471               // Map (k -> Map (v -> t) )
92472               qids: new Map(),
92473               // Map (wd/wp tag values -> qids)
92474               ids: new Map() // Map (id -> NSI item)
92475
92476             };
92477             _nsi.matcher = new Matcher();
92478
92479             _nsi.matcher.buildMatchIndex(_nsi.data);
92480
92481             _nsi.matcher.buildLocationIndex(_nsi.data, _mainLocations.loco());
92482
92483             Object.keys(_nsi.data).forEach(function (tkv) {
92484               var category = _nsi.data[tkv];
92485               var parts = tkv.split('/', 3); // tkv = "tree/key/value"
92486
92487               var t = parts[0];
92488               var k = parts[1];
92489               var v = parts[2]; // Build a reverse index of keys -> values -> trees present in the name-suggestion-index
92490               // Collect primary keys  (e.g. "amenity", "craft", "shop", "man_made", "route", etc)
92491               // "amenity": {
92492               //   "restaurant": "brands"
92493               // }
92494
92495               var vmap = _nsi.kvt.get(k);
92496
92497               if (!vmap) {
92498                 vmap = new Map();
92499
92500                 _nsi.kvt.set(k, vmap);
92501               }
92502
92503               vmap.set(v, t);
92504               var tree = _nsi.trees[t]; // e.g. "brands", "operators"
92505
92506               var mainTag = tree.mainTag; // e.g. "brand:wikidata", "operator:wikidata", etc
92507
92508               var items = category.items || [];
92509               items.forEach(function (item) {
92510                 // Remember some useful things for later, cache NSI id -> item
92511                 item.tkv = tkv;
92512                 item.mainTag = mainTag;
92513
92514                 _nsi.ids.set(item.id, item); // Cache Wikidata/Wikipedia values -> qid, for #6416
92515
92516
92517                 var wd = item.tags[mainTag];
92518                 var wp = item.tags[mainTag.replace('wikidata', 'wikipedia')];
92519                 if (wd) _nsi.qids.set(wd, wd);
92520                 if (wp && wd) _nsi.qids.set(wp, wd);
92521               });
92522             });
92523           });
92524         } // `gatherKVs()`
92525         // Gather all the k/v pairs that we will run through the NSI matcher.
92526         // An OSM tags object can contain anything, but only a few tags will be interesting to NSI.
92527         //
92528         // This function will return the interesting tag pairs like:
92529         //   "amenity/restaurant", "man_made/flagpole"
92530         // and fallbacks like
92531         //   "amenity/yes"
92532         // excluding things like
92533         //   "tiger:reviewed", "surface", "ref", etc.
92534         //
92535         // Arguments
92536         //   `tags`: `Object` containing the feature's OSM tags
92537         // Returns
92538         //   `Object` containing kv pairs to test:
92539         //   {
92540         //     'primary': Set(),
92541         //     'alternate': Set()
92542         //   }
92543         //
92544
92545
92546         function gatherKVs(tags) {
92547           var primary = new Set();
92548           var alternate = new Set();
92549           Object.keys(tags).forEach(function (osmkey) {
92550             var osmvalue = tags[osmkey];
92551             if (!osmvalue) return; // Match a 'route_master' as if it were a 'route' - name-suggestion-index#5184
92552
92553             if (osmkey === 'route_master') osmkey = 'route';
92554
92555             var vmap = _nsi.kvt.get(osmkey);
92556
92557             if (!vmap) return; // not an interesting key
92558
92559             if (vmap.get(osmvalue)) {
92560               // Matched a category in NSI
92561               primary.add("".concat(osmkey, "/").concat(osmvalue)); // interesting key/value
92562             } else if (osmvalue === 'yes') {
92563               alternate.add("".concat(osmkey, "/").concat(osmvalue)); // fallback key/yes
92564             }
92565           }); // Can we try a generic building fallback match? - See #6122, #7197
92566           // Only try this if we do a preset match and find nothing else remarkable about that building.
92567           // For example, a way with `building=yes` + `name=Westfield` may be a Westfield department store.
92568           // But a way with `building=yes` + `name=Westfield` + `public_transport=station` is a train station for a town named "Westfield"
92569
92570           var preset = _mainPresetIndex.matchTags(tags, 'area');
92571
92572           if (buildingPreset[preset.id]) {
92573             alternate.add('building/yes');
92574           }
92575
92576           return {
92577             primary: primary,
92578             alternate: alternate
92579           };
92580         } // `identifyTree()`
92581         // NSI has a concept of trees: "brands", "operators", "flags", "transit".
92582         // The tree determines things like which tags are namelike, and which tags hold important wikidata.
92583         // This takes an Object of tags and tries to identify what tree to use.
92584         //
92585         // Arguments
92586         //   `tags`: `Object` containing the feature's OSM tags
92587         // Returns
92588         //   `string` the name of the tree if known
92589         //   or 'unknown' if it could match several trees (e.g. amenity/yes)
92590         //   or null if no match
92591         //
92592
92593
92594         function identifyTree(tags) {
92595           var unknown;
92596           var t; // Check all tags
92597
92598           Object.keys(tags).forEach(function (osmkey) {
92599             if (t) return; // found already
92600
92601             var osmvalue = tags[osmkey];
92602             if (!osmvalue) return; // Match a 'route_master' as if it were a 'route' - name-suggestion-index#5184
92603
92604             if (osmkey === 'route_master') osmkey = 'route';
92605
92606             var vmap = _nsi.kvt.get(osmkey);
92607
92608             if (!vmap) return; // this key is not in nsi
92609
92610             if (osmvalue === 'yes') {
92611               unknown = 'unknown';
92612             } else {
92613               t = vmap.get(osmvalue);
92614             }
92615           });
92616           return t || unknown || null;
92617         } // `gatherNames()`
92618         // Gather all the namelike values that we will run through the NSI matcher.
92619         // It will gather values primarily from tags `name`, `name:ru`, `flag:name`
92620         //  and fallback to alternate tags like `brand`, `brand:ru`, `alt_name`
92621         //
92622         // Arguments
92623         //   `tags`: `Object` containing the feature's OSM tags
92624         // Returns
92625         //   `Object` containing namelike values to test:
92626         //   {
92627         //     'primary': Set(),
92628         //     'fallbacks': Set()
92629         //   }
92630         //
92631
92632
92633         function gatherNames(tags) {
92634           var empty = {
92635             primary: new Set(),
92636             alternate: new Set()
92637           };
92638           var primary = new Set();
92639           var alternate = new Set();
92640           var foundSemi = false;
92641           var testNameFragments = false;
92642           var patterns; // Patterns for matching OSM keys that might contain namelike values.
92643           // These roughly correspond to the "trees" concept in name-suggestion-index,
92644
92645           var t = identifyTree(tags);
92646           if (!t) return empty;
92647
92648           if (t === 'transit') {
92649             patterns = {
92650               primary: /^network$/i,
92651               alternate: /^(operator|operator:\w+|network:\w+|\w+_name|\w+_name:\w+)$/i
92652             };
92653           } else if (t === 'flags') {
92654             patterns = {
92655               primary: /^(flag:name|flag:name:\w+)$/i,
92656               alternate: /^(flag|flag:\w+|subject|subject:\w+)$/i // note: no `country`, we special-case it below
92657
92658             };
92659           } else if (t === 'brands') {
92660             testNameFragments = true;
92661             patterns = {
92662               primary: /^(name|name:\w+)$/i,
92663               alternate: /^(brand|brand:\w+|operator|operator:\w+|\w+_name|\w+_name:\w+)/i
92664             };
92665           } else if (t === 'operators') {
92666             testNameFragments = true;
92667             patterns = {
92668               primary: /^(name|name:\w+|operator|operator:\w+)$/i,
92669               alternate: /^(brand|brand:\w+|\w+_name|\w+_name:\w+)/i
92670             };
92671           } else {
92672             // unknown/multiple
92673             testNameFragments = true;
92674             patterns = {
92675               primary: /^(name|name:\w+)$/i,
92676               alternate: /^(brand|brand:\w+|network|network:\w+|operator|operator:\w+|\w+_name|\w+_name:\w+)/i
92677             };
92678           } // Test `name` fragments, longest to shortest, to fit them into a "Name Branch" pattern.
92679           // e.g. "TUI ReiseCenter - Neuss Innenstadt" -> ["TUI", "ReiseCenter", "Neuss", "Innenstadt"]
92680
92681
92682           if (tags.name && testNameFragments) {
92683             var nameParts = tags.name.split(/[\s\-\/,.]/);
92684
92685             for (var split = nameParts.length; split > 0; split--) {
92686               var name = nameParts.slice(0, split).join(' '); // e.g. "TUI ReiseCenter"
92687
92688               primary.add(name);
92689             }
92690           } // Check all tags
92691
92692
92693           Object.keys(tags).forEach(function (osmkey) {
92694             var osmvalue = tags[osmkey];
92695             if (!osmvalue) return;
92696
92697             if (isNamelike(osmkey, 'primary')) {
92698               if (/;/.test(osmvalue)) {
92699                 foundSemi = true;
92700               } else {
92701                 primary.add(osmvalue);
92702                 alternate["delete"](osmvalue);
92703               }
92704             } else if (!primary.has(osmvalue) && isNamelike(osmkey, 'alternate')) {
92705               if (/;/.test(osmvalue)) {
92706                 foundSemi = true;
92707               } else {
92708                 alternate.add(osmvalue);
92709               }
92710             }
92711           }); // For flags only, fallback to `country` tag only if no other namelike values were found.
92712           // See https://github.com/openstreetmap/iD/pull/8305#issuecomment-769174070
92713
92714           if (tags.man_made === 'flagpole' && !primary.size && !alternate.size && !!tags.country) {
92715             var osmvalue = tags.country;
92716
92717             if (/;/.test(osmvalue)) {
92718               foundSemi = true;
92719             } else {
92720               alternate.add(osmvalue);
92721             }
92722           } // If any namelike value contained a semicolon, return empty set and don't try matching anything.
92723
92724
92725           if (foundSemi) {
92726             return empty;
92727           } else {
92728             return {
92729               primary: primary,
92730               alternate: alternate
92731             };
92732           }
92733
92734           function isNamelike(osmkey, which) {
92735             if (osmkey === 'old_name') return false;
92736             return patterns[which].test(osmkey) && !notNames.test(osmkey);
92737           }
92738         } // `gatherTuples()`
92739         // Generate all combinations of [key,value,name] that we want to test.
92740         // This prioritizes them so that the primary name and k/v pairs go first
92741         //
92742         // Arguments
92743         //   `tryKVs`: `Object` containing primary and alternate k/v pairs to test
92744         //   `tryNames`: `Object` containing primary and alternate names to test
92745         // Returns
92746         //   `Array`: tuple objects ordered by priority
92747         //
92748
92749
92750         function gatherTuples(tryKVs, tryNames) {
92751           var tuples = [];
92752           ['primary', 'alternate'].forEach(function (whichName) {
92753             // test names longest to shortest
92754             var arr = Array.from(tryNames[whichName]).sort(function (a, b) {
92755               return b.length - a.length;
92756             });
92757             arr.forEach(function (n) {
92758               ['primary', 'alternate'].forEach(function (whichKV) {
92759                 tryKVs[whichKV].forEach(function (kv) {
92760                   var parts = kv.split('/', 2);
92761                   var k = parts[0];
92762                   var v = parts[1];
92763                   tuples.push({
92764                     k: k,
92765                     v: v,
92766                     n: n
92767                   });
92768                 });
92769               });
92770             });
92771           });
92772           return tuples;
92773         } // `_upgradeTags()`
92774         // Try to match a feature to a canonical record in name-suggestion-index
92775         // and upgrade the tags to match.
92776         //
92777         // Arguments
92778         //   `tags`: `Object` containing the feature's OSM tags
92779         //   `loc`: Location where this feature exists, as a [lon, lat]
92780         // Returns
92781         //   `Object` containing the result, or `null` if no changes needed:
92782         //   {
92783         //     'newTags': `Object` - The tags the the feature should have
92784         //     'matched': `Object` - The matched item
92785         //   }
92786         //
92787
92788
92789         function _upgradeTags(tags, loc) {
92790           var newTags = Object.assign({}, tags); // shallow copy
92791
92792           var changed = false; // Before anything, perform trivial Wikipedia/Wikidata replacements
92793
92794           Object.keys(newTags).forEach(function (osmkey) {
92795             var matchTag = osmkey.match(/^(\w+:)?wikidata$/);
92796
92797             if (matchTag) {
92798               // Look at '*:wikidata' tags
92799               var prefix = matchTag[1] || '';
92800               var wd = newTags[osmkey];
92801               var replace = _nsi.replacements[wd]; // If it matches a QID in the replacement list...
92802
92803               if (replace && replace.wikidata !== undefined) {
92804                 // replace or delete `*:wikidata` tag
92805                 changed = true;
92806
92807                 if (replace.wikidata) {
92808                   newTags[osmkey] = replace.wikidata;
92809                 } else {
92810                   delete newTags[osmkey];
92811                 }
92812               }
92813
92814               if (replace && replace.wikipedia !== undefined) {
92815                 // replace or delete `*:wikipedia` tag
92816                 changed = true;
92817                 var wpkey = "".concat(prefix, "wikipedia");
92818
92819                 if (replace.wikipedia) {
92820                   newTags[wpkey] = replace.wikipedia;
92821                 } else {
92822                   delete newTags[wpkey];
92823                 }
92824               }
92825             }
92826           }); // Match a 'route_master' as if it were a 'route' - name-suggestion-index#5184
92827
92828           var isRouteMaster = tags.type === 'route_master'; // Gather key/value tag pairs to try to match
92829
92830           var tryKVs = gatherKVs(tags);
92831
92832           if (!tryKVs.primary.size && !tryKVs.alternate.size) {
92833             return changed ? {
92834               newTags: newTags,
92835               matched: null
92836             } : null;
92837           } // Gather namelike tag values to try to match
92838
92839
92840           var tryNames = gatherNames(tags); // Do `wikidata=*` or `wikipedia=*` tags identify this entity as a chain? - See #6416
92841           // If so, these tags can be swapped to e.g. `brand:wikidata`/`brand:wikipedia`.
92842
92843           var foundQID = _nsi.qids.get(tags.wikidata) || _nsi.qids.get(tags.wikipedia);
92844
92845           if (foundQID) tryNames.primary.add(foundQID); // matcher will recognize the Wikidata QID as name too
92846
92847           if (!tryNames.primary.size && !tryNames.alternate.size) {
92848             return changed ? {
92849               newTags: newTags,
92850               matched: null
92851             } : null;
92852           } // Order the [key,value,name] tuples - test primary before alternate
92853
92854
92855           var tuples = gatherTuples(tryKVs, tryNames);
92856
92857           var _loop = function _loop(i) {
92858             var tuple = tuples[i];
92859
92860             var hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n, loc); // Attempt to match an item in NSI
92861
92862
92863             if (!hits || !hits.length) return "continue"; // no match, try next tuple
92864
92865             if (hits[0].match !== 'primary' && hits[0].match !== 'alternate') return "break"; // a generic match, stop looking
92866             // A match may contain multiple results, the first one is likely the best one for this location
92867             // e.g. `['pfk-a54c14', 'kfc-1ff19c', 'kfc-658eea']`
92868
92869             var itemID = void 0,
92870                 item = void 0;
92871
92872             for (var j = 0; j < hits.length; j++) {
92873               var hit = hits[j];
92874               itemID = hit.itemID;
92875               if (_nsi.dissolved[itemID]) continue; // Don't upgrade to a dissolved item
92876
92877               item = _nsi.ids.get(itemID);
92878               if (!item) continue;
92879               var mainTag = item.mainTag; // e.g. `brand:wikidata`
92880
92881               var itemQID = item.tags[mainTag]; // e.g. `brand:wikidata` qid
92882
92883               var notQID = newTags["not:".concat(mainTag)]; // e.g. `not:brand:wikidata` qid
92884
92885               if ( // Exceptions, skip this hit
92886               !itemQID || itemQID === notQID || // No `*:wikidata` or matched a `not:*:wikidata`
92887               newTags.office && !item.tags.office // feature may be a corporate office for a brand? - #6416
92888               ) {
92889                   item = null;
92890                   continue; // continue looking
92891                 } else {
92892                   break; // use `item`
92893                 }
92894             } // Can't use any of these hits, try next tuple..
92895
92896
92897             if (!item) return "continue"; // At this point we have matched a canonical item and can suggest tag upgrades..
92898
92899             item = JSON.parse(JSON.stringify(item)); // deep copy
92900
92901             var tkv = item.tkv;
92902             var parts = tkv.split('/', 3); // tkv = "tree/key/value"
92903
92904             var k = parts[1];
92905             var v = parts[2];
92906             var category = _nsi.data[tkv];
92907             var properties = category.properties || {}; // Preserve some tags that we specifically don't want NSI to overwrite. ('^name', sometimes)
92908
92909             var preserveTags = item.preserveTags || properties.preserveTags || []; // These tags can be toplevel tags -or- attributes - so we generally want to preserve existing values - #8615
92910             // We'll only _replace_ the tag value if this tag is the toplevel/defining tag for the matched item (`k`)
92911
92912             ['building', 'emergency', 'internet_access', 'takeaway'].forEach(function (osmkey) {
92913               if (k !== osmkey) preserveTags.push("^".concat(osmkey, "$"));
92914             });
92915             var regexes = preserveTags.map(function (s) {
92916               return new RegExp(s, 'i');
92917             });
92918             var keepTags = {};
92919             Object.keys(newTags).forEach(function (osmkey) {
92920               if (regexes.some(function (regex) {
92921                 return regex.test(osmkey);
92922               })) {
92923                 keepTags[osmkey] = newTags[osmkey];
92924               }
92925             }); // Remove any primary tags ("amenity", "craft", "shop", "man_made", "route", etc) that have a
92926             // value like `amenity=yes` or `shop=yes` (exceptions have already been added to `keepTags` above)
92927
92928             _nsi.kvt.forEach(function (vmap, k) {
92929               if (newTags[k] === 'yes') delete newTags[k];
92930             }); // Replace mistagged `wikidata`/`wikipedia` with e.g. `brand:wikidata`/`brand:wikipedia`
92931
92932
92933             if (foundQID) {
92934               delete newTags.wikipedia;
92935               delete newTags.wikidata;
92936             } // Do the tag upgrade
92937
92938
92939             Object.assign(newTags, item.tags, keepTags); // Swap `route` back to `route_master` - name-suggestion-index#5184
92940
92941             if (isRouteMaster) {
92942               newTags.route_master = newTags.route;
92943               delete newTags.route;
92944             } // Special `branch` splitting rules - IF..
92945             // - NSI is suggesting to replace `name`, AND
92946             // - `branch` doesn't already contain something, AND
92947             // - original name has not moved to an alternate name (e.g. "Dunkin' Donuts" -> "Dunkin'"), AND
92948             // - original name is "some name" + "some stuff", THEN
92949             // consider splitting `name` into `name`/`branch`..
92950
92951
92952             var origName = tags.name;
92953             var newName = newTags.name;
92954
92955             if (newName && origName && newName !== origName && !newTags.branch) {
92956               var newNames = gatherNames(newTags);
92957               var newSet = new Set([].concat(_toConsumableArray(newNames.primary), _toConsumableArray(newNames.alternate)));
92958               var isMoved = newSet.has(origName); // another tag holds the original name now
92959
92960               if (!isMoved) {
92961                 // Test name fragments, longest to shortest, to fit them into a "Name Branch" pattern.
92962                 // e.g. "TUI ReiseCenter - Neuss Innenstadt" -> ["TUI", "ReiseCenter", "Neuss", "Innenstadt"]
92963                 var nameParts = origName.split(/[\s\-\/,.]/);
92964
92965                 for (var split = nameParts.length; split > 0; split--) {
92966                   var name = nameParts.slice(0, split).join(' '); // e.g. "TUI ReiseCenter"
92967
92968                   var branch = nameParts.slice(split).join(' '); // e.g. "Neuss Innenstadt"
92969
92970                   var nameHits = _nsi.matcher.match(k, v, name, loc);
92971
92972                   if (!nameHits || !nameHits.length) continue; // no match, try next name fragment
92973
92974                   if (nameHits.some(function (hit) {
92975                     return hit.itemID === itemID;
92976                   })) {
92977                     // matched the name fragment to the same itemID above
92978                     if (branch) {
92979                       if (notBranches.test(branch)) {
92980                         // "branch" was detected but is noise ("factory outlet", etc)
92981                         newTags.name = origName; // Leave `name` alone, this part of the name may be significant..
92982                       } else {
92983                         var branchHits = _nsi.matcher.match(k, v, branch, loc);
92984
92985                         if (branchHits && branchHits.length) {
92986                           // if "branch" matched something else in NSI..
92987                           if (branchHits[0].match === 'primary' || branchHits[0].match === 'alternate') {
92988                             // if another brand! (e.g. "KFC - Taco Bell"?)
92989                             return {
92990                               v: null
92991                             }; //   bail out - can't suggest tags in this case
92992                           } // else a generic (e.g. "gas", "cafe") - ignore
92993
92994                         } else {
92995                           // "branch" is not noise and not something in NSI
92996                           newTags.branch = branch; // Stick it in the `branch` tag..
92997                         }
92998                       }
92999                     }
93000
93001                     break;
93002                   }
93003                 }
93004               }
93005             }
93006
93007             return {
93008               v: {
93009                 newTags: newTags,
93010                 matched: item
93011               }
93012             };
93013           };
93014
93015           for (var i = 0; i < tuples.length; i++) {
93016             var _ret = _loop(i);
93017
93018             if (_ret === "continue") continue;
93019             if (_ret === "break") break;
93020             if (_typeof(_ret) === "object") return _ret.v;
93021           }
93022
93023           return changed ? {
93024             newTags: newTags,
93025             matched: null
93026           } : null;
93027         } // `_isGenericName()`
93028         // Is the `name` tag generic?
93029         //
93030         // Arguments
93031         //   `tags`: `Object` containing the feature's OSM tags
93032         // Returns
93033         //   `true` if it is generic, `false` if not
93034         //
93035
93036
93037         function _isGenericName(tags) {
93038           var n = tags.name;
93039           if (!n) return false; // tryNames just contains the `name` tag value and nothing else
93040
93041           var tryNames = {
93042             primary: new Set([n]),
93043             alternate: new Set()
93044           }; // Gather key/value tag pairs to try to match
93045
93046           var tryKVs = gatherKVs(tags);
93047           if (!tryKVs.primary.size && !tryKVs.alternate.size) return false; // Order the [key,value,name] tuples - test primary before alternate
93048
93049           var tuples = gatherTuples(tryKVs, tryNames);
93050
93051           for (var i = 0; i < tuples.length; i++) {
93052             var tuple = tuples[i];
93053
93054             var hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n); // Attempt to match an item in NSI
93055             // If we get a `excludeGeneric` hit, this is a generic name.
93056
93057
93058             if (hits && hits.length && hits[0].match === 'excludeGeneric') return true;
93059           }
93060
93061           return false;
93062         } // PUBLIC INTERFACE
93063
93064
93065         var serviceNsi = {
93066           // `init()`
93067           // On init, start preparing the name-suggestion-index
93068           //
93069           init: function init() {
93070             // Note: service.init is called immediately after the presetManager has started loading its data.
93071             // We expect to chain onto an unfulfilled promise here.
93072             setNsiSources();
93073             _mainPresetIndex.ensureLoaded().then(function () {
93074               return loadNsiPresets();
93075             }).then(function () {
93076               return delay(100);
93077             }) // wait briefly for locationSets to enter the locationManager queue
93078             .then(function () {
93079               return _mainLocations.mergeLocationSets([]);
93080             }) // wait for locationSets to resolve
93081             .then(function () {
93082               return loadNsiData();
93083             }).then(function () {
93084               return _nsiStatus = 'ok';
93085             })["catch"](function () {
93086               return _nsiStatus = 'failed';
93087             });
93088
93089             function delay(msec) {
93090               return new Promise(function (resolve) {
93091                 window.setTimeout(resolve, msec);
93092               });
93093             }
93094           },
93095           // `reset()`
93096           // Reset is called when user saves data to OSM (does nothing here)
93097           //
93098           reset: function reset() {},
93099           // `status()`
93100           // To let other code know how it's going...
93101           //
93102           // Returns
93103           //   `String`: 'loading', 'ok', 'failed'
93104           //
93105           status: function status() {
93106             return _nsiStatus;
93107           },
93108           // `isGenericName()`
93109           // Is the `name` tag generic?
93110           //
93111           // Arguments
93112           //   `tags`: `Object` containing the feature's OSM tags
93113           // Returns
93114           //   `true` if it is generic, `false` if not
93115           //
93116           isGenericName: function isGenericName(tags) {
93117             return _isGenericName(tags);
93118           },
93119           // `upgradeTags()`
93120           // Suggest tag upgrades.
93121           // This function will not modify the input tags, it makes a copy.
93122           //
93123           // Arguments
93124           //   `tags`: `Object` containing the feature's OSM tags
93125           //   `loc`: Location where this feature exists, as a [lon, lat]
93126           // Returns
93127           //   `Object` containing the result, or `null` if no changes needed:
93128           //   {
93129           //     'newTags': `Object` - The tags the the feature should have
93130           //     'matched': `Object` - The matched item
93131           //   }
93132           //
93133           upgradeTags: function upgradeTags(tags, loc) {
93134             return _upgradeTags(tags, loc);
93135           },
93136           // `cache()`
93137           // Direct access to the NSI cache, useful for testing or breaking things
93138           //
93139           // Returns
93140           //   `Object`: the internal NSI cache
93141           //
93142           cache: function cache() {
93143             return _nsi;
93144           }
93145         };
93146
93147         var apibase$1 = 'https://openstreetcam.org';
93148         var maxResults$1 = 1000;
93149         var tileZoom$1 = 14;
93150         var tiler$3 = utilTiler().zoomExtent([tileZoom$1, tileZoom$1]).skipNullIsland(true);
93151         var dispatch$3 = dispatch$8('loadedImages');
93152         var imgZoom = d3_zoom().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
93153
93154         var _oscCache;
93155
93156         var _oscSelectedImage;
93157
93158         var _loadViewerPromise$1;
93159
93160         function abortRequest$3(controller) {
93161           controller.abort();
93162         }
93163
93164         function maxPageAtZoom(z) {
93165           if (z < 15) return 2;
93166           if (z === 15) return 5;
93167           if (z === 16) return 10;
93168           if (z === 17) return 20;
93169           if (z === 18) return 40;
93170           if (z > 18) return 80;
93171         }
93172
93173         function loadTiles$1(which, url, projection) {
93174           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
93175           var tiles = tiler$3.getTiles(projection); // abort inflight requests that are no longer needed
93176
93177           var cache = _oscCache[which];
93178           Object.keys(cache.inflight).forEach(function (k) {
93179             var wanted = tiles.find(function (tile) {
93180               return k.indexOf(tile.id + ',') === 0;
93181             });
93182
93183             if (!wanted) {
93184               abortRequest$3(cache.inflight[k]);
93185               delete cache.inflight[k];
93186             }
93187           });
93188           tiles.forEach(function (tile) {
93189             loadNextTilePage$1(which, currZoom, url, tile);
93190           });
93191         }
93192
93193         function loadNextTilePage$1(which, currZoom, url, tile) {
93194           var cache = _oscCache[which];
93195           var bbox = tile.extent.bbox();
93196           var maxPages = maxPageAtZoom(currZoom);
93197           var nextPage = cache.nextPage[tile.id] || 1;
93198           var params = utilQsString({
93199             ipp: maxResults$1,
93200             page: nextPage,
93201             // client_id: clientId,
93202             bbTopLeft: [bbox.maxY, bbox.minX].join(','),
93203             bbBottomRight: [bbox.minY, bbox.maxX].join(',')
93204           }, true);
93205           if (nextPage > maxPages) return;
93206           var id = tile.id + ',' + String(nextPage);
93207           if (cache.loaded[id] || cache.inflight[id]) return;
93208           var controller = new AbortController();
93209           cache.inflight[id] = controller;
93210           var options = {
93211             method: 'POST',
93212             signal: controller.signal,
93213             body: params,
93214             headers: {
93215               'Content-Type': 'application/x-www-form-urlencoded'
93216             }
93217           };
93218           d3_json(url, options).then(function (data) {
93219             cache.loaded[id] = true;
93220             delete cache.inflight[id];
93221
93222             if (!data || !data.currentPageItems || !data.currentPageItems.length) {
93223               throw new Error('No Data');
93224             }
93225
93226             var features = data.currentPageItems.map(function (item) {
93227               var loc = [+item.lng, +item.lat];
93228               var d;
93229
93230               if (which === 'images') {
93231                 d = {
93232                   loc: loc,
93233                   key: item.id,
93234                   ca: +item.heading,
93235                   captured_at: item.shot_date || item.date_added,
93236                   captured_by: item.username,
93237                   imagePath: item.lth_name,
93238                   sequence_id: item.sequence_id,
93239                   sequence_index: +item.sequence_index
93240                 }; // cache sequence info
93241
93242                 var seq = _oscCache.sequences[d.sequence_id];
93243
93244                 if (!seq) {
93245                   seq = {
93246                     rotation: 0,
93247                     images: []
93248                   };
93249                   _oscCache.sequences[d.sequence_id] = seq;
93250                 }
93251
93252                 seq.images[d.sequence_index] = d;
93253                 _oscCache.images.forImageKey[d.key] = d; // cache imageKey -> image
93254               }
93255
93256               return {
93257                 minX: loc[0],
93258                 minY: loc[1],
93259                 maxX: loc[0],
93260                 maxY: loc[1],
93261                 data: d
93262               };
93263             });
93264             cache.rtree.load(features);
93265
93266             if (data.currentPageItems.length === maxResults$1) {
93267               // more pages to load
93268               cache.nextPage[tile.id] = nextPage + 1;
93269               loadNextTilePage$1(which, currZoom, url, tile);
93270             } else {
93271               cache.nextPage[tile.id] = Infinity; // no more pages to load
93272             }
93273
93274             if (which === 'images') {
93275               dispatch$3.call('loadedImages');
93276             }
93277           })["catch"](function () {
93278             cache.loaded[id] = true;
93279             delete cache.inflight[id];
93280           });
93281         } // partition viewport into higher zoom tiles
93282
93283
93284         function partitionViewport$1(projection) {
93285           var z = geoScaleToZoom(projection.scale());
93286           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
93287
93288           var tiler = utilTiler().zoomExtent([z2, z2]);
93289           return tiler.getTiles(projection).map(function (tile) {
93290             return tile.extent;
93291           });
93292         } // no more than `limit` results per partition.
93293
93294
93295         function searchLimited$1(limit, projection, rtree) {
93296           limit = limit || 5;
93297           return partitionViewport$1(projection).reduce(function (result, extent) {
93298             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
93299               return d.data;
93300             });
93301             return found.length ? result.concat(found) : result;
93302           }, []);
93303         }
93304
93305         var serviceOpenstreetcam = {
93306           init: function init() {
93307             if (!_oscCache) {
93308               this.reset();
93309             }
93310
93311             this.event = utilRebind(this, dispatch$3, 'on');
93312           },
93313           reset: function reset() {
93314             if (_oscCache) {
93315               Object.values(_oscCache.images.inflight).forEach(abortRequest$3);
93316             }
93317
93318             _oscCache = {
93319               images: {
93320                 inflight: {},
93321                 loaded: {},
93322                 nextPage: {},
93323                 rtree: new RBush(),
93324                 forImageKey: {}
93325               },
93326               sequences: {}
93327             };
93328             _oscSelectedImage = null;
93329           },
93330           images: function images(projection) {
93331             var limit = 5;
93332             return searchLimited$1(limit, projection, _oscCache.images.rtree);
93333           },
93334           sequences: function sequences(projection) {
93335             var viewport = projection.clipExtent();
93336             var min = [viewport[0][0], viewport[1][1]];
93337             var max = [viewport[1][0], viewport[0][1]];
93338             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
93339             var sequenceKeys = {}; // all sequences for images in viewport
93340
93341             _oscCache.images.rtree.search(bbox).forEach(function (d) {
93342               sequenceKeys[d.data.sequence_id] = true;
93343             }); // make linestrings from those sequences
93344
93345
93346             var lineStrings = [];
93347             Object.keys(sequenceKeys).forEach(function (sequenceKey) {
93348               var seq = _oscCache.sequences[sequenceKey];
93349               var images = seq && seq.images;
93350
93351               if (images) {
93352                 lineStrings.push({
93353                   type: 'LineString',
93354                   coordinates: images.map(function (d) {
93355                     return d.loc;
93356                   }).filter(Boolean),
93357                   properties: {
93358                     captured_at: images[0] ? images[0].captured_at : null,
93359                     captured_by: images[0] ? images[0].captured_by : null,
93360                     key: sequenceKey
93361                   }
93362                 });
93363               }
93364             });
93365             return lineStrings;
93366           },
93367           cachedImage: function cachedImage(imageKey) {
93368             return _oscCache.images.forImageKey[imageKey];
93369           },
93370           loadImages: function loadImages(projection) {
93371             var url = apibase$1 + '/1.0/list/nearby-photos/';
93372             loadTiles$1('images', url, projection);
93373           },
93374           ensureViewerLoaded: function ensureViewerLoaded(context) {
93375             if (_loadViewerPromise$1) return _loadViewerPromise$1; // add osc-wrapper
93376
93377             var wrap = context.container().select('.photoviewer').selectAll('.osc-wrapper').data([0]);
93378             var that = this;
93379             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper osc-wrapper').classed('hide', true).call(imgZoom.on('zoom', zoomPan)).on('dblclick.zoom', null);
93380             wrapEnter.append('div').attr('class', 'photo-attribution fillD');
93381             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
93382             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
93383             controlsEnter.append('button').on('click.rotate-ccw', rotate(-90)).html('⤿');
93384             controlsEnter.append('button').on('click.rotate-cw', rotate(90)).html('⤾');
93385             controlsEnter.append('button').on('click.forward', step(1)).html('►');
93386             wrapEnter.append('div').attr('class', 'osc-image-wrap'); // Register viewer resize handler
93387
93388             context.ui().photoviewer.on('resize.openstreetcam', function (dimensions) {
93389               imgZoom = d3_zoom().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on('zoom', zoomPan);
93390             });
93391
93392             function zoomPan(d3_event) {
93393               var t = d3_event.transform;
93394               context.container().select('.photoviewer .osc-image-wrap').call(utilSetTransform, t.x, t.y, t.k);
93395             }
93396
93397             function rotate(deg) {
93398               return function () {
93399                 if (!_oscSelectedImage) return;
93400                 var sequenceKey = _oscSelectedImage.sequence_id;
93401                 var sequence = _oscCache.sequences[sequenceKey];
93402                 if (!sequence) return;
93403                 var r = sequence.rotation || 0;
93404                 r += deg;
93405                 if (r > 180) r -= 360;
93406                 if (r < -180) r += 360;
93407                 sequence.rotation = r;
93408                 var wrap = context.container().select('.photoviewer .osc-wrapper');
93409                 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
93410                 wrap.selectAll('.osc-image').transition().duration(100).style('transform', 'rotate(' + r + 'deg)');
93411               };
93412             }
93413
93414             function step(stepBy) {
93415               return function () {
93416                 if (!_oscSelectedImage) return;
93417                 var sequenceKey = _oscSelectedImage.sequence_id;
93418                 var sequence = _oscCache.sequences[sequenceKey];
93419                 if (!sequence) return;
93420                 var nextIndex = _oscSelectedImage.sequence_index + stepBy;
93421                 var nextImage = sequence.images[nextIndex];
93422                 if (!nextImage) return;
93423                 context.map().centerEase(nextImage.loc);
93424                 that.selectImage(context, nextImage.key);
93425               };
93426             } // don't need any async loading so resolve immediately
93427
93428
93429             _loadViewerPromise$1 = Promise.resolve();
93430             return _loadViewerPromise$1;
93431           },
93432           showViewer: function showViewer(context) {
93433             var viewer = context.container().select('.photoviewer').classed('hide', false);
93434             var isHidden = viewer.selectAll('.photo-wrapper.osc-wrapper.hide').size();
93435
93436             if (isHidden) {
93437               viewer.selectAll('.photo-wrapper:not(.osc-wrapper)').classed('hide', true);
93438               viewer.selectAll('.photo-wrapper.osc-wrapper').classed('hide', false);
93439             }
93440
93441             return this;
93442           },
93443           hideViewer: function hideViewer(context) {
93444             _oscSelectedImage = null;
93445             this.updateUrlImage(null);
93446             var viewer = context.container().select('.photoviewer');
93447             if (!viewer.empty()) viewer.datum(null);
93448             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
93449             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
93450             return this.setStyles(context, null, true);
93451           },
93452           selectImage: function selectImage(context, imageKey) {
93453             var d = this.cachedImage(imageKey);
93454             _oscSelectedImage = d;
93455             this.updateUrlImage(imageKey);
93456             var viewer = context.container().select('.photoviewer');
93457             if (!viewer.empty()) viewer.datum(d);
93458             this.setStyles(context, null, true);
93459             context.container().selectAll('.icon-sign').classed('currentView', false);
93460             if (!d) return this;
93461             var wrap = context.container().select('.photoviewer .osc-wrapper');
93462             var imageWrap = wrap.selectAll('.osc-image-wrap');
93463             var attribution = wrap.selectAll('.photo-attribution').html('');
93464             wrap.transition().duration(100).call(imgZoom.transform, identity$2);
93465             imageWrap.selectAll('.osc-image').remove();
93466
93467             if (d) {
93468               var sequence = _oscCache.sequences[d.sequence_id];
93469               var r = sequence && sequence.rotation || 0;
93470               imageWrap.append('img').attr('class', 'osc-image').attr('src', apibase$1 + '/' + d.imagePath).style('transform', 'rotate(' + r + 'deg)');
93471
93472               if (d.captured_by) {
93473                 attribution.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)).html('@' + d.captured_by);
93474                 attribution.append('span').html('|');
93475               }
93476
93477               if (d.captured_at) {
93478                 attribution.append('span').attr('class', 'captured_at').html(localeDateString(d.captured_at));
93479                 attribution.append('span').html('|');
93480               }
93481
93482               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');
93483             }
93484
93485             return this;
93486
93487             function localeDateString(s) {
93488               if (!s) return null;
93489               var options = {
93490                 day: 'numeric',
93491                 month: 'short',
93492                 year: 'numeric'
93493               };
93494               var d = new Date(s);
93495               if (isNaN(d.getTime())) return null;
93496               return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
93497             }
93498           },
93499           getSelectedImage: function getSelectedImage() {
93500             return _oscSelectedImage;
93501           },
93502           getSequenceKeyForImage: function getSequenceKeyForImage(d) {
93503             return d && d.sequence_id;
93504           },
93505           // Updates the currently highlighted sequence and selected bubble.
93506           // Reset is only necessary when interacting with the viewport because
93507           // this implicitly changes the currently selected bubble/sequence
93508           setStyles: function setStyles(context, hovered, reset) {
93509             if (reset) {
93510               // reset all layers
93511               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
93512               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
93513             }
93514
93515             var hoveredImageKey = hovered && hovered.key;
93516             var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
93517             var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
93518             var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function (d) {
93519               return d.key;
93520             }) || [];
93521             var viewer = context.container().select('.photoviewer');
93522             var selected = viewer.empty() ? undefined : viewer.datum();
93523             var selectedImageKey = selected && selected.key;
93524             var selectedSequenceKey = this.getSequenceKeyForImage(selected);
93525             var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
93526             var selectedImageKeys = selectedSequence && selectedSequence.images.map(function (d) {
93527               return d.key;
93528             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
93529
93530             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
93531             context.container().selectAll('.layer-openstreetcam .viewfield-group').classed('highlighted', function (d) {
93532               return highlightedImageKeys.indexOf(d.key) !== -1;
93533             }).classed('hovered', function (d) {
93534               return d.key === hoveredImageKey;
93535             }).classed('currentView', function (d) {
93536               return d.key === selectedImageKey;
93537             });
93538             context.container().selectAll('.layer-openstreetcam .sequence').classed('highlighted', function (d) {
93539               return d.properties.key === hoveredSequenceKey;
93540             }).classed('currentView', function (d) {
93541               return d.properties.key === selectedSequenceKey;
93542             }); // update viewfields if needed
93543
93544             context.container().selectAll('.layer-openstreetcam .viewfield-group .viewfield').attr('d', viewfieldPath);
93545
93546             function viewfieldPath() {
93547               var d = this.parentNode.__data__;
93548
93549               if (d.pano && d.key !== selectedImageKey) {
93550                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
93551               } else {
93552                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
93553               }
93554             }
93555
93556             return this;
93557           },
93558           updateUrlImage: function updateUrlImage(imageKey) {
93559             if (!window.mocha) {
93560               var hash = utilStringQs(window.location.hash);
93561
93562               if (imageKey) {
93563                 hash.photo = 'openstreetcam/' + imageKey;
93564               } else {
93565                 delete hash.photo;
93566               }
93567
93568               window.location.replace('#' + utilQsString(hash, true));
93569             }
93570           },
93571           cache: function cache() {
93572             return _oscCache;
93573           }
93574         };
93575
93576         var hashes$1 = {exports: {}};
93577
93578         (function (module, exports) {
93579           (function () {
93580             var Hashes;
93581
93582             function utf8Encode(str) {
93583               var x,
93584                   y,
93585                   output = '',
93586                   i = -1,
93587                   l;
93588
93589               if (str && str.length) {
93590                 l = str.length;
93591
93592                 while ((i += 1) < l) {
93593                   /* Decode utf-16 surrogate pairs */
93594                   x = str.charCodeAt(i);
93595                   y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
93596
93597                   if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
93598                     x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
93599                     i += 1;
93600                   }
93601                   /* Encode output as utf-8 */
93602
93603
93604                   if (x <= 0x7F) {
93605                     output += String.fromCharCode(x);
93606                   } else if (x <= 0x7FF) {
93607                     output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F);
93608                   } else if (x <= 0xFFFF) {
93609                     output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
93610                   } else if (x <= 0x1FFFFF) {
93611                     output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
93612                   }
93613                 }
93614               }
93615
93616               return output;
93617             }
93618
93619             function utf8Decode(str) {
93620               var i,
93621                   ac,
93622                   c1,
93623                   c2,
93624                   c3,
93625                   arr = [],
93626                   l;
93627               i = ac = c1 = c2 = c3 = 0;
93628
93629               if (str && str.length) {
93630                 l = str.length;
93631                 str += '';
93632
93633                 while (i < l) {
93634                   c1 = str.charCodeAt(i);
93635                   ac += 1;
93636
93637                   if (c1 < 128) {
93638                     arr[ac] = String.fromCharCode(c1);
93639                     i += 1;
93640                   } else if (c1 > 191 && c1 < 224) {
93641                     c2 = str.charCodeAt(i + 1);
93642                     arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
93643                     i += 2;
93644                   } else {
93645                     c2 = str.charCodeAt(i + 1);
93646                     c3 = str.charCodeAt(i + 2);
93647                     arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
93648                     i += 3;
93649                   }
93650                 }
93651               }
93652
93653               return arr.join('');
93654             }
93655             /**
93656              * Add integers, wrapping at 2^32. This uses 16-bit operations internally
93657              * to work around bugs in some JS interpreters.
93658              */
93659
93660
93661             function safe_add(x, y) {
93662               var lsw = (x & 0xFFFF) + (y & 0xFFFF),
93663                   msw = (x >> 16) + (y >> 16) + (lsw >> 16);
93664               return msw << 16 | lsw & 0xFFFF;
93665             }
93666             /**
93667              * Bitwise rotate a 32-bit number to the left.
93668              */
93669
93670
93671             function bit_rol(num, cnt) {
93672               return num << cnt | num >>> 32 - cnt;
93673             }
93674             /**
93675              * Convert a raw string to a hex string
93676              */
93677
93678
93679             function rstr2hex(input, hexcase) {
93680               var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
93681                   output = '',
93682                   x,
93683                   i = 0,
93684                   l = input.length;
93685
93686               for (; i < l; i += 1) {
93687                 x = input.charCodeAt(i);
93688                 output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F);
93689               }
93690
93691               return output;
93692             }
93693             /**
93694              * Convert an array of big-endian words to a string
93695              */
93696
93697
93698             function binb2rstr(input) {
93699               var i,
93700                   l = input.length * 32,
93701                   output = '';
93702
93703               for (i = 0; i < l; i += 8) {
93704                 output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF);
93705               }
93706
93707               return output;
93708             }
93709             /**
93710              * Convert an array of little-endian words to a string
93711              */
93712
93713
93714             function binl2rstr(input) {
93715               var i,
93716                   l = input.length * 32,
93717                   output = '';
93718
93719               for (i = 0; i < l; i += 8) {
93720                 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
93721               }
93722
93723               return output;
93724             }
93725             /**
93726              * Convert a raw string to an array of little-endian words
93727              * Characters >255 have their high-byte silently ignored.
93728              */
93729
93730
93731             function rstr2binl(input) {
93732               var i,
93733                   l = input.length * 8,
93734                   output = Array(input.length >> 2),
93735                   lo = output.length;
93736
93737               for (i = 0; i < lo; i += 1) {
93738                 output[i] = 0;
93739               }
93740
93741               for (i = 0; i < l; i += 8) {
93742                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32;
93743               }
93744
93745               return output;
93746             }
93747             /**
93748              * Convert a raw string to an array of big-endian words
93749              * Characters >255 have their high-byte silently ignored.
93750              */
93751
93752
93753             function rstr2binb(input) {
93754               var i,
93755                   l = input.length * 8,
93756                   output = Array(input.length >> 2),
93757                   lo = output.length;
93758
93759               for (i = 0; i < lo; i += 1) {
93760                 output[i] = 0;
93761               }
93762
93763               for (i = 0; i < l; i += 8) {
93764                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32;
93765               }
93766
93767               return output;
93768             }
93769             /**
93770              * Convert a raw string to an arbitrary string encoding
93771              */
93772
93773
93774             function rstr2any(input, encoding) {
93775               var divisor = encoding.length,
93776                   remainders = Array(),
93777                   i,
93778                   q,
93779                   x,
93780                   ld,
93781                   quotient,
93782                   dividend,
93783                   output,
93784                   full_length;
93785               /* Convert to an array of 16-bit big-endian values, forming the dividend */
93786
93787               dividend = Array(Math.ceil(input.length / 2));
93788               ld = dividend.length;
93789
93790               for (i = 0; i < ld; i += 1) {
93791                 dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1);
93792               }
93793               /**
93794                * Repeatedly perform a long division. The binary array forms the dividend,
93795                * the length of the encoding is the divisor. Once computed, the quotient
93796                * forms the dividend for the next step. We stop when the dividend is zerHashes.
93797                * All remainders are stored for later use.
93798                */
93799
93800
93801               while (dividend.length > 0) {
93802                 quotient = Array();
93803                 x = 0;
93804
93805                 for (i = 0; i < dividend.length; i += 1) {
93806                   x = (x << 16) + dividend[i];
93807                   q = Math.floor(x / divisor);
93808                   x -= q * divisor;
93809
93810                   if (quotient.length > 0 || q > 0) {
93811                     quotient[quotient.length] = q;
93812                   }
93813                 }
93814
93815                 remainders[remainders.length] = x;
93816                 dividend = quotient;
93817               }
93818               /* Convert the remainders to the output string */
93819
93820
93821               output = '';
93822
93823               for (i = remainders.length - 1; i >= 0; i--) {
93824                 output += encoding.charAt(remainders[i]);
93825               }
93826               /* Append leading zero equivalents */
93827
93828
93829               full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
93830
93831               for (i = output.length; i < full_length; i += 1) {
93832                 output = encoding[0] + output;
93833               }
93834
93835               return output;
93836             }
93837             /**
93838              * Convert a raw string to a base-64 string
93839              */
93840
93841
93842             function rstr2b64(input, b64pad) {
93843               var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
93844                   output = '',
93845                   len = input.length,
93846                   i,
93847                   j,
93848                   triplet;
93849               b64pad = b64pad || '=';
93850
93851               for (i = 0; i < len; i += 3) {
93852                 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
93853
93854                 for (j = 0; j < 4; j += 1) {
93855                   if (i * 8 + j * 6 > input.length * 8) {
93856                     output += b64pad;
93857                   } else {
93858                     output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
93859                   }
93860                 }
93861               }
93862
93863               return output;
93864             }
93865
93866             Hashes = {
93867               /**
93868                * @property {String} version
93869                * @readonly
93870                */
93871               VERSION: '1.0.6',
93872
93873               /**
93874                * @member Hashes
93875                * @class Base64
93876                * @constructor
93877                */
93878               Base64: function Base64() {
93879                 // private properties
93880                 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
93881                     pad = '=',
93882                     // URL encoding support @todo
93883                 utf8 = true; // by default enable UTF-8 support encoding
93884                 // public method for encoding
93885
93886                 this.encode = function (input) {
93887                   var i,
93888                       j,
93889                       triplet,
93890                       output = '',
93891                       len = input.length;
93892                   pad = pad || '=';
93893                   input = utf8 ? utf8Encode(input) : input;
93894
93895                   for (i = 0; i < len; i += 3) {
93896                     triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
93897
93898                     for (j = 0; j < 4; j += 1) {
93899                       if (i * 8 + j * 6 > len * 8) {
93900                         output += pad;
93901                       } else {
93902                         output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
93903                       }
93904                     }
93905                   }
93906
93907                   return output;
93908                 }; // public method for decoding
93909
93910
93911                 this.decode = function (input) {
93912                   // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
93913                   var i,
93914                       o1,
93915                       o2,
93916                       o3,
93917                       h1,
93918                       h2,
93919                       h3,
93920                       h4,
93921                       bits,
93922                       ac,
93923                       dec = '',
93924                       arr = [];
93925
93926                   if (!input) {
93927                     return input;
93928                   }
93929
93930                   i = ac = 0;
93931                   input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
93932                   //input += '';
93933
93934                   do {
93935                     // unpack four hexets into three octets using index points in b64
93936                     h1 = tab.indexOf(input.charAt(i += 1));
93937                     h2 = tab.indexOf(input.charAt(i += 1));
93938                     h3 = tab.indexOf(input.charAt(i += 1));
93939                     h4 = tab.indexOf(input.charAt(i += 1));
93940                     bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
93941                     o1 = bits >> 16 & 0xff;
93942                     o2 = bits >> 8 & 0xff;
93943                     o3 = bits & 0xff;
93944                     ac += 1;
93945
93946                     if (h3 === 64) {
93947                       arr[ac] = String.fromCharCode(o1);
93948                     } else if (h4 === 64) {
93949                       arr[ac] = String.fromCharCode(o1, o2);
93950                     } else {
93951                       arr[ac] = String.fromCharCode(o1, o2, o3);
93952                     }
93953                   } while (i < input.length);
93954
93955                   dec = arr.join('');
93956                   dec = utf8 ? utf8Decode(dec) : dec;
93957                   return dec;
93958                 }; // set custom pad string
93959
93960
93961                 this.setPad = function (str) {
93962                   pad = str || pad;
93963                   return this;
93964                 }; // set custom tab string characters
93965
93966
93967                 this.setTab = function (str) {
93968                   tab = str || tab;
93969                   return this;
93970                 };
93971
93972                 this.setUTF8 = function (bool) {
93973                   if (typeof bool === 'boolean') {
93974                     utf8 = bool;
93975                   }
93976
93977                   return this;
93978                 };
93979               },
93980
93981               /**
93982                * CRC-32 calculation
93983                * @member Hashes
93984                * @method CRC32
93985                * @static
93986                * @param {String} str Input String
93987                * @return {String}
93988                */
93989               CRC32: function CRC32(str) {
93990                 var crc = 0,
93991                     x = 0,
93992                     y = 0,
93993                     table,
93994                     i,
93995                     iTop;
93996                 str = utf8Encode(str);
93997                 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('');
93998                 crc = crc ^ -1;
93999
94000                 for (i = 0, iTop = str.length; i < iTop; i += 1) {
94001                   y = (crc ^ str.charCodeAt(i)) & 0xFF;
94002                   x = '0x' + table.substr(y * 9, 8);
94003                   crc = crc >>> 8 ^ x;
94004                 } // always return a positive number (that's what >>> 0 does)
94005
94006
94007                 return (crc ^ -1) >>> 0;
94008               },
94009
94010               /**
94011                * @member Hashes
94012                * @class MD5
94013                * @constructor
94014                * @param {Object} [config]
94015                *
94016                * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
94017                * Digest Algorithm, as defined in RFC 1321.
94018                * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
94019                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94020                * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
94021                */
94022               MD5: function MD5(options) {
94023                 /**
94024                  * Private config properties. You may need to tweak these to be compatible with
94025                  * the server-side, but the defaults work in most cases.
94026                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
94027                  */
94028                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
94029                     // hexadecimal output case format. false - lowercase; true - uppercase
94030                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94031                     // base-64 pad character. Defaults to '=' for strict RFC compliance
94032                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
94033                 // privileged (public) methods
94034
94035                 this.hex = function (s) {
94036                   return rstr2hex(rstr(s), hexcase);
94037                 };
94038
94039                 this.b64 = function (s) {
94040                   return rstr2b64(rstr(s), b64pad);
94041                 };
94042
94043                 this.any = function (s, e) {
94044                   return rstr2any(rstr(s), e);
94045                 };
94046
94047                 this.raw = function (s) {
94048                   return rstr(s);
94049                 };
94050
94051                 this.hex_hmac = function (k, d) {
94052                   return rstr2hex(rstr_hmac(k, d), hexcase);
94053                 };
94054
94055                 this.b64_hmac = function (k, d) {
94056                   return rstr2b64(rstr_hmac(k, d), b64pad);
94057                 };
94058
94059                 this.any_hmac = function (k, d, e) {
94060                   return rstr2any(rstr_hmac(k, d), e);
94061                 };
94062                 /**
94063                  * Perform a simple self-test to see if the VM is working
94064                  * @return {String} Hexadecimal hash sample
94065                  */
94066
94067
94068                 this.vm_test = function () {
94069                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94070                 };
94071                 /**
94072                  * Enable/disable uppercase hexadecimal returned string
94073                  * @param {Boolean}
94074                  * @return {Object} this
94075                  */
94076
94077
94078                 this.setUpperCase = function (a) {
94079                   if (typeof a === 'boolean') {
94080                     hexcase = a;
94081                   }
94082
94083                   return this;
94084                 };
94085                 /**
94086                  * Defines a base64 pad string
94087                  * @param {String} Pad
94088                  * @return {Object} this
94089                  */
94090
94091
94092                 this.setPad = function (a) {
94093                   b64pad = a || b64pad;
94094                   return this;
94095                 };
94096                 /**
94097                  * Defines a base64 pad string
94098                  * @param {Boolean}
94099                  * @return {Object} [this]
94100                  */
94101
94102
94103                 this.setUTF8 = function (a) {
94104                   if (typeof a === 'boolean') {
94105                     utf8 = a;
94106                   }
94107
94108                   return this;
94109                 }; // private methods
94110
94111                 /**
94112                  * Calculate the MD5 of a raw string
94113                  */
94114
94115
94116                 function rstr(s) {
94117                   s = utf8 ? utf8Encode(s) : s;
94118                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
94119                 }
94120                 /**
94121                  * Calculate the HMAC-MD5, of a key and some data (raw strings)
94122                  */
94123
94124
94125                 function rstr_hmac(key, data) {
94126                   var bkey, ipad, opad, hash, i;
94127                   key = utf8 ? utf8Encode(key) : key;
94128                   data = utf8 ? utf8Encode(data) : data;
94129                   bkey = rstr2binl(key);
94130
94131                   if (bkey.length > 16) {
94132                     bkey = binl(bkey, key.length * 8);
94133                   }
94134
94135                   ipad = Array(16), opad = Array(16);
94136
94137                   for (i = 0; i < 16; i += 1) {
94138                     ipad[i] = bkey[i] ^ 0x36363636;
94139                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
94140                   }
94141
94142                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
94143                   return binl2rstr(binl(opad.concat(hash), 512 + 128));
94144                 }
94145                 /**
94146                  * Calculate the MD5 of an array of little-endian words, and a bit length.
94147                  */
94148
94149
94150                 function binl(x, len) {
94151                   var i,
94152                       olda,
94153                       oldb,
94154                       oldc,
94155                       oldd,
94156                       a = 1732584193,
94157                       b = -271733879,
94158                       c = -1732584194,
94159                       d = 271733878;
94160                   /* append padding */
94161
94162                   x[len >> 5] |= 0x80 << len % 32;
94163                   x[(len + 64 >>> 9 << 4) + 14] = len;
94164
94165                   for (i = 0; i < x.length; i += 16) {
94166                     olda = a;
94167                     oldb = b;
94168                     oldc = c;
94169                     oldd = d;
94170                     a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
94171                     d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
94172                     c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
94173                     b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
94174                     a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
94175                     d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
94176                     c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
94177                     b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
94178                     a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
94179                     d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
94180                     c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
94181                     b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
94182                     a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
94183                     d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
94184                     c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
94185                     b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
94186                     a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
94187                     d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
94188                     c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
94189                     b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
94190                     a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
94191                     d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
94192                     c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
94193                     b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
94194                     a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
94195                     d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
94196                     c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
94197                     b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
94198                     a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
94199                     d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
94200                     c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
94201                     b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
94202                     a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
94203                     d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
94204                     c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
94205                     b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
94206                     a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
94207                     d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
94208                     c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
94209                     b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
94210                     a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
94211                     d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
94212                     c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
94213                     b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
94214                     a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
94215                     d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
94216                     c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
94217                     b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
94218                     a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
94219                     d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
94220                     c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
94221                     b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
94222                     a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
94223                     d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
94224                     c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
94225                     b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
94226                     a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
94227                     d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
94228                     c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
94229                     b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
94230                     a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
94231                     d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
94232                     c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
94233                     b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
94234                     a = safe_add(a, olda);
94235                     b = safe_add(b, oldb);
94236                     c = safe_add(c, oldc);
94237                     d = safe_add(d, oldd);
94238                   }
94239
94240                   return Array(a, b, c, d);
94241                 }
94242                 /**
94243                  * These functions implement the four basic operations the algorithm uses.
94244                  */
94245
94246
94247                 function md5_cmn(q, a, b, x, s, t) {
94248                   return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
94249                 }
94250
94251                 function md5_ff(a, b, c, d, x, s, t) {
94252                   return md5_cmn(b & c | ~b & d, a, b, x, s, t);
94253                 }
94254
94255                 function md5_gg(a, b, c, d, x, s, t) {
94256                   return md5_cmn(b & d | c & ~d, a, b, x, s, t);
94257                 }
94258
94259                 function md5_hh(a, b, c, d, x, s, t) {
94260                   return md5_cmn(b ^ c ^ d, a, b, x, s, t);
94261                 }
94262
94263                 function md5_ii(a, b, c, d, x, s, t) {
94264                   return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
94265                 }
94266               },
94267
94268               /**
94269                * @member Hashes
94270                * @class Hashes.SHA1
94271                * @param {Object} [config]
94272                * @constructor
94273                *
94274                * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
94275                * Version 2.2 Copyright Paul Johnston 2000 - 2009.
94276                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94277                * See http://pajhome.org.uk/crypt/md5 for details.
94278                */
94279               SHA1: function SHA1(options) {
94280                 /**
94281                  * Private config properties. You may need to tweak these to be compatible with
94282                  * the server-side, but the defaults work in most cases.
94283                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
94284                  */
94285                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
94286                     // hexadecimal output case format. false - lowercase; true - uppercase
94287                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94288                     // base-64 pad character. Defaults to '=' for strict RFC compliance
94289                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
94290                 // public methods
94291
94292                 this.hex = function (s) {
94293                   return rstr2hex(rstr(s), hexcase);
94294                 };
94295
94296                 this.b64 = function (s) {
94297                   return rstr2b64(rstr(s), b64pad);
94298                 };
94299
94300                 this.any = function (s, e) {
94301                   return rstr2any(rstr(s), e);
94302                 };
94303
94304                 this.raw = function (s) {
94305                   return rstr(s);
94306                 };
94307
94308                 this.hex_hmac = function (k, d) {
94309                   return rstr2hex(rstr_hmac(k, d));
94310                 };
94311
94312                 this.b64_hmac = function (k, d) {
94313                   return rstr2b64(rstr_hmac(k, d), b64pad);
94314                 };
94315
94316                 this.any_hmac = function (k, d, e) {
94317                   return rstr2any(rstr_hmac(k, d), e);
94318                 };
94319                 /**
94320                  * Perform a simple self-test to see if the VM is working
94321                  * @return {String} Hexadecimal hash sample
94322                  * @public
94323                  */
94324
94325
94326                 this.vm_test = function () {
94327                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94328                 };
94329                 /**
94330                  * @description Enable/disable uppercase hexadecimal returned string
94331                  * @param {boolean}
94332                  * @return {Object} this
94333                  * @public
94334                  */
94335
94336
94337                 this.setUpperCase = function (a) {
94338                   if (typeof a === 'boolean') {
94339                     hexcase = a;
94340                   }
94341
94342                   return this;
94343                 };
94344                 /**
94345                  * @description Defines a base64 pad string
94346                  * @param {string} Pad
94347                  * @return {Object} this
94348                  * @public
94349                  */
94350
94351
94352                 this.setPad = function (a) {
94353                   b64pad = a || b64pad;
94354                   return this;
94355                 };
94356                 /**
94357                  * @description Defines a base64 pad string
94358                  * @param {boolean}
94359                  * @return {Object} this
94360                  * @public
94361                  */
94362
94363
94364                 this.setUTF8 = function (a) {
94365                   if (typeof a === 'boolean') {
94366                     utf8 = a;
94367                   }
94368
94369                   return this;
94370                 }; // private methods
94371
94372                 /**
94373                  * Calculate the SHA-512 of a raw string
94374                  */
94375
94376
94377                 function rstr(s) {
94378                   s = utf8 ? utf8Encode(s) : s;
94379                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
94380                 }
94381                 /**
94382                  * Calculate the HMAC-SHA1 of a key and some data (raw strings)
94383                  */
94384
94385
94386                 function rstr_hmac(key, data) {
94387                   var bkey, ipad, opad, i, hash;
94388                   key = utf8 ? utf8Encode(key) : key;
94389                   data = utf8 ? utf8Encode(data) : data;
94390                   bkey = rstr2binb(key);
94391
94392                   if (bkey.length > 16) {
94393                     bkey = binb(bkey, key.length * 8);
94394                   }
94395
94396                   ipad = Array(16), opad = Array(16);
94397
94398                   for (i = 0; i < 16; i += 1) {
94399                     ipad[i] = bkey[i] ^ 0x36363636;
94400                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
94401                   }
94402
94403                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
94404                   return binb2rstr(binb(opad.concat(hash), 512 + 160));
94405                 }
94406                 /**
94407                  * Calculate the SHA-1 of an array of big-endian words, and a bit length
94408                  */
94409
94410
94411                 function binb(x, len) {
94412                   var i,
94413                       j,
94414                       t,
94415                       olda,
94416                       oldb,
94417                       oldc,
94418                       oldd,
94419                       olde,
94420                       w = Array(80),
94421                       a = 1732584193,
94422                       b = -271733879,
94423                       c = -1732584194,
94424                       d = 271733878,
94425                       e = -1009589776;
94426                   /* append padding */
94427
94428                   x[len >> 5] |= 0x80 << 24 - len % 32;
94429                   x[(len + 64 >> 9 << 4) + 15] = len;
94430
94431                   for (i = 0; i < x.length; i += 16) {
94432                     olda = a;
94433                     oldb = b;
94434                     oldc = c;
94435                     oldd = d;
94436                     olde = e;
94437
94438                     for (j = 0; j < 80; j += 1) {
94439                       if (j < 16) {
94440                         w[j] = x[i + j];
94441                       } else {
94442                         w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
94443                       }
94444
94445                       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)));
94446                       e = d;
94447                       d = c;
94448                       c = bit_rol(b, 30);
94449                       b = a;
94450                       a = t;
94451                     }
94452
94453                     a = safe_add(a, olda);
94454                     b = safe_add(b, oldb);
94455                     c = safe_add(c, oldc);
94456                     d = safe_add(d, oldd);
94457                     e = safe_add(e, olde);
94458                   }
94459
94460                   return Array(a, b, c, d, e);
94461                 }
94462                 /**
94463                  * Perform the appropriate triplet combination function for the current
94464                  * iteration
94465                  */
94466
94467
94468                 function sha1_ft(t, b, c, d) {
94469                   if (t < 20) {
94470                     return b & c | ~b & d;
94471                   }
94472
94473                   if (t < 40) {
94474                     return b ^ c ^ d;
94475                   }
94476
94477                   if (t < 60) {
94478                     return b & c | b & d | c & d;
94479                   }
94480
94481                   return b ^ c ^ d;
94482                 }
94483                 /**
94484                  * Determine the appropriate additive constant for the current iteration
94485                  */
94486
94487
94488                 function sha1_kt(t) {
94489                   return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;
94490                 }
94491               },
94492
94493               /**
94494                * @class Hashes.SHA256
94495                * @param {config}
94496                *
94497                * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
94498                * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
94499                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94500                * See http://pajhome.org.uk/crypt/md5 for details.
94501                * Also http://anmar.eu.org/projects/jssha2/
94502                */
94503               SHA256: function SHA256(options) {
94504                 /**
94505                  * Private properties configuration variables. You may need to tweak these to be compatible with
94506                  * the server-side, but the defaults work in most cases.
94507                  * @see this.setUpperCase() method
94508                  * @see this.setPad() method
94509                  */
94510                 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
94511                     var // hexadecimal output case format. false - lowercase; true - uppercase  */
94512                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94513
94514                 /* base-64 pad character. Default '=' for strict RFC compliance   */
94515                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
94516
94517                 /* enable/disable utf8 encoding */
94518                 sha256_K;
94519                 /* privileged (public) methods */
94520
94521                 this.hex = function (s) {
94522                   return rstr2hex(rstr(s, utf8));
94523                 };
94524
94525                 this.b64 = function (s) {
94526                   return rstr2b64(rstr(s, utf8), b64pad);
94527                 };
94528
94529                 this.any = function (s, e) {
94530                   return rstr2any(rstr(s, utf8), e);
94531                 };
94532
94533                 this.raw = function (s) {
94534                   return rstr(s, utf8);
94535                 };
94536
94537                 this.hex_hmac = function (k, d) {
94538                   return rstr2hex(rstr_hmac(k, d));
94539                 };
94540
94541                 this.b64_hmac = function (k, d) {
94542                   return rstr2b64(rstr_hmac(k, d), b64pad);
94543                 };
94544
94545                 this.any_hmac = function (k, d, e) {
94546                   return rstr2any(rstr_hmac(k, d), e);
94547                 };
94548                 /**
94549                  * Perform a simple self-test to see if the VM is working
94550                  * @return {String} Hexadecimal hash sample
94551                  * @public
94552                  */
94553
94554
94555                 this.vm_test = function () {
94556                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94557                 };
94558                 /**
94559                  * Enable/disable uppercase hexadecimal returned string
94560                  * @param {boolean}
94561                  * @return {Object} this
94562                  * @public
94563                  */
94564
94565
94566                 this.setUpperCase = function (a) {
94567
94568                   return this;
94569                 };
94570                 /**
94571                  * @description Defines a base64 pad string
94572                  * @param {string} Pad
94573                  * @return {Object} this
94574                  * @public
94575                  */
94576
94577
94578                 this.setPad = function (a) {
94579                   b64pad = a || b64pad;
94580                   return this;
94581                 };
94582                 /**
94583                  * Defines a base64 pad string
94584                  * @param {boolean}
94585                  * @return {Object} this
94586                  * @public
94587                  */
94588
94589
94590                 this.setUTF8 = function (a) {
94591                   if (typeof a === 'boolean') {
94592                     utf8 = a;
94593                   }
94594
94595                   return this;
94596                 }; // private methods
94597
94598                 /**
94599                  * Calculate the SHA-512 of a raw string
94600                  */
94601
94602
94603                 function rstr(s, utf8) {
94604                   s = utf8 ? utf8Encode(s) : s;
94605                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
94606                 }
94607                 /**
94608                  * Calculate the HMAC-sha256 of a key and some data (raw strings)
94609                  */
94610
94611
94612                 function rstr_hmac(key, data) {
94613                   key = utf8 ? utf8Encode(key) : key;
94614                   data = utf8 ? utf8Encode(data) : data;
94615                   var hash,
94616                       i = 0,
94617                       bkey = rstr2binb(key),
94618                       ipad = Array(16),
94619                       opad = Array(16);
94620
94621                   if (bkey.length > 16) {
94622                     bkey = binb(bkey, key.length * 8);
94623                   }
94624
94625                   for (; i < 16; i += 1) {
94626                     ipad[i] = bkey[i] ^ 0x36363636;
94627                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
94628                   }
94629
94630                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
94631                   return binb2rstr(binb(opad.concat(hash), 512 + 256));
94632                 }
94633                 /*
94634                  * Main sha256 function, with its support functions
94635                  */
94636
94637
94638                 function sha256_S(X, n) {
94639                   return X >>> n | X << 32 - n;
94640                 }
94641
94642                 function sha256_R(X, n) {
94643                   return X >>> n;
94644                 }
94645
94646                 function sha256_Ch(x, y, z) {
94647                   return x & y ^ ~x & z;
94648                 }
94649
94650                 function sha256_Maj(x, y, z) {
94651                   return x & y ^ x & z ^ y & z;
94652                 }
94653
94654                 function sha256_Sigma0256(x) {
94655                   return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22);
94656                 }
94657
94658                 function sha256_Sigma1256(x) {
94659                   return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25);
94660                 }
94661
94662                 function sha256_Gamma0256(x) {
94663                   return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3);
94664                 }
94665
94666                 function sha256_Gamma1256(x) {
94667                   return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10);
94668                 }
94669
94670                 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];
94671
94672                 function binb(m, l) {
94673                   var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225];
94674                   var W = new Array(64);
94675                   var a, b, c, d, e, f, g, h;
94676                   var i, j, T1, T2;
94677                   /* append padding */
94678
94679                   m[l >> 5] |= 0x80 << 24 - l % 32;
94680                   m[(l + 64 >> 9 << 4) + 15] = l;
94681
94682                   for (i = 0; i < m.length; i += 16) {
94683                     a = HASH[0];
94684                     b = HASH[1];
94685                     c = HASH[2];
94686                     d = HASH[3];
94687                     e = HASH[4];
94688                     f = HASH[5];
94689                     g = HASH[6];
94690                     h = HASH[7];
94691
94692                     for (j = 0; j < 64; j += 1) {
94693                       if (j < 16) {
94694                         W[j] = m[j + i];
94695                       } else {
94696                         W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]);
94697                       }
94698
94699                       T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]);
94700                       T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
94701                       h = g;
94702                       g = f;
94703                       f = e;
94704                       e = safe_add(d, T1);
94705                       d = c;
94706                       c = b;
94707                       b = a;
94708                       a = safe_add(T1, T2);
94709                     }
94710
94711                     HASH[0] = safe_add(a, HASH[0]);
94712                     HASH[1] = safe_add(b, HASH[1]);
94713                     HASH[2] = safe_add(c, HASH[2]);
94714                     HASH[3] = safe_add(d, HASH[3]);
94715                     HASH[4] = safe_add(e, HASH[4]);
94716                     HASH[5] = safe_add(f, HASH[5]);
94717                     HASH[6] = safe_add(g, HASH[6]);
94718                     HASH[7] = safe_add(h, HASH[7]);
94719                   }
94720
94721                   return HASH;
94722                 }
94723               },
94724
94725               /**
94726                * @class Hashes.SHA512
94727                * @param {config}
94728                *
94729                * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
94730                * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
94731                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94732                * See http://pajhome.org.uk/crypt/md5 for details.
94733                */
94734               SHA512: function SHA512(options) {
94735                 /**
94736                  * Private properties configuration variables. You may need to tweak these to be compatible with
94737                  * the server-side, but the defaults work in most cases.
94738                  * @see this.setUpperCase() method
94739                  * @see this.setPad() method
94740                  */
94741                 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
94742
94743                 var /* hexadecimal output case format. false - lowercase; true - uppercase  */
94744                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94745
94746                 /* base-64 pad character. Default '=' for strict RFC compliance   */
94747                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
94748
94749                 /* enable/disable utf8 encoding */
94750                 sha512_k;
94751                 /* privileged (public) methods */
94752
94753                 this.hex = function (s) {
94754                   return rstr2hex(rstr(s));
94755                 };
94756
94757                 this.b64 = function (s) {
94758                   return rstr2b64(rstr(s), b64pad);
94759                 };
94760
94761                 this.any = function (s, e) {
94762                   return rstr2any(rstr(s), e);
94763                 };
94764
94765                 this.raw = function (s) {
94766                   return rstr(s);
94767                 };
94768
94769                 this.hex_hmac = function (k, d) {
94770                   return rstr2hex(rstr_hmac(k, d));
94771                 };
94772
94773                 this.b64_hmac = function (k, d) {
94774                   return rstr2b64(rstr_hmac(k, d), b64pad);
94775                 };
94776
94777                 this.any_hmac = function (k, d, e) {
94778                   return rstr2any(rstr_hmac(k, d), e);
94779                 };
94780                 /**
94781                  * Perform a simple self-test to see if the VM is working
94782                  * @return {String} Hexadecimal hash sample
94783                  * @public
94784                  */
94785
94786
94787                 this.vm_test = function () {
94788                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94789                 };
94790                 /**
94791                  * @description Enable/disable uppercase hexadecimal returned string
94792                  * @param {boolean}
94793                  * @return {Object} this
94794                  * @public
94795                  */
94796
94797
94798                 this.setUpperCase = function (a) {
94799
94800                   return this;
94801                 };
94802                 /**
94803                  * @description Defines a base64 pad string
94804                  * @param {string} Pad
94805                  * @return {Object} this
94806                  * @public
94807                  */
94808
94809
94810                 this.setPad = function (a) {
94811                   b64pad = a || b64pad;
94812                   return this;
94813                 };
94814                 /**
94815                  * @description Defines a base64 pad string
94816                  * @param {boolean}
94817                  * @return {Object} this
94818                  * @public
94819                  */
94820
94821
94822                 this.setUTF8 = function (a) {
94823                   if (typeof a === 'boolean') {
94824                     utf8 = a;
94825                   }
94826
94827                   return this;
94828                 };
94829                 /* private methods */
94830
94831                 /**
94832                  * Calculate the SHA-512 of a raw string
94833                  */
94834
94835
94836                 function rstr(s) {
94837                   s = utf8 ? utf8Encode(s) : s;
94838                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
94839                 }
94840                 /*
94841                  * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
94842                  */
94843
94844
94845                 function rstr_hmac(key, data) {
94846                   key = utf8 ? utf8Encode(key) : key;
94847                   data = utf8 ? utf8Encode(data) : data;
94848                   var hash,
94849                       i = 0,
94850                       bkey = rstr2binb(key),
94851                       ipad = Array(32),
94852                       opad = Array(32);
94853
94854                   if (bkey.length > 32) {
94855                     bkey = binb(bkey, key.length * 8);
94856                   }
94857
94858                   for (; i < 32; i += 1) {
94859                     ipad[i] = bkey[i] ^ 0x36363636;
94860                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
94861                   }
94862
94863                   hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
94864                   return binb2rstr(binb(opad.concat(hash), 1024 + 512));
94865                 }
94866                 /**
94867                  * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
94868                  */
94869
94870
94871                 function binb(x, len) {
94872                   var j,
94873                       i,
94874                       l,
94875                       W = new Array(80),
94876                       hash = new Array(16),
94877                       //Initial hash values
94878                   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)],
94879                       T1 = new int64(0, 0),
94880                       T2 = new int64(0, 0),
94881                       a = new int64(0, 0),
94882                       b = new int64(0, 0),
94883                       c = new int64(0, 0),
94884                       d = new int64(0, 0),
94885                       e = new int64(0, 0),
94886                       f = new int64(0, 0),
94887                       g = new int64(0, 0),
94888                       h = new int64(0, 0),
94889                       //Temporary variables not specified by the document
94890                   s0 = new int64(0, 0),
94891                       s1 = new int64(0, 0),
94892                       Ch = new int64(0, 0),
94893                       Maj = new int64(0, 0),
94894                       r1 = new int64(0, 0),
94895                       r2 = new int64(0, 0),
94896                       r3 = new int64(0, 0);
94897
94898                   if (sha512_k === undefined) {
94899                     //SHA512 constants
94900                     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)];
94901                   }
94902
94903                   for (i = 0; i < 80; i += 1) {
94904                     W[i] = new int64(0, 0);
94905                   } // append padding to the source string. The format is described in the FIPS.
94906
94907
94908                   x[len >> 5] |= 0x80 << 24 - (len & 0x1f);
94909                   x[(len + 128 >> 10 << 5) + 31] = len;
94910                   l = x.length;
94911
94912                   for (i = 0; i < l; i += 32) {
94913                     //32 dwords is the block size
94914                     int64copy(a, H[0]);
94915                     int64copy(b, H[1]);
94916                     int64copy(c, H[2]);
94917                     int64copy(d, H[3]);
94918                     int64copy(e, H[4]);
94919                     int64copy(f, H[5]);
94920                     int64copy(g, H[6]);
94921                     int64copy(h, H[7]);
94922
94923                     for (j = 0; j < 16; j += 1) {
94924                       W[j].h = x[i + 2 * j];
94925                       W[j].l = x[i + 2 * j + 1];
94926                     }
94927
94928                     for (j = 16; j < 80; j += 1) {
94929                       //sigma1
94930                       int64rrot(r1, W[j - 2], 19);
94931                       int64revrrot(r2, W[j - 2], 29);
94932                       int64shr(r3, W[j - 2], 6);
94933                       s1.l = r1.l ^ r2.l ^ r3.l;
94934                       s1.h = r1.h ^ r2.h ^ r3.h; //sigma0
94935
94936                       int64rrot(r1, W[j - 15], 1);
94937                       int64rrot(r2, W[j - 15], 8);
94938                       int64shr(r3, W[j - 15], 7);
94939                       s0.l = r1.l ^ r2.l ^ r3.l;
94940                       s0.h = r1.h ^ r2.h ^ r3.h;
94941                       int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
94942                     }
94943
94944                     for (j = 0; j < 80; j += 1) {
94945                       //Ch
94946                       Ch.l = e.l & f.l ^ ~e.l & g.l;
94947                       Ch.h = e.h & f.h ^ ~e.h & g.h; //Sigma1
94948
94949                       int64rrot(r1, e, 14);
94950                       int64rrot(r2, e, 18);
94951                       int64revrrot(r3, e, 9);
94952                       s1.l = r1.l ^ r2.l ^ r3.l;
94953                       s1.h = r1.h ^ r2.h ^ r3.h; //Sigma0
94954
94955                       int64rrot(r1, a, 28);
94956                       int64revrrot(r2, a, 2);
94957                       int64revrrot(r3, a, 7);
94958                       s0.l = r1.l ^ r2.l ^ r3.l;
94959                       s0.h = r1.h ^ r2.h ^ r3.h; //Maj
94960
94961                       Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l;
94962                       Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h;
94963                       int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
94964                       int64add(T2, s0, Maj);
94965                       int64copy(h, g);
94966                       int64copy(g, f);
94967                       int64copy(f, e);
94968                       int64add(e, d, T1);
94969                       int64copy(d, c);
94970                       int64copy(c, b);
94971                       int64copy(b, a);
94972                       int64add(a, T1, T2);
94973                     }
94974
94975                     int64add(H[0], H[0], a);
94976                     int64add(H[1], H[1], b);
94977                     int64add(H[2], H[2], c);
94978                     int64add(H[3], H[3], d);
94979                     int64add(H[4], H[4], e);
94980                     int64add(H[5], H[5], f);
94981                     int64add(H[6], H[6], g);
94982                     int64add(H[7], H[7], h);
94983                   } //represent the hash as an array of 32-bit dwords
94984
94985
94986                   for (i = 0; i < 8; i += 1) {
94987                     hash[2 * i] = H[i].h;
94988                     hash[2 * i + 1] = H[i].l;
94989                   }
94990
94991                   return hash;
94992                 } //A constructor for 64-bit numbers
94993
94994
94995                 function int64(h, l) {
94996                   this.h = h;
94997                   this.l = l; //this.toString = int64toString;
94998                 } //Copies src into dst, assuming both are 64-bit numbers
94999
95000
95001                 function int64copy(dst, src) {
95002                   dst.h = src.h;
95003                   dst.l = src.l;
95004                 } //Right-rotates a 64-bit number by shift
95005                 //Won't handle cases of shift>=32
95006                 //The function revrrot() is for that
95007
95008
95009                 function int64rrot(dst, x, shift) {
95010                   dst.l = x.l >>> shift | x.h << 32 - shift;
95011                   dst.h = x.h >>> shift | x.l << 32 - shift;
95012                 } //Reverses the dwords of the source and then rotates right by shift.
95013                 //This is equivalent to rotation by 32+shift
95014
95015
95016                 function int64revrrot(dst, x, shift) {
95017                   dst.l = x.h >>> shift | x.l << 32 - shift;
95018                   dst.h = x.l >>> shift | x.h << 32 - shift;
95019                 } //Bitwise-shifts right a 64-bit number by shift
95020                 //Won't handle shift>=32, but it's never needed in SHA512
95021
95022
95023                 function int64shr(dst, x, shift) {
95024                   dst.l = x.l >>> shift | x.h << 32 - shift;
95025                   dst.h = x.h >>> shift;
95026                 } //Adds two 64-bit numbers
95027                 //Like the original implementation, does not rely on 32-bit operations
95028
95029
95030                 function int64add(dst, x, y) {
95031                   var w0 = (x.l & 0xffff) + (y.l & 0xffff);
95032                   var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
95033                   var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
95034                   var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
95035                   dst.l = w0 & 0xffff | w1 << 16;
95036                   dst.h = w2 & 0xffff | w3 << 16;
95037                 } //Same, except with 4 addends. Works faster than adding them one by one.
95038
95039
95040                 function int64add4(dst, a, b, c, d) {
95041                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
95042                   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
95043                   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
95044                   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
95045                   dst.l = w0 & 0xffff | w1 << 16;
95046                   dst.h = w2 & 0xffff | w3 << 16;
95047                 } //Same, except with 5 addends
95048
95049
95050                 function int64add5(dst, a, b, c, d, e) {
95051                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
95052                       w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
95053                       w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
95054                       w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
95055                   dst.l = w0 & 0xffff | w1 << 16;
95056                   dst.h = w2 & 0xffff | w3 << 16;
95057                 }
95058               },
95059
95060               /**
95061                * @class Hashes.RMD160
95062                * @constructor
95063                * @param {Object} [config]
95064                *
95065                * A JavaScript implementation of the RIPEMD-160 Algorithm
95066                * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
95067                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
95068                * See http://pajhome.org.uk/crypt/md5 for details.
95069                * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
95070                */
95071               RMD160: function RMD160(options) {
95072                 /**
95073                  * Private properties configuration variables. You may need to tweak these to be compatible with
95074                  * the server-side, but the defaults work in most cases.
95075                  * @see this.setUpperCase() method
95076                  * @see this.setPad() method
95077                  */
95078                 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
95079
95080                 var /* hexadecimal output case format. false - lowercase; true - uppercase  */
95081                 b64pad = options && typeof options.pad === 'string' ? options.pa : '=',
95082
95083                 /* base-64 pad character. Default '=' for strict RFC compliance   */
95084                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
95085
95086                 /* enable/disable utf8 encoding */
95087                 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],
95088                     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],
95089                     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],
95090                     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];
95091                 /* privileged (public) methods */
95092
95093                 this.hex = function (s) {
95094                   return rstr2hex(rstr(s));
95095                 };
95096
95097                 this.b64 = function (s) {
95098                   return rstr2b64(rstr(s), b64pad);
95099                 };
95100
95101                 this.any = function (s, e) {
95102                   return rstr2any(rstr(s), e);
95103                 };
95104
95105                 this.raw = function (s) {
95106                   return rstr(s);
95107                 };
95108
95109                 this.hex_hmac = function (k, d) {
95110                   return rstr2hex(rstr_hmac(k, d));
95111                 };
95112
95113                 this.b64_hmac = function (k, d) {
95114                   return rstr2b64(rstr_hmac(k, d), b64pad);
95115                 };
95116
95117                 this.any_hmac = function (k, d, e) {
95118                   return rstr2any(rstr_hmac(k, d), e);
95119                 };
95120                 /**
95121                  * Perform a simple self-test to see if the VM is working
95122                  * @return {String} Hexadecimal hash sample
95123                  * @public
95124                  */
95125
95126
95127                 this.vm_test = function () {
95128                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
95129                 };
95130                 /**
95131                  * @description Enable/disable uppercase hexadecimal returned string
95132                  * @param {boolean}
95133                  * @return {Object} this
95134                  * @public
95135                  */
95136
95137
95138                 this.setUpperCase = function (a) {
95139
95140                   return this;
95141                 };
95142                 /**
95143                  * @description Defines a base64 pad string
95144                  * @param {string} Pad
95145                  * @return {Object} this
95146                  * @public
95147                  */
95148
95149
95150                 this.setPad = function (a) {
95151                   if (typeof a !== 'undefined') {
95152                     b64pad = a;
95153                   }
95154
95155                   return this;
95156                 };
95157                 /**
95158                  * @description Defines a base64 pad string
95159                  * @param {boolean}
95160                  * @return {Object} this
95161                  * @public
95162                  */
95163
95164
95165                 this.setUTF8 = function (a) {
95166                   if (typeof a === 'boolean') {
95167                     utf8 = a;
95168                   }
95169
95170                   return this;
95171                 };
95172                 /* private methods */
95173
95174                 /**
95175                  * Calculate the rmd160 of a raw string
95176                  */
95177
95178
95179                 function rstr(s) {
95180                   s = utf8 ? utf8Encode(s) : s;
95181                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
95182                 }
95183                 /**
95184                  * Calculate the HMAC-rmd160 of a key and some data (raw strings)
95185                  */
95186
95187
95188                 function rstr_hmac(key, data) {
95189                   key = utf8 ? utf8Encode(key) : key;
95190                   data = utf8 ? utf8Encode(data) : data;
95191                   var i,
95192                       hash,
95193                       bkey = rstr2binl(key),
95194                       ipad = Array(16),
95195                       opad = Array(16);
95196
95197                   if (bkey.length > 16) {
95198                     bkey = binl(bkey, key.length * 8);
95199                   }
95200
95201                   for (i = 0; i < 16; i += 1) {
95202                     ipad[i] = bkey[i] ^ 0x36363636;
95203                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
95204                   }
95205
95206                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
95207                   return binl2rstr(binl(opad.concat(hash), 512 + 160));
95208                 }
95209                 /**
95210                  * Convert an array of little-endian words to a string
95211                  */
95212
95213
95214                 function binl2rstr(input) {
95215                   var i,
95216                       output = '',
95217                       l = input.length * 32;
95218
95219                   for (i = 0; i < l; i += 8) {
95220                     output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
95221                   }
95222
95223                   return output;
95224                 }
95225                 /**
95226                  * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
95227                  */
95228
95229
95230                 function binl(x, len) {
95231                   var T,
95232                       j,
95233                       i,
95234                       l,
95235                       h0 = 0x67452301,
95236                       h1 = 0xefcdab89,
95237                       h2 = 0x98badcfe,
95238                       h3 = 0x10325476,
95239                       h4 = 0xc3d2e1f0,
95240                       A1,
95241                       B1,
95242                       C1,
95243                       D1,
95244                       E1,
95245                       A2,
95246                       B2,
95247                       C2,
95248                       D2,
95249                       E2;
95250                   /* append padding */
95251
95252                   x[len >> 5] |= 0x80 << len % 32;
95253                   x[(len + 64 >>> 9 << 4) + 14] = len;
95254                   l = x.length;
95255
95256                   for (i = 0; i < l; i += 16) {
95257                     A1 = A2 = h0;
95258                     B1 = B2 = h1;
95259                     C1 = C2 = h2;
95260                     D1 = D2 = h3;
95261                     E1 = E2 = h4;
95262
95263                     for (j = 0; j <= 79; j += 1) {
95264                       T = safe_add(A1, rmd160_f(j, B1, C1, D1));
95265                       T = safe_add(T, x[i + rmd160_r1[j]]);
95266                       T = safe_add(T, rmd160_K1(j));
95267                       T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
95268                       A1 = E1;
95269                       E1 = D1;
95270                       D1 = bit_rol(C1, 10);
95271                       C1 = B1;
95272                       B1 = T;
95273                       T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
95274                       T = safe_add(T, x[i + rmd160_r2[j]]);
95275                       T = safe_add(T, rmd160_K2(j));
95276                       T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
95277                       A2 = E2;
95278                       E2 = D2;
95279                       D2 = bit_rol(C2, 10);
95280                       C2 = B2;
95281                       B2 = T;
95282                     }
95283
95284                     T = safe_add(h1, safe_add(C1, D2));
95285                     h1 = safe_add(h2, safe_add(D1, E2));
95286                     h2 = safe_add(h3, safe_add(E1, A2));
95287                     h3 = safe_add(h4, safe_add(A1, B2));
95288                     h4 = safe_add(h0, safe_add(B1, C2));
95289                     h0 = T;
95290                   }
95291
95292                   return [h0, h1, h2, h3, h4];
95293                 } // specific algorithm methods
95294
95295
95296                 function rmd160_f(j, x, y, z) {
95297                   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';
95298                 }
95299
95300                 function rmd160_K1(j) {
95301                   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';
95302                 }
95303
95304                 function rmd160_K2(j) {
95305                   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';
95306                 }
95307               }
95308             }; // exposes Hashes
95309
95310             (function (window, undefined$1) {
95311               var freeExports = false;
95312
95313               {
95314                 freeExports = exports;
95315
95316                 if (exports && _typeof(commonjsGlobal) === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
95317                   window = commonjsGlobal;
95318                 }
95319               }
95320
95321               if (typeof undefined$1 === 'function' && _typeof(undefined$1.amd) === 'object' && undefined$1.amd) {
95322                 // define as an anonymous module, so, through path mapping, it can be aliased
95323                 undefined$1(function () {
95324                   return Hashes;
95325                 });
95326               } else if (freeExports) {
95327                 // in Node.js or RingoJS v0.8.0+
95328                 if (module && module.exports === freeExports) {
95329                   module.exports = Hashes;
95330                 } // in Narwhal or RingoJS v0.7.0-
95331                 else {
95332                     freeExports.Hashes = Hashes;
95333                   }
95334               } else {
95335                 // in a browser or Rhino
95336                 window.Hashes = Hashes;
95337               }
95338             })(this);
95339           })(); // IIFE
95340
95341         })(hashes$1, hashes$1.exports);
95342
95343         var hashes = hashes$1.exports,
95344             sha1 = new hashes.SHA1(); // # xtend
95345
95346         var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
95347
95348         function xtend$1() {
95349           var target = {};
95350
95351           for (var i = 0; i < arguments.length; i++) {
95352             var source = arguments[i];
95353
95354             for (var key in source) {
95355               if (hasOwnProperty$1.call(source, key)) {
95356                 target[key] = source[key];
95357               }
95358             }
95359           }
95360
95361           return target;
95362         }
95363
95364         var ohauth$1 = {};
95365
95366         ohauth$1.qsString = function (obj) {
95367           return Object.keys(obj).sort().map(function (key) {
95368             return ohauth$1.percentEncode(key) + '=' + ohauth$1.percentEncode(obj[key]);
95369           }).join('&');
95370         };
95371
95372         ohauth$1.stringQs = function (str) {
95373           return str.split('&').filter(function (pair) {
95374             return pair !== '';
95375           }).reduce(function (obj, pair) {
95376             var parts = pair.split('=');
95377             obj[decodeURIComponent(parts[0])] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
95378             return obj;
95379           }, {});
95380         };
95381
95382         ohauth$1.rawxhr = function (method, url, data, headers, callback) {
95383           var xhr = new XMLHttpRequest(),
95384               twoHundred = /^20\d$/;
95385
95386           xhr.onreadystatechange = function () {
95387             if (4 === xhr.readyState && 0 !== xhr.status) {
95388               if (twoHundred.test(xhr.status)) callback(null, xhr);else return callback(xhr, null);
95389             }
95390           };
95391
95392           xhr.onerror = function (e) {
95393             return callback(e, null);
95394           };
95395
95396           xhr.open(method, url, true);
95397
95398           for (var h in headers) {
95399             xhr.setRequestHeader(h, headers[h]);
95400           }
95401
95402           xhr.send(data);
95403           return xhr;
95404         };
95405
95406         ohauth$1.xhr = function (method, url, auth, data, options, callback) {
95407           var headers = options && options.header || {
95408             'Content-Type': 'application/x-www-form-urlencoded'
95409           };
95410           headers.Authorization = 'OAuth ' + ohauth$1.authHeader(auth);
95411           return ohauth$1.rawxhr(method, url, data, headers, callback);
95412         };
95413
95414         ohauth$1.nonce = function () {
95415           for (var o = ''; o.length < 6;) {
95416             o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
95417           }
95418
95419           return o;
95420         };
95421
95422         ohauth$1.authHeader = function (obj) {
95423           return Object.keys(obj).sort().map(function (key) {
95424             return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
95425           }).join(', ');
95426         };
95427
95428         ohauth$1.timestamp = function () {
95429           return ~~(+new Date() / 1000);
95430         };
95431
95432         ohauth$1.percentEncode = function (s) {
95433           return encodeURIComponent(s).replace(/\!/g, '%21').replace(/\'/g, '%27').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
95434         };
95435
95436         ohauth$1.baseString = function (method, url, params) {
95437           if (params.oauth_signature) delete params.oauth_signature;
95438           return [method, ohauth$1.percentEncode(url), ohauth$1.percentEncode(ohauth$1.qsString(params))].join('&');
95439         };
95440
95441         ohauth$1.signature = function (oauth_secret, token_secret, baseString) {
95442           return sha1.b64_hmac(ohauth$1.percentEncode(oauth_secret) + '&' + ohauth$1.percentEncode(token_secret), baseString);
95443         };
95444         /**
95445          * Takes an options object for configuration (consumer_key,
95446          * consumer_secret, version, signature_method, token, token_secret)
95447          * and returns a function that generates the Authorization header
95448          * for given data.
95449          *
95450          * The returned function takes these parameters:
95451          * - method: GET/POST/...
95452          * - uri: full URI with protocol, port, path and query string
95453          * - extra_params: any extra parameters (that are passed in the POST data),
95454          *   can be an object or a from-urlencoded string.
95455          *
95456          * Returned function returns full OAuth header with "OAuth" string in it.
95457          */
95458
95459
95460         ohauth$1.headerGenerator = function (options) {
95461           options = options || {};
95462           var consumer_key = options.consumer_key || '',
95463               consumer_secret = options.consumer_secret || '',
95464               signature_method = options.signature_method || 'HMAC-SHA1',
95465               version = options.version || '1.0',
95466               token = options.token || '',
95467               token_secret = options.token_secret || '';
95468           return function (method, uri, extra_params) {
95469             method = method.toUpperCase();
95470
95471             if (typeof extra_params === 'string' && extra_params.length > 0) {
95472               extra_params = ohauth$1.stringQs(extra_params);
95473             }
95474
95475             var uri_parts = uri.split('?', 2),
95476                 base_uri = uri_parts[0];
95477             var query_params = uri_parts.length === 2 ? ohauth$1.stringQs(uri_parts[1]) : {};
95478             var oauth_params = {
95479               oauth_consumer_key: consumer_key,
95480               oauth_signature_method: signature_method,
95481               oauth_version: version,
95482               oauth_timestamp: ohauth$1.timestamp(),
95483               oauth_nonce: ohauth$1.nonce()
95484             };
95485             if (token) oauth_params.oauth_token = token;
95486             var all_params = xtend$1({}, oauth_params, query_params, extra_params),
95487                 base_str = ohauth$1.baseString(method, base_uri, all_params);
95488             oauth_params.oauth_signature = ohauth$1.signature(consumer_secret, token_secret, base_str);
95489             return 'OAuth ' + ohauth$1.authHeader(oauth_params);
95490           };
95491         };
95492
95493         var ohauth_1 = ohauth$1;
95494
95495         var resolveUrl$1 = {exports: {}};
95496
95497         (function (module, exports) {
95498           // Copyright 2014 Simon Lydell
95499           // X11 (“MIT”) Licensed. (See LICENSE.)
95500           void function (root, factory) {
95501             {
95502               module.exports = factory();
95503             }
95504           }(commonjsGlobal, function () {
95505             function resolveUrl()
95506             /* ...urls */
95507             {
95508               var numUrls = arguments.length;
95509
95510               if (numUrls === 0) {
95511                 throw new Error("resolveUrl requires at least one argument; got none.");
95512               }
95513
95514               var base = document.createElement("base");
95515               base.href = arguments[0];
95516
95517               if (numUrls === 1) {
95518                 return base.href;
95519               }
95520
95521               var head = document.getElementsByTagName("head")[0];
95522               head.insertBefore(base, head.firstChild);
95523               var a = document.createElement("a");
95524               var resolved;
95525
95526               for (var index = 1; index < numUrls; index++) {
95527                 a.href = arguments[index];
95528                 resolved = a.href;
95529                 base.href = resolved;
95530               }
95531
95532               head.removeChild(base);
95533               return resolved;
95534             }
95535
95536             return resolveUrl;
95537           });
95538         })(resolveUrl$1);
95539
95540         var assign = make_assign();
95541         var create$1 = make_create();
95542         var trim$1 = make_trim();
95543         var Global$5 = typeof window !== 'undefined' ? window : commonjsGlobal;
95544         var util$6 = {
95545           assign: assign,
95546           create: create$1,
95547           trim: trim$1,
95548           bind: bind$1,
95549           slice: slice$1,
95550           each: each$7,
95551           map: map,
95552           pluck: pluck$1,
95553           isList: isList$1,
95554           isFunction: isFunction$1,
95555           isObject: isObject$1,
95556           Global: Global$5
95557         };
95558
95559         function make_assign() {
95560           if (Object.assign) {
95561             return Object.assign;
95562           } else {
95563             return function shimAssign(obj, props1, props2, etc) {
95564               for (var i = 1; i < arguments.length; i++) {
95565                 each$7(Object(arguments[i]), function (val, key) {
95566                   obj[key] = val;
95567                 });
95568               }
95569
95570               return obj;
95571             };
95572           }
95573         }
95574
95575         function make_create() {
95576           if (Object.create) {
95577             return function create(obj, assignProps1, assignProps2, etc) {
95578               var assignArgsList = slice$1(arguments, 1);
95579               return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
95580             };
95581           } else {
95582             var F = function F() {}; // eslint-disable-line no-inner-declarations
95583
95584
95585             return function create(obj, assignProps1, assignProps2, etc) {
95586               var assignArgsList = slice$1(arguments, 1);
95587               F.prototype = obj;
95588               return assign.apply(this, [new F()].concat(assignArgsList));
95589             };
95590           }
95591         }
95592
95593         function make_trim() {
95594           if (String.prototype.trim) {
95595             return function trim(str) {
95596               return String.prototype.trim.call(str);
95597             };
95598           } else {
95599             return function trim(str) {
95600               return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
95601             };
95602           }
95603         }
95604
95605         function bind$1(obj, fn) {
95606           return function () {
95607             return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
95608           };
95609         }
95610
95611         function slice$1(arr, index) {
95612           return Array.prototype.slice.call(arr, index || 0);
95613         }
95614
95615         function each$7(obj, fn) {
95616           pluck$1(obj, function (val, key) {
95617             fn(val, key);
95618             return false;
95619           });
95620         }
95621
95622         function map(obj, fn) {
95623           var res = isList$1(obj) ? [] : {};
95624           pluck$1(obj, function (v, k) {
95625             res[k] = fn(v, k);
95626             return false;
95627           });
95628           return res;
95629         }
95630
95631         function pluck$1(obj, fn) {
95632           if (isList$1(obj)) {
95633             for (var i = 0; i < obj.length; i++) {
95634               if (fn(obj[i], i)) {
95635                 return obj[i];
95636               }
95637             }
95638           } else {
95639             for (var key in obj) {
95640               if (obj.hasOwnProperty(key)) {
95641                 if (fn(obj[key], key)) {
95642                   return obj[key];
95643                 }
95644               }
95645             }
95646           }
95647         }
95648
95649         function isList$1(val) {
95650           return val != null && typeof val != 'function' && typeof val.length == 'number';
95651         }
95652
95653         function isFunction$1(val) {
95654           return val && {}.toString.call(val) === '[object Function]';
95655         }
95656
95657         function isObject$1(val) {
95658           return val && {}.toString.call(val) === '[object Object]';
95659         }
95660
95661         var util$5 = util$6;
95662         var slice = util$5.slice;
95663         var pluck = util$5.pluck;
95664         var each$6 = util$5.each;
95665         var bind = util$5.bind;
95666         var create = util$5.create;
95667         var isList = util$5.isList;
95668         var isFunction = util$5.isFunction;
95669         var isObject = util$5.isObject;
95670         var storeEngine = {
95671           createStore: _createStore
95672         };
95673         var storeAPI = {
95674           version: '2.0.12',
95675           enabled: false,
95676           // get returns the value of the given key. If that value
95677           // is undefined, it returns optionalDefaultValue instead.
95678           get: function get(key, optionalDefaultValue) {
95679             var data = this.storage.read(this._namespacePrefix + key);
95680             return this._deserialize(data, optionalDefaultValue);
95681           },
95682           // set will store the given value at key and returns value.
95683           // Calling set with value === undefined is equivalent to calling remove.
95684           set: function set(key, value) {
95685             if (value === undefined) {
95686               return this.remove(key);
95687             }
95688
95689             this.storage.write(this._namespacePrefix + key, this._serialize(value));
95690             return value;
95691           },
95692           // remove deletes the key and value stored at the given key.
95693           remove: function remove(key) {
95694             this.storage.remove(this._namespacePrefix + key);
95695           },
95696           // each will call the given callback once for each key-value pair
95697           // in this store.
95698           each: function each(callback) {
95699             var self = this;
95700             this.storage.each(function (val, namespacedKey) {
95701               callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
95702             });
95703           },
95704           // clearAll will remove all the stored key-value pairs in this store.
95705           clearAll: function clearAll() {
95706             this.storage.clearAll();
95707           },
95708           // additional functionality that can't live in plugins
95709           // ---------------------------------------------------
95710           // hasNamespace returns true if this store instance has the given namespace.
95711           hasNamespace: function hasNamespace(namespace) {
95712             return this._namespacePrefix == '__storejs_' + namespace + '_';
95713           },
95714           // createStore creates a store.js instance with the first
95715           // functioning storage in the list of storage candidates,
95716           // and applies the the given mixins to the instance.
95717           createStore: function createStore() {
95718             return _createStore.apply(this, arguments);
95719           },
95720           addPlugin: function addPlugin(plugin) {
95721             this._addPlugin(plugin);
95722           },
95723           namespace: function namespace(_namespace) {
95724             return _createStore(this.storage, this.plugins, _namespace);
95725           }
95726         };
95727
95728         function _warn() {
95729           var _console = typeof console == 'undefined' ? null : console;
95730
95731           if (!_console) {
95732             return;
95733           }
95734
95735           var fn = _console.warn ? _console.warn : _console.log;
95736           fn.apply(_console, arguments);
95737         }
95738
95739         function _createStore(storages, plugins, namespace) {
95740           if (!namespace) {
95741             namespace = '';
95742           }
95743
95744           if (storages && !isList(storages)) {
95745             storages = [storages];
95746           }
95747
95748           if (plugins && !isList(plugins)) {
95749             plugins = [plugins];
95750           }
95751
95752           var namespacePrefix = namespace ? '__storejs_' + namespace + '_' : '';
95753           var namespaceRegexp = namespace ? new RegExp('^' + namespacePrefix) : null;
95754           var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
95755
95756           if (!legalNamespaces.test(namespace)) {
95757             throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes');
95758           }
95759
95760           var _privateStoreProps = {
95761             _namespacePrefix: namespacePrefix,
95762             _namespaceRegexp: namespaceRegexp,
95763             _testStorage: function _testStorage(storage) {
95764               try {
95765                 var testStr = '__storejs__test__';
95766                 storage.write(testStr, testStr);
95767                 var ok = storage.read(testStr) === testStr;
95768                 storage.remove(testStr);
95769                 return ok;
95770               } catch (e) {
95771                 return false;
95772               }
95773             },
95774             _assignPluginFnProp: function _assignPluginFnProp(pluginFnProp, propName) {
95775               var oldFn = this[propName];
95776
95777               this[propName] = function pluginFn() {
95778                 var args = slice(arguments, 0);
95779                 var self = this; // super_fn calls the old function which was overwritten by
95780                 // this mixin.
95781
95782                 function super_fn() {
95783                   if (!oldFn) {
95784                     return;
95785                   }
95786
95787                   each$6(arguments, function (arg, i) {
95788                     args[i] = arg;
95789                   });
95790                   return oldFn.apply(self, args);
95791                 } // Give mixing function access to super_fn by prefixing all mixin function
95792                 // arguments with super_fn.
95793
95794
95795                 var newFnArgs = [super_fn].concat(args);
95796                 return pluginFnProp.apply(self, newFnArgs);
95797               };
95798             },
95799             _serialize: function _serialize(obj) {
95800               return JSON.stringify(obj);
95801             },
95802             _deserialize: function _deserialize(strVal, defaultVal) {
95803               if (!strVal) {
95804                 return defaultVal;
95805               } // It is possible that a raw string value has been previously stored
95806               // in a storage without using store.js, meaning it will be a raw
95807               // string value instead of a JSON serialized string. By defaulting
95808               // to the raw string value in case of a JSON parse error, we allow
95809               // for past stored values to be forwards-compatible with store.js
95810
95811
95812               var val = '';
95813
95814               try {
95815                 val = JSON.parse(strVal);
95816               } catch (e) {
95817                 val = strVal;
95818               }
95819
95820               return val !== undefined ? val : defaultVal;
95821             },
95822             _addStorage: function _addStorage(storage) {
95823               if (this.enabled) {
95824                 return;
95825               }
95826
95827               if (this._testStorage(storage)) {
95828                 this.storage = storage;
95829                 this.enabled = true;
95830               }
95831             },
95832             _addPlugin: function _addPlugin(plugin) {
95833               var self = this; // If the plugin is an array, then add all plugins in the array.
95834               // This allows for a plugin to depend on other plugins.
95835
95836               if (isList(plugin)) {
95837                 each$6(plugin, function (plugin) {
95838                   self._addPlugin(plugin);
95839                 });
95840                 return;
95841               } // Keep track of all plugins we've seen so far, so that we
95842               // don't add any of them twice.
95843
95844
95845               var seenPlugin = pluck(this.plugins, function (seenPlugin) {
95846                 return plugin === seenPlugin;
95847               });
95848
95849               if (seenPlugin) {
95850                 return;
95851               }
95852
95853               this.plugins.push(plugin); // Check that the plugin is properly formed
95854
95855               if (!isFunction(plugin)) {
95856                 throw new Error('Plugins must be function values that return objects');
95857               }
95858
95859               var pluginProperties = plugin.call(this);
95860
95861               if (!isObject(pluginProperties)) {
95862                 throw new Error('Plugins must return an object of function properties');
95863               } // Add the plugin function properties to this store instance.
95864
95865
95866               each$6(pluginProperties, function (pluginFnProp, propName) {
95867                 if (!isFunction(pluginFnProp)) {
95868                   throw new Error('Bad plugin property: ' + propName + ' from plugin ' + plugin.name + '. Plugins should only return functions.');
95869                 }
95870
95871                 self._assignPluginFnProp(pluginFnProp, propName);
95872               });
95873             },
95874             // Put deprecated properties in the private API, so as to not expose it to accidential
95875             // discovery through inspection of the store object.
95876             // Deprecated: addStorage
95877             addStorage: function addStorage(storage) {
95878               _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
95879
95880               this._addStorage(storage);
95881             }
95882           };
95883           var store = create(_privateStoreProps, storeAPI, {
95884             plugins: []
95885           });
95886           store.raw = {};
95887           each$6(store, function (prop, propName) {
95888             if (isFunction(prop)) {
95889               store.raw[propName] = bind(store, prop);
95890             }
95891           });
95892           each$6(storages, function (storage) {
95893             store._addStorage(storage);
95894           });
95895           each$6(plugins, function (plugin) {
95896             store._addPlugin(plugin);
95897           });
95898           return store;
95899         }
95900
95901         var util$4 = util$6;
95902         var Global$4 = util$4.Global;
95903         var localStorage_1 = {
95904           name: 'localStorage',
95905           read: read$5,
95906           write: write$5,
95907           each: each$5,
95908           remove: remove$5,
95909           clearAll: clearAll$5
95910         };
95911
95912         function localStorage$1() {
95913           return Global$4.localStorage;
95914         }
95915
95916         function read$5(key) {
95917           return localStorage$1().getItem(key);
95918         }
95919
95920         function write$5(key, data) {
95921           return localStorage$1().setItem(key, data);
95922         }
95923
95924         function each$5(fn) {
95925           for (var i = localStorage$1().length - 1; i >= 0; i--) {
95926             var key = localStorage$1().key(i);
95927             fn(read$5(key), key);
95928           }
95929         }
95930
95931         function remove$5(key) {
95932           return localStorage$1().removeItem(key);
95933         }
95934
95935         function clearAll$5() {
95936           return localStorage$1().clear();
95937         }
95938
95939         // versions 6 and 7, where no localStorage, etc
95940         // is available.
95941
95942         var util$3 = util$6;
95943         var Global$3 = util$3.Global;
95944         var oldFFGlobalStorage = {
95945           name: 'oldFF-globalStorage',
95946           read: read$4,
95947           write: write$4,
95948           each: each$4,
95949           remove: remove$4,
95950           clearAll: clearAll$4
95951         };
95952         var globalStorage = Global$3.globalStorage;
95953
95954         function read$4(key) {
95955           return globalStorage[key];
95956         }
95957
95958         function write$4(key, data) {
95959           globalStorage[key] = data;
95960         }
95961
95962         function each$4(fn) {
95963           for (var i = globalStorage.length - 1; i >= 0; i--) {
95964             var key = globalStorage.key(i);
95965             fn(globalStorage[key], key);
95966           }
95967         }
95968
95969         function remove$4(key) {
95970           return globalStorage.removeItem(key);
95971         }
95972
95973         function clearAll$4() {
95974           each$4(function (key, _) {
95975             delete globalStorage[key];
95976           });
95977         }
95978
95979         // versions 6 and 7, where no localStorage, sessionStorage, etc
95980         // is available.
95981
95982         var util$2 = util$6;
95983         var Global$2 = util$2.Global;
95984         var oldIEUserDataStorage = {
95985           name: 'oldIE-userDataStorage',
95986           write: write$3,
95987           read: read$3,
95988           each: each$3,
95989           remove: remove$3,
95990           clearAll: clearAll$3
95991         };
95992         var storageName = 'storejs';
95993         var doc$1 = Global$2.document;
95994
95995         var _withStorageEl = _makeIEStorageElFunction();
95996
95997         var disable = (Global$2.navigator ? Global$2.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
95998
95999         function write$3(unfixedKey, data) {
96000           if (disable) {
96001             return;
96002           }
96003
96004           var fixedKey = fixKey(unfixedKey);
96005
96006           _withStorageEl(function (storageEl) {
96007             storageEl.setAttribute(fixedKey, data);
96008             storageEl.save(storageName);
96009           });
96010         }
96011
96012         function read$3(unfixedKey) {
96013           if (disable) {
96014             return;
96015           }
96016
96017           var fixedKey = fixKey(unfixedKey);
96018           var res = null;
96019
96020           _withStorageEl(function (storageEl) {
96021             res = storageEl.getAttribute(fixedKey);
96022           });
96023
96024           return res;
96025         }
96026
96027         function each$3(callback) {
96028           _withStorageEl(function (storageEl) {
96029             var attributes = storageEl.XMLDocument.documentElement.attributes;
96030
96031             for (var i = attributes.length - 1; i >= 0; i--) {
96032               var attr = attributes[i];
96033               callback(storageEl.getAttribute(attr.name), attr.name);
96034             }
96035           });
96036         }
96037
96038         function remove$3(unfixedKey) {
96039           var fixedKey = fixKey(unfixedKey);
96040
96041           _withStorageEl(function (storageEl) {
96042             storageEl.removeAttribute(fixedKey);
96043             storageEl.save(storageName);
96044           });
96045         }
96046
96047         function clearAll$3() {
96048           _withStorageEl(function (storageEl) {
96049             var attributes = storageEl.XMLDocument.documentElement.attributes;
96050             storageEl.load(storageName);
96051
96052             for (var i = attributes.length - 1; i >= 0; i--) {
96053               storageEl.removeAttribute(attributes[i].name);
96054             }
96055
96056             storageEl.save(storageName);
96057           });
96058         } // Helpers
96059         //////////
96060         // In IE7, keys cannot start with a digit or contain certain chars.
96061         // See https://github.com/marcuswestin/store.js/issues/40
96062         // See https://github.com/marcuswestin/store.js/issues/83
96063
96064
96065         var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
96066
96067         function fixKey(key) {
96068           return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___');
96069         }
96070
96071         function _makeIEStorageElFunction() {
96072           if (!doc$1 || !doc$1.documentElement || !doc$1.documentElement.addBehavior) {
96073             return null;
96074           }
96075
96076           var scriptTag = 'script',
96077               storageOwner,
96078               storageContainer,
96079               storageEl; // Since #userData storage applies only to specific paths, we need to
96080           // somehow link our data to a specific path.  We choose /favicon.ico
96081           // as a pretty safe option, since all browsers already make a request to
96082           // this URL anyway and being a 404 will not hurt us here.  We wrap an
96083           // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
96084           // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
96085           // since the iframe access rules appear to allow direct access and
96086           // manipulation of the document element, even for a 404 page.  This
96087           // document can be used instead of the current document (which would
96088           // have been limited to the current path) to perform #userData storage.
96089
96090           try {
96091             /* global ActiveXObject */
96092             storageContainer = new ActiveXObject('htmlfile');
96093             storageContainer.open();
96094             storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
96095             storageContainer.close();
96096             storageOwner = storageContainer.w.frames[0].document;
96097             storageEl = storageOwner.createElement('div');
96098           } catch (e) {
96099             // somehow ActiveXObject instantiation failed (perhaps some special
96100             // security settings or otherwse), fall back to per-path storage
96101             storageEl = doc$1.createElement('div');
96102             storageOwner = doc$1.body;
96103           }
96104
96105           return function (storeFunction) {
96106             var args = [].slice.call(arguments, 0);
96107             args.unshift(storageEl); // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
96108             // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
96109
96110             storageOwner.appendChild(storageEl);
96111             storageEl.addBehavior('#default#userData');
96112             storageEl.load(storageName);
96113             storeFunction.apply(this, args);
96114             storageOwner.removeChild(storageEl);
96115             return;
96116           };
96117         }
96118
96119         // doesn't work but cookies do. This implementation is adopted from
96120         // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
96121
96122         var util$1 = util$6;
96123         var Global$1 = util$1.Global;
96124         var trim = util$1.trim;
96125         var cookieStorage = {
96126           name: 'cookieStorage',
96127           read: read$2,
96128           write: write$2,
96129           each: each$2,
96130           remove: remove$2,
96131           clearAll: clearAll$2
96132         };
96133         var doc = Global$1.document;
96134
96135         function read$2(key) {
96136           if (!key || !_has(key)) {
96137             return null;
96138           }
96139
96140           var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
96141           return unescape(doc.cookie.replace(new RegExp(regexpStr), "$1"));
96142         }
96143
96144         function each$2(callback) {
96145           var cookies = doc.cookie.split(/; ?/g);
96146
96147           for (var i = cookies.length - 1; i >= 0; i--) {
96148             if (!trim(cookies[i])) {
96149               continue;
96150             }
96151
96152             var kvp = cookies[i].split('=');
96153             var key = unescape(kvp[0]);
96154             var val = unescape(kvp[1]);
96155             callback(val, key);
96156           }
96157         }
96158
96159         function write$2(key, data) {
96160           if (!key) {
96161             return;
96162           }
96163
96164           doc.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
96165         }
96166
96167         function remove$2(key) {
96168           if (!key || !_has(key)) {
96169             return;
96170           }
96171
96172           doc.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
96173         }
96174
96175         function clearAll$2() {
96176           each$2(function (_, key) {
96177             remove$2(key);
96178           });
96179         }
96180
96181         function _has(key) {
96182           return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc.cookie);
96183         }
96184
96185         var util = util$6;
96186         var Global = util.Global;
96187         var sessionStorage_1 = {
96188           name: 'sessionStorage',
96189           read: read$1,
96190           write: write$1,
96191           each: each$1,
96192           remove: remove$1,
96193           clearAll: clearAll$1
96194         };
96195
96196         function sessionStorage() {
96197           return Global.sessionStorage;
96198         }
96199
96200         function read$1(key) {
96201           return sessionStorage().getItem(key);
96202         }
96203
96204         function write$1(key, data) {
96205           return sessionStorage().setItem(key, data);
96206         }
96207
96208         function each$1(fn) {
96209           for (var i = sessionStorage().length - 1; i >= 0; i--) {
96210             var key = sessionStorage().key(i);
96211             fn(read$1(key), key);
96212           }
96213         }
96214
96215         function remove$1(key) {
96216           return sessionStorage().removeItem(key);
96217         }
96218
96219         function clearAll$1() {
96220           return sessionStorage().clear();
96221         }
96222
96223         // is functions (meaning store.get(), store.set(), etc will all function).
96224         // However, stored values will not persist when the browser navigates to
96225         // a new page or reloads the current page.
96226
96227         var memoryStorage_1 = {
96228           name: 'memoryStorage',
96229           read: read,
96230           write: write,
96231           each: each,
96232           remove: remove,
96233           clearAll: clearAll
96234         };
96235         var memoryStorage = {};
96236
96237         function read(key) {
96238           return memoryStorage[key];
96239         }
96240
96241         function write(key, data) {
96242           memoryStorage[key] = data;
96243         }
96244
96245         function each(callback) {
96246           for (var key in memoryStorage) {
96247             if (memoryStorage.hasOwnProperty(key)) {
96248               callback(memoryStorage[key], key);
96249             }
96250           }
96251         }
96252
96253         function remove(key) {
96254           delete memoryStorage[key];
96255         }
96256
96257         function clearAll(key) {
96258           memoryStorage = {};
96259         }
96260
96261         var all = [// Listed in order of usage preference
96262         localStorage_1, oldFFGlobalStorage, oldIEUserDataStorage, cookieStorage, sessionStorage_1, memoryStorage_1];
96263
96264         /* eslint-disable */
96265         //  json2.js
96266         //  2016-10-28
96267         //  Public Domain.
96268         //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
96269         //  See http://www.JSON.org/js.html
96270         //  This code should be minified before deployment.
96271         //  See http://javascript.crockford.com/jsmin.html
96272         //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
96273         //  NOT CONTROL.
96274         //  This file creates a global JSON object containing two methods: stringify
96275         //  and parse. This file provides the ES5 JSON capability to ES3 systems.
96276         //  If a project might run on IE8 or earlier, then this file should be included.
96277         //  This file does nothing on ES5 systems.
96278         //      JSON.stringify(value, replacer, space)
96279         //          value       any JavaScript value, usually an object or array.
96280         //          replacer    an optional parameter that determines how object
96281         //                      values are stringified for objects. It can be a
96282         //                      function or an array of strings.
96283         //          space       an optional parameter that specifies the indentation
96284         //                      of nested structures. If it is omitted, the text will
96285         //                      be packed without extra whitespace. If it is a number,
96286         //                      it will specify the number of spaces to indent at each
96287         //                      level. If it is a string (such as "\t" or "&nbsp;"),
96288         //                      it contains the characters used to indent at each level.
96289         //          This method produces a JSON text from a JavaScript value.
96290         //          When an object value is found, if the object contains a toJSON
96291         //          method, its toJSON method will be called and the result will be
96292         //          stringified. A toJSON method does not serialize: it returns the
96293         //          value represented by the name/value pair that should be serialized,
96294         //          or undefined if nothing should be serialized. The toJSON method
96295         //          will be passed the key associated with the value, and this will be
96296         //          bound to the value.
96297         //          For example, this would serialize Dates as ISO strings.
96298         //              Date.prototype.toJSON = function (key) {
96299         //                  function f(n) {
96300         //                      // Format integers to have at least two digits.
96301         //                      return (n < 10)
96302         //                          ? "0" + n
96303         //                          : n;
96304         //                  }
96305         //                  return this.getUTCFullYear()   + "-" +
96306         //                       f(this.getUTCMonth() + 1) + "-" +
96307         //                       f(this.getUTCDate())      + "T" +
96308         //                       f(this.getUTCHours())     + ":" +
96309         //                       f(this.getUTCMinutes())   + ":" +
96310         //                       f(this.getUTCSeconds())   + "Z";
96311         //              };
96312         //          You can provide an optional replacer method. It will be passed the
96313         //          key and value of each member, with this bound to the containing
96314         //          object. The value that is returned from your method will be
96315         //          serialized. If your method returns undefined, then the member will
96316         //          be excluded from the serialization.
96317         //          If the replacer parameter is an array of strings, then it will be
96318         //          used to select the members to be serialized. It filters the results
96319         //          such that only members with keys listed in the replacer array are
96320         //          stringified.
96321         //          Values that do not have JSON representations, such as undefined or
96322         //          functions, will not be serialized. Such values in objects will be
96323         //          dropped; in arrays they will be replaced with null. You can use
96324         //          a replacer function to replace those with JSON values.
96325         //          JSON.stringify(undefined) returns undefined.
96326         //          The optional space parameter produces a stringification of the
96327         //          value that is filled with line breaks and indentation to make it
96328         //          easier to read.
96329         //          If the space parameter is a non-empty string, then that string will
96330         //          be used for indentation. If the space parameter is a number, then
96331         //          the indentation will be that many spaces.
96332         //          Example:
96333         //          text = JSON.stringify(["e", {pluribus: "unum"}]);
96334         //          // text is '["e",{"pluribus":"unum"}]'
96335         //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
96336         //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
96337         //          text = JSON.stringify([new Date()], function (key, value) {
96338         //              return this[key] instanceof Date
96339         //                  ? "Date(" + this[key] + ")"
96340         //                  : value;
96341         //          });
96342         //          // text is '["Date(---current time---)"]'
96343         //      JSON.parse(text, reviver)
96344         //          This method parses a JSON text to produce an object or array.
96345         //          It can throw a SyntaxError exception.
96346         //          The optional reviver parameter is a function that can filter and
96347         //          transform the results. It receives each of the keys and values,
96348         //          and its return value is used instead of the original value.
96349         //          If it returns what it received, then the structure is not modified.
96350         //          If it returns undefined then the member is deleted.
96351         //          Example:
96352         //          // Parse the text. Values that look like ISO date strings will
96353         //          // be converted to Date objects.
96354         //          myData = JSON.parse(text, function (key, value) {
96355         //              var a;
96356         //              if (typeof value === "string") {
96357         //                  a =
96358         //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
96359         //                  if (a) {
96360         //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
96361         //                          +a[5], +a[6]));
96362         //                  }
96363         //              }
96364         //              return value;
96365         //          });
96366         //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
96367         //              var d;
96368         //              if (typeof value === "string" &&
96369         //                      value.slice(0, 5) === "Date(" &&
96370         //                      value.slice(-1) === ")") {
96371         //                  d = new Date(value.slice(5, -1));
96372         //                  if (d) {
96373         //                      return d;
96374         //                  }
96375         //              }
96376         //              return value;
96377         //          });
96378         //  This is a reference implementation. You are free to copy, modify, or
96379         //  redistribute.
96380
96381         /*jslint
96382             eval, for, this
96383         */
96384
96385         /*property
96386             JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
96387             getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
96388             lastIndex, length, parse, prototype, push, replace, slice, stringify,
96389             test, toJSON, toString, valueOf
96390         */
96391         // Create a JSON object only if one does not already exist. We create the
96392         // methods in a closure to avoid creating global variables.
96393         if ((typeof JSON === "undefined" ? "undefined" : _typeof(JSON)) !== "object") {
96394           JSON = {};
96395         }
96396
96397         (function () {
96398
96399           var rx_one = /^[\],:{}\s]*$/;
96400           var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
96401           var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
96402           var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
96403           var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
96404           var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
96405
96406           function f(n) {
96407             // Format integers to have at least two digits.
96408             return n < 10 ? "0" + n : n;
96409           }
96410
96411           function this_value() {
96412             return this.valueOf();
96413           }
96414
96415           if (typeof Date.prototype.toJSON !== "function") {
96416             Date.prototype.toJSON = function () {
96417               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;
96418             };
96419
96420             Boolean.prototype.toJSON = this_value;
96421             Number.prototype.toJSON = this_value;
96422             String.prototype.toJSON = this_value;
96423           }
96424
96425           var gap;
96426           var indent;
96427           var meta;
96428           var rep;
96429
96430           function quote(string) {
96431             // If the string contains no control characters, no quote characters, and no
96432             // backslash characters, then we can safely slap some quotes around it.
96433             // Otherwise we must also replace the offending characters with safe escape
96434             // sequences.
96435             rx_escapable.lastIndex = 0;
96436             return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) {
96437               var c = meta[a];
96438               return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
96439             }) + "\"" : "\"" + string + "\"";
96440           }
96441
96442           function str(key, holder) {
96443             // Produce a string from holder[key].
96444             var i; // The loop counter.
96445
96446             var k; // The member key.
96447
96448             var v; // The member value.
96449
96450             var length;
96451             var mind = gap;
96452             var partial;
96453             var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value.
96454
96455             if (value && _typeof(value) === "object" && typeof value.toJSON === "function") {
96456               value = value.toJSON(key);
96457             } // If we were called with a replacer function, then call the replacer to
96458             // obtain a replacement value.
96459
96460
96461             if (typeof rep === "function") {
96462               value = rep.call(holder, key, value);
96463             } // What happens next depends on the value's type.
96464
96465
96466             switch (_typeof(value)) {
96467               case "string":
96468                 return quote(value);
96469
96470               case "number":
96471                 // JSON numbers must be finite. Encode non-finite numbers as null.
96472                 return isFinite(value) ? String(value) : "null";
96473
96474               case "boolean":
96475               case "null":
96476                 // If the value is a boolean or null, convert it to a string. Note:
96477                 // typeof null does not produce "null". The case is included here in
96478                 // the remote chance that this gets fixed someday.
96479                 return String(value);
96480               // If the type is "object", we might be dealing with an object or an array or
96481               // null.
96482
96483               case "object":
96484                 // Due to a specification blunder in ECMAScript, typeof null is "object",
96485                 // so watch out for that case.
96486                 if (!value) {
96487                   return "null";
96488                 } // Make an array to hold the partial results of stringifying this object value.
96489
96490
96491                 gap += indent;
96492                 partial = []; // Is the value an array?
96493
96494                 if (Object.prototype.toString.apply(value) === "[object Array]") {
96495                   // The value is an array. Stringify every element. Use null as a placeholder
96496                   // for non-JSON values.
96497                   length = value.length;
96498
96499                   for (i = 0; i < length; i += 1) {
96500                     partial[i] = str(i, value) || "null";
96501                   } // Join all of the elements together, separated with commas, and wrap them in
96502                   // brackets.
96503
96504
96505                   v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
96506                   gap = mind;
96507                   return v;
96508                 } // If the replacer is an array, use it to select the members to be stringified.
96509
96510
96511                 if (rep && _typeof(rep) === "object") {
96512                   length = rep.length;
96513
96514                   for (i = 0; i < length; i += 1) {
96515                     if (typeof rep[i] === "string") {
96516                       k = rep[i];
96517                       v = str(k, value);
96518
96519                       if (v) {
96520                         partial.push(quote(k) + (gap ? ": " : ":") + v);
96521                       }
96522                     }
96523                   }
96524                 } else {
96525                   // Otherwise, iterate through all of the keys in the object.
96526                   for (k in value) {
96527                     if (Object.prototype.hasOwnProperty.call(value, k)) {
96528                       v = str(k, value);
96529
96530                       if (v) {
96531                         partial.push(quote(k) + (gap ? ": " : ":") + v);
96532                       }
96533                     }
96534                   }
96535                 } // Join all of the member texts together, separated with commas,
96536                 // and wrap them in braces.
96537
96538
96539                 v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
96540                 gap = mind;
96541                 return v;
96542             }
96543           } // If the JSON object does not yet have a stringify method, give it one.
96544
96545
96546           if (typeof JSON.stringify !== "function") {
96547             meta = {
96548               // table of character substitutions
96549               "\b": "\\b",
96550               "\t": "\\t",
96551               "\n": "\\n",
96552               "\f": "\\f",
96553               "\r": "\\r",
96554               "\"": "\\\"",
96555               "\\": "\\\\"
96556             };
96557
96558             JSON.stringify = function (value, replacer, space) {
96559               // The stringify method takes a value and an optional replacer, and an optional
96560               // space parameter, and returns a JSON text. The replacer can be a function
96561               // that can replace values, or an array of strings that will select the keys.
96562               // A default replacer method can be provided. Use of the space parameter can
96563               // produce text that is more easily readable.
96564               var i;
96565               gap = "";
96566               indent = ""; // If the space parameter is a number, make an indent string containing that
96567               // many spaces.
96568
96569               if (typeof space === "number") {
96570                 for (i = 0; i < space; i += 1) {
96571                   indent += " ";
96572                 } // If the space parameter is a string, it will be used as the indent string.
96573
96574               } else if (typeof space === "string") {
96575                 indent = space;
96576               } // If there is a replacer, it must be a function or an array.
96577               // Otherwise, throw an error.
96578
96579
96580               rep = replacer;
96581
96582               if (replacer && typeof replacer !== "function" && (_typeof(replacer) !== "object" || typeof replacer.length !== "number")) {
96583                 throw new Error("JSON.stringify");
96584               } // Make a fake root object containing our value under the key of "".
96585               // Return the result of stringifying the value.
96586
96587
96588               return str("", {
96589                 "": value
96590               });
96591             };
96592           } // If the JSON object does not yet have a parse method, give it one.
96593
96594
96595           if (typeof JSON.parse !== "function") {
96596             JSON.parse = function (text, reviver) {
96597               // The parse method takes a text and an optional reviver function, and returns
96598               // a JavaScript value if the text is a valid JSON text.
96599               var j;
96600
96601               function walk(holder, key) {
96602                 // The walk method is used to recursively walk the resulting structure so
96603                 // that modifications can be made.
96604                 var k;
96605                 var v;
96606                 var value = holder[key];
96607
96608                 if (value && _typeof(value) === "object") {
96609                   for (k in value) {
96610                     if (Object.prototype.hasOwnProperty.call(value, k)) {
96611                       v = walk(value, k);
96612
96613                       if (v !== undefined) {
96614                         value[k] = v;
96615                       } else {
96616                         delete value[k];
96617                       }
96618                     }
96619                   }
96620                 }
96621
96622                 return reviver.call(holder, key, value);
96623               } // Parsing happens in four stages. In the first stage, we replace certain
96624               // Unicode characters with escape sequences. JavaScript handles many characters
96625               // incorrectly, either silently deleting them, or treating them as line endings.
96626
96627
96628               text = String(text);
96629               rx_dangerous.lastIndex = 0;
96630
96631               if (rx_dangerous.test(text)) {
96632                 text = text.replace(rx_dangerous, function (a) {
96633                   return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
96634                 });
96635               } // In the second stage, we run the text against regular expressions that look
96636               // for non-JSON patterns. We are especially concerned with "()" and "new"
96637               // because they can cause invocation, and "=" because it can cause mutation.
96638               // But just to be safe, we want to reject all unexpected forms.
96639               // We split the second stage into 4 regexp operations in order to work around
96640               // crippling inefficiencies in IE's and Safari's regexp engines. First we
96641               // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
96642               // replace all simple value tokens with "]" characters. Third, we delete all
96643               // open brackets that follow a colon or comma or that begin the text. Finally,
96644               // we look to see that the remaining characters are only whitespace or "]" or
96645               // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
96646
96647
96648               if (rx_one.test(text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, ""))) {
96649                 // In the third stage we use the eval function to compile the text into a
96650                 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
96651                 // in JavaScript: it can begin a block or an object literal. We wrap the text
96652                 // in parens to eliminate the ambiguity.
96653                 j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing
96654                 // each name/value pair to a reviver function for possible transformation.
96655
96656                 return typeof reviver === "function" ? walk({
96657                   "": j
96658                 }, "") : j;
96659               } // If the text is not JSON parseable, then a SyntaxError is thrown.
96660
96661
96662               throw new SyntaxError("JSON.parse");
96663             };
96664           }
96665         })();
96666
96667         var json2 = json2Plugin;
96668
96669         function json2Plugin() {
96670           return {};
96671         }
96672
96673         var engine = storeEngine;
96674         var storages = all;
96675         var plugins = [json2];
96676         var store_legacy = engine.createStore(storages, plugins);
96677
96678         var immutable = extend;
96679         var hasOwnProperty = Object.prototype.hasOwnProperty;
96680
96681         function extend() {
96682           var target = {};
96683
96684           for (var i = 0; i < arguments.length; i++) {
96685             var source = arguments[i];
96686
96687             for (var key in source) {
96688               if (hasOwnProperty.call(source, key)) {
96689                 target[key] = source[key];
96690               }
96691             }
96692           }
96693
96694           return target;
96695         }
96696
96697         var ohauth = ohauth_1;
96698         var resolveUrl = resolveUrl$1.exports;
96699         var store = store_legacy;
96700         var xtend = immutable; // # osm-auth
96701         //
96702         // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
96703         // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
96704         // does not support custom headers, which this uses everywhere.
96705
96706         var osmAuth = function osmAuth(o) {
96707           var oauth = {}; // authenticated users will also have a request token secret, but it's
96708           // not used in transactions with the server
96709
96710           oauth.authenticated = function () {
96711             return !!(token('oauth_token') && token('oauth_token_secret'));
96712           };
96713
96714           oauth.logout = function () {
96715             token('oauth_token', '');
96716             token('oauth_token_secret', '');
96717             token('oauth_request_token_secret', '');
96718             return oauth;
96719           }; // TODO: detect lack of click event
96720
96721
96722           oauth.authenticate = function (callback) {
96723             if (oauth.authenticated()) return callback();
96724             oauth.logout(); // ## Getting a request token
96725
96726             var params = timenonce(getAuth(o)),
96727                 url = o.url + '/oauth/request_token';
96728             params.oauth_signature = ohauth.signature(o.oauth_secret, '', ohauth.baseString('POST', url, params));
96729
96730             if (!o.singlepage) {
96731               // Create a 600x550 popup window in the center of the screen
96732               var w = 600,
96733                   h = 550,
96734                   settings = [['width', w], ['height', h], ['left', screen.width / 2 - w / 2], ['top', screen.height / 2 - h / 2]].map(function (x) {
96735                 return x.join('=');
96736               }).join(','),
96737                   popup = window.open('about:blank', 'oauth_window', settings);
96738               oauth.popupWindow = popup;
96739
96740               if (!popup) {
96741                 var error = new Error('Popup was blocked');
96742                 error.status = 'popup-blocked';
96743                 throw error;
96744               }
96745             } // Request a request token. When this is complete, the popup
96746             // window is redirected to OSM's authorization page.
96747
96748
96749             ohauth.xhr('POST', url, params, null, {}, reqTokenDone);
96750             o.loading();
96751
96752             function reqTokenDone(err, xhr) {
96753               o.done();
96754               if (err) return callback(err);
96755               var resp = ohauth.stringQs(xhr.response);
96756               token('oauth_request_token_secret', resp.oauth_token_secret);
96757               var authorize_url = o.url + '/oauth/authorize?' + ohauth.qsString({
96758                 oauth_token: resp.oauth_token,
96759                 oauth_callback: resolveUrl(o.landing)
96760               });
96761
96762               if (o.singlepage) {
96763                 location.href = authorize_url;
96764               } else {
96765                 popup.location = authorize_url;
96766               }
96767             } // Called by a function in a landing page, in the popup window. The
96768             // window closes itself.
96769
96770
96771             window.authComplete = function (token) {
96772               var oauth_token = ohauth.stringQs(token.split('?')[1]);
96773               get_access_token(oauth_token.oauth_token);
96774               delete window.authComplete;
96775             }; // ## Getting an request token
96776             //
96777             // At this point we have an `oauth_token`, brought in from a function
96778             // call on a landing page popup.
96779
96780
96781             function get_access_token(oauth_token) {
96782               var url = o.url + '/oauth/access_token',
96783                   params = timenonce(getAuth(o)),
96784                   request_token_secret = token('oauth_request_token_secret');
96785               params.oauth_token = oauth_token;
96786               params.oauth_signature = ohauth.signature(o.oauth_secret, request_token_secret, ohauth.baseString('POST', url, params)); // ## Getting an access token
96787               //
96788               // The final token required for authentication. At this point
96789               // we have a `request token secret`
96790
96791               ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
96792               o.loading();
96793             }
96794
96795             function accessTokenDone(err, xhr) {
96796               o.done();
96797               if (err) return callback(err);
96798               var access_token = ohauth.stringQs(xhr.response);
96799               token('oauth_token', access_token.oauth_token);
96800               token('oauth_token_secret', access_token.oauth_token_secret);
96801               callback(null, oauth);
96802             }
96803           };
96804
96805           oauth.bringPopupWindowToFront = function () {
96806             var brougtPopupToFront = false;
96807
96808             try {
96809               // This may cause a cross-origin error:
96810               // `DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.`
96811               if (oauth.popupWindow && !oauth.popupWindow.closed) {
96812                 oauth.popupWindow.focus();
96813                 brougtPopupToFront = true;
96814               }
96815             } catch (err) {// Bringing popup window to front failed (probably because of the cross-origin error mentioned above)
96816             }
96817
96818             return brougtPopupToFront;
96819           };
96820
96821           oauth.bootstrapToken = function (oauth_token, callback) {
96822             // ## Getting an request token
96823             // At this point we have an `oauth_token`, brought in from a function
96824             // call on a landing page popup.
96825             function get_access_token(oauth_token) {
96826               var url = o.url + '/oauth/access_token',
96827                   params = timenonce(getAuth(o)),
96828                   request_token_secret = token('oauth_request_token_secret');
96829               params.oauth_token = oauth_token;
96830               params.oauth_signature = ohauth.signature(o.oauth_secret, request_token_secret, ohauth.baseString('POST', url, params)); // ## Getting an access token
96831               // The final token required for authentication. At this point
96832               // we have a `request token secret`
96833
96834               ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
96835               o.loading();
96836             }
96837
96838             function accessTokenDone(err, xhr) {
96839               o.done();
96840               if (err) return callback(err);
96841               var access_token = ohauth.stringQs(xhr.response);
96842               token('oauth_token', access_token.oauth_token);
96843               token('oauth_token_secret', access_token.oauth_token_secret);
96844               callback(null, oauth);
96845             }
96846
96847             get_access_token(oauth_token);
96848           }; // # xhr
96849           //
96850           // A single XMLHttpRequest wrapper that does authenticated calls if the
96851           // user has logged in.
96852
96853
96854           oauth.xhr = function (options, callback) {
96855             if (!oauth.authenticated()) {
96856               if (o.auto) {
96857                 return oauth.authenticate(run);
96858               } else {
96859                 callback('not authenticated', null);
96860                 return;
96861               }
96862             } else {
96863               return run();
96864             }
96865
96866             function run() {
96867               var params = timenonce(getAuth(o)),
96868                   oauth_token_secret = token('oauth_token_secret'),
96869                   url = options.prefix !== false ? o.url + options.path : options.path,
96870                   url_parts = url.replace(/#.*$/, '').split('?', 2),
96871                   base_url = url_parts[0],
96872                   query = url_parts.length === 2 ? url_parts[1] : ''; // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
96873
96874               if ((!options.options || !options.options.header || options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') && options.content) {
96875                 params = xtend(params, ohauth.stringQs(options.content));
96876               }
96877
96878               params.oauth_token = token('oauth_token');
96879               params.oauth_signature = ohauth.signature(o.oauth_secret, oauth_token_secret, ohauth.baseString(options.method, base_url, xtend(params, ohauth.stringQs(query))));
96880               return ohauth.xhr(options.method, url, params, options.content, options.options, done);
96881             }
96882
96883             function done(err, xhr) {
96884               if (err) return callback(err);else if (xhr.responseXML) return callback(err, xhr.responseXML);else return callback(err, xhr.response);
96885             }
96886           }; // pre-authorize this object, if we can just get a token and token_secret
96887           // from the start
96888
96889
96890           oauth.preauth = function (c) {
96891             if (!c) return;
96892             if (c.oauth_token) token('oauth_token', c.oauth_token);
96893             if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
96894             return oauth;
96895           };
96896
96897           oauth.options = function (_) {
96898             if (!arguments.length) return o;
96899             o = _;
96900             o.url = o.url || 'https://www.openstreetmap.org';
96901             o.landing = o.landing || 'land.html';
96902             o.singlepage = o.singlepage || false; // Optional loading and loading-done functions for nice UI feedback.
96903             // by default, no-ops
96904
96905             o.loading = o.loading || function () {};
96906
96907             o.done = o.done || function () {};
96908
96909             return oauth.preauth(o);
96910           }; // 'stamp' an authentication object from `getAuth()`
96911           // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
96912           // and timestamp
96913
96914
96915           function timenonce(o) {
96916             o.oauth_timestamp = ohauth.timestamp();
96917             o.oauth_nonce = ohauth.nonce();
96918             return o;
96919           } // get/set tokens. These are prefixed with the base URL so that `osm-auth`
96920           // can be used with multiple APIs and the keys in `localStorage`
96921           // will not clash
96922
96923
96924           var token;
96925
96926           if (store.enabled) {
96927             token = function token(x, y) {
96928               if (arguments.length === 1) return store.get(o.url + x);else if (arguments.length === 2) return store.set(o.url + x, y);
96929             };
96930           } else {
96931             var storage = {};
96932
96933             token = function token(x, y) {
96934               if (arguments.length === 1) return storage[o.url + x];else if (arguments.length === 2) return storage[o.url + x] = y;
96935             };
96936           } // Get an authentication object. If you just add and remove properties
96937           // from a single object, you'll need to use `delete` to make sure that
96938           // it doesn't contain undesired properties for authentication
96939
96940
96941           function getAuth(o) {
96942             return {
96943               oauth_consumer_key: o.oauth_consumer_key,
96944               oauth_signature_method: 'HMAC-SHA1'
96945             };
96946           } // potentially pre-authorize
96947
96948
96949           oauth.options(o);
96950           return oauth;
96951         };
96952
96953         var tiler$2 = utilTiler();
96954         var dispatch$2 = dispatch$8('apiStatusChange', 'authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedNotes');
96955         var urlroot = 'https://www.openstreetmap.org';
96956         var oauth = osmAuth({
96957           url: urlroot,
96958           oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
96959           oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
96960           loading: authLoading,
96961           done: authDone
96962         }); // hardcode default block of Google Maps
96963
96964         var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
96965         var _tileCache = {
96966           toLoad: {},
96967           loaded: {},
96968           inflight: {},
96969           seen: {},
96970           rtree: new RBush()
96971         };
96972         var _noteCache = {
96973           toLoad: {},
96974           loaded: {},
96975           inflight: {},
96976           inflightPost: {},
96977           note: {},
96978           closed: {},
96979           rtree: new RBush()
96980         };
96981         var _userCache = {
96982           toLoad: {},
96983           user: {}
96984         };
96985
96986         var _cachedApiStatus;
96987
96988         var _changeset = {};
96989
96990         var _deferred = new Set();
96991
96992         var _connectionID = 1;
96993         var _tileZoom = 16;
96994         var _noteZoom = 12;
96995
96996         var _rateLimitError;
96997
96998         var _userChangesets;
96999
97000         var _userDetails;
97001
97002         var _off; // set a default but also load this from the API status
97003
97004
97005         var _maxWayNodes = 2000;
97006
97007         function authLoading() {
97008           dispatch$2.call('authLoading');
97009         }
97010
97011         function authDone() {
97012           dispatch$2.call('authDone');
97013         }
97014
97015         function abortRequest$2(controllerOrXHR) {
97016           if (controllerOrXHR) {
97017             controllerOrXHR.abort();
97018           }
97019         }
97020
97021         function hasInflightRequests(cache) {
97022           return Object.keys(cache.inflight).length;
97023         }
97024
97025         function abortUnwantedRequests(cache, visibleTiles) {
97026           Object.keys(cache.inflight).forEach(function (k) {
97027             if (cache.toLoad[k]) return;
97028             if (visibleTiles.find(function (tile) {
97029               return k === tile.id;
97030             })) return;
97031             abortRequest$2(cache.inflight[k]);
97032             delete cache.inflight[k];
97033           });
97034         }
97035
97036         function getLoc(attrs) {
97037           var lon = attrs.lon && attrs.lon.value;
97038           var lat = attrs.lat && attrs.lat.value;
97039           return [parseFloat(lon), parseFloat(lat)];
97040         }
97041
97042         function getNodes(obj) {
97043           var elems = obj.getElementsByTagName('nd');
97044           var nodes = new Array(elems.length);
97045
97046           for (var i = 0, l = elems.length; i < l; i++) {
97047             nodes[i] = 'n' + elems[i].attributes.ref.value;
97048           }
97049
97050           return nodes;
97051         }
97052
97053         function getNodesJSON(obj) {
97054           var elems = obj.nodes;
97055           var nodes = new Array(elems.length);
97056
97057           for (var i = 0, l = elems.length; i < l; i++) {
97058             nodes[i] = 'n' + elems[i];
97059           }
97060
97061           return nodes;
97062         }
97063
97064         function getTags(obj) {
97065           var elems = obj.getElementsByTagName('tag');
97066           var tags = {};
97067
97068           for (var i = 0, l = elems.length; i < l; i++) {
97069             var attrs = elems[i].attributes;
97070             tags[attrs.k.value] = attrs.v.value;
97071           }
97072
97073           return tags;
97074         }
97075
97076         function getMembers(obj) {
97077           var elems = obj.getElementsByTagName('member');
97078           var members = new Array(elems.length);
97079
97080           for (var i = 0, l = elems.length; i < l; i++) {
97081             var attrs = elems[i].attributes;
97082             members[i] = {
97083               id: attrs.type.value[0] + attrs.ref.value,
97084               type: attrs.type.value,
97085               role: attrs.role.value
97086             };
97087           }
97088
97089           return members;
97090         }
97091
97092         function getMembersJSON(obj) {
97093           var elems = obj.members;
97094           var members = new Array(elems.length);
97095
97096           for (var i = 0, l = elems.length; i < l; i++) {
97097             var attrs = elems[i];
97098             members[i] = {
97099               id: attrs.type[0] + attrs.ref,
97100               type: attrs.type,
97101               role: attrs.role
97102             };
97103           }
97104
97105           return members;
97106         }
97107
97108         function getVisible(attrs) {
97109           return !attrs.visible || attrs.visible.value !== 'false';
97110         }
97111
97112         function parseComments(comments) {
97113           var parsedComments = []; // for each comment
97114
97115           for (var i = 0; i < comments.length; i++) {
97116             var comment = comments[i];
97117
97118             if (comment.nodeName === 'comment') {
97119               var childNodes = comment.childNodes;
97120               var parsedComment = {};
97121
97122               for (var j = 0; j < childNodes.length; j++) {
97123                 var node = childNodes[j];
97124                 var nodeName = node.nodeName;
97125                 if (nodeName === '#text') continue;
97126                 parsedComment[nodeName] = node.textContent;
97127
97128                 if (nodeName === 'uid') {
97129                   var uid = node.textContent;
97130
97131                   if (uid && !_userCache.user[uid]) {
97132                     _userCache.toLoad[uid] = true;
97133                   }
97134                 }
97135               }
97136
97137               if (parsedComment) {
97138                 parsedComments.push(parsedComment);
97139               }
97140             }
97141           }
97142
97143           return parsedComments;
97144         }
97145
97146         function encodeNoteRtree(note) {
97147           return {
97148             minX: note.loc[0],
97149             minY: note.loc[1],
97150             maxX: note.loc[0],
97151             maxY: note.loc[1],
97152             data: note
97153           };
97154         }
97155
97156         var jsonparsers = {
97157           node: function nodeData(obj, uid) {
97158             return new osmNode({
97159               id: uid,
97160               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
97161               version: obj.version && obj.version.toString(),
97162               changeset: obj.changeset && obj.changeset.toString(),
97163               timestamp: obj.timestamp,
97164               user: obj.user,
97165               uid: obj.uid && obj.uid.toString(),
97166               loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
97167               tags: obj.tags
97168             });
97169           },
97170           way: function wayData(obj, uid) {
97171             return new osmWay({
97172               id: uid,
97173               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
97174               version: obj.version && obj.version.toString(),
97175               changeset: obj.changeset && obj.changeset.toString(),
97176               timestamp: obj.timestamp,
97177               user: obj.user,
97178               uid: obj.uid && obj.uid.toString(),
97179               tags: obj.tags,
97180               nodes: getNodesJSON(obj)
97181             });
97182           },
97183           relation: function relationData(obj, uid) {
97184             return new osmRelation({
97185               id: uid,
97186               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
97187               version: obj.version && obj.version.toString(),
97188               changeset: obj.changeset && obj.changeset.toString(),
97189               timestamp: obj.timestamp,
97190               user: obj.user,
97191               uid: obj.uid && obj.uid.toString(),
97192               tags: obj.tags,
97193               members: getMembersJSON(obj)
97194             });
97195           },
97196           user: function parseUser(obj, uid) {
97197             return {
97198               id: uid,
97199               display_name: obj.display_name,
97200               account_created: obj.account_created,
97201               image_url: obj.img && obj.img.href,
97202               changesets_count: obj.changesets && obj.changesets.count && obj.changesets.count.toString() || '0',
97203               active_blocks: obj.blocks && obj.blocks.received && obj.blocks.received.active && obj.blocks.received.active.toString() || '0'
97204             };
97205           }
97206         };
97207
97208         function parseJSON(payload, callback, options) {
97209           options = Object.assign({
97210             skipSeen: true
97211           }, options);
97212
97213           if (!payload) {
97214             return callback({
97215               message: 'No JSON',
97216               status: -1
97217             });
97218           }
97219
97220           var json = payload;
97221           if (_typeof(json) !== 'object') json = JSON.parse(payload);
97222           if (!json.elements) return callback({
97223             message: 'No JSON',
97224             status: -1
97225           });
97226           var children = json.elements;
97227           var handle = window.requestIdleCallback(function () {
97228             _deferred["delete"](handle);
97229
97230             var results = [];
97231             var result;
97232
97233             for (var i = 0; i < children.length; i++) {
97234               result = parseChild(children[i]);
97235               if (result) results.push(result);
97236             }
97237
97238             callback(null, results);
97239           });
97240
97241           _deferred.add(handle);
97242
97243           function parseChild(child) {
97244             var parser = jsonparsers[child.type];
97245             if (!parser) return null;
97246             var uid;
97247             uid = osmEntity.id.fromOSM(child.type, child.id);
97248
97249             if (options.skipSeen) {
97250               if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
97251
97252               _tileCache.seen[uid] = true;
97253             }
97254
97255             return parser(child, uid);
97256           }
97257         }
97258
97259         function parseUserJSON(payload, callback, options) {
97260           options = Object.assign({
97261             skipSeen: true
97262           }, options);
97263
97264           if (!payload) {
97265             return callback({
97266               message: 'No JSON',
97267               status: -1
97268             });
97269           }
97270
97271           var json = payload;
97272           if (_typeof(json) !== 'object') json = JSON.parse(payload);
97273           if (!json.users && !json.user) return callback({
97274             message: 'No JSON',
97275             status: -1
97276           });
97277           var objs = json.users || [json];
97278           var handle = window.requestIdleCallback(function () {
97279             _deferred["delete"](handle);
97280
97281             var results = [];
97282             var result;
97283
97284             for (var i = 0; i < objs.length; i++) {
97285               result = parseObj(objs[i]);
97286               if (result) results.push(result);
97287             }
97288
97289             callback(null, results);
97290           });
97291
97292           _deferred.add(handle);
97293
97294           function parseObj(obj) {
97295             var uid = obj.user.id && obj.user.id.toString();
97296
97297             if (options.skipSeen && _userCache.user[uid]) {
97298               delete _userCache.toLoad[uid];
97299               return null;
97300             }
97301
97302             var user = jsonparsers.user(obj.user, uid);
97303             _userCache.user[uid] = user;
97304             delete _userCache.toLoad[uid];
97305             return user;
97306           }
97307         }
97308
97309         var parsers = {
97310           node: function nodeData(obj, uid) {
97311             var attrs = obj.attributes;
97312             return new osmNode({
97313               id: uid,
97314               visible: getVisible(attrs),
97315               version: attrs.version.value,
97316               changeset: attrs.changeset && attrs.changeset.value,
97317               timestamp: attrs.timestamp && attrs.timestamp.value,
97318               user: attrs.user && attrs.user.value,
97319               uid: attrs.uid && attrs.uid.value,
97320               loc: getLoc(attrs),
97321               tags: getTags(obj)
97322             });
97323           },
97324           way: function wayData(obj, uid) {
97325             var attrs = obj.attributes;
97326             return new osmWay({
97327               id: uid,
97328               visible: getVisible(attrs),
97329               version: attrs.version.value,
97330               changeset: attrs.changeset && attrs.changeset.value,
97331               timestamp: attrs.timestamp && attrs.timestamp.value,
97332               user: attrs.user && attrs.user.value,
97333               uid: attrs.uid && attrs.uid.value,
97334               tags: getTags(obj),
97335               nodes: getNodes(obj)
97336             });
97337           },
97338           relation: function relationData(obj, uid) {
97339             var attrs = obj.attributes;
97340             return new osmRelation({
97341               id: uid,
97342               visible: getVisible(attrs),
97343               version: attrs.version.value,
97344               changeset: attrs.changeset && attrs.changeset.value,
97345               timestamp: attrs.timestamp && attrs.timestamp.value,
97346               user: attrs.user && attrs.user.value,
97347               uid: attrs.uid && attrs.uid.value,
97348               tags: getTags(obj),
97349               members: getMembers(obj)
97350             });
97351           },
97352           note: function parseNote(obj, uid) {
97353             var attrs = obj.attributes;
97354             var childNodes = obj.childNodes;
97355             var props = {};
97356             props.id = uid;
97357             props.loc = getLoc(attrs); // if notes are coincident, move them apart slightly
97358
97359             var coincident = false;
97360             var epsilon = 0.00001;
97361
97362             do {
97363               if (coincident) {
97364                 props.loc = geoVecAdd(props.loc, [epsilon, epsilon]);
97365               }
97366
97367               var bbox = geoExtent(props.loc).bbox();
97368               coincident = _noteCache.rtree.search(bbox).length;
97369             } while (coincident); // parse note contents
97370
97371
97372             for (var i = 0; i < childNodes.length; i++) {
97373               var node = childNodes[i];
97374               var nodeName = node.nodeName;
97375               if (nodeName === '#text') continue; // if the element is comments, parse the comments
97376
97377               if (nodeName === 'comments') {
97378                 props[nodeName] = parseComments(node.childNodes);
97379               } else {
97380                 props[nodeName] = node.textContent;
97381               }
97382             }
97383
97384             var note = new osmNote(props);
97385             var item = encodeNoteRtree(note);
97386             _noteCache.note[note.id] = note;
97387
97388             _noteCache.rtree.insert(item);
97389
97390             return note;
97391           },
97392           user: function parseUser(obj, uid) {
97393             var attrs = obj.attributes;
97394             var user = {
97395               id: uid,
97396               display_name: attrs.display_name && attrs.display_name.value,
97397               account_created: attrs.account_created && attrs.account_created.value,
97398               changesets_count: '0',
97399               active_blocks: '0'
97400             };
97401             var img = obj.getElementsByTagName('img');
97402
97403             if (img && img[0] && img[0].getAttribute('href')) {
97404               user.image_url = img[0].getAttribute('href');
97405             }
97406
97407             var changesets = obj.getElementsByTagName('changesets');
97408
97409             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
97410               user.changesets_count = changesets[0].getAttribute('count');
97411             }
97412
97413             var blocks = obj.getElementsByTagName('blocks');
97414
97415             if (blocks && blocks[0]) {
97416               var received = blocks[0].getElementsByTagName('received');
97417
97418               if (received && received[0] && received[0].getAttribute('active')) {
97419                 user.active_blocks = received[0].getAttribute('active');
97420               }
97421             }
97422
97423             _userCache.user[uid] = user;
97424             delete _userCache.toLoad[uid];
97425             return user;
97426           }
97427         };
97428
97429         function parseXML(xml, callback, options) {
97430           options = Object.assign({
97431             skipSeen: true
97432           }, options);
97433
97434           if (!xml || !xml.childNodes) {
97435             return callback({
97436               message: 'No XML',
97437               status: -1
97438             });
97439           }
97440
97441           var root = xml.childNodes[0];
97442           var children = root.childNodes;
97443           var handle = window.requestIdleCallback(function () {
97444             _deferred["delete"](handle);
97445
97446             var results = [];
97447             var result;
97448
97449             for (var i = 0; i < children.length; i++) {
97450               result = parseChild(children[i]);
97451               if (result) results.push(result);
97452             }
97453
97454             callback(null, results);
97455           });
97456
97457           _deferred.add(handle);
97458
97459           function parseChild(child) {
97460             var parser = parsers[child.nodeName];
97461             if (!parser) return null;
97462             var uid;
97463
97464             if (child.nodeName === 'user') {
97465               uid = child.attributes.id.value;
97466
97467               if (options.skipSeen && _userCache.user[uid]) {
97468                 delete _userCache.toLoad[uid];
97469                 return null;
97470               }
97471             } else if (child.nodeName === 'note') {
97472               uid = child.getElementsByTagName('id')[0].textContent;
97473             } else {
97474               uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
97475
97476               if (options.skipSeen) {
97477                 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
97478
97479                 _tileCache.seen[uid] = true;
97480               }
97481             }
97482
97483             return parser(child, uid);
97484           }
97485         } // replace or remove note from rtree
97486
97487
97488         function updateRtree(item, replace) {
97489           _noteCache.rtree.remove(item, function isEql(a, b) {
97490             return a.data.id === b.data.id;
97491           });
97492
97493           if (replace) {
97494             _noteCache.rtree.insert(item);
97495           }
97496         }
97497
97498         function wrapcb(thisArg, callback, cid) {
97499           return function (err, result) {
97500             if (err) {
97501               // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
97502               if (err.status === 400 || err.status === 401 || err.status === 403) {
97503                 thisArg.logout();
97504               }
97505
97506               return callback.call(thisArg, err);
97507             } else if (thisArg.getConnectionId() !== cid) {
97508               return callback.call(thisArg, {
97509                 message: 'Connection Switched',
97510                 status: -1
97511               });
97512             } else {
97513               return callback.call(thisArg, err, result);
97514             }
97515           };
97516         }
97517
97518         var serviceOsm = {
97519           init: function init() {
97520             utilRebind(this, dispatch$2, 'on');
97521           },
97522           reset: function reset() {
97523             Array.from(_deferred).forEach(function (handle) {
97524               window.cancelIdleCallback(handle);
97525
97526               _deferred["delete"](handle);
97527             });
97528             _connectionID++;
97529             _userChangesets = undefined;
97530             _userDetails = undefined;
97531             _rateLimitError = undefined;
97532             Object.values(_tileCache.inflight).forEach(abortRequest$2);
97533             Object.values(_noteCache.inflight).forEach(abortRequest$2);
97534             Object.values(_noteCache.inflightPost).forEach(abortRequest$2);
97535             if (_changeset.inflight) abortRequest$2(_changeset.inflight);
97536             _tileCache = {
97537               toLoad: {},
97538               loaded: {},
97539               inflight: {},
97540               seen: {},
97541               rtree: new RBush()
97542             };
97543             _noteCache = {
97544               toLoad: {},
97545               loaded: {},
97546               inflight: {},
97547               inflightPost: {},
97548               note: {},
97549               closed: {},
97550               rtree: new RBush()
97551             };
97552             _userCache = {
97553               toLoad: {},
97554               user: {}
97555             };
97556             _cachedApiStatus = undefined;
97557             _changeset = {};
97558             return this;
97559           },
97560           getConnectionId: function getConnectionId() {
97561             return _connectionID;
97562           },
97563           changesetURL: function changesetURL(changesetID) {
97564             return urlroot + '/changeset/' + changesetID;
97565           },
97566           changesetsURL: function changesetsURL(center, zoom) {
97567             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
97568             return urlroot + '/history#map=' + Math.floor(zoom) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
97569           },
97570           entityURL: function entityURL(entity) {
97571             return urlroot + '/' + entity.type + '/' + entity.osmId();
97572           },
97573           historyURL: function historyURL(entity) {
97574             return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
97575           },
97576           userURL: function userURL(username) {
97577             return urlroot + '/user/' + username;
97578           },
97579           noteURL: function noteURL(note) {
97580             return urlroot + '/note/' + note.id;
97581           },
97582           noteReportURL: function noteReportURL(note) {
97583             return urlroot + '/reports/new?reportable_type=Note&reportable_id=' + note.id;
97584           },
97585           // Generic method to load data from the OSM API
97586           // Can handle either auth or unauth calls.
97587           loadFromAPI: function loadFromAPI(path, callback, options) {
97588             options = Object.assign({
97589               skipSeen: true
97590             }, options);
97591             var that = this;
97592             var cid = _connectionID;
97593
97594             function done(err, payload) {
97595               if (that.getConnectionId() !== cid) {
97596                 if (callback) callback({
97597                   message: 'Connection Switched',
97598                   status: -1
97599                 });
97600                 return;
97601               }
97602
97603               var isAuthenticated = that.authenticated(); // 400 Bad Request, 401 Unauthorized, 403 Forbidden
97604               // Logout and retry the request..
97605
97606               if (isAuthenticated && err && err.status && (err.status === 400 || err.status === 401 || err.status === 403)) {
97607                 that.logout();
97608                 that.loadFromAPI(path, callback, options); // else, no retry..
97609               } else {
97610                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
97611                 // Set the rateLimitError flag and trigger a warning..
97612                 if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
97613                   _rateLimitError = err;
97614                   dispatch$2.call('change');
97615                   that.reloadApiStatus();
97616                 } else if (err && _cachedApiStatus === 'online' || !err && _cachedApiStatus !== 'online') {
97617                   // If the response's error state doesn't match the status,
97618                   // it's likely we lost or gained the connection so reload the status
97619                   that.reloadApiStatus();
97620                 }
97621
97622                 if (callback) {
97623                   if (err) {
97624                     return callback(err);
97625                   } else {
97626                     if (path.indexOf('.json') !== -1) {
97627                       return parseJSON(payload, callback, options);
97628                     } else {
97629                       return parseXML(payload, callback, options);
97630                     }
97631                   }
97632                 }
97633               }
97634             }
97635
97636             if (this.authenticated()) {
97637               return oauth.xhr({
97638                 method: 'GET',
97639                 path: path
97640               }, done);
97641             } else {
97642               var url = urlroot + path;
97643               var controller = new AbortController();
97644               var fn;
97645
97646               if (path.indexOf('.json') !== -1) {
97647                 fn = d3_json;
97648               } else {
97649                 fn = d3_xml;
97650               }
97651
97652               fn(url, {
97653                 signal: controller.signal
97654               }).then(function (data) {
97655                 done(null, data);
97656               })["catch"](function (err) {
97657                 if (err.name === 'AbortError') return; // d3-fetch includes status in the error message,
97658                 // but we can't access the response itself
97659                 // https://github.com/d3/d3-fetch/issues/27
97660
97661                 var match = err.message.match(/^\d{3}/);
97662
97663                 if (match) {
97664                   done({
97665                     status: +match[0],
97666                     statusText: err.message
97667                   });
97668                 } else {
97669                   done(err.message);
97670                 }
97671               });
97672               return controller;
97673             }
97674           },
97675           // Load a single entity by id (ways and relations use the `/full` call to include
97676           // nodes and members). Parent relations are not included, see `loadEntityRelations`.
97677           // GET /api/0.6/node/#id
97678           // GET /api/0.6/[way|relation]/#id/full
97679           loadEntity: function loadEntity(id, callback) {
97680             var type = osmEntity.id.type(id);
97681             var osmID = osmEntity.id.toOSM(id);
97682             var options = {
97683               skipSeen: false
97684             };
97685             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : '') + '.json', function (err, entities) {
97686               if (callback) callback(err, {
97687                 data: entities
97688               });
97689             }, options);
97690           },
97691           // Load a single entity with a specific version
97692           // GET /api/0.6/[node|way|relation]/#id/#version
97693           loadEntityVersion: function loadEntityVersion(id, version, callback) {
97694             var type = osmEntity.id.type(id);
97695             var osmID = osmEntity.id.toOSM(id);
97696             var options = {
97697               skipSeen: false
97698             };
97699             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/' + version + '.json', function (err, entities) {
97700               if (callback) callback(err, {
97701                 data: entities
97702               });
97703             }, options);
97704           },
97705           // Load the relations of a single entity with the given.
97706           // GET /api/0.6/[node|way|relation]/#id/relations
97707           loadEntityRelations: function loadEntityRelations(id, callback) {
97708             var type = osmEntity.id.type(id);
97709             var osmID = osmEntity.id.toOSM(id);
97710             var options = {
97711               skipSeen: false
97712             };
97713             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/relations.json', function (err, entities) {
97714               if (callback) callback(err, {
97715                 data: entities
97716               });
97717             }, options);
97718           },
97719           // Load multiple entities in chunks
97720           // (note: callback may be called multiple times)
97721           // Unlike `loadEntity`, child nodes and members are not fetched
97722           // GET /api/0.6/[nodes|ways|relations]?#parameters
97723           loadMultiple: function loadMultiple(ids, callback) {
97724             var that = this;
97725             var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
97726             Object.keys(groups).forEach(function (k) {
97727               var type = k + 's'; // nodes, ways, relations
97728
97729               var osmIDs = groups[k].map(function (id) {
97730                 return osmEntity.id.toOSM(id);
97731               });
97732               var options = {
97733                 skipSeen: false
97734               };
97735               utilArrayChunk(osmIDs, 150).forEach(function (arr) {
97736                 that.loadFromAPI('/api/0.6/' + type + '.json?' + type + '=' + arr.join(), function (err, entities) {
97737                   if (callback) callback(err, {
97738                     data: entities
97739                   });
97740                 }, options);
97741               });
97742             });
97743           },
97744           // Create, upload, and close a changeset
97745           // PUT /api/0.6/changeset/create
97746           // POST /api/0.6/changeset/#id/upload
97747           // PUT /api/0.6/changeset/#id/close
97748           putChangeset: function putChangeset(changeset, changes, callback) {
97749             var cid = _connectionID;
97750
97751             if (_changeset.inflight) {
97752               return callback({
97753                 message: 'Changeset already inflight',
97754                 status: -2
97755               }, changeset);
97756             } else if (_changeset.open) {
97757               // reuse existing open changeset..
97758               return createdChangeset.call(this, null, _changeset.open);
97759             } else {
97760               // Open a new changeset..
97761               var options = {
97762                 method: 'PUT',
97763                 path: '/api/0.6/changeset/create',
97764                 options: {
97765                   header: {
97766                     'Content-Type': 'text/xml'
97767                   }
97768                 },
97769                 content: JXON.stringify(changeset.asJXON())
97770               };
97771               _changeset.inflight = oauth.xhr(options, wrapcb(this, createdChangeset, cid));
97772             }
97773
97774             function createdChangeset(err, changesetID) {
97775               _changeset.inflight = null;
97776
97777               if (err) {
97778                 return callback(err, changeset);
97779               }
97780
97781               _changeset.open = changesetID;
97782               changeset = changeset.update({
97783                 id: changesetID
97784               }); // Upload the changeset..
97785
97786               var options = {
97787                 method: 'POST',
97788                 path: '/api/0.6/changeset/' + changesetID + '/upload',
97789                 options: {
97790                   header: {
97791                     'Content-Type': 'text/xml'
97792                   }
97793                 },
97794                 content: JXON.stringify(changeset.osmChangeJXON(changes))
97795               };
97796               _changeset.inflight = oauth.xhr(options, wrapcb(this, uploadedChangeset, cid));
97797             }
97798
97799             function uploadedChangeset(err) {
97800               _changeset.inflight = null;
97801               if (err) return callback(err, changeset); // Upload was successful, safe to call the callback.
97802               // Add delay to allow for postgres replication #1646 #2678
97803
97804               window.setTimeout(function () {
97805                 callback(null, changeset);
97806               }, 2500);
97807               _changeset.open = null; // At this point, we don't really care if the connection was switched..
97808               // Only try to close the changeset if we're still talking to the same server.
97809
97810               if (this.getConnectionId() === cid) {
97811                 // Still attempt to close changeset, but ignore response because #2667
97812                 oauth.xhr({
97813                   method: 'PUT',
97814                   path: '/api/0.6/changeset/' + changeset.id + '/close',
97815                   options: {
97816                     header: {
97817                       'Content-Type': 'text/xml'
97818                     }
97819                   }
97820                 }, function () {
97821                   return true;
97822                 });
97823               }
97824             }
97825           },
97826           // Load multiple users in chunks
97827           // (note: callback may be called multiple times)
97828           // GET /api/0.6/users?users=#id1,#id2,...,#idn
97829           loadUsers: function loadUsers(uids, callback) {
97830             var toLoad = [];
97831             var cached = [];
97832             utilArrayUniq(uids).forEach(function (uid) {
97833               if (_userCache.user[uid]) {
97834                 delete _userCache.toLoad[uid];
97835                 cached.push(_userCache.user[uid]);
97836               } else {
97837                 toLoad.push(uid);
97838               }
97839             });
97840
97841             if (cached.length || !this.authenticated()) {
97842               callback(undefined, cached);
97843               if (!this.authenticated()) return; // require auth
97844             }
97845
97846             utilArrayChunk(toLoad, 150).forEach(function (arr) {
97847               oauth.xhr({
97848                 method: 'GET',
97849                 path: '/api/0.6/users.json?users=' + arr.join()
97850               }, wrapcb(this, done, _connectionID));
97851             }.bind(this));
97852
97853             function done(err, payload) {
97854               if (err) return callback(err);
97855               var options = {
97856                 skipSeen: true
97857               };
97858               return parseUserJSON(payload, function (err, results) {
97859                 if (err) return callback(err);
97860                 return callback(undefined, results);
97861               }, options);
97862             }
97863           },
97864           // Load a given user by id
97865           // GET /api/0.6/user/#id
97866           loadUser: function loadUser(uid, callback) {
97867             if (_userCache.user[uid] || !this.authenticated()) {
97868               // require auth
97869               delete _userCache.toLoad[uid];
97870               return callback(undefined, _userCache.user[uid]);
97871             }
97872
97873             oauth.xhr({
97874               method: 'GET',
97875               path: '/api/0.6/user/' + uid + '.json'
97876             }, wrapcb(this, done, _connectionID));
97877
97878             function done(err, payload) {
97879               if (err) return callback(err);
97880               var options = {
97881                 skipSeen: true
97882               };
97883               return parseUserJSON(payload, function (err, results) {
97884                 if (err) return callback(err);
97885                 return callback(undefined, results[0]);
97886               }, options);
97887             }
97888           },
97889           // Load the details of the logged-in user
97890           // GET /api/0.6/user/details
97891           userDetails: function userDetails(callback) {
97892             if (_userDetails) {
97893               // retrieve cached
97894               return callback(undefined, _userDetails);
97895             }
97896
97897             oauth.xhr({
97898               method: 'GET',
97899               path: '/api/0.6/user/details.json'
97900             }, wrapcb(this, done, _connectionID));
97901
97902             function done(err, payload) {
97903               if (err) return callback(err);
97904               var options = {
97905                 skipSeen: false
97906               };
97907               return parseUserJSON(payload, function (err, results) {
97908                 if (err) return callback(err);
97909                 _userDetails = results[0];
97910                 return callback(undefined, _userDetails);
97911               }, options);
97912             }
97913           },
97914           // Load previous changesets for the logged in user
97915           // GET /api/0.6/changesets?user=#id
97916           userChangesets: function userChangesets(callback) {
97917             if (_userChangesets) {
97918               // retrieve cached
97919               return callback(undefined, _userChangesets);
97920             }
97921
97922             this.userDetails(wrapcb(this, gotDetails, _connectionID));
97923
97924             function gotDetails(err, user) {
97925               if (err) {
97926                 return callback(err);
97927               }
97928
97929               oauth.xhr({
97930                 method: 'GET',
97931                 path: '/api/0.6/changesets?user=' + user.id
97932               }, wrapcb(this, done, _connectionID));
97933             }
97934
97935             function done(err, xml) {
97936               if (err) {
97937                 return callback(err);
97938               }
97939
97940               _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
97941                 return {
97942                   tags: getTags(changeset)
97943                 };
97944               }).filter(function (changeset) {
97945                 var comment = changeset.tags.comment;
97946                 return comment && comment !== '';
97947               });
97948               return callback(undefined, _userChangesets);
97949             }
97950           },
97951           // Fetch the status of the OSM API
97952           // GET /api/capabilities
97953           status: function status(callback) {
97954             var url = urlroot + '/api/capabilities';
97955             var errback = wrapcb(this, done, _connectionID);
97956             d3_xml(url).then(function (data) {
97957               errback(null, data);
97958             })["catch"](function (err) {
97959               errback(err.message);
97960             });
97961
97962             function done(err, xml) {
97963               if (err) {
97964                 // the status is null if no response could be retrieved
97965                 return callback(err, null);
97966               } // update blocklists
97967
97968
97969               var elements = xml.getElementsByTagName('blacklist');
97970               var regexes = [];
97971
97972               for (var i = 0; i < elements.length; i++) {
97973                 var regexString = elements[i].getAttribute('regex'); // needs unencode?
97974
97975                 if (regexString) {
97976                   try {
97977                     var regex = new RegExp(regexString);
97978                     regexes.push(regex);
97979                   } catch (e) {
97980                     /* noop */
97981                   }
97982                 }
97983               }
97984
97985               if (regexes.length) {
97986                 _imageryBlocklists = regexes;
97987               }
97988
97989               if (_rateLimitError) {
97990                 return callback(_rateLimitError, 'rateLimited');
97991               } else {
97992                 var waynodes = xml.getElementsByTagName('waynodes');
97993                 var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
97994                 if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
97995                 var apiStatus = xml.getElementsByTagName('status');
97996                 var val = apiStatus[0].getAttribute('api');
97997                 return callback(undefined, val);
97998               }
97999             }
98000           },
98001           // Calls `status` and dispatches an `apiStatusChange` event if the returned
98002           // status differs from the cached status.
98003           reloadApiStatus: function reloadApiStatus() {
98004             // throttle to avoid unnecessary API calls
98005             if (!this.throttledReloadApiStatus) {
98006               var that = this;
98007               this.throttledReloadApiStatus = throttle(function () {
98008                 that.status(function (err, status) {
98009                   if (status !== _cachedApiStatus) {
98010                     _cachedApiStatus = status;
98011                     dispatch$2.call('apiStatusChange', that, err, status);
98012                   }
98013                 });
98014               }, 500);
98015             }
98016
98017             this.throttledReloadApiStatus();
98018           },
98019           // Returns the maximum number of nodes a single way can have
98020           maxWayNodes: function maxWayNodes() {
98021             return _maxWayNodes;
98022           },
98023           // Load data (entities) from the API in tiles
98024           // GET /api/0.6/map?bbox=
98025           loadTiles: function loadTiles(projection, callback) {
98026             if (_off) return; // determine the needed tiles to cover the view
98027
98028             var tiles = tiler$2.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection); // abort inflight requests that are no longer needed
98029
98030             var hadRequests = hasInflightRequests(_tileCache);
98031             abortUnwantedRequests(_tileCache, tiles);
98032
98033             if (hadRequests && !hasInflightRequests(_tileCache)) {
98034               dispatch$2.call('loaded'); // stop the spinner
98035             } // issue new requests..
98036
98037
98038             tiles.forEach(function (tile) {
98039               this.loadTile(tile, callback);
98040             }, this);
98041           },
98042           // Load a single data tile
98043           // GET /api/0.6/map?bbox=
98044           loadTile: function loadTile(tile, callback) {
98045             if (_off) return;
98046             if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
98047
98048             if (!hasInflightRequests(_tileCache)) {
98049               dispatch$2.call('loading'); // start the spinner
98050             }
98051
98052             var path = '/api/0.6/map.json?bbox=';
98053             var options = {
98054               skipSeen: true
98055             };
98056             _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
98057
98058             function tileCallback(err, parsed) {
98059               delete _tileCache.inflight[tile.id];
98060
98061               if (!err) {
98062                 delete _tileCache.toLoad[tile.id];
98063                 _tileCache.loaded[tile.id] = true;
98064                 var bbox = tile.extent.bbox();
98065                 bbox.id = tile.id;
98066
98067                 _tileCache.rtree.insert(bbox);
98068               }
98069
98070               if (callback) {
98071                 callback(err, Object.assign({
98072                   data: parsed
98073                 }, tile));
98074               }
98075
98076               if (!hasInflightRequests(_tileCache)) {
98077                 dispatch$2.call('loaded'); // stop the spinner
98078               }
98079             }
98080           },
98081           isDataLoaded: function isDataLoaded(loc) {
98082             var bbox = {
98083               minX: loc[0],
98084               minY: loc[1],
98085               maxX: loc[0],
98086               maxY: loc[1]
98087             };
98088             return _tileCache.rtree.collides(bbox);
98089           },
98090           // load the tile that covers the given `loc`
98091           loadTileAtLoc: function loadTileAtLoc(loc, callback) {
98092             // Back off if the toLoad queue is filling up.. re #6417
98093             // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
98094             // let users safely edit geometries which extend to unloaded tiles.  We can drop some.)
98095             if (Object.keys(_tileCache.toLoad).length > 50) return;
98096             var k = geoZoomToScale(_tileZoom + 1);
98097             var offset = geoRawMercator().scale(k)(loc);
98098             var projection = geoRawMercator().transform({
98099               k: k,
98100               x: -offset[0],
98101               y: -offset[1]
98102             });
98103             var tiles = tiler$2.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection);
98104             tiles.forEach(function (tile) {
98105               if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
98106               _tileCache.toLoad[tile.id] = true;
98107               this.loadTile(tile, callback);
98108             }, this);
98109           },
98110           // Load notes from the API in tiles
98111           // GET /api/0.6/notes?bbox=
98112           loadNotes: function loadNotes(projection, noteOptions) {
98113             noteOptions = Object.assign({
98114               limit: 10000,
98115               closed: 7
98116             }, noteOptions);
98117             if (_off) return;
98118             var that = this;
98119             var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
98120
98121             var throttleLoadUsers = throttle(function () {
98122               var uids = Object.keys(_userCache.toLoad);
98123               if (!uids.length) return;
98124               that.loadUsers(uids, function () {}); // eagerly load user details
98125             }, 750); // determine the needed tiles to cover the view
98126
98127
98128             var tiles = tiler$2.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
98129
98130             abortUnwantedRequests(_noteCache, tiles); // issue new requests..
98131
98132             tiles.forEach(function (tile) {
98133               if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
98134               var options = {
98135                 skipSeen: false
98136               };
98137               _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
98138                 delete _noteCache.inflight[tile.id];
98139
98140                 if (!err) {
98141                   _noteCache.loaded[tile.id] = true;
98142                 }
98143
98144                 throttleLoadUsers();
98145                 dispatch$2.call('loadedNotes');
98146               }, options);
98147             });
98148           },
98149           // Create a note
98150           // POST /api/0.6/notes?params
98151           postNoteCreate: function postNoteCreate(note, callback) {
98152             if (!this.authenticated()) {
98153               return callback({
98154                 message: 'Not Authenticated',
98155                 status: -3
98156               }, note);
98157             }
98158
98159             if (_noteCache.inflightPost[note.id]) {
98160               return callback({
98161                 message: 'Note update already inflight',
98162                 status: -2
98163               }, note);
98164             }
98165
98166             if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
98167
98168             var comment = note.newComment;
98169
98170             if (note.newCategory && note.newCategory !== 'None') {
98171               comment += ' #' + note.newCategory;
98172             }
98173
98174             var path = '/api/0.6/notes?' + utilQsString({
98175               lon: note.loc[0],
98176               lat: note.loc[1],
98177               text: comment
98178             });
98179             _noteCache.inflightPost[note.id] = oauth.xhr({
98180               method: 'POST',
98181               path: path
98182             }, wrapcb(this, done, _connectionID));
98183
98184             function done(err, xml) {
98185               delete _noteCache.inflightPost[note.id];
98186
98187               if (err) {
98188                 return callback(err);
98189               } // we get the updated note back, remove from caches and reparse..
98190
98191
98192               this.removeNote(note);
98193               var options = {
98194                 skipSeen: false
98195               };
98196               return parseXML(xml, function (err, results) {
98197                 if (err) {
98198                   return callback(err);
98199                 } else {
98200                   return callback(undefined, results[0]);
98201                 }
98202               }, options);
98203             }
98204           },
98205           // Update a note
98206           // POST /api/0.6/notes/#id/comment?text=comment
98207           // POST /api/0.6/notes/#id/close?text=comment
98208           // POST /api/0.6/notes/#id/reopen?text=comment
98209           postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
98210             if (!this.authenticated()) {
98211               return callback({
98212                 message: 'Not Authenticated',
98213                 status: -3
98214               }, note);
98215             }
98216
98217             if (_noteCache.inflightPost[note.id]) {
98218               return callback({
98219                 message: 'Note update already inflight',
98220                 status: -2
98221               }, note);
98222             }
98223
98224             var action;
98225
98226             if (note.status !== 'closed' && newStatus === 'closed') {
98227               action = 'close';
98228             } else if (note.status !== 'open' && newStatus === 'open') {
98229               action = 'reopen';
98230             } else {
98231               action = 'comment';
98232               if (!note.newComment) return; // when commenting, comment required
98233             }
98234
98235             var path = '/api/0.6/notes/' + note.id + '/' + action;
98236
98237             if (note.newComment) {
98238               path += '?' + utilQsString({
98239                 text: note.newComment
98240               });
98241             }
98242
98243             _noteCache.inflightPost[note.id] = oauth.xhr({
98244               method: 'POST',
98245               path: path
98246             }, wrapcb(this, done, _connectionID));
98247
98248             function done(err, xml) {
98249               delete _noteCache.inflightPost[note.id];
98250
98251               if (err) {
98252                 return callback(err);
98253               } // we get the updated note back, remove from caches and reparse..
98254
98255
98256               this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
98257
98258               if (action === 'close') {
98259                 _noteCache.closed[note.id] = true;
98260               } else if (action === 'reopen') {
98261                 delete _noteCache.closed[note.id];
98262               }
98263
98264               var options = {
98265                 skipSeen: false
98266               };
98267               return parseXML(xml, function (err, results) {
98268                 if (err) {
98269                   return callback(err);
98270                 } else {
98271                   return callback(undefined, results[0]);
98272                 }
98273               }, options);
98274             }
98275           },
98276           "switch": function _switch(options) {
98277             urlroot = options.urlroot;
98278             oauth.options(Object.assign({
98279               url: urlroot,
98280               loading: authLoading,
98281               done: authDone
98282             }, options));
98283             this.reset();
98284             this.userChangesets(function () {}); // eagerly load user details/changesets
98285
98286             dispatch$2.call('change');
98287             return this;
98288           },
98289           toggle: function toggle(val) {
98290             _off = !val;
98291             return this;
98292           },
98293           isChangesetInflight: function isChangesetInflight() {
98294             return !!_changeset.inflight;
98295           },
98296           // get/set cached data
98297           // This is used to save/restore the state when entering/exiting the walkthrough
98298           // Also used for testing purposes.
98299           caches: function caches(obj) {
98300             function cloneCache(source) {
98301               var target = {};
98302               Object.keys(source).forEach(function (k) {
98303                 if (k === 'rtree') {
98304                   target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
98305                 } else if (k === 'note') {
98306                   target.note = {};
98307                   Object.keys(source.note).forEach(function (id) {
98308                     target.note[id] = osmNote(source.note[id]); // copy notes
98309                   });
98310                 } else {
98311                   target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
98312                 }
98313               });
98314               return target;
98315             }
98316
98317             if (!arguments.length) {
98318               return {
98319                 tile: cloneCache(_tileCache),
98320                 note: cloneCache(_noteCache),
98321                 user: cloneCache(_userCache)
98322               };
98323             } // access caches directly for testing (e.g., loading notes rtree)
98324
98325
98326             if (obj === 'get') {
98327               return {
98328                 tile: _tileCache,
98329                 note: _noteCache,
98330                 user: _userCache
98331               };
98332             }
98333
98334             if (obj.tile) {
98335               _tileCache = obj.tile;
98336               _tileCache.inflight = {};
98337             }
98338
98339             if (obj.note) {
98340               _noteCache = obj.note;
98341               _noteCache.inflight = {};
98342               _noteCache.inflightPost = {};
98343             }
98344
98345             if (obj.user) {
98346               _userCache = obj.user;
98347             }
98348
98349             return this;
98350           },
98351           logout: function logout() {
98352             _userChangesets = undefined;
98353             _userDetails = undefined;
98354             oauth.logout();
98355             dispatch$2.call('change');
98356             return this;
98357           },
98358           authenticated: function authenticated() {
98359             return oauth.authenticated();
98360           },
98361           authenticate: function authenticate(callback) {
98362             var that = this;
98363             var cid = _connectionID;
98364             _userChangesets = undefined;
98365             _userDetails = undefined;
98366
98367             function done(err, res) {
98368               if (err) {
98369                 if (callback) callback(err);
98370                 return;
98371               }
98372
98373               if (that.getConnectionId() !== cid) {
98374                 if (callback) callback({
98375                   message: 'Connection Switched',
98376                   status: -1
98377                 });
98378                 return;
98379               }
98380
98381               _rateLimitError = undefined;
98382               dispatch$2.call('change');
98383               if (callback) callback(err, res);
98384               that.userChangesets(function () {}); // eagerly load user details/changesets
98385             }
98386
98387             return oauth.authenticate(done);
98388           },
98389           imageryBlocklists: function imageryBlocklists() {
98390             return _imageryBlocklists;
98391           },
98392           tileZoom: function tileZoom(val) {
98393             if (!arguments.length) return _tileZoom;
98394             _tileZoom = val;
98395             return this;
98396           },
98397           // get all cached notes covering the viewport
98398           notes: function notes(projection) {
98399             var viewport = projection.clipExtent();
98400             var min = [viewport[0][0], viewport[1][1]];
98401             var max = [viewport[1][0], viewport[0][1]];
98402             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
98403             return _noteCache.rtree.search(bbox).map(function (d) {
98404               return d.data;
98405             });
98406           },
98407           // get a single note from the cache
98408           getNote: function getNote(id) {
98409             return _noteCache.note[id];
98410           },
98411           // remove a single note from the cache
98412           removeNote: function removeNote(note) {
98413             if (!(note instanceof osmNote) || !note.id) return;
98414             delete _noteCache.note[note.id];
98415             updateRtree(encodeNoteRtree(note), false); // false = remove
98416           },
98417           // replace a single note in the cache
98418           replaceNote: function replaceNote(note) {
98419             if (!(note instanceof osmNote) || !note.id) return;
98420             _noteCache.note[note.id] = note;
98421             updateRtree(encodeNoteRtree(note), true); // true = replace
98422
98423             return note;
98424           },
98425           // Get an array of note IDs closed during this session.
98426           // Used to populate `closed:note` changeset tag
98427           getClosedIDs: function getClosedIDs() {
98428             return Object.keys(_noteCache.closed).sort();
98429           }
98430         };
98431
98432         var _apibase$1 = 'https://wiki.openstreetmap.org/w/api.php';
98433         var _inflight$1 = {};
98434         var _wikibaseCache = {};
98435         var _localeIDs = {
98436           en: false
98437         };
98438
98439         var debouncedRequest$1 = debounce(request$1, 500, {
98440           leading: false
98441         });
98442
98443         function request$1(url, callback) {
98444           if (_inflight$1[url]) return;
98445           var controller = new AbortController();
98446           _inflight$1[url] = controller;
98447           d3_json(url, {
98448             signal: controller.signal
98449           }).then(function (result) {
98450             delete _inflight$1[url];
98451             if (callback) callback(null, result);
98452           })["catch"](function (err) {
98453             delete _inflight$1[url];
98454             if (err.name === 'AbortError') return;
98455             if (callback) callback(err.message);
98456           });
98457         }
98458
98459         var serviceOsmWikibase = {
98460           init: function init() {
98461             _inflight$1 = {};
98462             _wikibaseCache = {};
98463             _localeIDs = {};
98464           },
98465           reset: function reset() {
98466             Object.values(_inflight$1).forEach(function (controller) {
98467               controller.abort();
98468             });
98469             _inflight$1 = {};
98470           },
98471
98472           /**
98473            * Get the best value for the property, or undefined if not found
98474            * @param entity object from wikibase
98475            * @param property string e.g. 'P4' for image
98476            * @param langCode string e.g. 'fr' for French
98477            */
98478           claimToValue: function claimToValue(entity, property, langCode) {
98479             if (!entity.claims[property]) return undefined;
98480             var locale = _localeIDs[langCode];
98481             var preferredPick, localePick;
98482             entity.claims[property].forEach(function (stmt) {
98483               // If exists, use value limited to the needed language (has a qualifier P26 = locale)
98484               // Or if not found, use the first value with the "preferred" rank
98485               if (!preferredPick && stmt.rank === 'preferred') {
98486                 preferredPick = stmt;
98487               }
98488
98489               if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
98490                 localePick = stmt;
98491               }
98492             });
98493             var result = localePick || preferredPick;
98494
98495             if (result) {
98496               var datavalue = result.mainsnak.datavalue;
98497               return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
98498             } else {
98499               return undefined;
98500             }
98501           },
98502
98503           /**
98504            * Convert monolingual property into a key-value object (language -> value)
98505            * @param entity object from wikibase
98506            * @param property string e.g. 'P31' for monolingual wiki page title
98507            */
98508           monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
98509             if (!entity || !entity.claims[property]) return undefined;
98510             return entity.claims[property].reduce(function (acc, obj) {
98511               var value = obj.mainsnak.datavalue.value;
98512               acc[value.language] = value.text;
98513               return acc;
98514             }, {});
98515           },
98516           toSitelink: function toSitelink(key, value) {
98517             var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
98518             return result.replace(/_/g, ' ').trim();
98519           },
98520           //
98521           // Pass params object of the form:
98522           // {
98523           //   key: 'string',
98524           //   value: 'string',
98525           //   langCode: 'string'
98526           // }
98527           //
98528           getEntity: function getEntity(params, callback) {
98529             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
98530             var that = this;
98531             var titles = [];
98532             var result = {};
98533             var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
98534             var keySitelink = params.key ? this.toSitelink(params.key) : false;
98535             var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
98536             var localeSitelink;
98537
98538             if (params.langCodes) {
98539               params.langCodes.forEach(function (langCode) {
98540                 if (_localeIDs[langCode] === undefined) {
98541                   // If this is the first time we are asking about this locale,
98542                   // fetch corresponding entity (if it exists), and cache it.
98543                   // If there is no such entry, cache `false` value to avoid re-requesting it.
98544                   localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
98545                   titles.push(localeSitelink);
98546                 }
98547               });
98548             }
98549
98550             if (rtypeSitelink) {
98551               if (_wikibaseCache[rtypeSitelink]) {
98552                 result.rtype = _wikibaseCache[rtypeSitelink];
98553               } else {
98554                 titles.push(rtypeSitelink);
98555               }
98556             }
98557
98558             if (keySitelink) {
98559               if (_wikibaseCache[keySitelink]) {
98560                 result.key = _wikibaseCache[keySitelink];
98561               } else {
98562                 titles.push(keySitelink);
98563               }
98564             }
98565
98566             if (tagSitelink) {
98567               if (_wikibaseCache[tagSitelink]) {
98568                 result.tag = _wikibaseCache[tagSitelink];
98569               } else {
98570                 titles.push(tagSitelink);
98571               }
98572             }
98573
98574             if (!titles.length) {
98575               // Nothing to do, we already had everything in the cache
98576               return callback(null, result);
98577             } // Requesting just the user language code
98578             // If backend recognizes the code, it will perform proper fallbacks,
98579             // and the result will contain the requested code. If not, all values are returned:
98580             // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
98581             // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
98582
98583
98584             var obj = {
98585               action: 'wbgetentities',
98586               sites: 'wiki',
98587               titles: titles.join('|'),
98588               languages: params.langCodes.join('|'),
98589               languagefallback: 1,
98590               origin: '*',
98591               format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
98592               // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
98593               // formatversion: 2,
98594
98595             };
98596             var url = _apibase$1 + '?' + utilQsString(obj);
98597             doRequest(url, function (err, d) {
98598               if (err) {
98599                 callback(err);
98600               } else if (!d.success || d.error) {
98601                 callback(d.error.messages.map(function (v) {
98602                   return v.html['*'];
98603                 }).join('<br>'));
98604               } else {
98605                 var localeID = false;
98606                 Object.values(d.entities).forEach(function (res) {
98607                   if (res.missing !== '') {
98608                     var title = res.sitelinks.wiki.title;
98609
98610                     if (title === rtypeSitelink) {
98611                       _wikibaseCache[rtypeSitelink] = res;
98612                       result.rtype = res;
98613                     } else if (title === keySitelink) {
98614                       _wikibaseCache[keySitelink] = res;
98615                       result.key = res;
98616                     } else if (title === tagSitelink) {
98617                       _wikibaseCache[tagSitelink] = res;
98618                       result.tag = res;
98619                     } else if (title === localeSitelink) {
98620                       localeID = res.id;
98621                     } else {
98622                       console.log('Unexpected title ' + title); // eslint-disable-line no-console
98623                     }
98624                   }
98625                 });
98626
98627                 if (localeSitelink) {
98628                   // If locale ID is not found, store false to prevent repeated queries
98629                   that.addLocale(params.langCodes[0], localeID);
98630                 }
98631
98632                 callback(null, result);
98633               }
98634             });
98635           },
98636           //
98637           // Pass params object of the form:
98638           // {
98639           //   key: 'string',     // required
98640           //   value: 'string'    // optional
98641           // }
98642           //
98643           // Get an result object used to display tag documentation
98644           // {
98645           //   title:        'string',
98646           //   description:  'string',
98647           //   editURL:      'string',
98648           //   imageURL:     'string',
98649           //   wiki:         { title: 'string', text: 'string', url: 'string' }
98650           // }
98651           //
98652           getDocs: function getDocs(params, callback) {
98653             var that = this;
98654             var langCodes = _mainLocalizer.localeCodes().map(function (code) {
98655               return code.toLowerCase();
98656             });
98657             params.langCodes = langCodes;
98658             this.getEntity(params, function (err, data) {
98659               if (err) {
98660                 callback(err);
98661                 return;
98662               }
98663
98664               var entity = data.rtype || data.tag || data.key;
98665
98666               if (!entity) {
98667                 callback('No entity');
98668                 return;
98669               }
98670
98671               var i;
98672               var description;
98673
98674               for (i in langCodes) {
98675                 var _code = langCodes[i];
98676
98677                 if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
98678                   description = entity.descriptions[_code];
98679                   break;
98680                 }
98681               }
98682
98683               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
98684
98685               var result = {
98686                 title: entity.title,
98687                 description: description ? description.value : '',
98688                 descriptionLocaleCode: description ? description.language : '',
98689                 editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
98690               }; // add image
98691
98692               if (entity.claims) {
98693                 var imageroot;
98694                 var image = that.claimToValue(entity, 'P4', langCodes[0]);
98695
98696                 if (image) {
98697                   imageroot = 'https://commons.wikimedia.org/w/index.php';
98698                 } else {
98699                   image = that.claimToValue(entity, 'P28', langCodes[0]);
98700
98701                   if (image) {
98702                     imageroot = 'https://wiki.openstreetmap.org/w/index.php';
98703                   }
98704                 }
98705
98706                 if (imageroot && image) {
98707                   result.imageURL = imageroot + '?' + utilQsString({
98708                     title: 'Special:Redirect/file/' + image,
98709                     width: 400
98710                   });
98711                 }
98712               } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
98713               // If neither tag nor key data item contain a wiki page in the needed language nor English,
98714               // get the first found wiki page from either the tag or the key item.
98715
98716
98717               var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
98718               var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
98719               var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
98720               var wikis = [rtypeWiki, tagWiki, keyWiki];
98721
98722               for (i in wikis) {
98723                 var wiki = wikis[i];
98724
98725                 for (var j in langCodes) {
98726                   var code = langCodes[j];
98727                   var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
98728                   var info = getWikiInfo(wiki, code, referenceId);
98729
98730                   if (info) {
98731                     result.wiki = info;
98732                     break;
98733                   }
98734                 }
98735
98736                 if (result.wiki) break;
98737               }
98738
98739               callback(null, result); // Helper method to get wiki info if a given language exists
98740
98741               function getWikiInfo(wiki, langCode, tKey) {
98742                 if (wiki && wiki[langCode]) {
98743                   return {
98744                     title: wiki[langCode],
98745                     text: tKey,
98746                     url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
98747                   };
98748                 }
98749               }
98750             });
98751           },
98752           addLocale: function addLocale(langCode, qid) {
98753             // Makes it easier to unit test
98754             _localeIDs[langCode] = qid;
98755           },
98756           apibase: function apibase(val) {
98757             if (!arguments.length) return _apibase$1;
98758             _apibase$1 = val;
98759             return this;
98760           }
98761         };
98762
98763         var jsonpCache = {};
98764         window.jsonpCache = jsonpCache;
98765         function jsonpRequest(url, callback) {
98766           var request = {
98767             abort: function abort() {}
98768           };
98769
98770           if (window.JSONP_FIX) {
98771             if (window.JSONP_DELAY === 0) {
98772               callback(window.JSONP_FIX);
98773             } else {
98774               var t = window.setTimeout(function () {
98775                 callback(window.JSONP_FIX);
98776               }, window.JSONP_DELAY || 0);
98777
98778               request.abort = function () {
98779                 window.clearTimeout(t);
98780               };
98781             }
98782
98783             return request;
98784           }
98785
98786           function rand() {
98787             var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
98788             var c = '';
98789             var i = -1;
98790
98791             while (++i < 15) {
98792               c += chars.charAt(Math.floor(Math.random() * 52));
98793             }
98794
98795             return c;
98796           }
98797
98798           function create(url) {
98799             var e = url.match(/callback=(\w+)/);
98800             var c = e ? e[1] : rand();
98801
98802             jsonpCache[c] = function (data) {
98803               if (jsonpCache[c]) {
98804                 callback(data);
98805               }
98806
98807               finalize();
98808             };
98809
98810             function finalize() {
98811               delete jsonpCache[c];
98812               script.remove();
98813             }
98814
98815             request.abort = finalize;
98816             return 'jsonpCache.' + c;
98817           }
98818
98819           var cb = create(url);
98820           var script = select('head').append('script').attr('type', 'text/javascript').attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
98821           return request;
98822         }
98823
98824         var bubbleApi = 'https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?';
98825         var streetsideImagesApi = 'https://t.ssl.ak.tiles.virtualearth.net/tiles/';
98826         var bubbleAppKey = 'AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm';
98827         var pannellumViewerCSS = 'pannellum-streetside/pannellum.css';
98828         var pannellumViewerJS = 'pannellum-streetside/pannellum.js';
98829         var maxResults = 2000;
98830         var tileZoom = 16.5;
98831         var tiler$1 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
98832         var dispatch$1 = dispatch$8('loadedImages', 'viewerChanged');
98833         var minHfov = 10; // zoom in degrees:  20, 10, 5
98834
98835         var maxHfov = 90; // zoom out degrees
98836
98837         var defaultHfov = 45;
98838         var _hires = false;
98839         var _resolution = 512; // higher numbers are slower - 512, 1024, 2048, 4096
98840
98841         var _currScene = 0;
98842
98843         var _ssCache;
98844
98845         var _pannellumViewer;
98846
98847         var _sceneOptions = {
98848           showFullscreenCtrl: false,
98849           autoLoad: true,
98850           compass: true,
98851           yaw: 0,
98852           minHfov: minHfov,
98853           maxHfov: maxHfov,
98854           hfov: defaultHfov,
98855           type: 'cubemap',
98856           cubeMap: []
98857         };
98858
98859         var _loadViewerPromise;
98860         /**
98861          * abortRequest().
98862          */
98863
98864
98865         function abortRequest$1(i) {
98866           i.abort();
98867         }
98868         /**
98869          * localeTimeStamp().
98870          */
98871
98872
98873         function localeTimestamp(s) {
98874           if (!s) return null;
98875           var options = {
98876             day: 'numeric',
98877             month: 'short',
98878             year: 'numeric'
98879           };
98880           var d = new Date(s);
98881           if (isNaN(d.getTime())) return null;
98882           return d.toLocaleString(_mainLocalizer.localeCode(), options);
98883         }
98884         /**
98885          * loadTiles() wraps the process of generating tiles and then fetching image points for each tile.
98886          */
98887
98888
98889         function loadTiles(which, url, projection, margin) {
98890           var tiles = tiler$1.margin(margin).getTiles(projection); // abort inflight requests that are no longer needed
98891
98892           var cache = _ssCache[which];
98893           Object.keys(cache.inflight).forEach(function (k) {
98894             var wanted = tiles.find(function (tile) {
98895               return k.indexOf(tile.id + ',') === 0;
98896             });
98897
98898             if (!wanted) {
98899               abortRequest$1(cache.inflight[k]);
98900               delete cache.inflight[k];
98901             }
98902           });
98903           tiles.forEach(function (tile) {
98904             return loadNextTilePage(which, url, tile);
98905           });
98906         }
98907         /**
98908          * loadNextTilePage() load data for the next tile page in line.
98909          */
98910
98911
98912         function loadNextTilePage(which, url, tile) {
98913           var cache = _ssCache[which];
98914           var nextPage = cache.nextPage[tile.id] || 0;
98915           var id = tile.id + ',' + String(nextPage);
98916           if (cache.loaded[id] || cache.inflight[id]) return;
98917           cache.inflight[id] = getBubbles(url, tile, function (bubbles) {
98918             cache.loaded[id] = true;
98919             delete cache.inflight[id];
98920             if (!bubbles) return; // [].shift() removes the first element, some statistics info, not a bubble point
98921
98922             bubbles.shift();
98923             var features = bubbles.map(function (bubble) {
98924               if (cache.points[bubble.id]) return null; // skip duplicates
98925
98926               var loc = [bubble.lo, bubble.la];
98927               var d = {
98928                 loc: loc,
98929                 key: bubble.id,
98930                 ca: bubble.he,
98931                 captured_at: bubble.cd,
98932                 captured_by: 'microsoft',
98933                 // nbn: bubble.nbn,
98934                 // pbn: bubble.pbn,
98935                 // ad: bubble.ad,
98936                 // rn: bubble.rn,
98937                 pr: bubble.pr,
98938                 // previous
98939                 ne: bubble.ne,
98940                 // next
98941                 pano: true,
98942                 sequenceKey: null
98943               };
98944               cache.points[bubble.id] = d; // a sequence starts here
98945
98946               if (bubble.pr === undefined) {
98947                 cache.leaders.push(bubble.id);
98948               }
98949
98950               return {
98951                 minX: loc[0],
98952                 minY: loc[1],
98953                 maxX: loc[0],
98954                 maxY: loc[1],
98955                 data: d
98956               };
98957             }).filter(Boolean);
98958             cache.rtree.load(features);
98959             connectSequences();
98960
98961             if (which === 'bubbles') {
98962               dispatch$1.call('loadedImages');
98963             }
98964           });
98965         } // call this sometimes to connect the bubbles into sequences
98966
98967
98968         function connectSequences() {
98969           var cache = _ssCache.bubbles;
98970           var keepLeaders = [];
98971
98972           for (var i = 0; i < cache.leaders.length; i++) {
98973             var bubble = cache.points[cache.leaders[i]];
98974             var seen = {}; // try to make a sequence.. use the key of the leader bubble.
98975
98976             var sequence = {
98977               key: bubble.key,
98978               bubbles: []
98979             };
98980             var complete = false;
98981
98982             do {
98983               sequence.bubbles.push(bubble);
98984               seen[bubble.key] = true;
98985
98986               if (bubble.ne === undefined) {
98987                 complete = true;
98988               } else {
98989                 bubble = cache.points[bubble.ne]; // advance to next
98990               }
98991             } while (bubble && !seen[bubble.key] && !complete);
98992
98993             if (complete) {
98994               _ssCache.sequences[sequence.key] = sequence; // assign bubbles to the sequence
98995
98996               for (var j = 0; j < sequence.bubbles.length; j++) {
98997                 sequence.bubbles[j].sequenceKey = sequence.key;
98998               } // create a GeoJSON LineString
98999
99000
99001               sequence.geojson = {
99002                 type: 'LineString',
99003                 properties: {
99004                   captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
99005                   captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
99006                   key: sequence.key
99007                 },
99008                 coordinates: sequence.bubbles.map(function (d) {
99009                   return d.loc;
99010                 })
99011               };
99012             } else {
99013               keepLeaders.push(cache.leaders[i]);
99014             }
99015           } // couldn't complete these, save for later
99016
99017
99018           cache.leaders = keepLeaders;
99019         }
99020         /**
99021          * getBubbles() handles the request to the server for a tile extent of 'bubbles' (streetside image locations).
99022          */
99023
99024
99025         function getBubbles(url, tile, callback) {
99026           var rect = tile.extent.rectangle();
99027           var urlForRequest = url + utilQsString({
99028             n: rect[3],
99029             s: rect[1],
99030             e: rect[2],
99031             w: rect[0],
99032             c: maxResults,
99033             appkey: bubbleAppKey,
99034             jsCallback: '{callback}'
99035           });
99036           return jsonpRequest(urlForRequest, function (data) {
99037             if (!data || data.error) {
99038               callback(null);
99039             } else {
99040               callback(data);
99041             }
99042           });
99043         } // partition viewport into higher zoom tiles
99044
99045
99046         function partitionViewport(projection) {
99047           var z = geoScaleToZoom(projection.scale());
99048           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
99049
99050           var tiler = utilTiler().zoomExtent([z2, z2]);
99051           return tiler.getTiles(projection).map(function (tile) {
99052             return tile.extent;
99053           });
99054         } // no more than `limit` results per partition.
99055
99056
99057         function searchLimited(limit, projection, rtree) {
99058           limit = limit || 5;
99059           return partitionViewport(projection).reduce(function (result, extent) {
99060             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
99061               return d.data;
99062             });
99063             return found.length ? result.concat(found) : result;
99064           }, []);
99065         }
99066         /**
99067          * loadImage()
99068          */
99069
99070
99071         function loadImage(imgInfo) {
99072           return new Promise(function (resolve) {
99073             var img = new Image();
99074
99075             img.onload = function () {
99076               var canvas = document.getElementById('ideditor-canvas' + imgInfo.face);
99077               var ctx = canvas.getContext('2d');
99078               ctx.drawImage(img, imgInfo.x, imgInfo.y);
99079               resolve({
99080                 imgInfo: imgInfo,
99081                 status: 'ok'
99082               });
99083             };
99084
99085             img.onerror = function () {
99086               resolve({
99087                 data: imgInfo,
99088                 status: 'error'
99089               });
99090             };
99091
99092             img.setAttribute('crossorigin', '');
99093             img.src = imgInfo.url;
99094           });
99095         }
99096         /**
99097          * loadCanvas()
99098          */
99099
99100
99101         function loadCanvas(imageGroup) {
99102           return Promise.all(imageGroup.map(loadImage)).then(function (data) {
99103             var canvas = document.getElementById('ideditor-canvas' + data[0].imgInfo.face);
99104             var which = {
99105               '01': 0,
99106               '02': 1,
99107               '03': 2,
99108               '10': 3,
99109               '11': 4,
99110               '12': 5
99111             };
99112             var face = data[0].imgInfo.face;
99113             _sceneOptions.cubeMap[which[face]] = canvas.toDataURL('image/jpeg', 1.0);
99114             return {
99115               status: 'loadCanvas for face ' + data[0].imgInfo.face + 'ok'
99116             };
99117           });
99118         }
99119         /**
99120          * loadFaces()
99121          */
99122
99123
99124         function loadFaces(faceGroup) {
99125           return Promise.all(faceGroup.map(loadCanvas)).then(function () {
99126             return {
99127               status: 'loadFaces done'
99128             };
99129           });
99130         }
99131
99132         function setupCanvas(selection, reset) {
99133           if (reset) {
99134             selection.selectAll('#ideditor-stitcher-canvases').remove();
99135           } // Add the Streetside working canvases. These are used for 'stitching', or combining,
99136           // multiple images for each of the six faces, before passing to the Pannellum control as DataUrls
99137
99138
99139           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) {
99140             return 'ideditor-' + d;
99141           }).attr('width', _resolution).attr('height', _resolution);
99142         }
99143
99144         function qkToXY(qk) {
99145           var x = 0;
99146           var y = 0;
99147           var scale = 256;
99148
99149           for (var i = qk.length; i > 0; i--) {
99150             var key = qk[i - 1];
99151             x += +(key === '1' || key === '3') * scale;
99152             y += +(key === '2' || key === '3') * scale;
99153             scale *= 2;
99154           }
99155
99156           return [x, y];
99157         }
99158
99159         function getQuadKeys() {
99160           var dim = _resolution / 256;
99161           var quadKeys;
99162
99163           if (dim === 16) {
99164             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'];
99165           } else if (dim === 8) {
99166             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'];
99167           } else if (dim === 4) {
99168             quadKeys = ['00', '01', '10', '11', '02', '03', '12', '13', '20', '21', '30', '31', '22', '23', '32', '33'];
99169           } else {
99170             // dim === 2
99171             quadKeys = ['0', '1', '2', '3'];
99172           }
99173
99174           return quadKeys;
99175         }
99176
99177         var serviceStreetside = {
99178           /**
99179            * init() initialize streetside.
99180            */
99181           init: function init() {
99182             if (!_ssCache) {
99183               this.reset();
99184             }
99185
99186             this.event = utilRebind(this, dispatch$1, 'on');
99187           },
99188
99189           /**
99190            * reset() reset the cache.
99191            */
99192           reset: function reset() {
99193             if (_ssCache) {
99194               Object.values(_ssCache.bubbles.inflight).forEach(abortRequest$1);
99195             }
99196
99197             _ssCache = {
99198               bubbles: {
99199                 inflight: {},
99200                 loaded: {},
99201                 nextPage: {},
99202                 rtree: new RBush(),
99203                 points: {},
99204                 leaders: []
99205               },
99206               sequences: {}
99207             };
99208           },
99209
99210           /**
99211            * bubbles()
99212            */
99213           bubbles: function bubbles(projection) {
99214             var limit = 5;
99215             return searchLimited(limit, projection, _ssCache.bubbles.rtree);
99216           },
99217           cachedImage: function cachedImage(imageKey) {
99218             return _ssCache.bubbles.points[imageKey];
99219           },
99220           sequences: function sequences(projection) {
99221             var viewport = projection.clipExtent();
99222             var min = [viewport[0][0], viewport[1][1]];
99223             var max = [viewport[1][0], viewport[0][1]];
99224             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
99225             var seen = {};
99226             var results = []; // all sequences for bubbles in viewport
99227
99228             _ssCache.bubbles.rtree.search(bbox).forEach(function (d) {
99229               var key = d.data.sequenceKey;
99230
99231               if (key && !seen[key]) {
99232                 seen[key] = true;
99233                 results.push(_ssCache.sequences[key].geojson);
99234               }
99235             });
99236
99237             return results;
99238           },
99239
99240           /**
99241            * loadBubbles()
99242            */
99243           loadBubbles: function loadBubbles(projection, margin) {
99244             // by default: request 2 nearby tiles so we can connect sequences.
99245             if (margin === undefined) margin = 2;
99246             loadTiles('bubbles', bubbleApi, projection, margin);
99247           },
99248           viewer: function viewer() {
99249             return _pannellumViewer;
99250           },
99251           initViewer: function initViewer() {
99252             if (!window.pannellum) return;
99253             if (_pannellumViewer) return;
99254             _currScene += 1;
99255
99256             var sceneID = _currScene.toString();
99257
99258             var options = {
99259               'default': {
99260                 firstScene: sceneID
99261               },
99262               scenes: {}
99263             };
99264             options.scenes[sceneID] = _sceneOptions;
99265             _pannellumViewer = window.pannellum.viewer('ideditor-viewer-streetside', options);
99266           },
99267           ensureViewerLoaded: function ensureViewerLoaded(context) {
99268             if (_loadViewerPromise) return _loadViewerPromise; // create ms-wrapper, a photo wrapper class
99269
99270             var wrap = context.container().select('.photoviewer').selectAll('.ms-wrapper').data([0]); // inject ms-wrapper into the photoviewer div
99271             // (used by all to house each custom photo viewer)
99272
99273             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper ms-wrapper').classed('hide', true);
99274             var that = this;
99275             var pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // inject div to support streetside viewer (pannellum) and attribution line
99276
99277             wrapEnter.append('div').attr('id', 'ideditor-viewer-streetside').on(pointerPrefix + 'down.streetside', function () {
99278               select(window).on(pointerPrefix + 'move.streetside', function () {
99279                 dispatch$1.call('viewerChanged');
99280               }, true);
99281             }).on(pointerPrefix + 'up.streetside pointercancel.streetside', function () {
99282               select(window).on(pointerPrefix + 'move.streetside', null); // continue dispatching events for a few seconds, in case viewer has inertia.
99283
99284               var t = timer(function (elapsed) {
99285                 dispatch$1.call('viewerChanged');
99286
99287                 if (elapsed > 2000) {
99288                   t.stop();
99289                 }
99290               });
99291             }).append('div').attr('class', 'photo-attribution fillD');
99292             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
99293             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
99294             controlsEnter.append('button').on('click.forward', step(1)).html('►'); // create working canvas for stitching together images
99295
99296             wrap = wrap.merge(wrapEnter).call(setupCanvas, true); // Register viewer resize handler
99297
99298             context.ui().photoviewer.on('resize.streetside', function () {
99299               if (_pannellumViewer) {
99300                 _pannellumViewer.resize();
99301               }
99302             });
99303             _loadViewerPromise = new Promise(function (resolve, reject) {
99304               var loadedCount = 0;
99305
99306               function loaded() {
99307                 loadedCount += 1; // wait until both files are loaded
99308
99309                 if (loadedCount === 2) resolve();
99310               }
99311
99312               var head = select('head'); // load streetside pannellum viewer css
99313
99314               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 () {
99315                 reject();
99316               }); // load streetside pannellum viewer js
99317
99318               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 () {
99319                 reject();
99320               });
99321             })["catch"](function () {
99322               _loadViewerPromise = null;
99323             });
99324             return _loadViewerPromise;
99325
99326             function step(stepBy) {
99327               return function () {
99328                 var viewer = context.container().select('.photoviewer');
99329                 var selected = viewer.empty() ? undefined : viewer.datum();
99330                 if (!selected) return;
99331                 var nextID = stepBy === 1 ? selected.ne : selected.pr;
99332
99333                 var yaw = _pannellumViewer.getYaw();
99334
99335                 var ca = selected.ca + yaw;
99336                 var origin = selected.loc; // construct a search trapezoid pointing out from current bubble
99337
99338                 var meters = 35;
99339                 var p1 = [origin[0] + geoMetersToLon(meters / 5, origin[1]), origin[1]];
99340                 var p2 = [origin[0] + geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
99341                 var p3 = [origin[0] - geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
99342                 var p4 = [origin[0] - geoMetersToLon(meters / 5, origin[1]), origin[1]];
99343                 var poly = [p1, p2, p3, p4, p1]; // rotate it to face forward/backward
99344
99345                 var angle = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
99346                 poly = geoRotate(poly, -angle, origin);
99347                 var extent = poly.reduce(function (extent, point) {
99348                   return extent.extend(geoExtent(point));
99349                 }, geoExtent()); // find nearest other bubble in the search polygon
99350
99351                 var minDist = Infinity;
99352
99353                 _ssCache.bubbles.rtree.search(extent.bbox()).forEach(function (d) {
99354                   if (d.data.key === selected.key) return;
99355                   if (!geoPointInPolygon(d.data.loc, poly)) return;
99356                   var dist = geoVecLength(d.data.loc, selected.loc);
99357                   var theta = selected.ca - d.data.ca;
99358                   var minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
99359
99360                   if (minTheta > 20) {
99361                     dist += 5; // penalize distance if camera angles don't match
99362                   }
99363
99364                   if (dist < minDist) {
99365                     nextID = d.data.key;
99366                     minDist = dist;
99367                   }
99368                 });
99369
99370                 var nextBubble = nextID && that.cachedImage(nextID);
99371                 if (!nextBubble) return;
99372                 context.map().centerEase(nextBubble.loc);
99373                 that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
99374               };
99375             }
99376           },
99377           yaw: function yaw(_yaw) {
99378             if (typeof _yaw !== 'number') return _yaw;
99379             _sceneOptions.yaw = _yaw;
99380             return this;
99381           },
99382
99383           /**
99384            * showViewer()
99385            */
99386           showViewer: function showViewer(context) {
99387             var wrap = context.container().select('.photoviewer').classed('hide', false);
99388             var isHidden = wrap.selectAll('.photo-wrapper.ms-wrapper.hide').size();
99389
99390             if (isHidden) {
99391               wrap.selectAll('.photo-wrapper:not(.ms-wrapper)').classed('hide', true);
99392               wrap.selectAll('.photo-wrapper.ms-wrapper').classed('hide', false);
99393             }
99394
99395             return this;
99396           },
99397
99398           /**
99399            * hideViewer()
99400            */
99401           hideViewer: function hideViewer(context) {
99402             var viewer = context.container().select('.photoviewer');
99403             if (!viewer.empty()) viewer.datum(null);
99404             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
99405             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
99406             this.updateUrlImage(null);
99407             return this.setStyles(context, null, true);
99408           },
99409
99410           /**
99411            * selectImage().
99412            */
99413           selectImage: function selectImage(context, key) {
99414             var that = this;
99415             var d = this.cachedImage(key);
99416             var viewer = context.container().select('.photoviewer');
99417             if (!viewer.empty()) viewer.datum(d);
99418             this.setStyles(context, null, true);
99419             var wrap = context.container().select('.photoviewer .ms-wrapper');
99420             var attribution = wrap.selectAll('.photo-attribution').html('');
99421             wrap.selectAll('.pnlm-load-box') // display "loading.."
99422             .style('display', 'block');
99423             if (!d) return this;
99424             this.updateUrlImage(key);
99425             _sceneOptions.northOffset = d.ca;
99426             var line1 = attribution.append('div').attr('class', 'attribution-row');
99427             var hiresDomId = utilUniqueDomId('streetside-hires'); // Add hires checkbox
99428
99429             var label = line1.append('label').attr('for', hiresDomId).attr('class', 'streetside-hires');
99430             label.append('input').attr('type', 'checkbox').attr('id', hiresDomId).property('checked', _hires).on('click', function (d3_event) {
99431               d3_event.stopPropagation();
99432               _hires = !_hires;
99433               _resolution = _hires ? 1024 : 512;
99434               wrap.call(setupCanvas, true);
99435               var viewstate = {
99436                 yaw: _pannellumViewer.getYaw(),
99437                 pitch: _pannellumViewer.getPitch(),
99438                 hfov: _pannellumViewer.getHfov()
99439               };
99440               _sceneOptions = Object.assign(_sceneOptions, viewstate);
99441               that.selectImage(context, d.key).showViewer(context);
99442             });
99443             label.append('span').html(_t.html('streetside.hires'));
99444             var captureInfo = line1.append('div').attr('class', 'attribution-capture-info'); // Add capture date
99445
99446             if (d.captured_by) {
99447               var yyyy = new Date().getFullYear();
99448               captureInfo.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://www.microsoft.com/en-us/maps/streetside').html('©' + yyyy + ' Microsoft');
99449               captureInfo.append('span').html('|');
99450             }
99451
99452             if (d.captured_at) {
99453               captureInfo.append('span').attr('class', 'captured_at').html(localeTimestamp(d.captured_at));
99454             } // Add image links
99455
99456
99457             var line2 = attribution.append('div').attr('class', 'attribution-row');
99458             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'));
99459             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'));
99460             var bubbleIdQuadKey = d.key.toString(4);
99461             var paddingNeeded = 16 - bubbleIdQuadKey.length;
99462
99463             for (var i = 0; i < paddingNeeded; i++) {
99464               bubbleIdQuadKey = '0' + bubbleIdQuadKey;
99465             }
99466
99467             var imgUrlPrefix = streetsideImagesApi + 'hs' + bubbleIdQuadKey;
99468             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
99469
99470             var faceKeys = ['01', '02', '03', '10', '11', '12']; // Map images to cube faces
99471
99472             var quadKeys = getQuadKeys();
99473             var faces = faceKeys.map(function (faceKey) {
99474               return quadKeys.map(function (quadKey) {
99475                 var xy = qkToXY(quadKey);
99476                 return {
99477                   face: faceKey,
99478                   url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
99479                   x: xy[0],
99480                   y: xy[1]
99481                 };
99482               });
99483             });
99484             loadFaces(faces).then(function () {
99485               if (!_pannellumViewer) {
99486                 that.initViewer();
99487               } else {
99488                 // make a new scene
99489                 _currScene += 1;
99490
99491                 var sceneID = _currScene.toString();
99492
99493                 _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID); // remove previous scene
99494
99495
99496                 if (_currScene > 2) {
99497                   sceneID = (_currScene - 1).toString();
99498
99499                   _pannellumViewer.removeScene(sceneID);
99500                 }
99501               }
99502             });
99503             return this;
99504           },
99505           getSequenceKeyForBubble: function getSequenceKeyForBubble(d) {
99506             return d && d.sequenceKey;
99507           },
99508           // Updates the currently highlighted sequence and selected bubble.
99509           // Reset is only necessary when interacting with the viewport because
99510           // this implicitly changes the currently selected bubble/sequence
99511           setStyles: function setStyles(context, hovered, reset) {
99512             if (reset) {
99513               // reset all layers
99514               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
99515               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
99516             }
99517
99518             var hoveredBubbleKey = hovered && hovered.key;
99519             var hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
99520             var hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
99521             var hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map(function (d) {
99522               return d.key;
99523             }) || [];
99524             var viewer = context.container().select('.photoviewer');
99525             var selected = viewer.empty() ? undefined : viewer.datum();
99526             var selectedBubbleKey = selected && selected.key;
99527             var selectedSequenceKey = this.getSequenceKeyForBubble(selected);
99528             var selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
99529             var selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map(function (d) {
99530               return d.key;
99531             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
99532
99533             var highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
99534             context.container().selectAll('.layer-streetside-images .viewfield-group').classed('highlighted', function (d) {
99535               return highlightedBubbleKeys.indexOf(d.key) !== -1;
99536             }).classed('hovered', function (d) {
99537               return d.key === hoveredBubbleKey;
99538             }).classed('currentView', function (d) {
99539               return d.key === selectedBubbleKey;
99540             });
99541             context.container().selectAll('.layer-streetside-images .sequence').classed('highlighted', function (d) {
99542               return d.properties.key === hoveredSequenceKey;
99543             }).classed('currentView', function (d) {
99544               return d.properties.key === selectedSequenceKey;
99545             }); // update viewfields if needed
99546
99547             context.container().selectAll('.layer-streetside-images .viewfield-group .viewfield').attr('d', viewfieldPath);
99548
99549             function viewfieldPath() {
99550               var d = this.parentNode.__data__;
99551
99552               if (d.pano && d.key !== selectedBubbleKey) {
99553                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
99554               } else {
99555                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
99556               }
99557             }
99558
99559             return this;
99560           },
99561           updateUrlImage: function updateUrlImage(imageKey) {
99562             if (!window.mocha) {
99563               var hash = utilStringQs(window.location.hash);
99564
99565               if (imageKey) {
99566                 hash.photo = 'streetside/' + imageKey;
99567               } else {
99568                 delete hash.photo;
99569               }
99570
99571               window.location.replace('#' + utilQsString(hash, true));
99572             }
99573           },
99574
99575           /**
99576            * cache().
99577            */
99578           cache: function cache() {
99579             return _ssCache;
99580           }
99581         };
99582
99583         var _apibase = 'https://taginfo.openstreetmap.org/api/4/';
99584         var _inflight = {};
99585         var _popularKeys = {};
99586         var _taginfoCache = {};
99587         var tag_sorts = {
99588           point: 'count_nodes',
99589           vertex: 'count_nodes',
99590           area: 'count_ways',
99591           line: 'count_ways'
99592         };
99593         var tag_sort_members = {
99594           point: 'count_node_members',
99595           vertex: 'count_node_members',
99596           area: 'count_way_members',
99597           line: 'count_way_members',
99598           relation: 'count_relation_members'
99599         };
99600         var tag_filters = {
99601           point: 'nodes',
99602           vertex: 'nodes',
99603           area: 'ways',
99604           line: 'ways'
99605         };
99606         var tag_members_fractions = {
99607           point: 'count_node_members_fraction',
99608           vertex: 'count_node_members_fraction',
99609           area: 'count_way_members_fraction',
99610           line: 'count_way_members_fraction',
99611           relation: 'count_relation_members_fraction'
99612         };
99613
99614         function sets(params, n, o) {
99615           if (params.geometry && o[params.geometry]) {
99616             params[n] = o[params.geometry];
99617           }
99618
99619           return params;
99620         }
99621
99622         function setFilter(params) {
99623           return sets(params, 'filter', tag_filters);
99624         }
99625
99626         function setSort(params) {
99627           return sets(params, 'sortname', tag_sorts);
99628         }
99629
99630         function setSortMembers(params) {
99631           return sets(params, 'sortname', tag_sort_members);
99632         }
99633
99634         function clean(params) {
99635           return utilObjectOmit(params, ['geometry', 'debounce']);
99636         }
99637
99638         function filterKeys(type) {
99639           var count_type = type ? 'count_' + type : 'count_all';
99640           return function (d) {
99641             return parseFloat(d[count_type]) > 2500 || d.in_wiki;
99642           };
99643         }
99644
99645         function filterMultikeys(prefix) {
99646           return function (d) {
99647             // d.key begins with prefix, and d.key contains no additional ':'s
99648             var re = new RegExp('^' + prefix + '(.*)$');
99649             var matches = d.key.match(re) || [];
99650             return matches.length === 2 && matches[1].indexOf(':') === -1;
99651           };
99652         }
99653
99654         function filterValues(allowUpperCase) {
99655           return function (d) {
99656             if (d.value.match(/[;,]/) !== null) return false; // exclude some punctuation
99657
99658             if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false; // exclude uppercase letters
99659
99660             return parseFloat(d.fraction) > 0.0;
99661           };
99662         }
99663
99664         function filterRoles(geometry) {
99665           return function (d) {
99666             if (d.role === '') return false; // exclude empty role
99667
99668             if (d.role.match(/[A-Z*;,]/) !== null) return false; // exclude uppercase letters and some punctuation
99669
99670             return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
99671           };
99672         }
99673
99674         function valKey(d) {
99675           return {
99676             value: d.key,
99677             title: d.key
99678           };
99679         }
99680
99681         function valKeyDescription(d) {
99682           var obj = {
99683             value: d.value,
99684             title: d.description || d.value
99685           };
99686
99687           if (d.count) {
99688             obj.count = d.count;
99689           }
99690
99691           return obj;
99692         }
99693
99694         function roleKey(d) {
99695           return {
99696             value: d.role,
99697             title: d.role
99698           };
99699         } // sort keys with ':' lower than keys without ':'
99700
99701
99702         function sortKeys(a, b) {
99703           return a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1 ? -1 : a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1 ? 1 : 0;
99704         }
99705
99706         var debouncedRequest = debounce(request, 300, {
99707           leading: false
99708         });
99709
99710         function request(url, params, exactMatch, callback, loaded) {
99711           if (_inflight[url]) return;
99712           if (checkCache(url, params, exactMatch, callback)) return;
99713           var controller = new AbortController();
99714           _inflight[url] = controller;
99715           d3_json(url, {
99716             signal: controller.signal
99717           }).then(function (result) {
99718             delete _inflight[url];
99719             if (loaded) loaded(null, result);
99720           })["catch"](function (err) {
99721             delete _inflight[url];
99722             if (err.name === 'AbortError') return;
99723             if (loaded) loaded(err.message);
99724           });
99725         }
99726
99727         function checkCache(url, params, exactMatch, callback) {
99728           var rp = params.rp || 25;
99729           var testQuery = params.query || '';
99730           var testUrl = url;
99731
99732           do {
99733             var hit = _taginfoCache[testUrl]; // exact match, or shorter match yielding fewer than max results (rp)
99734
99735             if (hit && (url === testUrl || hit.length < rp)) {
99736               callback(null, hit);
99737               return true;
99738             } // don't try to shorten the query
99739
99740
99741             if (exactMatch || !testQuery.length) return false; // do shorten the query to see if we already have a cached result
99742             // that has returned fewer than max results (rp)
99743
99744             testQuery = testQuery.slice(0, -1);
99745             testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
99746           } while (testQuery.length >= 0);
99747
99748           return false;
99749         }
99750
99751         var serviceTaginfo = {
99752           init: function init() {
99753             _inflight = {};
99754             _taginfoCache = {};
99755             _popularKeys = {
99756               // manually exclude some keys – #5377, #7485
99757               postal_code: true,
99758               full_name: true,
99759               loc_name: true,
99760               reg_name: true,
99761               short_name: true,
99762               sorting_name: true,
99763               artist_name: true,
99764               nat_name: true,
99765               long_name: true,
99766               'bridge:name': true
99767             }; // Fetch popular keys.  We'll exclude these from `values`
99768             // lookups because they stress taginfo, and they aren't likely
99769             // to yield meaningful autocomplete results.. see #3955
99770
99771             var params = {
99772               rp: 100,
99773               sortname: 'values_all',
99774               sortorder: 'desc',
99775               page: 1,
99776               debounce: false,
99777               lang: _mainLocalizer.languageCode()
99778             };
99779             this.keys(params, function (err, data) {
99780               if (err) return;
99781               data.forEach(function (d) {
99782                 if (d.value === 'opening_hours') return; // exception
99783
99784                 _popularKeys[d.value] = true;
99785               });
99786             });
99787           },
99788           reset: function reset() {
99789             Object.values(_inflight).forEach(function (controller) {
99790               controller.abort();
99791             });
99792             _inflight = {};
99793           },
99794           keys: function keys(params, callback) {
99795             var doRequest = params.debounce ? debouncedRequest : request;
99796             params = clean(setSort(params));
99797             params = Object.assign({
99798               rp: 10,
99799               sortname: 'count_all',
99800               sortorder: 'desc',
99801               page: 1,
99802               lang: _mainLocalizer.languageCode()
99803             }, params);
99804             var url = _apibase + 'keys/all?' + utilQsString(params);
99805             doRequest(url, params, false, callback, function (err, d) {
99806               if (err) {
99807                 callback(err);
99808               } else {
99809                 var f = filterKeys(params.filter);
99810                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
99811                 _taginfoCache[url] = result;
99812                 callback(null, result);
99813               }
99814             });
99815           },
99816           multikeys: function multikeys(params, callback) {
99817             var doRequest = params.debounce ? debouncedRequest : request;
99818             params = clean(setSort(params));
99819             params = Object.assign({
99820               rp: 25,
99821               sortname: 'count_all',
99822               sortorder: 'desc',
99823               page: 1,
99824               lang: _mainLocalizer.languageCode()
99825             }, params);
99826             var prefix = params.query;
99827             var url = _apibase + 'keys/all?' + utilQsString(params);
99828             doRequest(url, params, true, callback, function (err, d) {
99829               if (err) {
99830                 callback(err);
99831               } else {
99832                 var f = filterMultikeys(prefix);
99833                 var result = d.data.filter(f).map(valKey);
99834                 _taginfoCache[url] = result;
99835                 callback(null, result);
99836               }
99837             });
99838           },
99839           values: function values(params, callback) {
99840             // Exclude popular keys from values lookups.. see #3955
99841             var key = params.key;
99842
99843             if (key && _popularKeys[key]) {
99844               callback(null, []);
99845               return;
99846             }
99847
99848             var doRequest = params.debounce ? debouncedRequest : request;
99849             params = clean(setSort(setFilter(params)));
99850             params = Object.assign({
99851               rp: 25,
99852               sortname: 'count_all',
99853               sortorder: 'desc',
99854               page: 1,
99855               lang: _mainLocalizer.languageCode()
99856             }, params);
99857             var url = _apibase + 'key/values?' + utilQsString(params);
99858             doRequest(url, params, false, callback, function (err, d) {
99859               if (err) {
99860                 callback(err);
99861               } else {
99862                 // In most cases we prefer taginfo value results with lowercase letters.
99863                 // A few OSM keys expect values to contain uppercase values (see #3377).
99864                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
99865                 // but these are the fields where taginfo value lookup is most useful.
99866                 var re = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery/;
99867                 var allowUpperCase = re.test(params.key);
99868                 var f = filterValues(allowUpperCase);
99869                 var result = d.data.filter(f).map(valKeyDescription);
99870                 _taginfoCache[url] = result;
99871                 callback(null, result);
99872               }
99873             });
99874           },
99875           roles: function roles(params, callback) {
99876             var doRequest = params.debounce ? debouncedRequest : request;
99877             var geometry = params.geometry;
99878             params = clean(setSortMembers(params));
99879             params = Object.assign({
99880               rp: 25,
99881               sortname: 'count_all_members',
99882               sortorder: 'desc',
99883               page: 1,
99884               lang: _mainLocalizer.languageCode()
99885             }, params);
99886             var url = _apibase + 'relation/roles?' + utilQsString(params);
99887             doRequest(url, params, true, callback, function (err, d) {
99888               if (err) {
99889                 callback(err);
99890               } else {
99891                 var f = filterRoles(geometry);
99892                 var result = d.data.filter(f).map(roleKey);
99893                 _taginfoCache[url] = result;
99894                 callback(null, result);
99895               }
99896             });
99897           },
99898           docs: function docs(params, callback) {
99899             var doRequest = params.debounce ? debouncedRequest : request;
99900             params = clean(setSort(params));
99901             var path = 'key/wiki_pages?';
99902
99903             if (params.value) {
99904               path = 'tag/wiki_pages?';
99905             } else if (params.rtype) {
99906               path = 'relation/wiki_pages?';
99907             }
99908
99909             var url = _apibase + path + utilQsString(params);
99910             doRequest(url, params, true, callback, function (err, d) {
99911               if (err) {
99912                 callback(err);
99913               } else {
99914                 _taginfoCache[url] = d.data;
99915                 callback(null, d.data);
99916               }
99917             });
99918           },
99919           apibase: function apibase(_) {
99920             if (!arguments.length) return _apibase;
99921             _apibase = _;
99922             return this;
99923           }
99924         };
99925
99926         /**
99927          * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
99928          *
99929          * @name feature
99930          * @param {Geometry} geometry input geometry
99931          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
99932          * @param {Object} [options={}] Optional Parameters
99933          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
99934          * @param {string|number} [options.id] Identifier associated with the Feature
99935          * @returns {Feature} a GeoJSON Feature
99936          * @example
99937          * var geometry = {
99938          *   "type": "Point",
99939          *   "coordinates": [110, 50]
99940          * };
99941          *
99942          * var feature = turf.feature(geometry);
99943          *
99944          * //=feature
99945          */
99946
99947         function feature(geom, properties, options) {
99948           if (options === void 0) {
99949             options = {};
99950           }
99951
99952           var feat = {
99953             type: "Feature"
99954           };
99955
99956           if (options.id === 0 || options.id) {
99957             feat.id = options.id;
99958           }
99959
99960           if (options.bbox) {
99961             feat.bbox = options.bbox;
99962           }
99963
99964           feat.properties = properties || {};
99965           feat.geometry = geom;
99966           return feat;
99967         }
99968         /**
99969          * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
99970          *
99971          * @name polygon
99972          * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
99973          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
99974          * @param {Object} [options={}] Optional Parameters
99975          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
99976          * @param {string|number} [options.id] Identifier associated with the Feature
99977          * @returns {Feature<Polygon>} Polygon Feature
99978          * @example
99979          * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
99980          *
99981          * //=polygon
99982          */
99983
99984         function polygon(coordinates, properties, options) {
99985           if (options === void 0) {
99986             options = {};
99987           }
99988
99989           for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
99990             var ring = coordinates_1[_i];
99991
99992             if (ring.length < 4) {
99993               throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
99994             }
99995
99996             for (var j = 0; j < ring[ring.length - 1].length; j++) {
99997               // Check if first point of Polygon contains two numbers
99998               if (ring[ring.length - 1][j] !== ring[0][j]) {
99999                 throw new Error("First and last Position are not equivalent.");
100000               }
100001             }
100002           }
100003
100004           var geom = {
100005             type: "Polygon",
100006             coordinates: coordinates
100007           };
100008           return feature(geom, properties, options);
100009         }
100010         /**
100011          * Creates a {@link LineString} {@link Feature} from an Array of Positions.
100012          *
100013          * @name lineString
100014          * @param {Array<Array<number>>} coordinates an array of Positions
100015          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100016          * @param {Object} [options={}] Optional Parameters
100017          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100018          * @param {string|number} [options.id] Identifier associated with the Feature
100019          * @returns {Feature<LineString>} LineString Feature
100020          * @example
100021          * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
100022          * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
100023          *
100024          * //=linestring1
100025          * //=linestring2
100026          */
100027
100028         function lineString(coordinates, properties, options) {
100029           if (options === void 0) {
100030             options = {};
100031           }
100032
100033           if (coordinates.length < 2) {
100034             throw new Error("coordinates must be an array of two or more positions");
100035           }
100036
100037           var geom = {
100038             type: "LineString",
100039             coordinates: coordinates
100040           };
100041           return feature(geom, properties, options);
100042         }
100043         /**
100044          * Creates a {@link Feature<MultiLineString>} based on a
100045          * coordinate array. Properties can be added optionally.
100046          *
100047          * @name multiLineString
100048          * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
100049          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100050          * @param {Object} [options={}] Optional Parameters
100051          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100052          * @param {string|number} [options.id] Identifier associated with the Feature
100053          * @returns {Feature<MultiLineString>} a MultiLineString feature
100054          * @throws {Error} if no coordinates are passed
100055          * @example
100056          * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
100057          *
100058          * //=multiLine
100059          */
100060
100061         function multiLineString(coordinates, properties, options) {
100062           if (options === void 0) {
100063             options = {};
100064           }
100065
100066           var geom = {
100067             type: "MultiLineString",
100068             coordinates: coordinates
100069           };
100070           return feature(geom, properties, options);
100071         }
100072         /**
100073          * Creates a {@link Feature<MultiPolygon>} based on a
100074          * coordinate array. Properties can be added optionally.
100075          *
100076          * @name multiPolygon
100077          * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
100078          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100079          * @param {Object} [options={}] Optional Parameters
100080          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100081          * @param {string|number} [options.id] Identifier associated with the Feature
100082          * @returns {Feature<MultiPolygon>} a multipolygon feature
100083          * @throws {Error} if no coordinates are passed
100084          * @example
100085          * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
100086          *
100087          * //=multiPoly
100088          *
100089          */
100090
100091         function multiPolygon(coordinates, properties, options) {
100092           if (options === void 0) {
100093             options = {};
100094           }
100095
100096           var geom = {
100097             type: "MultiPolygon",
100098             coordinates: coordinates
100099           };
100100           return feature(geom, properties, options);
100101         }
100102
100103         /**
100104          * Get Geometry from Feature or Geometry Object
100105          *
100106          * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
100107          * @returns {Geometry|null} GeoJSON Geometry Object
100108          * @throws {Error} if geojson is not a Feature or Geometry Object
100109          * @example
100110          * var point = {
100111          *   "type": "Feature",
100112          *   "properties": {},
100113          *   "geometry": {
100114          *     "type": "Point",
100115          *     "coordinates": [110, 40]
100116          *   }
100117          * }
100118          * var geom = turf.getGeom(point)
100119          * //={"type": "Point", "coordinates": [110, 40]}
100120          */
100121
100122         function getGeom(geojson) {
100123           if (geojson.type === "Feature") {
100124             return geojson.geometry;
100125           }
100126
100127           return geojson;
100128         }
100129
100130         // Cohen-Sutherland line clipping algorithm, adapted to efficiently
100131         // handle polylines rather than just segments
100132         function lineclip(points, bbox, result) {
100133           var len = points.length,
100134               codeA = bitCode(points[0], bbox),
100135               part = [],
100136               i,
100137               codeB,
100138               lastCode;
100139           var a;
100140           var b;
100141           if (!result) result = [];
100142
100143           for (i = 1; i < len; i++) {
100144             a = points[i - 1];
100145             b = points[i];
100146             codeB = lastCode = bitCode(b, bbox);
100147
100148             while (true) {
100149               if (!(codeA | codeB)) {
100150                 // accept
100151                 part.push(a);
100152
100153                 if (codeB !== lastCode) {
100154                   // segment went outside
100155                   part.push(b);
100156
100157                   if (i < len - 1) {
100158                     // start a new line
100159                     result.push(part);
100160                     part = [];
100161                   }
100162                 } else if (i === len - 1) {
100163                   part.push(b);
100164                 }
100165
100166                 break;
100167               } else if (codeA & codeB) {
100168                 // trivial reject
100169                 break;
100170               } else if (codeA) {
100171                 // a outside, intersect with clip edge
100172                 a = intersect(a, b, codeA, bbox);
100173                 codeA = bitCode(a, bbox);
100174               } else {
100175                 // b outside
100176                 b = intersect(a, b, codeB, bbox);
100177                 codeB = bitCode(b, bbox);
100178               }
100179             }
100180
100181             codeA = lastCode;
100182           }
100183
100184           if (part.length) result.push(part);
100185           return result;
100186         } // Sutherland-Hodgeman polygon clipping algorithm
100187
100188         function polygonclip(points, bbox) {
100189           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
100190
100191           for (edge = 1; edge <= 8; edge *= 2) {
100192             result = [];
100193             prev = points[points.length - 1];
100194             prevInside = !(bitCode(prev, bbox) & edge);
100195
100196             for (i = 0; i < points.length; i++) {
100197               p = points[i];
100198               inside = !(bitCode(p, bbox) & edge); // if segment goes through the clip window, add an intersection
100199
100200               if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
100201               if (inside) result.push(p); // add a point if it's inside
100202
100203               prev = p;
100204               prevInside = inside;
100205             }
100206
100207             points = result;
100208             if (!points.length) break;
100209           }
100210
100211           return result;
100212         } // intersect a segment against one of the 4 lines that make up the bbox
100213
100214         function intersect(a, b, edge, bbox) {
100215           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] // top
100216           : edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] // bottom
100217           : edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] // right
100218           : edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] // left
100219           : null;
100220         } // bit code reflects the point position relative to the bbox:
100221         //         left  mid  right
100222         //    top  1001  1000  1010
100223         //    mid  0001  0000  0010
100224         // bottom  0101  0100  0110
100225
100226
100227         function bitCode(p, bbox) {
100228           var code = 0;
100229           if (p[0] < bbox[0]) code |= 1; // left
100230           else if (p[0] > bbox[2]) code |= 2; // right
100231
100232           if (p[1] < bbox[1]) code |= 4; // bottom
100233           else if (p[1] > bbox[3]) code |= 8; // top
100234
100235           return code;
100236         }
100237
100238         /**
100239          * Takes a {@link Feature} and a bbox and clips the feature to the bbox using
100240          * [lineclip](https://github.com/mapbox/lineclip).
100241          * May result in degenerate edges when clipping Polygons.
100242          *
100243          * @name bboxClip
100244          * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
100245          * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
100246          * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
100247          * @example
100248          * var bbox = [0, 0, 10, 10];
100249          * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
100250          *
100251          * var clipped = turf.bboxClip(poly, bbox);
100252          *
100253          * //addToMap
100254          * var addToMap = [bbox, poly, clipped]
100255          */
100256
100257         function bboxClip(feature, bbox) {
100258           var geom = getGeom(feature);
100259           var type = geom.type;
100260           var properties = feature.type === "Feature" ? feature.properties : {};
100261           var coords = geom.coordinates;
100262
100263           switch (type) {
100264             case "LineString":
100265             case "MultiLineString":
100266               var lines_1 = [];
100267
100268               if (type === "LineString") {
100269                 coords = [coords];
100270               }
100271
100272               coords.forEach(function (line) {
100273                 lineclip(line, bbox, lines_1);
100274               });
100275
100276               if (lines_1.length === 1) {
100277                 return lineString(lines_1[0], properties);
100278               }
100279
100280               return multiLineString(lines_1, properties);
100281
100282             case "Polygon":
100283               return polygon(clipPolygon(coords, bbox), properties);
100284
100285             case "MultiPolygon":
100286               return multiPolygon(coords.map(function (poly) {
100287                 return clipPolygon(poly, bbox);
100288               }), properties);
100289
100290             default:
100291               throw new Error("geometry " + type + " not supported");
100292           }
100293         }
100294
100295         function clipPolygon(rings, bbox) {
100296           var outRings = [];
100297
100298           for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
100299             var ring = rings_1[_i];
100300             var clipped = polygonclip(ring, bbox);
100301
100302             if (clipped.length > 0) {
100303               if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
100304                 clipped.push(clipped[0]);
100305               }
100306
100307               if (clipped.length >= 4) {
100308                 outRings.push(clipped);
100309               }
100310             }
100311           }
100312
100313           return outRings;
100314         }
100315
100316         var tiler = utilTiler().tileSize(512).margin(1);
100317         var dispatch = dispatch$8('loadedData');
100318
100319         var _vtCache;
100320
100321         function abortRequest(controller) {
100322           controller.abort();
100323         }
100324
100325         function vtToGeoJSON(data, tile, mergeCache) {
100326           var vectorTile$1 = new vectorTile.VectorTile(new pbf(data));
100327           var layers = Object.keys(vectorTile$1.layers);
100328
100329           if (!Array.isArray(layers)) {
100330             layers = [layers];
100331           }
100332
100333           var features = [];
100334           layers.forEach(function (layerID) {
100335             var layer = vectorTile$1.layers[layerID];
100336
100337             if (layer) {
100338               for (var i = 0; i < layer.length; i++) {
100339                 var feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
100340                 var geometry = feature.geometry; // Treat all Polygons as MultiPolygons
100341
100342                 if (geometry.type === 'Polygon') {
100343                   geometry.type = 'MultiPolygon';
100344                   geometry.coordinates = [geometry.coordinates];
100345                 }
100346
100347                 var isClipped = false; // Clip to tile bounds
100348
100349                 if (geometry.type === 'MultiPolygon') {
100350                   var featureClip = bboxClip(feature, tile.extent.rectangle());
100351
100352                   if (!fastDeepEqual(feature.geometry, featureClip.geometry)) {
100353                     // feature = featureClip;
100354                     isClipped = true;
100355                   }
100356
100357                   if (!feature.geometry.coordinates.length) continue; // not actually on this tile
100358
100359                   if (!feature.geometry.coordinates[0].length) continue; // not actually on this tile
100360                 } // Generate some unique IDs and add some metadata
100361
100362
100363                 var featurehash = utilHashcode(fastJsonStableStringify(feature));
100364                 var propertyhash = utilHashcode(fastJsonStableStringify(feature.properties || {}));
100365                 feature.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, '_');
100366                 feature.__featurehash__ = featurehash;
100367                 feature.__propertyhash__ = propertyhash;
100368                 features.push(feature); // Clipped Polygons at same zoom with identical properties can get merged
100369
100370                 if (isClipped && geometry.type === 'MultiPolygon') {
100371                   var merged = mergeCache[propertyhash];
100372
100373                   if (merged && merged.length) {
100374                     var other = merged[0];
100375                     var coords = index.union(feature.geometry.coordinates, other.geometry.coordinates);
100376
100377                     if (!coords || !coords.length) {
100378                       continue; // something failed in polygon union
100379                     }
100380
100381                     merged.push(feature);
100382
100383                     for (var j = 0; j < merged.length; j++) {
100384                       // all these features get...
100385                       merged[j].geometry.coordinates = coords; // same coords
100386
100387                       merged[j].__featurehash__ = featurehash; // same hash, so deduplication works
100388                     }
100389                   } else {
100390                     mergeCache[propertyhash] = [feature];
100391                   }
100392                 }
100393               }
100394             }
100395           });
100396           return features;
100397         }
100398
100399         function loadTile(source, tile) {
100400           if (source.loaded[tile.id] || source.inflight[tile.id]) return;
100401           var url = source.template.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]) // TMS-flipped y coordinate
100402           .replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function (s, r) {
100403             var subdomains = r.split(',');
100404             return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
100405           });
100406           var controller = new AbortController();
100407           source.inflight[tile.id] = controller;
100408           fetch(url, {
100409             signal: controller.signal
100410           }).then(function (response) {
100411             if (!response.ok) {
100412               throw new Error(response.status + ' ' + response.statusText);
100413             }
100414
100415             source.loaded[tile.id] = [];
100416             delete source.inflight[tile.id];
100417             return response.arrayBuffer();
100418           }).then(function (data) {
100419             if (!data) {
100420               throw new Error('No Data');
100421             }
100422
100423             var z = tile.xyz[2];
100424
100425             if (!source.canMerge[z]) {
100426               source.canMerge[z] = {}; // initialize mergeCache
100427             }
100428
100429             source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
100430             dispatch.call('loadedData');
100431           })["catch"](function () {
100432             source.loaded[tile.id] = [];
100433             delete source.inflight[tile.id];
100434           });
100435         }
100436
100437         var serviceVectorTile = {
100438           init: function init() {
100439             if (!_vtCache) {
100440               this.reset();
100441             }
100442
100443             this.event = utilRebind(this, dispatch, 'on');
100444           },
100445           reset: function reset() {
100446             for (var sourceID in _vtCache) {
100447               var source = _vtCache[sourceID];
100448
100449               if (source && source.inflight) {
100450                 Object.values(source.inflight).forEach(abortRequest);
100451               }
100452             }
100453
100454             _vtCache = {};
100455           },
100456           addSource: function addSource(sourceID, template) {
100457             _vtCache[sourceID] = {
100458               template: template,
100459               inflight: {},
100460               loaded: {},
100461               canMerge: {}
100462             };
100463             return _vtCache[sourceID];
100464           },
100465           data: function data(sourceID, projection) {
100466             var source = _vtCache[sourceID];
100467             if (!source) return [];
100468             var tiles = tiler.getTiles(projection);
100469             var seen = {};
100470             var results = [];
100471
100472             for (var i = 0; i < tiles.length; i++) {
100473               var features = source.loaded[tiles[i].id];
100474               if (!features || !features.length) continue;
100475
100476               for (var j = 0; j < features.length; j++) {
100477                 var feature = features[j];
100478                 var hash = feature.__featurehash__;
100479                 if (seen[hash]) continue;
100480                 seen[hash] = true; // return a shallow copy, because the hash may change
100481                 // later if this feature gets merged with another
100482
100483                 results.push(Object.assign({}, feature)); // shallow copy
100484               }
100485             }
100486
100487             return results;
100488           },
100489           loadTiles: function loadTiles(sourceID, template, projection) {
100490             var source = _vtCache[sourceID];
100491
100492             if (!source) {
100493               source = this.addSource(sourceID, template);
100494             }
100495
100496             var tiles = tiler.getTiles(projection); // abort inflight requests that are no longer needed
100497
100498             Object.keys(source.inflight).forEach(function (k) {
100499               var wanted = tiles.find(function (tile) {
100500                 return k === tile.id;
100501               });
100502
100503               if (!wanted) {
100504                 abortRequest(source.inflight[k]);
100505                 delete source.inflight[k];
100506               }
100507             });
100508             tiles.forEach(function (tile) {
100509               loadTile(source, tile);
100510             });
100511           },
100512           cache: function cache() {
100513             return _vtCache;
100514           }
100515         };
100516
100517         var apibase = 'https://www.wikidata.org/w/api.php?';
100518         var _wikidataCache = {};
100519         var serviceWikidata = {
100520           init: function init() {},
100521           reset: function reset() {
100522             _wikidataCache = {};
100523           },
100524           // Search for Wikidata items matching the query
100525           itemsForSearchQuery: function itemsForSearchQuery(query, callback) {
100526             if (!query) {
100527               if (callback) callback('No query', {});
100528               return;
100529             }
100530
100531             var lang = this.languagesToQuery()[0];
100532             var url = apibase + utilQsString({
100533               action: 'wbsearchentities',
100534               format: 'json',
100535               formatversion: 2,
100536               search: query,
100537               type: 'item',
100538               // the language to search
100539               language: lang,
100540               // the language for the label and description in the result
100541               uselang: lang,
100542               limit: 10,
100543               origin: '*'
100544             });
100545             d3_json(url).then(function (result) {
100546               if (result && result.error) {
100547                 throw new Error(result.error);
100548               }
100549
100550               if (callback) callback(null, result.search || {});
100551             })["catch"](function (err) {
100552               if (callback) callback(err.message, {});
100553             });
100554           },
100555           // Given a Wikipedia language and article title,
100556           // return an array of corresponding Wikidata entities.
100557           itemsByTitle: function itemsByTitle(lang, title, callback) {
100558             if (!title) {
100559               if (callback) callback('No title', {});
100560               return;
100561             }
100562
100563             lang = lang || 'en';
100564             var url = apibase + utilQsString({
100565               action: 'wbgetentities',
100566               format: 'json',
100567               formatversion: 2,
100568               sites: lang.replace(/-/g, '_') + 'wiki',
100569               titles: title,
100570               languages: 'en',
100571               // shrink response by filtering to one language
100572               origin: '*'
100573             });
100574             d3_json(url).then(function (result) {
100575               if (result && result.error) {
100576                 throw new Error(result.error);
100577               }
100578
100579               if (callback) callback(null, result.entities || {});
100580             })["catch"](function (err) {
100581               if (callback) callback(err.message, {});
100582             });
100583           },
100584           languagesToQuery: function languagesToQuery() {
100585             return _mainLocalizer.localeCodes().map(function (code) {
100586               return code.toLowerCase();
100587             }).filter(function (code) {
100588               // HACK: en-us isn't a wikidata language. We should really be filtering by
100589               // the languages known to be supported by wikidata.
100590               return code !== 'en-us';
100591             });
100592           },
100593           entityByQID: function entityByQID(qid, callback) {
100594             if (!qid) {
100595               callback('No qid', {});
100596               return;
100597             }
100598
100599             if (_wikidataCache[qid]) {
100600               if (callback) callback(null, _wikidataCache[qid]);
100601               return;
100602             }
100603
100604             var langs = this.languagesToQuery();
100605             var url = apibase + utilQsString({
100606               action: 'wbgetentities',
100607               format: 'json',
100608               formatversion: 2,
100609               ids: qid,
100610               props: 'labels|descriptions|claims|sitelinks',
100611               sitefilter: langs.map(function (d) {
100612                 return d + 'wiki';
100613               }).join('|'),
100614               languages: langs.join('|'),
100615               languagefallback: 1,
100616               origin: '*'
100617             });
100618             d3_json(url).then(function (result) {
100619               if (result && result.error) {
100620                 throw new Error(result.error);
100621               }
100622
100623               if (callback) callback(null, result.entities[qid] || {});
100624             })["catch"](function (err) {
100625               if (callback) callback(err.message, {});
100626             });
100627           },
100628           // Pass `params` object of the form:
100629           // {
100630           //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
100631           // }
100632           //
100633           // Get an result object used to display tag documentation
100634           // {
100635           //   title:        'string',
100636           //   description:  'string',
100637           //   editURL:      'string',
100638           //   imageURL:     'string',
100639           //   wiki:         { title: 'string', text: 'string', url: 'string' }
100640           // }
100641           //
100642           getDocs: function getDocs(params, callback) {
100643             var langs = this.languagesToQuery();
100644             this.entityByQID(params.qid, function (err, entity) {
100645               if (err || !entity) {
100646                 callback(err || 'No entity');
100647                 return;
100648               }
100649
100650               var i;
100651               var description;
100652
100653               for (i in langs) {
100654                 var code = langs[i];
100655
100656                 if (entity.descriptions[code] && entity.descriptions[code].language === code) {
100657                   description = entity.descriptions[code];
100658                   break;
100659                 }
100660               }
100661
100662               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
100663
100664               var result = {
100665                 title: entity.id,
100666                 description: description ? description.value : '',
100667                 descriptionLocaleCode: description ? description.language : '',
100668                 editURL: 'https://www.wikidata.org/wiki/' + entity.id
100669               }; // add image
100670
100671               if (entity.claims) {
100672                 var imageroot = 'https://commons.wikimedia.org/w/index.php';
100673                 var props = ['P154', 'P18']; // logo image, image
100674
100675                 var prop, image;
100676
100677                 for (i = 0; i < props.length; i++) {
100678                   prop = entity.claims[props[i]];
100679
100680                   if (prop && Object.keys(prop).length > 0) {
100681                     image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
100682
100683                     if (image) {
100684                       result.imageURL = imageroot + '?' + utilQsString({
100685                         title: 'Special:Redirect/file/' + image,
100686                         width: 400
100687                       });
100688                       break;
100689                     }
100690                   }
100691                 }
100692               }
100693
100694               if (entity.sitelinks) {
100695                 var englishLocale = _mainLocalizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested..
100696
100697                 for (i = 0; i < langs.length; i++) {
100698                   // check each, in order of preference
100699                   var w = langs[i] + 'wiki';
100700
100701                   if (entity.sitelinks[w]) {
100702                     var title = entity.sitelinks[w].title;
100703                     var tKey = 'inspector.wiki_reference';
100704
100705                     if (!englishLocale && langs[i] === 'en') {
100706                       // user's locale isn't English but
100707                       tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
100708                     }
100709
100710                     result.wiki = {
100711                       title: title,
100712                       text: tKey,
100713                       url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
100714                     };
100715                     break;
100716                   }
100717                 }
100718               }
100719
100720               callback(null, result);
100721             });
100722           }
100723         };
100724
100725         var endpoint = 'https://en.wikipedia.org/w/api.php?';
100726         var serviceWikipedia = {
100727           init: function init() {},
100728           reset: function reset() {},
100729           search: function search(lang, query, callback) {
100730             if (!query) {
100731               if (callback) callback('No Query', []);
100732               return;
100733             }
100734
100735             lang = lang || 'en';
100736             var url = endpoint.replace('en', lang) + utilQsString({
100737               action: 'query',
100738               list: 'search',
100739               srlimit: '10',
100740               srinfo: 'suggestion',
100741               format: 'json',
100742               origin: '*',
100743               srsearch: query
100744             });
100745             d3_json(url).then(function (result) {
100746               if (result && result.error) {
100747                 throw new Error(result.error);
100748               } else if (!result || !result.query || !result.query.search) {
100749                 throw new Error('No Results');
100750               }
100751
100752               if (callback) {
100753                 var titles = result.query.search.map(function (d) {
100754                   return d.title;
100755                 });
100756                 callback(null, titles);
100757               }
100758             })["catch"](function (err) {
100759               if (callback) callback(err, []);
100760             });
100761           },
100762           suggestions: function suggestions(lang, query, callback) {
100763             if (!query) {
100764               if (callback) callback('', []);
100765               return;
100766             }
100767
100768             lang = lang || 'en';
100769             var url = endpoint.replace('en', lang) + utilQsString({
100770               action: 'opensearch',
100771               namespace: 0,
100772               suggest: '',
100773               format: 'json',
100774               origin: '*',
100775               search: query
100776             });
100777             d3_json(url).then(function (result) {
100778               if (result && result.error) {
100779                 throw new Error(result.error);
100780               } else if (!result || result.length < 2) {
100781                 throw new Error('No Results');
100782               }
100783
100784               if (callback) callback(null, result[1] || []);
100785             })["catch"](function (err) {
100786               if (callback) callback(err.message, []);
100787             });
100788           },
100789           translations: function translations(lang, title, callback) {
100790             if (!title) {
100791               if (callback) callback('No Title');
100792               return;
100793             }
100794
100795             var url = endpoint.replace('en', lang) + utilQsString({
100796               action: 'query',
100797               prop: 'langlinks',
100798               format: 'json',
100799               origin: '*',
100800               lllimit: 500,
100801               titles: title
100802             });
100803             d3_json(url).then(function (result) {
100804               if (result && result.error) {
100805                 throw new Error(result.error);
100806               } else if (!result || !result.query || !result.query.pages) {
100807                 throw new Error('No Results');
100808               }
100809
100810               if (callback) {
100811                 var list = result.query.pages[Object.keys(result.query.pages)[0]];
100812                 var translations = {};
100813
100814                 if (list && list.langlinks) {
100815                   list.langlinks.forEach(function (d) {
100816                     translations[d.lang] = d['*'];
100817                   });
100818                 }
100819
100820                 callback(null, translations);
100821               }
100822             })["catch"](function (err) {
100823               if (callback) callback(err.message);
100824             });
100825           }
100826         };
100827
100828         var services = {
100829           geocoder: serviceNominatim,
100830           keepRight: serviceKeepRight,
100831           improveOSM: serviceImproveOSM,
100832           osmose: serviceOsmose,
100833           mapillary: serviceMapillary,
100834           nsi: serviceNsi,
100835           openstreetcam: serviceOpenstreetcam,
100836           osm: serviceOsm,
100837           osmWikibase: serviceOsmWikibase,
100838           maprules: serviceMapRules,
100839           streetside: serviceStreetside,
100840           taginfo: serviceTaginfo,
100841           vectorTile: serviceVectorTile,
100842           wikidata: serviceWikidata,
100843           wikipedia: serviceWikipedia
100844         };
100845
100846         function modeDragNote(context) {
100847           var mode = {
100848             id: 'drag-note',
100849             button: 'browse'
100850           };
100851           var edit = behaviorEdit(context);
100852
100853           var _nudgeInterval;
100854
100855           var _lastLoc;
100856
100857           var _note; // most current note.. dragged note may have stale datum.
100858
100859
100860           function startNudge(d3_event, nudge) {
100861             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
100862             _nudgeInterval = window.setInterval(function () {
100863               context.map().pan(nudge);
100864               doMove(d3_event, nudge);
100865             }, 50);
100866           }
100867
100868           function stopNudge() {
100869             if (_nudgeInterval) {
100870               window.clearInterval(_nudgeInterval);
100871               _nudgeInterval = null;
100872             }
100873           }
100874
100875           function origin(note) {
100876             return context.projection(note.loc);
100877           }
100878
100879           function start(d3_event, note) {
100880             _note = note;
100881             var osm = services.osm;
100882
100883             if (osm) {
100884               // Get latest note from cache.. The marker may have a stale datum bound to it
100885               // and dragging it around can sometimes delete the users note comment.
100886               _note = osm.getNote(_note.id);
100887             }
100888
100889             context.surface().selectAll('.note-' + _note.id).classed('active', true);
100890             context.perform(actionNoop());
100891             context.enter(mode);
100892             context.selectedNoteID(_note.id);
100893           }
100894
100895           function move(d3_event, entity, point) {
100896             d3_event.stopPropagation();
100897             _lastLoc = context.projection.invert(point);
100898             doMove(d3_event);
100899             var nudge = geoViewportEdge(point, context.map().dimensions());
100900
100901             if (nudge) {
100902               startNudge(d3_event, nudge);
100903             } else {
100904               stopNudge();
100905             }
100906           }
100907
100908           function doMove(d3_event, nudge) {
100909             nudge = nudge || [0, 0];
100910             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
100911             var currMouse = geoVecSubtract(currPoint, nudge);
100912             var loc = context.projection.invert(currMouse);
100913             _note = _note.move(loc);
100914             var osm = services.osm;
100915
100916             if (osm) {
100917               osm.replaceNote(_note); // update note cache
100918             }
100919
100920             context.replace(actionNoop()); // trigger redraw
100921           }
100922
100923           function end() {
100924             context.replace(actionNoop()); // trigger redraw
100925
100926             context.selectedNoteID(_note.id).enter(modeSelectNote(context, _note.id));
100927           }
100928
100929           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);
100930
100931           mode.enter = function () {
100932             context.install(edit);
100933           };
100934
100935           mode.exit = function () {
100936             context.ui().sidebar.hover.cancel();
100937             context.uninstall(edit);
100938             context.surface().selectAll('.active').classed('active', false);
100939             stopNudge();
100940           };
100941
100942           mode.behavior = drag;
100943           return mode;
100944         }
100945
100946         function modeSelectData(context, selectedDatum) {
100947           var mode = {
100948             id: 'select-data',
100949             button: 'browse'
100950           };
100951           var keybinding = utilKeybinding('select-data');
100952           var dataEditor = uiDataEditor(context);
100953           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
100954
100955           function selectData(d3_event, drawn) {
100956             var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__);
100957
100958             if (selection.empty()) {
100959               // Return to browse mode if selected DOM elements have
100960               // disappeared because the user moved them out of view..
100961               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
100962
100963               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
100964                 context.enter(modeBrowse(context));
100965               }
100966             } else {
100967               selection.classed('selected', true);
100968             }
100969           }
100970
100971           function esc() {
100972             if (context.container().select('.combobox').size()) return;
100973             context.enter(modeBrowse(context));
100974           }
100975
100976           mode.zoomToSelected = function () {
100977             var extent = geoExtent(d3_geoBounds(selectedDatum));
100978             context.map().centerZoomEase(extent.center(), context.map().trimmedExtentZoom(extent));
100979           };
100980
100981           mode.enter = function () {
100982             behaviors.forEach(context.install);
100983             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
100984             select(document).call(keybinding);
100985             selectData();
100986             var sidebar = context.ui().sidebar;
100987             sidebar.show(dataEditor.datum(selectedDatum)); // expand the sidebar, avoid obscuring the data if needed
100988
100989             var extent = geoExtent(d3_geoBounds(selectedDatum));
100990             sidebar.expand(sidebar.intersects(extent));
100991             context.map().on('drawn.select-data', selectData);
100992           };
100993
100994           mode.exit = function () {
100995             behaviors.forEach(context.uninstall);
100996             select(document).call(keybinding.unbind);
100997             context.surface().selectAll('.layer-mapdata .selected').classed('selected hover', false);
100998             context.map().on('drawn.select-data', null);
100999             context.ui().sidebar.hide();
101000           };
101001
101002           return mode;
101003         }
101004
101005         function behaviorSelect(context) {
101006           var _tolerancePx = 4; // see also behaviorDrag
101007
101008           var _lastMouseEvent = null;
101009           var _showMenu = false;
101010           var _downPointers = {};
101011           var _longPressTimeout = null;
101012           var _lastInteractionType = null; // the id of the down pointer that's enabling multiselection while down
101013
101014           var _multiselectionPointerId = null; // use pointer events on supported platforms; fallback to mouse events
101015
101016           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
101017
101018           function keydown(d3_event) {
101019             if (d3_event.keyCode === 32) {
101020               // don't react to spacebar events during text input
101021               var activeNode = document.activeElement;
101022               if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
101023             }
101024
101025             if (d3_event.keyCode === 93 || // context menu key
101026             d3_event.keyCode === 32) {
101027               // spacebar
101028               d3_event.preventDefault();
101029             }
101030
101031             if (d3_event.repeat) return; // ignore repeated events for held keys
101032             // if any key is pressed the user is probably doing something other than long-pressing
101033
101034             cancelLongPress();
101035
101036             if (d3_event.shiftKey) {
101037               context.surface().classed('behavior-multiselect', true);
101038             }
101039
101040             if (d3_event.keyCode === 32) {
101041               // spacebar
101042               if (!_downPointers.spacebar && _lastMouseEvent) {
101043                 cancelLongPress();
101044                 _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar', 'spacebar');
101045                 _downPointers.spacebar = {
101046                   firstEvent: _lastMouseEvent,
101047                   lastEvent: _lastMouseEvent
101048                 };
101049               }
101050             }
101051           }
101052
101053           function keyup(d3_event) {
101054             cancelLongPress();
101055
101056             if (!d3_event.shiftKey) {
101057               context.surface().classed('behavior-multiselect', false);
101058             }
101059
101060             if (d3_event.keyCode === 93) {
101061               // context menu key
101062               d3_event.preventDefault();
101063               _lastInteractionType = 'menukey';
101064               contextmenu(d3_event);
101065             } else if (d3_event.keyCode === 32) {
101066               // spacebar
101067               var pointer = _downPointers.spacebar;
101068
101069               if (pointer) {
101070                 delete _downPointers.spacebar;
101071                 if (pointer.done) return;
101072                 d3_event.preventDefault();
101073                 _lastInteractionType = 'spacebar';
101074                 click(pointer.firstEvent, pointer.lastEvent, 'spacebar');
101075               }
101076             }
101077           }
101078
101079           function pointerdown(d3_event) {
101080             var id = (d3_event.pointerId || 'mouse').toString();
101081             cancelLongPress();
101082             if (d3_event.buttons && d3_event.buttons !== 1) return;
101083             context.ui().closeEditMenu();
101084             _longPressTimeout = window.setTimeout(didLongPress, 500, id, 'longdown-' + (d3_event.pointerType || 'mouse'));
101085             _downPointers[id] = {
101086               firstEvent: d3_event,
101087               lastEvent: d3_event
101088             };
101089           }
101090
101091           function didLongPress(id, interactionType) {
101092             var pointer = _downPointers[id];
101093             if (!pointer) return;
101094
101095             for (var i in _downPointers) {
101096               // don't allow this or any currently down pointer to trigger another click
101097               _downPointers[i].done = true;
101098             } // treat long presses like right-clicks
101099
101100
101101             _longPressTimeout = null;
101102             _lastInteractionType = interactionType;
101103             _showMenu = true;
101104             click(pointer.firstEvent, pointer.lastEvent, id);
101105           }
101106
101107           function pointermove(d3_event) {
101108             var id = (d3_event.pointerId || 'mouse').toString();
101109
101110             if (_downPointers[id]) {
101111               _downPointers[id].lastEvent = d3_event;
101112             }
101113
101114             if (!d3_event.pointerType || d3_event.pointerType === 'mouse') {
101115               _lastMouseEvent = d3_event;
101116
101117               if (_downPointers.spacebar) {
101118                 _downPointers.spacebar.lastEvent = d3_event;
101119               }
101120             }
101121           }
101122
101123           function pointerup(d3_event) {
101124             var id = (d3_event.pointerId || 'mouse').toString();
101125             var pointer = _downPointers[id];
101126             if (!pointer) return;
101127             delete _downPointers[id];
101128
101129             if (_multiselectionPointerId === id) {
101130               _multiselectionPointerId = null;
101131             }
101132
101133             if (pointer.done) return;
101134             click(pointer.firstEvent, d3_event, id);
101135           }
101136
101137           function pointercancel(d3_event) {
101138             var id = (d3_event.pointerId || 'mouse').toString();
101139             if (!_downPointers[id]) return;
101140             delete _downPointers[id];
101141
101142             if (_multiselectionPointerId === id) {
101143               _multiselectionPointerId = null;
101144             }
101145           }
101146
101147           function contextmenu(d3_event) {
101148             d3_event.preventDefault();
101149
101150             if (!+d3_event.clientX && !+d3_event.clientY) {
101151               if (_lastMouseEvent) {
101152                 d3_event.sourceEvent = _lastMouseEvent;
101153               } else {
101154                 return;
101155               }
101156             } else {
101157               _lastMouseEvent = d3_event;
101158               _lastInteractionType = 'rightclick';
101159             }
101160
101161             _showMenu = true;
101162             click(d3_event, d3_event);
101163           }
101164
101165           function click(firstEvent, lastEvent, pointerId) {
101166             cancelLongPress();
101167             var mapNode = context.container().select('.main-map').node(); // Use the `main-map` coordinate system since the surface and supersurface
101168             // are transformed when drag-panning.
101169
101170             var pointGetter = utilFastMouse(mapNode);
101171             var p1 = pointGetter(firstEvent);
101172             var p2 = pointGetter(lastEvent);
101173             var dist = geoVecLength(p1, p2);
101174
101175             if (dist > _tolerancePx || !mapContains(lastEvent)) {
101176               resetProperties();
101177               return;
101178             }
101179
101180             var targetDatum = lastEvent.target.__data__;
101181             var multiselectEntityId;
101182
101183             if (!_multiselectionPointerId) {
101184               // If a different pointer than the one triggering this click is down on a
101185               // feature, treat this and all future clicks as multiselection until that
101186               // pointer is raised.
101187               var selectPointerInfo = pointerDownOnSelection(pointerId);
101188
101189               if (selectPointerInfo) {
101190                 _multiselectionPointerId = selectPointerInfo.pointerId; // if the other feature isn't selected yet, make sure we select it
101191
101192                 multiselectEntityId = !selectPointerInfo.selected && selectPointerInfo.entityId;
101193                 _downPointers[selectPointerInfo.pointerId].done = true;
101194               }
101195             } // support multiselect if data is already selected
101196
101197
101198             var isMultiselect = context.mode().id === 'select' && ( // and shift key is down
101199             lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
101200             context.surface().select('.lasso').node() || // or a pointer is down over a selected feature
101201             _multiselectionPointerId && !multiselectEntityId);
101202
101203             processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
101204
101205             function mapContains(event) {
101206               var rect = mapNode.getBoundingClientRect();
101207               return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
101208             }
101209
101210             function pointerDownOnSelection(skipPointerId) {
101211               var mode = context.mode();
101212               var selectedIDs = mode.id === 'select' ? mode.selectedIDs() : [];
101213
101214               for (var pointerId in _downPointers) {
101215                 if (pointerId === 'spacebar' || pointerId === skipPointerId) continue;
101216                 var pointerInfo = _downPointers[pointerId];
101217                 var p1 = pointGetter(pointerInfo.firstEvent);
101218                 var p2 = pointGetter(pointerInfo.lastEvent);
101219                 if (geoVecLength(p1, p2) > _tolerancePx) continue;
101220                 var datum = pointerInfo.firstEvent.target.__data__;
101221                 var entity = datum && datum.properties && datum.properties.entity || datum;
101222
101223                 if (context.graph().hasEntity(entity.id)) {
101224                   return {
101225                     pointerId: pointerId,
101226                     entityId: entity.id,
101227                     selected: selectedIDs.indexOf(entity.id) !== -1
101228                   };
101229                 }
101230               }
101231
101232               return null;
101233             }
101234           }
101235
101236           function processClick(datum, isMultiselect, point, alsoSelectId) {
101237             var mode = context.mode();
101238             var showMenu = _showMenu;
101239             var interactionType = _lastInteractionType;
101240             var entity = datum && datum.properties && datum.properties.entity;
101241             if (entity) datum = entity;
101242
101243             if (datum && datum.type === 'midpoint') {
101244               // treat targeting midpoints as if targeting the parent way
101245               datum = datum.parents[0];
101246             }
101247
101248             var newMode;
101249
101250             if (datum instanceof osmEntity) {
101251               // targeting an entity
101252               var selectedIDs = context.selectedIDs();
101253               context.selectedNoteID(null);
101254               context.selectedErrorID(null);
101255
101256               if (!isMultiselect) {
101257                 // don't change the selection if we're toggling the menu atop a multiselection
101258                 if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum.id) === -1) {
101259                   if (alsoSelectId === datum.id) alsoSelectId = null;
101260                   selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum.id]); // always enter modeSelect even if the entity is already
101261                   // selected since listeners may expect `context.enter` events,
101262                   // e.g. in the walkthrough
101263
101264                   newMode = mode.id === 'select' ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
101265                   context.enter(newMode);
101266                 }
101267               } else {
101268                 if (selectedIDs.indexOf(datum.id) !== -1) {
101269                   // clicked entity is already in the selectedIDs list..
101270                   if (!showMenu) {
101271                     // deselect clicked entity, then reenter select mode or return to browse mode..
101272                     selectedIDs = selectedIDs.filter(function (id) {
101273                       return id !== datum.id;
101274                     });
101275                     newMode = selectedIDs.length ? mode.selectedIDs(selectedIDs) : modeBrowse(context).selectBehavior(behavior);
101276                     context.enter(newMode);
101277                   }
101278                 } else {
101279                   // clicked entity is not in the selected list, add it..
101280                   selectedIDs = selectedIDs.concat([datum.id]);
101281                   newMode = mode.selectedIDs(selectedIDs);
101282                   context.enter(newMode);
101283                 }
101284               }
101285             } else if (datum && datum.__featurehash__ && !isMultiselect) {
101286               // targeting custom data
101287               context.selectedNoteID(null).enter(modeSelectData(context, datum));
101288             } else if (datum instanceof osmNote && !isMultiselect) {
101289               // targeting a note
101290               context.selectedNoteID(datum.id).enter(modeSelectNote(context, datum.id));
101291             } else if (datum instanceof QAItem & !isMultiselect) {
101292               // targeting an external QA issue
101293               context.selectedErrorID(datum.id).enter(modeSelectError(context, datum.id, datum.service));
101294             } else {
101295               // targeting nothing
101296               context.selectedNoteID(null);
101297               context.selectedErrorID(null);
101298
101299               if (!isMultiselect && mode.id !== 'browse') {
101300                 context.enter(modeBrowse(context));
101301               }
101302             }
101303
101304             context.ui().closeEditMenu(); // always request to show the edit menu in case the mode needs it
101305
101306             if (showMenu) context.ui().showEditMenu(point, interactionType);
101307             resetProperties();
101308           }
101309
101310           function cancelLongPress() {
101311             if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
101312             _longPressTimeout = null;
101313           }
101314
101315           function resetProperties() {
101316             cancelLongPress();
101317             _showMenu = false;
101318             _lastInteractionType = null; // don't reset _lastMouseEvent since it might still be useful
101319           }
101320
101321           function behavior(selection) {
101322             resetProperties();
101323             _lastMouseEvent = context.map().lastPointerEvent();
101324             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) {
101325               // Edge and IE really like to show the contextmenu on the
101326               // menubar when user presses a keyboard menu button
101327               // even after we've already preventdefaulted the key event.
101328               var e = d3_event;
101329
101330               if (+e.clientX === 0 && +e.clientY === 0) {
101331                 d3_event.preventDefault();
101332               }
101333             });
101334             selection.on(_pointerPrefix + 'down.select', pointerdown).on('contextmenu.select', contextmenu);
101335             /*if (d3_event && d3_event.shiftKey) {
101336                 context.surface()
101337                     .classed('behavior-multiselect', true);
101338             }*/
101339           }
101340
101341           behavior.off = function (selection) {
101342             cancelLongPress();
101343             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);
101344             selection.on(_pointerPrefix + 'down.select', null).on('contextmenu.select', null);
101345             context.surface().classed('behavior-multiselect', false);
101346           };
101347
101348           return behavior;
101349         }
101350
101351         function operationContinue(context, selectedIDs) {
101352           var _entities = selectedIDs.map(function (id) {
101353             return context.graph().entity(id);
101354           });
101355
101356           var _geometries = Object.assign({
101357             line: [],
101358             vertex: []
101359           }, utilArrayGroupBy(_entities, function (entity) {
101360             return entity.geometry(context.graph());
101361           }));
101362
101363           var _vertex = _geometries.vertex.length && _geometries.vertex[0];
101364
101365           function candidateWays() {
101366             return _vertex ? context.graph().parentWays(_vertex).filter(function (parent) {
101367               return parent.geometry(context.graph()) === 'line' && !parent.isClosed() && parent.affix(_vertex.id) && (_geometries.line.length === 0 || _geometries.line[0] === parent);
101368             }) : [];
101369           }
101370
101371           var _candidates = candidateWays();
101372
101373           var operation = function operation() {
101374             var candidate = _candidates[0];
101375             context.enter(modeDrawLine(context, candidate.id, context.graph(), 'line', candidate.affix(_vertex.id), true));
101376           };
101377
101378           operation.relatedEntityIds = function () {
101379             return _candidates.length ? [_candidates[0].id] : [];
101380           };
101381
101382           operation.available = function () {
101383             return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
101384           };
101385
101386           operation.disabled = function () {
101387             if (_candidates.length === 0) {
101388               return 'not_eligible';
101389             } else if (_candidates.length > 1) {
101390               return 'multiple';
101391             }
101392
101393             return false;
101394           };
101395
101396           operation.tooltip = function () {
101397             var disable = operation.disabled();
101398             return disable ? _t('operations.continue.' + disable) : _t('operations.continue.description');
101399           };
101400
101401           operation.annotation = function () {
101402             return _t('operations.continue.annotation.line');
101403           };
101404
101405           operation.id = 'continue';
101406           operation.keys = [_t('operations.continue.key')];
101407           operation.title = _t('operations.continue.title');
101408           operation.behavior = behaviorOperation(context).which(operation);
101409           return operation;
101410         }
101411
101412         function operationCopy(context, selectedIDs) {
101413           function getFilteredIdsToCopy() {
101414             return selectedIDs.filter(function (selectedID) {
101415               var entity = context.graph().hasEntity(selectedID); // don't copy untagged vertices separately from ways
101416
101417               return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
101418             });
101419           }
101420
101421           var operation = function operation() {
101422             var graph = context.graph();
101423             var selected = groupEntities(getFilteredIdsToCopy(), graph);
101424             var canCopy = [];
101425             var skip = {};
101426             var entity;
101427             var i;
101428
101429             for (i = 0; i < selected.relation.length; i++) {
101430               entity = selected.relation[i];
101431
101432               if (!skip[entity.id] && entity.isComplete(graph)) {
101433                 canCopy.push(entity.id);
101434                 skip = getDescendants(entity.id, graph, skip);
101435               }
101436             }
101437
101438             for (i = 0; i < selected.way.length; i++) {
101439               entity = selected.way[i];
101440
101441               if (!skip[entity.id]) {
101442                 canCopy.push(entity.id);
101443                 skip = getDescendants(entity.id, graph, skip);
101444               }
101445             }
101446
101447             for (i = 0; i < selected.node.length; i++) {
101448               entity = selected.node[i];
101449
101450               if (!skip[entity.id]) {
101451                 canCopy.push(entity.id);
101452               }
101453             }
101454
101455             context.copyIDs(canCopy);
101456
101457             if (_point && (canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
101458               // store the anchor coordinates if copying more than a single node
101459               context.copyLonLat(context.projection.invert(_point));
101460             } else {
101461               context.copyLonLat(null);
101462             }
101463           };
101464
101465           function groupEntities(ids, graph) {
101466             var entities = ids.map(function (id) {
101467               return graph.entity(id);
101468             });
101469             return Object.assign({
101470               relation: [],
101471               way: [],
101472               node: []
101473             }, utilArrayGroupBy(entities, 'type'));
101474           }
101475
101476           function getDescendants(id, graph, descendants) {
101477             var entity = graph.entity(id);
101478             var children;
101479             descendants = descendants || {};
101480
101481             if (entity.type === 'relation') {
101482               children = entity.members.map(function (m) {
101483                 return m.id;
101484               });
101485             } else if (entity.type === 'way') {
101486               children = entity.nodes;
101487             } else {
101488               children = [];
101489             }
101490
101491             for (var i = 0; i < children.length; i++) {
101492               if (!descendants[children[i]]) {
101493                 descendants[children[i]] = true;
101494                 descendants = getDescendants(children[i], graph, descendants);
101495               }
101496             }
101497
101498             return descendants;
101499           }
101500
101501           operation.available = function () {
101502             return getFilteredIdsToCopy().length > 0;
101503           };
101504
101505           operation.disabled = function () {
101506             var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
101507
101508             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
101509               return 'too_large';
101510             }
101511
101512             return false;
101513           };
101514
101515           operation.availableForKeypress = function () {
101516             var selection = window.getSelection && window.getSelection(); // if the user has text selected then let them copy that, not the selected feature
101517
101518             return !selection || !selection.toString();
101519           };
101520
101521           operation.tooltip = function () {
101522             var disable = operation.disabled();
101523             return disable ? _t('operations.copy.' + disable, {
101524               n: selectedIDs.length
101525             }) : _t('operations.copy.description', {
101526               n: selectedIDs.length
101527             });
101528           };
101529
101530           operation.annotation = function () {
101531             return _t('operations.copy.annotation', {
101532               n: selectedIDs.length
101533             });
101534           };
101535
101536           var _point;
101537
101538           operation.point = function (val) {
101539             _point = val;
101540             return operation;
101541           };
101542
101543           operation.id = 'copy';
101544           operation.keys = [uiCmd('⌘C')];
101545           operation.title = _t('operations.copy.title');
101546           operation.behavior = behaviorOperation(context).which(operation);
101547           return operation;
101548         }
101549
101550         function operationDisconnect(context, selectedIDs) {
101551           var _vertexIDs = [];
101552           var _wayIDs = [];
101553           var _otherIDs = [];
101554           var _actions = [];
101555           selectedIDs.forEach(function (id) {
101556             var entity = context.entity(id);
101557
101558             if (entity.type === 'way') {
101559               _wayIDs.push(id);
101560             } else if (entity.geometry(context.graph()) === 'vertex') {
101561               _vertexIDs.push(id);
101562             } else {
101563               _otherIDs.push(id);
101564             }
101565           });
101566
101567           var _coords,
101568               _descriptionID = '',
101569               _annotationID = 'features';
101570
101571           var _disconnectingVertexIds = [];
101572           var _disconnectingWayIds = [];
101573
101574           if (_vertexIDs.length > 0) {
101575             // At the selected vertices, disconnect the selected ways, if any, else
101576             // disconnect all connected ways
101577             _disconnectingVertexIds = _vertexIDs;
101578
101579             _vertexIDs.forEach(function (vertexID) {
101580               var action = actionDisconnect(vertexID);
101581
101582               if (_wayIDs.length > 0) {
101583                 var waysIDsForVertex = _wayIDs.filter(function (wayID) {
101584                   var way = context.entity(wayID);
101585                   return way.nodes.indexOf(vertexID) !== -1;
101586                 });
101587
101588                 action.limitWays(waysIDsForVertex);
101589               }
101590
101591               _actions.push(action);
101592
101593               _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map(function (d) {
101594                 return d.id;
101595               }));
101596             });
101597
101598             _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function (id) {
101599               return _wayIDs.indexOf(id) === -1;
101600             });
101601             _descriptionID += _actions.length === 1 ? 'single_point.' : 'multiple_points.';
101602
101603             if (_wayIDs.length === 1) {
101604               _descriptionID += 'single_way.' + context.graph().geometry(_wayIDs[0]);
101605             } else {
101606               _descriptionID += _wayIDs.length === 0 ? 'no_ways' : 'multiple_ways';
101607             }
101608           } else if (_wayIDs.length > 0) {
101609             // Disconnect the selected ways from each other, if they're connected,
101610             // else disconnect them from all connected ways
101611             var ways = _wayIDs.map(function (id) {
101612               return context.entity(id);
101613             });
101614
101615             var nodes = utilGetAllNodes(_wayIDs, context.graph());
101616             _coords = nodes.map(function (n) {
101617               return n.loc;
101618             }); // actions for connected nodes shared by at least two selected ways
101619
101620             var sharedActions = [];
101621             var sharedNodes = []; // actions for connected nodes
101622
101623             var unsharedActions = [];
101624             var unsharedNodes = [];
101625             nodes.forEach(function (node) {
101626               var action = actionDisconnect(node.id).limitWays(_wayIDs);
101627
101628               if (action.disabled(context.graph()) !== 'not_connected') {
101629                 var count = 0;
101630
101631                 for (var i in ways) {
101632                   var way = ways[i];
101633
101634                   if (way.nodes.indexOf(node.id) !== -1) {
101635                     count += 1;
101636                   }
101637
101638                   if (count > 1) break;
101639                 }
101640
101641                 if (count > 1) {
101642                   sharedActions.push(action);
101643                   sharedNodes.push(node);
101644                 } else {
101645                   unsharedActions.push(action);
101646                   unsharedNodes.push(node);
101647                 }
101648               }
101649             });
101650             _descriptionID += 'no_points.';
101651             _descriptionID += _wayIDs.length === 1 ? 'single_way.' : 'multiple_ways.';
101652
101653             if (sharedActions.length) {
101654               // if any nodes are shared, only disconnect the selected ways from each other
101655               _actions = sharedActions;
101656               _disconnectingVertexIds = sharedNodes.map(function (node) {
101657                 return node.id;
101658               });
101659               _descriptionID += 'conjoined';
101660               _annotationID = 'from_each_other';
101661             } else {
101662               // if no nodes are shared, disconnect the selected ways from all connected ways
101663               _actions = unsharedActions;
101664               _disconnectingVertexIds = unsharedNodes.map(function (node) {
101665                 return node.id;
101666               });
101667
101668               if (_wayIDs.length === 1) {
101669                 _descriptionID += context.graph().geometry(_wayIDs[0]);
101670               } else {
101671                 _descriptionID += 'separate';
101672               }
101673             }
101674           }
101675
101676           var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
101677
101678           var operation = function operation() {
101679             context.perform(function (graph) {
101680               return _actions.reduce(function (graph, action) {
101681                 return action(graph);
101682               }, graph);
101683             }, operation.annotation());
101684             context.validator().validate();
101685           };
101686
101687           operation.relatedEntityIds = function () {
101688             if (_vertexIDs.length) {
101689               return _disconnectingWayIds;
101690             }
101691
101692             return _disconnectingVertexIds;
101693           };
101694
101695           operation.available = function () {
101696             if (_actions.length === 0) return false;
101697             if (_otherIDs.length !== 0) return false;
101698             if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function (wayID) {
101699               return _vertexIDs.some(function (vertexID) {
101700                 var way = context.entity(wayID);
101701                 return way.nodes.indexOf(vertexID) !== -1;
101702               });
101703             })) return false;
101704             return true;
101705           };
101706
101707           operation.disabled = function () {
101708             var reason;
101709
101710             for (var actionIndex in _actions) {
101711               reason = _actions[actionIndex].disabled(context.graph());
101712               if (reason) return reason;
101713             }
101714
101715             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
101716               return 'too_large.' + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? 'single' : 'multiple');
101717             } else if (_coords && someMissing()) {
101718               return 'not_downloaded';
101719             } else if (selectedIDs.some(context.hasHiddenConnections)) {
101720               return 'connected_to_hidden';
101721             }
101722
101723             return false;
101724
101725             function someMissing() {
101726               if (context.inIntro()) return false;
101727               var osm = context.connection();
101728
101729               if (osm) {
101730                 var missing = _coords.filter(function (loc) {
101731                   return !osm.isDataLoaded(loc);
101732                 });
101733
101734                 if (missing.length) {
101735                   missing.forEach(function (loc) {
101736                     context.loadTileAtLoc(loc);
101737                   });
101738                   return true;
101739                 }
101740               }
101741
101742               return false;
101743             }
101744           };
101745
101746           operation.tooltip = function () {
101747             var disable = operation.disabled();
101748
101749             if (disable) {
101750               return _t('operations.disconnect.' + disable);
101751             }
101752
101753             return _t('operations.disconnect.description.' + _descriptionID);
101754           };
101755
101756           operation.annotation = function () {
101757             return _t('operations.disconnect.annotation.' + _annotationID);
101758           };
101759
101760           operation.id = 'disconnect';
101761           operation.keys = [_t('operations.disconnect.key')];
101762           operation.title = _t('operations.disconnect.title');
101763           operation.behavior = behaviorOperation(context).which(operation);
101764           return operation;
101765         }
101766
101767         function operationDowngrade(context, selectedIDs) {
101768           var _affectedFeatureCount = 0;
101769
101770           var _downgradeType = downgradeTypeForEntityIDs(selectedIDs);
101771
101772           var _multi = _affectedFeatureCount === 1 ? 'single' : 'multiple';
101773
101774           function downgradeTypeForEntityIDs(entityIds) {
101775             var downgradeType;
101776             _affectedFeatureCount = 0;
101777
101778             for (var i in entityIds) {
101779               var entityID = entityIds[i];
101780               var type = downgradeTypeForEntityID(entityID);
101781
101782               if (type) {
101783                 _affectedFeatureCount += 1;
101784
101785                 if (downgradeType && type !== downgradeType) {
101786                   if (downgradeType !== 'generic' && type !== 'generic') {
101787                     downgradeType = 'building_address';
101788                   } else {
101789                     downgradeType = 'generic';
101790                   }
101791                 } else {
101792                   downgradeType = type;
101793                 }
101794               }
101795             }
101796
101797             return downgradeType;
101798           }
101799
101800           function downgradeTypeForEntityID(entityID) {
101801             var graph = context.graph();
101802             var entity = graph.entity(entityID);
101803             var preset = _mainPresetIndex.match(entity, graph);
101804             if (!preset || preset.isFallback()) return null;
101805
101806             if (entity.type === 'node' && preset.id !== 'address' && Object.keys(entity.tags).some(function (key) {
101807               return key.match(/^addr:.{1,}/);
101808             })) {
101809               return 'address';
101810             }
101811
101812             var geometry = entity.geometry(graph);
101813
101814             if (geometry === 'area' && entity.tags.building && !preset.tags.building) {
101815               return 'building';
101816             }
101817
101818             if (geometry === 'vertex' && Object.keys(entity.tags).length) {
101819               return 'generic';
101820             }
101821
101822             return null;
101823           }
101824
101825           var buildingKeysToKeep = ['architect', 'building', 'height', 'layer', 'source', 'type', 'wheelchair'];
101826           var addressKeysToKeep = ['source'];
101827
101828           var operation = function operation() {
101829             context.perform(function (graph) {
101830               for (var i in selectedIDs) {
101831                 var entityID = selectedIDs[i];
101832                 var type = downgradeTypeForEntityID(entityID);
101833                 if (!type) continue;
101834                 var tags = Object.assign({}, graph.entity(entityID).tags); // shallow copy
101835
101836                 for (var key in tags) {
101837                   if (type === 'address' && addressKeysToKeep.indexOf(key) !== -1) continue;
101838
101839                   if (type === 'building') {
101840                     if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
101841                   }
101842
101843                   if (type !== 'generic') {
101844                     if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
101845                   }
101846
101847                   delete tags[key];
101848                 }
101849
101850                 graph = actionChangeTags(entityID, tags)(graph);
101851               }
101852
101853               return graph;
101854             }, operation.annotation());
101855             context.validator().validate(); // refresh the select mode to enable the delete operation
101856
101857             context.enter(modeSelect(context, selectedIDs));
101858           };
101859
101860           operation.available = function () {
101861             return _downgradeType;
101862           };
101863
101864           operation.disabled = function () {
101865             if (selectedIDs.some(hasWikidataTag)) {
101866               return 'has_wikidata_tag';
101867             }
101868
101869             return false;
101870
101871             function hasWikidataTag(id) {
101872               var entity = context.entity(id);
101873               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
101874             }
101875           };
101876
101877           operation.tooltip = function () {
101878             var disable = operation.disabled();
101879             return disable ? _t('operations.downgrade.' + disable + '.' + _multi) : _t('operations.downgrade.description.' + _downgradeType);
101880           };
101881
101882           operation.annotation = function () {
101883             var suffix;
101884
101885             if (_downgradeType === 'building_address') {
101886               suffix = 'generic';
101887             } else {
101888               suffix = _downgradeType;
101889             }
101890
101891             return _t('operations.downgrade.annotation.' + suffix, {
101892               n: _affectedFeatureCount
101893             });
101894           };
101895
101896           operation.id = 'downgrade';
101897           operation.keys = [uiCmd('⌫')];
101898           operation.title = _t('operations.downgrade.title');
101899           operation.behavior = behaviorOperation(context).which(operation);
101900           return operation;
101901         }
101902
101903         function operationExtract(context, selectedIDs) {
101904           var _amount = selectedIDs.length === 1 ? 'single' : 'multiple';
101905
101906           var _geometries = utilArrayUniq(selectedIDs.map(function (entityID) {
101907             return context.graph().hasEntity(entityID) && context.graph().geometry(entityID);
101908           }).filter(Boolean));
101909
101910           var _geometryID = _geometries.length === 1 ? _geometries[0] : 'feature';
101911
101912           var _extent;
101913
101914           var _actions = selectedIDs.map(function (entityID) {
101915             var graph = context.graph();
101916             var entity = graph.hasEntity(entityID);
101917             if (!entity || !entity.hasInterestingTags()) return null;
101918             if (entity.type === 'node' && graph.parentWays(entity).length === 0) return null;
101919
101920             if (entity.type !== 'node') {
101921               var preset = _mainPresetIndex.match(entity, graph); // only allow extraction from ways/relations if the preset supports points
101922
101923               if (preset.geometry.indexOf('point') === -1) return null;
101924             }
101925
101926             _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
101927             return actionExtract(entityID, context.projection);
101928           }).filter(Boolean);
101929
101930           var operation = function operation() {
101931             var combinedAction = function combinedAction(graph) {
101932               _actions.forEach(function (action) {
101933                 graph = action(graph);
101934               });
101935
101936               return graph;
101937             };
101938
101939             context.perform(combinedAction, operation.annotation()); // do the extract
101940
101941             var extractedNodeIDs = _actions.map(function (action) {
101942               return action.getExtractedNodeID();
101943             });
101944
101945             context.enter(modeSelect(context, extractedNodeIDs));
101946           };
101947
101948           operation.available = function () {
101949             return _actions.length && selectedIDs.length === _actions.length;
101950           };
101951
101952           operation.disabled = function () {
101953             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
101954               return 'too_large';
101955             } else if (selectedIDs.some(function (entityID) {
101956               return context.graph().geometry(entityID) === 'vertex' && context.hasHiddenConnections(entityID);
101957             })) {
101958               return 'connected_to_hidden';
101959             }
101960
101961             return false;
101962           };
101963
101964           operation.tooltip = function () {
101965             var disableReason = operation.disabled();
101966
101967             if (disableReason) {
101968               return _t('operations.extract.' + disableReason + '.' + _amount);
101969             } else {
101970               return _t('operations.extract.description.' + _geometryID + '.' + _amount);
101971             }
101972           };
101973
101974           operation.annotation = function () {
101975             return _t('operations.extract.annotation', {
101976               n: selectedIDs.length
101977             });
101978           };
101979
101980           operation.id = 'extract';
101981           operation.keys = [_t('operations.extract.key')];
101982           operation.title = _t('operations.extract.title');
101983           operation.behavior = behaviorOperation(context).which(operation);
101984           return operation;
101985         }
101986
101987         function operationMerge(context, selectedIDs) {
101988           var _action = getAction();
101989
101990           function getAction() {
101991             // prefer a non-disabled action first
101992             var join = actionJoin(selectedIDs);
101993             if (!join.disabled(context.graph())) return join;
101994             var merge = actionMerge(selectedIDs);
101995             if (!merge.disabled(context.graph())) return merge;
101996             var mergePolygon = actionMergePolygon(selectedIDs);
101997             if (!mergePolygon.disabled(context.graph())) return mergePolygon;
101998             var mergeNodes = actionMergeNodes(selectedIDs);
101999             if (!mergeNodes.disabled(context.graph())) return mergeNodes; // otherwise prefer an action with an interesting disabled reason
102000
102001             if (join.disabled(context.graph()) !== 'not_eligible') return join;
102002             if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
102003             if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
102004             return mergeNodes;
102005           }
102006
102007           var operation = function operation() {
102008             if (operation.disabled()) return;
102009             context.perform(_action, operation.annotation());
102010             context.validator().validate();
102011             var resultIDs = selectedIDs.filter(context.hasEntity);
102012
102013             if (resultIDs.length > 1) {
102014               var interestingIDs = resultIDs.filter(function (id) {
102015                 return context.entity(id).hasInterestingTags();
102016               });
102017               if (interestingIDs.length) resultIDs = interestingIDs;
102018             }
102019
102020             context.enter(modeSelect(context, resultIDs));
102021           };
102022
102023           operation.available = function () {
102024             return selectedIDs.length >= 2;
102025           };
102026
102027           operation.disabled = function () {
102028             var actionDisabled = _action.disabled(context.graph());
102029
102030             if (actionDisabled) return actionDisabled;
102031             var osm = context.connection();
102032
102033             if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
102034               return 'too_many_vertices';
102035             }
102036
102037             return false;
102038           };
102039
102040           operation.tooltip = function () {
102041             var disabled = operation.disabled();
102042
102043             if (disabled) {
102044               if (disabled === 'conflicting_relations') {
102045                 return _t('operations.merge.conflicting_relations');
102046               }
102047
102048               if (disabled === 'restriction' || disabled === 'connectivity') {
102049                 return _t('operations.merge.damage_relation', {
102050                   relation: _mainPresetIndex.item('type/' + disabled).name()
102051                 });
102052               }
102053
102054               return _t('operations.merge.' + disabled);
102055             }
102056
102057             return _t('operations.merge.description');
102058           };
102059
102060           operation.annotation = function () {
102061             return _t('operations.merge.annotation', {
102062               n: selectedIDs.length
102063             });
102064           };
102065
102066           operation.id = 'merge';
102067           operation.keys = [_t('operations.merge.key')];
102068           operation.title = _t('operations.merge.title');
102069           operation.behavior = behaviorOperation(context).which(operation);
102070           return operation;
102071         }
102072
102073         function operationPaste(context) {
102074           var _pastePoint;
102075
102076           var operation = function operation() {
102077             if (!_pastePoint) return;
102078             var oldIDs = context.copyIDs();
102079             if (!oldIDs.length) return;
102080             var projection = context.projection;
102081             var extent = geoExtent();
102082             var oldGraph = context.copyGraph();
102083             var newIDs = [];
102084             var action = actionCopyEntities(oldIDs, oldGraph);
102085             context.perform(action);
102086             var copies = action.copies();
102087             var originals = new Set();
102088             Object.values(copies).forEach(function (entity) {
102089               originals.add(entity.id);
102090             });
102091
102092             for (var id in copies) {
102093               var oldEntity = oldGraph.entity(id);
102094               var newEntity = copies[id];
102095
102096               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
102097
102098
102099               var parents = context.graph().parentWays(newEntity);
102100               var parentCopied = parents.some(function (parent) {
102101                 return originals.has(parent.id);
102102               });
102103
102104               if (!parentCopied) {
102105                 newIDs.push(newEntity.id);
102106               }
102107             } // Use the location of the copy operation to offset the paste location,
102108             // or else use the center of the pasted extent
102109
102110
102111             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
102112             var delta = geoVecSubtract(_pastePoint, copyPoint); // Move the pasted objects to be anchored at the paste location
102113
102114             context.replace(actionMove(newIDs, delta, projection), operation.annotation());
102115             context.enter(modeSelect(context, newIDs));
102116           };
102117
102118           operation.point = function (val) {
102119             _pastePoint = val;
102120             return operation;
102121           };
102122
102123           operation.available = function () {
102124             return context.mode().id === 'browse';
102125           };
102126
102127           operation.disabled = function () {
102128             return !context.copyIDs().length;
102129           };
102130
102131           operation.tooltip = function () {
102132             var oldGraph = context.copyGraph();
102133             var ids = context.copyIDs();
102134
102135             if (!ids.length) {
102136               return _t('operations.paste.nothing_copied');
102137             }
102138
102139             return _t('operations.paste.description', {
102140               feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph),
102141               n: ids.length
102142             });
102143           };
102144
102145           operation.annotation = function () {
102146             var ids = context.copyIDs();
102147             return _t('operations.paste.annotation', {
102148               n: ids.length
102149             });
102150           };
102151
102152           operation.id = 'paste';
102153           operation.keys = [uiCmd('⌘V')];
102154           operation.title = _t('operations.paste.title');
102155           return operation;
102156         }
102157
102158         function operationReverse(context, selectedIDs) {
102159           var operation = function operation() {
102160             context.perform(function combinedReverseAction(graph) {
102161               actions().forEach(function (action) {
102162                 graph = action(graph);
102163               });
102164               return graph;
102165             }, operation.annotation());
102166             context.validator().validate();
102167           };
102168
102169           function actions(situation) {
102170             return selectedIDs.map(function (entityID) {
102171               var entity = context.hasEntity(entityID);
102172               if (!entity) return null;
102173
102174               if (situation === 'toolbar') {
102175                 if (entity.type === 'way' && !entity.isOneWay() && !entity.isSided()) return null;
102176               }
102177
102178               var geometry = entity.geometry(context.graph());
102179               if (entity.type !== 'node' && geometry !== 'line') return null;
102180               var action = actionReverse(entityID);
102181               if (action.disabled(context.graph())) return null;
102182               return action;
102183             }).filter(Boolean);
102184           }
102185
102186           function reverseTypeID() {
102187             var acts = actions();
102188             var nodeActionCount = acts.filter(function (act) {
102189               var entity = context.hasEntity(act.entityID());
102190               return entity && entity.type === 'node';
102191             }).length;
102192             if (nodeActionCount === 0) return 'line';
102193             if (nodeActionCount === acts.length) return 'point';
102194             return 'feature';
102195           }
102196
102197           operation.available = function (situation) {
102198             return actions(situation).length > 0;
102199           };
102200
102201           operation.disabled = function () {
102202             return false;
102203           };
102204
102205           operation.tooltip = function () {
102206             return _t('operations.reverse.description.' + reverseTypeID());
102207           };
102208
102209           operation.annotation = function () {
102210             var acts = actions();
102211             return _t('operations.reverse.annotation.' + reverseTypeID(), {
102212               n: acts.length
102213             });
102214           };
102215
102216           operation.id = 'reverse';
102217           operation.keys = [_t('operations.reverse.key')];
102218           operation.title = _t('operations.reverse.title');
102219           operation.behavior = behaviorOperation(context).which(operation);
102220           return operation;
102221         }
102222
102223         function operationSplit(context, selectedIDs) {
102224           var _vertexIds = selectedIDs.filter(function (id) {
102225             return context.graph().geometry(id) === 'vertex';
102226           });
102227
102228           var _selectedWayIds = selectedIDs.filter(function (id) {
102229             var entity = context.graph().hasEntity(id);
102230             return entity && entity.type === 'way';
102231           });
102232
102233           var _isAvailable = _vertexIds.length > 0 && _vertexIds.length + _selectedWayIds.length === selectedIDs.length;
102234
102235           var _action = actionSplit(_vertexIds);
102236
102237           var _ways = [];
102238           var _geometry = 'feature';
102239           var _waysAmount = 'single';
102240
102241           var _nodesAmount = _vertexIds.length === 1 ? 'single' : 'multiple';
102242
102243           if (_isAvailable) {
102244             if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
102245             _ways = _action.ways(context.graph());
102246             var geometries = {};
102247
102248             _ways.forEach(function (way) {
102249               geometries[way.geometry(context.graph())] = true;
102250             });
102251
102252             if (Object.keys(geometries).length === 1) {
102253               _geometry = Object.keys(geometries)[0];
102254             }
102255
102256             _waysAmount = _ways.length === 1 ? 'single' : 'multiple';
102257           }
102258
102259           var operation = function operation() {
102260             var difference = context.perform(_action, operation.annotation()); // select both the nodes and the ways so the mapper can immediately disconnect them if desired
102261
102262             var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function (id) {
102263               // filter out relations that may have had member additions
102264               return context.entity(id).type === 'way';
102265             }));
102266
102267             context.enter(modeSelect(context, idsToSelect));
102268           };
102269
102270           operation.relatedEntityIds = function () {
102271             return _selectedWayIds.length ? [] : _ways.map(function (way) {
102272               return way.id;
102273             });
102274           };
102275
102276           operation.available = function () {
102277             return _isAvailable;
102278           };
102279
102280           operation.disabled = function () {
102281             var reason = _action.disabled(context.graph());
102282
102283             if (reason) {
102284               return reason;
102285             } else if (selectedIDs.some(context.hasHiddenConnections)) {
102286               return 'connected_to_hidden';
102287             }
102288
102289             return false;
102290           };
102291
102292           operation.tooltip = function () {
102293             var disable = operation.disabled();
102294             if (disable) return _t('operations.split.' + disable);
102295             return _t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node');
102296           };
102297
102298           operation.annotation = function () {
102299             return _t('operations.split.annotation.' + _geometry, {
102300               n: _ways.length
102301             });
102302           };
102303
102304           operation.id = 'split';
102305           operation.keys = [_t('operations.split.key')];
102306           operation.title = _t('operations.split.title');
102307           operation.behavior = behaviorOperation(context).which(operation);
102308           return operation;
102309         }
102310
102311         function operationStraighten(context, selectedIDs) {
102312           var _wayIDs = selectedIDs.filter(function (id) {
102313             return id.charAt(0) === 'w';
102314           });
102315
102316           var _nodeIDs = selectedIDs.filter(function (id) {
102317             return id.charAt(0) === 'n';
102318           });
102319
102320           var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? 'single' : 'multiple';
102321
102322           var _nodes = utilGetAllNodes(selectedIDs, context.graph());
102323
102324           var _coords = _nodes.map(function (n) {
102325             return n.loc;
102326           });
102327
102328           var _extent = utilTotalExtent(selectedIDs, context.graph());
102329
102330           var _action = chooseAction();
102331
102332           var _geometry;
102333
102334           function chooseAction() {
102335             // straighten selected nodes
102336             if (_wayIDs.length === 0 && _nodeIDs.length > 2) {
102337               _geometry = 'point';
102338               return actionStraightenNodes(_nodeIDs, context.projection); // straighten selected ways (possibly between range of 2 selected nodes)
102339             } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
102340               var startNodeIDs = [];
102341               var endNodeIDs = [];
102342
102343               for (var i = 0; i < selectedIDs.length; i++) {
102344                 var entity = context.entity(selectedIDs[i]);
102345
102346                 if (entity.type === 'node') {
102347                   continue;
102348                 } else if (entity.type !== 'way' || entity.isClosed()) {
102349                   return null; // exit early, can't straighten these
102350                 }
102351
102352                 startNodeIDs.push(entity.first());
102353                 endNodeIDs.push(entity.last());
102354               } // Remove duplicate end/startNodeIDs (duplicate nodes cannot be at the line end)
102355
102356
102357               startNodeIDs = startNodeIDs.filter(function (n) {
102358                 return startNodeIDs.indexOf(n) === startNodeIDs.lastIndexOf(n);
102359               });
102360               endNodeIDs = endNodeIDs.filter(function (n) {
102361                 return endNodeIDs.indexOf(n) === endNodeIDs.lastIndexOf(n);
102362               }); // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints)
102363
102364               if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null; // Ensure path contains at least 3 unique nodes
102365
102366               var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function (node) {
102367                 return node.id;
102368               });
102369               if (wayNodeIDs.length <= 2) return null; // If range of 2 selected nodes is supplied, ensure nodes lie on the selected path
102370
102371               if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
102372
102373               if (_nodeIDs.length) {
102374                 // If we're only straightenting between two points, we only need that extent visible
102375                 _extent = utilTotalExtent(_nodeIDs, context.graph());
102376               }
102377
102378               _geometry = 'line';
102379               return actionStraightenWay(selectedIDs, context.projection);
102380             }
102381
102382             return null;
102383           }
102384
102385           function operation() {
102386             if (!_action) return;
102387             context.perform(_action, operation.annotation());
102388             window.setTimeout(function () {
102389               context.validator().validate();
102390             }, 300); // after any transition
102391           }
102392
102393           operation.available = function () {
102394             return Boolean(_action);
102395           };
102396
102397           operation.disabled = function () {
102398             var reason = _action.disabled(context.graph());
102399
102400             if (reason) {
102401               return reason;
102402             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
102403               return 'too_large';
102404             } else if (someMissing()) {
102405               return 'not_downloaded';
102406             } else if (selectedIDs.some(context.hasHiddenConnections)) {
102407               return 'connected_to_hidden';
102408             }
102409
102410             return false;
102411
102412             function someMissing() {
102413               if (context.inIntro()) return false;
102414               var osm = context.connection();
102415
102416               if (osm) {
102417                 var missing = _coords.filter(function (loc) {
102418                   return !osm.isDataLoaded(loc);
102419                 });
102420
102421                 if (missing.length) {
102422                   missing.forEach(function (loc) {
102423                     context.loadTileAtLoc(loc);
102424                   });
102425                   return true;
102426                 }
102427               }
102428
102429               return false;
102430             }
102431           };
102432
102433           operation.tooltip = function () {
102434             var disable = operation.disabled();
102435             return disable ? _t('operations.straighten.' + disable + '.' + _amount) : _t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's'));
102436           };
102437
102438           operation.annotation = function () {
102439             return _t('operations.straighten.annotation.' + _geometry, {
102440               n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length
102441             });
102442           };
102443
102444           operation.id = 'straighten';
102445           operation.keys = [_t('operations.straighten.key')];
102446           operation.title = _t('operations.straighten.title');
102447           operation.behavior = behaviorOperation(context).which(operation);
102448           return operation;
102449         }
102450
102451         var Operations = /*#__PURE__*/Object.freeze({
102452                 __proto__: null,
102453                 operationCircularize: operationCircularize,
102454                 operationContinue: operationContinue,
102455                 operationCopy: operationCopy,
102456                 operationDelete: operationDelete,
102457                 operationDisconnect: operationDisconnect,
102458                 operationDowngrade: operationDowngrade,
102459                 operationExtract: operationExtract,
102460                 operationMerge: operationMerge,
102461                 operationMove: operationMove,
102462                 operationOrthogonalize: operationOrthogonalize,
102463                 operationPaste: operationPaste,
102464                 operationReflectShort: operationReflectShort,
102465                 operationReflectLong: operationReflectLong,
102466                 operationReverse: operationReverse,
102467                 operationRotate: operationRotate,
102468                 operationSplit: operationSplit,
102469                 operationStraighten: operationStraighten
102470         });
102471
102472         function modeSelect(context, selectedIDs) {
102473           var mode = {
102474             id: 'select',
102475             button: 'browse'
102476           };
102477           var keybinding = utilKeybinding('select');
102478
102479           var _breatheBehavior = behaviorBreathe();
102480
102481           var _modeDragNode = modeDragNode(context);
102482
102483           var _selectBehavior;
102484
102485           var _behaviors = [];
102486           var _operations = [];
102487           var _newFeature = false;
102488           var _follow = false; // `_focusedParentWayId` is used when we visit a vertex with multiple
102489           // parents, and we want to remember which parent line we started on.
102490
102491           var _focusedParentWayId;
102492
102493           var _focusedVertexIds;
102494
102495           function singular() {
102496             if (selectedIDs && selectedIDs.length === 1) {
102497               return context.hasEntity(selectedIDs[0]);
102498             }
102499           }
102500
102501           function selectedEntities() {
102502             return selectedIDs.map(function (id) {
102503               return context.hasEntity(id);
102504             }).filter(Boolean);
102505           }
102506
102507           function checkSelectedIDs() {
102508             var ids = [];
102509
102510             if (Array.isArray(selectedIDs)) {
102511               ids = selectedIDs.filter(function (id) {
102512                 return context.hasEntity(id);
102513               });
102514             }
102515
102516             if (!ids.length) {
102517               context.enter(modeBrowse(context));
102518               return false;
102519             } else if (selectedIDs.length > 1 && ids.length === 1 || selectedIDs.length === 1 && ids.length > 1) {
102520               // switch between single- and multi-select UI
102521               context.enter(modeSelect(context, ids));
102522               return false;
102523             }
102524
102525             selectedIDs = ids;
102526             return true;
102527           } // find the parent ways for nextVertex, previousVertex, and selectParent
102528
102529
102530           function parentWaysIdsOfSelection(onlyCommonParents) {
102531             var graph = context.graph();
102532             var parents = [];
102533
102534             for (var i = 0; i < selectedIDs.length; i++) {
102535               var entity = context.hasEntity(selectedIDs[i]);
102536
102537               if (!entity || entity.geometry(graph) !== 'vertex') {
102538                 return []; // selection includes some non-vertices
102539               }
102540
102541               var currParents = graph.parentWays(entity).map(function (w) {
102542                 return w.id;
102543               });
102544
102545               if (!parents.length) {
102546                 parents = currParents;
102547                 continue;
102548               }
102549
102550               parents = (onlyCommonParents ? utilArrayIntersection : utilArrayUnion)(parents, currParents);
102551
102552               if (!parents.length) {
102553                 return [];
102554               }
102555             }
102556
102557             return parents;
102558           } // find the child nodes for selected ways
102559
102560
102561           function childNodeIdsOfSelection(onlyCommon) {
102562             var graph = context.graph();
102563             var childs = [];
102564
102565             for (var i = 0; i < selectedIDs.length; i++) {
102566               var entity = context.hasEntity(selectedIDs[i]);
102567
102568               if (!entity || !['area', 'line'].includes(entity.geometry(graph))) {
102569                 return []; // selection includes non-area/non-line
102570               }
102571
102572               var currChilds = graph.childNodes(entity).map(function (node) {
102573                 return node.id;
102574               });
102575
102576               if (!childs.length) {
102577                 childs = currChilds;
102578                 continue;
102579               }
102580
102581               childs = (onlyCommon ? utilArrayIntersection : utilArrayUnion)(childs, currChilds);
102582
102583               if (!childs.length) {
102584                 return [];
102585               }
102586             }
102587
102588             return childs;
102589           }
102590
102591           function checkFocusedParent() {
102592             if (_focusedParentWayId) {
102593               var parents = parentWaysIdsOfSelection(true);
102594               if (parents.indexOf(_focusedParentWayId) === -1) _focusedParentWayId = null;
102595             }
102596           }
102597
102598           function parentWayIdForVertexNavigation() {
102599             var parentIds = parentWaysIdsOfSelection(true);
102600
102601             if (_focusedParentWayId && parentIds.indexOf(_focusedParentWayId) !== -1) {
102602               // prefer the previously seen parent
102603               return _focusedParentWayId;
102604             }
102605
102606             return parentIds.length ? parentIds[0] : null;
102607           }
102608
102609           mode.selectedIDs = function (val) {
102610             if (!arguments.length) return selectedIDs;
102611             selectedIDs = val;
102612             return mode;
102613           };
102614
102615           mode.zoomToSelected = function () {
102616             context.map().zoomToEase(selectedEntities());
102617           };
102618
102619           mode.newFeature = function (val) {
102620             if (!arguments.length) return _newFeature;
102621             _newFeature = val;
102622             return mode;
102623           };
102624
102625           mode.selectBehavior = function (val) {
102626             if (!arguments.length) return _selectBehavior;
102627             _selectBehavior = val;
102628             return mode;
102629           };
102630
102631           mode.follow = function (val) {
102632             if (!arguments.length) return _follow;
102633             _follow = val;
102634             return mode;
102635           };
102636
102637           function loadOperations() {
102638             _operations.forEach(function (operation) {
102639               if (operation.behavior) {
102640                 context.uninstall(operation.behavior);
102641               }
102642             });
102643
102644             _operations = Object.values(Operations).map(function (o) {
102645               return o(context, selectedIDs);
102646             }).filter(function (o) {
102647               return o.id !== 'delete' && o.id !== 'downgrade' && o.id !== 'copy';
102648             }).concat([// group copy/downgrade/delete operation together at the end of the list
102649             operationCopy(context, selectedIDs), operationDowngrade(context, selectedIDs), operationDelete(context, selectedIDs)]).filter(function (operation) {
102650               return operation.available();
102651             });
102652
102653             _operations.forEach(function (operation) {
102654               if (operation.behavior) {
102655                 context.install(operation.behavior);
102656               }
102657             }); // remove any displayed menu
102658
102659
102660             context.ui().closeEditMenu();
102661           }
102662
102663           mode.operations = function () {
102664             return _operations;
102665           };
102666
102667           mode.enter = function () {
102668             if (!checkSelectedIDs()) return;
102669             context.features().forceVisible(selectedIDs);
102670
102671             _modeDragNode.restoreSelectedIDs(selectedIDs);
102672
102673             loadOperations();
102674
102675             if (!_behaviors.length) {
102676               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
102677               _behaviors = [behaviorPaste(context), _breatheBehavior, behaviorHover(context).on('hover', context.ui().sidebar.hoverModeSelect), _selectBehavior, behaviorLasso(context), _modeDragNode.behavior, modeDragNote(context).behavior];
102678             }
102679
102680             _behaviors.forEach(context.install);
102681
102682             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) {
102683               return uiCmd('⇧' + key);
102684             }), scaleSelection(1.05)).on(utilKeybinding.plusKeys.map(function (key) {
102685               return uiCmd('⇧⌥' + key);
102686             }), scaleSelection(Math.pow(1.05, 5))).on(utilKeybinding.minusKeys.map(function (key) {
102687               return uiCmd('⇧' + key);
102688             }), scaleSelection(1 / 1.05)).on(utilKeybinding.minusKeys.map(function (key) {
102689               return uiCmd('⇧⌥' + key);
102690             }), scaleSelection(1 / Math.pow(1.05, 5))).on(['\\', 'pause'], focusNextParent).on(uiCmd('⌘↑'), selectParent).on(uiCmd('⌘↓'), selectChild).on('⎋', esc, true);
102691             select(document).call(keybinding);
102692             context.ui().sidebar.select(selectedIDs, _newFeature);
102693             context.history().on('change.select', function () {
102694               loadOperations(); // reselect after change in case relation members were removed or added
102695
102696               selectElements();
102697             }).on('undone.select', checkSelectedIDs).on('redone.select', checkSelectedIDs);
102698             context.map().on('drawn.select', selectElements).on('crossEditableZoom.select', function () {
102699               selectElements();
102700
102701               _breatheBehavior.restartIfNeeded(context.surface());
102702             });
102703             context.map().doubleUpHandler().on('doubleUp.modeSelect', didDoubleUp);
102704             selectElements();
102705
102706             if (_follow) {
102707               var extent = geoExtent();
102708               var graph = context.graph();
102709               selectedIDs.forEach(function (id) {
102710                 var entity = context.entity(id);
102711
102712                 extent._extend(entity.extent(graph));
102713               });
102714               var loc = extent.center();
102715               context.map().centerEase(loc); // we could enter the mode multiple times, so reset follow for next time
102716
102717               _follow = false;
102718             }
102719
102720             function nudgeSelection(delta) {
102721               return function () {
102722                 // prevent nudging during low zoom selection
102723                 if (!context.map().withinEditableZoom()) return;
102724                 var moveOp = operationMove(context, selectedIDs);
102725
102726                 if (moveOp.disabled()) {
102727                   context.ui().flash.duration(4000).iconName('#iD-operation-' + moveOp.id).iconClass('operation disabled').label(moveOp.tooltip)();
102728                 } else {
102729                   context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation());
102730                   context.validator().validate();
102731                 }
102732               };
102733             }
102734
102735             function scaleSelection(factor) {
102736               return function () {
102737                 // prevent scaling during low zoom selection
102738                 if (!context.map().withinEditableZoom()) return;
102739                 var nodes = utilGetAllNodes(selectedIDs, context.graph());
102740                 var isUp = factor > 1; // can only scale if multiple nodes are selected
102741
102742                 if (nodes.length <= 1) return;
102743                 var extent = utilTotalExtent(selectedIDs, context.graph()); // These disabled checks would normally be handled by an operation
102744                 // object, but we don't want an actual scale operation at this point.
102745
102746                 function scalingDisabled() {
102747                   if (tooSmall()) {
102748                     return 'too_small';
102749                   } else if (extent.percentContainedIn(context.map().extent()) < 0.8) {
102750                     return 'too_large';
102751                   } else if (someMissing() || selectedIDs.some(incompleteRelation)) {
102752                     return 'not_downloaded';
102753                   } else if (selectedIDs.some(context.hasHiddenConnections)) {
102754                     return 'connected_to_hidden';
102755                   }
102756
102757                   return false;
102758
102759                   function tooSmall() {
102760                     if (isUp) return false;
102761                     var dLon = Math.abs(extent[1][0] - extent[0][0]);
102762                     var dLat = Math.abs(extent[1][1] - extent[0][1]);
102763                     return dLon < geoMetersToLon(1, extent[1][1]) && dLat < geoMetersToLat(1);
102764                   }
102765
102766                   function someMissing() {
102767                     if (context.inIntro()) return false;
102768                     var osm = context.connection();
102769
102770                     if (osm) {
102771                       var missing = nodes.filter(function (n) {
102772                         return !osm.isDataLoaded(n.loc);
102773                       });
102774
102775                       if (missing.length) {
102776                         missing.forEach(function (loc) {
102777                           context.loadTileAtLoc(loc);
102778                         });
102779                         return true;
102780                       }
102781                     }
102782
102783                     return false;
102784                   }
102785
102786                   function incompleteRelation(id) {
102787                     var entity = context.entity(id);
102788                     return entity.type === 'relation' && !entity.isComplete(context.graph());
102789                   }
102790                 }
102791
102792                 var disabled = scalingDisabled();
102793
102794                 if (disabled) {
102795                   var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
102796                   context.ui().flash.duration(4000).iconName('#iD-icon-no').iconClass('operation disabled').label(_t('operations.scale.' + disabled + '.' + multi))();
102797                 } else {
102798                   var pivot = context.projection(extent.center());
102799                   var annotation = _t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', {
102800                     n: selectedIDs.length
102801                   });
102802                   context.perform(actionScale(selectedIDs, pivot, factor, context.projection), annotation);
102803                   context.validator().validate();
102804                 }
102805               };
102806             }
102807
102808             function didDoubleUp(d3_event, loc) {
102809               if (!context.map().withinEditableZoom()) return;
102810               var target = select(d3_event.target);
102811               var datum = target.datum();
102812               var entity = datum && datum.properties && datum.properties.entity;
102813               if (!entity) return;
102814
102815               if (entity instanceof osmWay && target.classed('target')) {
102816                 var choice = geoChooseEdge(context.graph().childNodes(entity), loc, context.projection);
102817                 var prev = entity.nodes[choice.index - 1];
102818                 var next = entity.nodes[choice.index];
102819                 context.perform(actionAddMidpoint({
102820                   loc: choice.loc,
102821                   edge: [prev, next]
102822                 }, osmNode()), _t('operations.add.annotation.vertex'));
102823                 context.validator().validate();
102824               } else if (entity.type === 'midpoint') {
102825                 context.perform(actionAddMidpoint({
102826                   loc: entity.loc,
102827                   edge: entity.edge
102828                 }, osmNode()), _t('operations.add.annotation.vertex'));
102829                 context.validator().validate();
102830               }
102831             }
102832
102833             function selectElements() {
102834               if (!checkSelectedIDs()) return;
102835               var surface = context.surface();
102836               surface.selectAll('.selected-member').classed('selected-member', false);
102837               surface.selectAll('.selected').classed('selected', false);
102838               surface.selectAll('.related').classed('related', false); // reload `_focusedParentWayId` based on the current selection
102839
102840               checkFocusedParent();
102841
102842               if (_focusedParentWayId) {
102843                 surface.selectAll(utilEntitySelector([_focusedParentWayId])).classed('related', true);
102844               }
102845
102846               if (context.map().withinEditableZoom()) {
102847                 // Apply selection styling if not in wide selection
102848                 surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true
102849                 /* skipMultipolgonMembers */
102850                 )).classed('selected-member', true);
102851                 surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed('selected', true);
102852               }
102853             }
102854
102855             function esc() {
102856               if (context.container().select('.combobox').size()) return;
102857               context.enter(modeBrowse(context));
102858             }
102859
102860             function firstVertex(d3_event) {
102861               d3_event.preventDefault();
102862               var entity = singular();
102863               var parentId = parentWayIdForVertexNavigation();
102864               var way;
102865
102866               if (entity && entity.type === 'way') {
102867                 way = entity;
102868               } else if (parentId) {
102869                 way = context.entity(parentId);
102870               }
102871
102872               _focusedParentWayId = way && way.id;
102873
102874               if (way) {
102875                 context.enter(mode.selectedIDs([way.first()]).follow(true));
102876               }
102877             }
102878
102879             function lastVertex(d3_event) {
102880               d3_event.preventDefault();
102881               var entity = singular();
102882               var parentId = parentWayIdForVertexNavigation();
102883               var way;
102884
102885               if (entity && entity.type === 'way') {
102886                 way = entity;
102887               } else if (parentId) {
102888                 way = context.entity(parentId);
102889               }
102890
102891               _focusedParentWayId = way && way.id;
102892
102893               if (way) {
102894                 context.enter(mode.selectedIDs([way.last()]).follow(true));
102895               }
102896             }
102897
102898             function previousVertex(d3_event) {
102899               d3_event.preventDefault();
102900               var parentId = parentWayIdForVertexNavigation();
102901               _focusedParentWayId = parentId;
102902               if (!parentId) return;
102903               var way = context.entity(parentId);
102904               var length = way.nodes.length;
102905               var curr = way.nodes.indexOf(selectedIDs[0]);
102906               var index = -1;
102907
102908               if (curr > 0) {
102909                 index = curr - 1;
102910               } else if (way.isClosed()) {
102911                 index = length - 2;
102912               }
102913
102914               if (index !== -1) {
102915                 context.enter(mode.selectedIDs([way.nodes[index]]).follow(true));
102916               }
102917             }
102918
102919             function nextVertex(d3_event) {
102920               d3_event.preventDefault();
102921               var parentId = parentWayIdForVertexNavigation();
102922               _focusedParentWayId = parentId;
102923               if (!parentId) return;
102924               var way = context.entity(parentId);
102925               var length = way.nodes.length;
102926               var curr = way.nodes.indexOf(selectedIDs[0]);
102927               var index = -1;
102928
102929               if (curr < length - 1) {
102930                 index = curr + 1;
102931               } else if (way.isClosed()) {
102932                 index = 0;
102933               }
102934
102935               if (index !== -1) {
102936                 context.enter(mode.selectedIDs([way.nodes[index]]).follow(true));
102937               }
102938             }
102939
102940             function focusNextParent(d3_event) {
102941               d3_event.preventDefault();
102942               var parents = parentWaysIdsOfSelection(true);
102943               if (!parents || parents.length < 2) return;
102944               var index = parents.indexOf(_focusedParentWayId);
102945
102946               if (index < 0 || index > parents.length - 2) {
102947                 _focusedParentWayId = parents[0];
102948               } else {
102949                 _focusedParentWayId = parents[index + 1];
102950               }
102951
102952               var surface = context.surface();
102953               surface.selectAll('.related').classed('related', false);
102954
102955               if (_focusedParentWayId) {
102956                 surface.selectAll(utilEntitySelector([_focusedParentWayId])).classed('related', true);
102957               }
102958             }
102959
102960             function selectParent(d3_event) {
102961               d3_event.preventDefault();
102962               var currentSelectedIds = mode.selectedIDs();
102963               var parentIds = _focusedParentWayId ? [_focusedParentWayId] : parentWaysIdsOfSelection(false);
102964               if (!parentIds.length) return;
102965               context.enter(mode.selectedIDs(parentIds)); // set this after re-entering the selection since we normally want it cleared on exit
102966
102967               _focusedVertexIds = currentSelectedIds;
102968             }
102969
102970             function selectChild(d3_event) {
102971               d3_event.preventDefault();
102972               var currentSelectedIds = mode.selectedIDs();
102973               var childIds = _focusedVertexIds ? _focusedVertexIds.filter(function (id) {
102974                 return context.hasEntity(id);
102975               }) : childNodeIdsOfSelection(true);
102976               if (!childIds || !childIds.length) return;
102977               if (currentSelectedIds.length === 1) _focusedParentWayId = currentSelectedIds[0];
102978               context.enter(mode.selectedIDs(childIds));
102979             }
102980           };
102981
102982           mode.exit = function () {
102983             // we could enter the mode multiple times but it's only new the first time
102984             _newFeature = false;
102985             _focusedVertexIds = null;
102986
102987             _operations.forEach(function (operation) {
102988               if (operation.behavior) {
102989                 context.uninstall(operation.behavior);
102990               }
102991             });
102992
102993             _operations = [];
102994
102995             _behaviors.forEach(context.uninstall);
102996
102997             select(document).call(keybinding.unbind);
102998             context.ui().closeEditMenu();
102999             context.history().on('change.select', null).on('undone.select', null).on('redone.select', null);
103000             var surface = context.surface();
103001             surface.selectAll('.selected-member').classed('selected-member', false);
103002             surface.selectAll('.selected').classed('selected', false);
103003             surface.selectAll('.highlighted').classed('highlighted', false);
103004             surface.selectAll('.related').classed('related', false);
103005             context.map().on('drawn.select', null);
103006             context.ui().sidebar.hide();
103007             context.features().forceVisible([]);
103008             var entity = singular();
103009
103010             if (_newFeature && entity && entity.type === 'relation' && // no tags
103011             Object.keys(entity.tags).length === 0 && // no parent relations
103012             context.graph().parentRelations(entity).length === 0 && ( // no members or one member with no role
103013             entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
103014               // the user added this relation but didn't edit it at all, so just delete it
103015               var deleteAction = actionDeleteRelation(entity.id, true
103016               /* don't delete untagged members */
103017               );
103018               context.perform(deleteAction, _t('operations.delete.annotation.relation'));
103019               context.validator().validate();
103020             }
103021           };
103022
103023           return mode;
103024         }
103025
103026         function uiLasso(context) {
103027           var group, polygon;
103028           lasso.coordinates = [];
103029
103030           function lasso(selection) {
103031             context.container().classed('lasso', true);
103032             group = selection.append('g').attr('class', 'lasso hide');
103033             polygon = group.append('path').attr('class', 'lasso-path');
103034             group.call(uiToggle(true));
103035           }
103036
103037           function draw() {
103038             if (polygon) {
103039               polygon.data([lasso.coordinates]).attr('d', function (d) {
103040                 return 'M' + d.join(' L') + ' Z';
103041               });
103042             }
103043           }
103044
103045           lasso.extent = function () {
103046             return lasso.coordinates.reduce(function (extent, point) {
103047               return extent.extend(geoExtent(point));
103048             }, geoExtent());
103049           };
103050
103051           lasso.p = function (_) {
103052             if (!arguments.length) return lasso;
103053             lasso.coordinates.push(_);
103054             draw();
103055             return lasso;
103056           };
103057
103058           lasso.close = function () {
103059             if (group) {
103060               group.call(uiToggle(false, function () {
103061                 select(this).remove();
103062               }));
103063             }
103064
103065             context.container().classed('lasso', false);
103066           };
103067
103068           return lasso;
103069         }
103070
103071         function behaviorLasso(context) {
103072           // use pointer events on supported platforms; fallback to mouse events
103073           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
103074
103075           var behavior = function behavior(selection) {
103076             var lasso;
103077
103078             function pointerdown(d3_event) {
103079               var button = 0; // left
103080
103081               if (d3_event.button === button && d3_event.shiftKey === true) {
103082                 lasso = null;
103083                 select(window).on(_pointerPrefix + 'move.lasso', pointermove).on(_pointerPrefix + 'up.lasso', pointerup);
103084                 d3_event.stopPropagation();
103085               }
103086             }
103087
103088             function pointermove() {
103089               if (!lasso) {
103090                 lasso = uiLasso(context);
103091                 context.surface().call(lasso);
103092               }
103093
103094               lasso.p(context.map().mouse());
103095             }
103096
103097             function normalize(a, b) {
103098               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])]];
103099             }
103100
103101             function lassoed() {
103102               if (!lasso) return [];
103103               var graph = context.graph();
103104               var limitToNodes;
103105
103106               if (context.map().editableDataEnabled(true
103107               /* skipZoomCheck */
103108               ) && context.map().isInWideSelection()) {
103109                 // only select from the visible nodes
103110                 limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
103111               } else if (!context.map().editableDataEnabled()) {
103112                 return [];
103113               }
103114
103115               var bounds = lasso.extent().map(context.projection.invert);
103116               var extent = geoExtent(normalize(bounds[0], bounds[1]));
103117               var intersects = context.history().intersects(extent).filter(function (entity) {
103118                 return entity.type === 'node' && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
103119               }); // sort the lassoed nodes as best we can
103120
103121               intersects.sort(function (node1, node2) {
103122                 var parents1 = graph.parentWays(node1);
103123                 var parents2 = graph.parentWays(node2);
103124
103125                 if (parents1.length && parents2.length) {
103126                   // both nodes are vertices
103127                   var sharedParents = utilArrayIntersection(parents1, parents2);
103128
103129                   if (sharedParents.length) {
103130                     var sharedParentNodes = sharedParents[0].nodes; // vertices are members of the same way; sort them in their listed order
103131
103132                     return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
103133                   } else {
103134                     // vertices do not share a way; group them by their respective parent ways
103135                     return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
103136                   }
103137                 } else if (parents1.length || parents2.length) {
103138                   // only one node is a vertex; sort standalone points before vertices
103139                   return parents1.length - parents2.length;
103140                 } // both nodes are standalone points; sort left to right
103141
103142
103143                 return node1.loc[0] - node2.loc[0];
103144               });
103145               return intersects.map(function (entity) {
103146                 return entity.id;
103147               });
103148             }
103149
103150             function pointerup() {
103151               select(window).on(_pointerPrefix + 'move.lasso', null).on(_pointerPrefix + 'up.lasso', null);
103152               if (!lasso) return;
103153               var ids = lassoed();
103154               lasso.close();
103155
103156               if (ids.length) {
103157                 context.enter(modeSelect(context, ids));
103158               }
103159             }
103160
103161             selection.on(_pointerPrefix + 'down.lasso', pointerdown);
103162           };
103163
103164           behavior.off = function (selection) {
103165             selection.on(_pointerPrefix + 'down.lasso', null);
103166           };
103167
103168           return behavior;
103169         }
103170
103171         function modeBrowse(context) {
103172           var mode = {
103173             button: 'browse',
103174             id: 'browse',
103175             title: _t('modes.browse.title'),
103176             description: _t('modes.browse.description')
103177           };
103178           var sidebar;
103179
103180           var _selectBehavior;
103181
103182           var _behaviors = [];
103183
103184           mode.selectBehavior = function (val) {
103185             if (!arguments.length) return _selectBehavior;
103186             _selectBehavior = val;
103187             return mode;
103188           };
103189
103190           mode.enter = function () {
103191             if (!_behaviors.length) {
103192               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
103193               _behaviors = [behaviorPaste(context), behaviorHover(context).on('hover', context.ui().sidebar.hover), _selectBehavior, behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
103194             }
103195
103196             _behaviors.forEach(context.install); // Get focus on the body.
103197
103198
103199             if (document.activeElement && document.activeElement.blur) {
103200               document.activeElement.blur();
103201             }
103202
103203             if (sidebar) {
103204               context.ui().sidebar.show(sidebar);
103205             } else {
103206               context.ui().sidebar.select(null);
103207             }
103208           };
103209
103210           mode.exit = function () {
103211             context.ui().sidebar.hover.cancel();
103212
103213             _behaviors.forEach(context.uninstall);
103214
103215             if (sidebar) {
103216               context.ui().sidebar.hide();
103217             }
103218           };
103219
103220           mode.sidebar = function (_) {
103221             if (!arguments.length) return sidebar;
103222             sidebar = _;
103223             return mode;
103224           };
103225
103226           mode.operations = function () {
103227             return [operationPaste(context)];
103228           };
103229
103230           return mode;
103231         }
103232
103233         function behaviorAddWay(context) {
103234           var dispatch = dispatch$8('start', 'startFromWay', 'startFromNode');
103235           var draw = behaviorDraw(context);
103236
103237           function behavior(surface) {
103238             draw.on('click', function () {
103239               dispatch.apply('start', this, arguments);
103240             }).on('clickWay', function () {
103241               dispatch.apply('startFromWay', this, arguments);
103242             }).on('clickNode', function () {
103243               dispatch.apply('startFromNode', this, arguments);
103244             }).on('cancel', behavior.cancel).on('finish', behavior.cancel);
103245             context.map().dblclickZoomEnable(false);
103246             surface.call(draw);
103247           }
103248
103249           behavior.off = function (surface) {
103250             surface.call(draw.off);
103251           };
103252
103253           behavior.cancel = function () {
103254             window.setTimeout(function () {
103255               context.map().dblclickZoomEnable(true);
103256             }, 1000);
103257             context.enter(modeBrowse(context));
103258           };
103259
103260           return utilRebind(behavior, dispatch, 'on');
103261         }
103262
103263         function behaviorHash(context) {
103264           // cached window.location.hash
103265           var _cachedHash = null; // allowable latitude range
103266
103267           var _latitudeLimit = 90 - 1e-8;
103268
103269           function computedHashParameters() {
103270             var map = context.map();
103271             var center = map.center();
103272             var zoom = map.zoom();
103273             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
103274             var oldParams = utilObjectOmit(utilStringQs(window.location.hash), ['comment', 'source', 'hashtags', 'walkthrough']);
103275             var newParams = {};
103276             delete oldParams.id;
103277             var selected = context.selectedIDs().filter(function (id) {
103278               return context.hasEntity(id);
103279             });
103280
103281             if (selected.length) {
103282               newParams.id = selected.join(',');
103283             }
103284
103285             newParams.map = zoom.toFixed(2) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
103286             return Object.assign(oldParams, newParams);
103287           }
103288
103289           function computedHash() {
103290             return '#' + utilQsString(computedHashParameters(), true);
103291           }
103292
103293           function computedTitle(includeChangeCount) {
103294             var baseTitle = context.documentTitleBase() || 'iD';
103295             var contextual;
103296             var changeCount;
103297             var titleID;
103298             var selected = context.selectedIDs().filter(function (id) {
103299               return context.hasEntity(id);
103300             });
103301
103302             if (selected.length) {
103303               var firstLabel = utilDisplayLabel(context.entity(selected[0]), context.graph());
103304
103305               if (selected.length > 1) {
103306                 contextual = _t('title.labeled_and_more', {
103307                   labeled: firstLabel,
103308                   count: selected.length - 1
103309                 });
103310               } else {
103311                 contextual = firstLabel;
103312               }
103313
103314               titleID = 'context';
103315             }
103316
103317             if (includeChangeCount) {
103318               changeCount = context.history().difference().summary().length;
103319
103320               if (changeCount > 0) {
103321                 titleID = contextual ? 'changes_context' : 'changes';
103322               }
103323             }
103324
103325             if (titleID) {
103326               return _t('title.format.' + titleID, {
103327                 changes: changeCount,
103328                 base: baseTitle,
103329                 context: contextual
103330               });
103331             }
103332
103333             return baseTitle;
103334           }
103335
103336           function updateTitle(includeChangeCount) {
103337             if (!context.setsDocumentTitle()) return;
103338             var newTitle = computedTitle(includeChangeCount);
103339
103340             if (document.title !== newTitle) {
103341               document.title = newTitle;
103342             }
103343           }
103344
103345           function updateHashIfNeeded() {
103346             if (context.inIntro()) return;
103347             var latestHash = computedHash();
103348
103349             if (_cachedHash !== latestHash) {
103350               _cachedHash = latestHash; // Update the URL hash without affecting the browser navigation stack,
103351               // though unavoidably creating a browser history entry
103352
103353               window.history.replaceState(null, computedTitle(false
103354               /* includeChangeCount */
103355               ), latestHash); // set the title we want displayed for the browser tab/window
103356
103357               updateTitle(true
103358               /* includeChangeCount */
103359               );
103360             }
103361           }
103362
103363           var _throttledUpdate = throttle(updateHashIfNeeded, 500);
103364
103365           var _throttledUpdateTitle = throttle(function () {
103366             updateTitle(true
103367             /* includeChangeCount */
103368             );
103369           }, 500);
103370
103371           function hashchange() {
103372             // ignore spurious hashchange events
103373             if (window.location.hash === _cachedHash) return;
103374             _cachedHash = window.location.hash;
103375             var q = utilStringQs(_cachedHash);
103376             var mapArgs = (q.map || '').split('/').map(Number);
103377
103378             if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
103379               // replace bogus hash
103380               updateHashIfNeeded();
103381             } else {
103382               // don't update if the new hash already reflects the state of iD
103383               if (_cachedHash === computedHash()) return;
103384               var mode = context.mode();
103385               context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
103386
103387               if (q.id && mode) {
103388                 var ids = q.id.split(',').filter(function (id) {
103389                   return context.hasEntity(id);
103390                 });
103391
103392                 if (ids.length && (mode.id === 'browse' || mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids))) {
103393                   context.enter(modeSelect(context, ids));
103394                   return;
103395                 }
103396               }
103397
103398               var center = context.map().center();
103399               var dist = geoSphericalDistance(center, [mapArgs[2], mapArgs[1]]);
103400               var maxdist = 500; // Don't allow the hash location to change too much while drawing
103401               // This can happen if the user accidentally hit the back button.  #3996
103402
103403               if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
103404                 context.enter(modeBrowse(context));
103405                 return;
103406               }
103407             }
103408           }
103409
103410           function behavior() {
103411             context.map().on('move.behaviorHash', _throttledUpdate);
103412             context.history().on('change.behaviorHash', _throttledUpdateTitle);
103413             context.on('enter.behaviorHash', _throttledUpdate);
103414             select(window).on('hashchange.behaviorHash', hashchange);
103415
103416             if (window.location.hash) {
103417               var q = utilStringQs(window.location.hash);
103418
103419               if (q.id) {
103420                 //if (!context.history().hasRestorableChanges()) {
103421                 // targeting specific features: download, select, and zoom to them
103422                 context.zoomToEntity(q.id.split(',')[0], !q.map); //}
103423               }
103424
103425               if (q.walkthrough === 'true') {
103426                 behavior.startWalkthrough = true;
103427               }
103428
103429               if (q.map) {
103430                 behavior.hadHash = true;
103431               }
103432
103433               hashchange();
103434               updateTitle(false);
103435             }
103436           }
103437
103438           behavior.off = function () {
103439             _throttledUpdate.cancel();
103440
103441             _throttledUpdateTitle.cancel();
103442
103443             context.map().on('move.behaviorHash', null);
103444             context.on('enter.behaviorHash', null);
103445             select(window).on('hashchange.behaviorHash', null);
103446             window.location.hash = '';
103447           };
103448
103449           return behavior;
103450         }
103451
103452         // This is only done in testing because of the performance penalty.
103453
103454         var debug = false; // Reexport just what our tests use, see #4379
103455         var d3 = {
103456           dispatch: dispatch$8,
103457           geoMercator: mercator,
103458           geoProjection: projection,
103459           polygonArea: d3_polygonArea,
103460           polygonCentroid: d3_polygonCentroid,
103461           select: select,
103462           selectAll: selectAll,
103463           timerFlush: timerFlush
103464         };
103465
103466         var iD = /*#__PURE__*/Object.freeze({
103467                 __proto__: null,
103468                 debug: debug,
103469                 d3: d3,
103470                 actionAddEntity: actionAddEntity,
103471                 actionAddMember: actionAddMember,
103472                 actionAddMidpoint: actionAddMidpoint,
103473                 actionAddVertex: actionAddVertex,
103474                 actionChangeMember: actionChangeMember,
103475                 actionChangePreset: actionChangePreset,
103476                 actionChangeTags: actionChangeTags,
103477                 actionCircularize: actionCircularize,
103478                 actionConnect: actionConnect,
103479                 actionCopyEntities: actionCopyEntities,
103480                 actionDeleteMember: actionDeleteMember,
103481                 actionDeleteMultiple: actionDeleteMultiple,
103482                 actionDeleteNode: actionDeleteNode,
103483                 actionDeleteRelation: actionDeleteRelation,
103484                 actionDeleteWay: actionDeleteWay,
103485                 actionDiscardTags: actionDiscardTags,
103486                 actionDisconnect: actionDisconnect,
103487                 actionExtract: actionExtract,
103488                 actionJoin: actionJoin,
103489                 actionMerge: actionMerge,
103490                 actionMergeNodes: actionMergeNodes,
103491                 actionMergePolygon: actionMergePolygon,
103492                 actionMergeRemoteChanges: actionMergeRemoteChanges,
103493                 actionMove: actionMove,
103494                 actionMoveMember: actionMoveMember,
103495                 actionMoveNode: actionMoveNode,
103496                 actionNoop: actionNoop,
103497                 actionOrthogonalize: actionOrthogonalize,
103498                 actionRestrictTurn: actionRestrictTurn,
103499                 actionReverse: actionReverse,
103500                 actionRevert: actionRevert,
103501                 actionRotate: actionRotate,
103502                 actionScale: actionScale,
103503                 actionSplit: actionSplit,
103504                 actionStraightenNodes: actionStraightenNodes,
103505                 actionStraightenWay: actionStraightenWay,
103506                 actionUnrestrictTurn: actionUnrestrictTurn,
103507                 actionReflect: actionReflect,
103508                 actionUpgradeTags: actionUpgradeTags,
103509                 behaviorAddWay: behaviorAddWay,
103510                 behaviorBreathe: behaviorBreathe,
103511                 behaviorDrag: behaviorDrag,
103512                 behaviorDrawWay: behaviorDrawWay,
103513                 behaviorDraw: behaviorDraw,
103514                 behaviorEdit: behaviorEdit,
103515                 behaviorHash: behaviorHash,
103516                 behaviorHover: behaviorHover,
103517                 behaviorLasso: behaviorLasso,
103518                 behaviorOperation: behaviorOperation,
103519                 behaviorPaste: behaviorPaste,
103520                 behaviorSelect: behaviorSelect,
103521                 coreContext: coreContext,
103522                 coreFileFetcher: coreFileFetcher,
103523                 fileFetcher: _mainFileFetcher,
103524                 coreDifference: coreDifference,
103525                 coreGraph: coreGraph,
103526                 coreHistory: coreHistory,
103527                 coreLocalizer: coreLocalizer,
103528                 t: _t,
103529                 localizer: _mainLocalizer,
103530                 coreLocations: coreLocations,
103531                 locationManager: _mainLocations,
103532                 prefs: corePreferences,
103533                 coreTree: coreTree,
103534                 coreUploader: coreUploader,
103535                 coreValidator: coreValidator,
103536                 geoExtent: geoExtent,
103537                 geoLatToMeters: geoLatToMeters,
103538                 geoLonToMeters: geoLonToMeters,
103539                 geoMetersToLat: geoMetersToLat,
103540                 geoMetersToLon: geoMetersToLon,
103541                 geoMetersToOffset: geoMetersToOffset,
103542                 geoOffsetToMeters: geoOffsetToMeters,
103543                 geoScaleToZoom: geoScaleToZoom,
103544                 geoSphericalClosestNode: geoSphericalClosestNode,
103545                 geoSphericalDistance: geoSphericalDistance,
103546                 geoZoomToScale: geoZoomToScale,
103547                 geoAngle: geoAngle,
103548                 geoChooseEdge: geoChooseEdge,
103549                 geoEdgeEqual: geoEdgeEqual,
103550                 geoGetSmallestSurroundingRectangle: geoGetSmallestSurroundingRectangle,
103551                 geoHasLineIntersections: geoHasLineIntersections,
103552                 geoHasSelfIntersections: geoHasSelfIntersections,
103553                 geoRotate: geoRotate,
103554                 geoLineIntersection: geoLineIntersection,
103555                 geoPathHasIntersections: geoPathHasIntersections,
103556                 geoPathIntersections: geoPathIntersections,
103557                 geoPathLength: geoPathLength,
103558                 geoPointInPolygon: geoPointInPolygon,
103559                 geoPolygonContainsPolygon: geoPolygonContainsPolygon,
103560                 geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
103561                 geoViewportEdge: geoViewportEdge,
103562                 geoRawMercator: geoRawMercator,
103563                 geoVecAdd: geoVecAdd,
103564                 geoVecAngle: geoVecAngle,
103565                 geoVecCross: geoVecCross,
103566                 geoVecDot: geoVecDot,
103567                 geoVecEqual: geoVecEqual,
103568                 geoVecFloor: geoVecFloor,
103569                 geoVecInterp: geoVecInterp,
103570                 geoVecLength: geoVecLength,
103571                 geoVecLengthSquare: geoVecLengthSquare,
103572                 geoVecNormalize: geoVecNormalize,
103573                 geoVecNormalizedDot: geoVecNormalizedDot,
103574                 geoVecProject: geoVecProject,
103575                 geoVecSubtract: geoVecSubtract,
103576                 geoVecScale: geoVecScale,
103577                 geoOrthoNormalizedDotProduct: geoOrthoNormalizedDotProduct,
103578                 geoOrthoCalcScore: geoOrthoCalcScore,
103579                 geoOrthoMaxOffsetAngle: geoOrthoMaxOffsetAngle,
103580                 geoOrthoCanOrthogonalize: geoOrthoCanOrthogonalize,
103581                 modeAddArea: modeAddArea,
103582                 modeAddLine: modeAddLine,
103583                 modeAddPoint: modeAddPoint,
103584                 modeAddNote: modeAddNote,
103585                 modeBrowse: modeBrowse,
103586                 modeDragNode: modeDragNode,
103587                 modeDragNote: modeDragNote,
103588                 modeDrawArea: modeDrawArea,
103589                 modeDrawLine: modeDrawLine,
103590                 modeMove: modeMove,
103591                 modeRotate: modeRotate,
103592                 modeSave: modeSave,
103593                 modeSelect: modeSelect,
103594                 modeSelectData: modeSelectData,
103595                 modeSelectError: modeSelectError,
103596                 modeSelectNote: modeSelectNote,
103597                 operationCircularize: operationCircularize,
103598                 operationContinue: operationContinue,
103599                 operationCopy: operationCopy,
103600                 operationDelete: operationDelete,
103601                 operationDisconnect: operationDisconnect,
103602                 operationDowngrade: operationDowngrade,
103603                 operationExtract: operationExtract,
103604                 operationMerge: operationMerge,
103605                 operationMove: operationMove,
103606                 operationOrthogonalize: operationOrthogonalize,
103607                 operationPaste: operationPaste,
103608                 operationReflectShort: operationReflectShort,
103609                 operationReflectLong: operationReflectLong,
103610                 operationReverse: operationReverse,
103611                 operationRotate: operationRotate,
103612                 operationSplit: operationSplit,
103613                 operationStraighten: operationStraighten,
103614                 osmChangeset: osmChangeset,
103615                 osmEntity: osmEntity,
103616                 osmNode: osmNode,
103617                 osmNote: osmNote,
103618                 osmRelation: osmRelation,
103619                 osmWay: osmWay,
103620                 QAItem: QAItem,
103621                 osmIntersection: osmIntersection,
103622                 osmTurn: osmTurn,
103623                 osmInferRestriction: osmInferRestriction,
103624                 osmLanes: osmLanes,
103625                 osmOldMultipolygonOuterMemberOfRelation: osmOldMultipolygonOuterMemberOfRelation,
103626                 osmIsOldMultipolygonOuterMember: osmIsOldMultipolygonOuterMember,
103627                 osmOldMultipolygonOuterMember: osmOldMultipolygonOuterMember,
103628                 osmJoinWays: osmJoinWays,
103629                 get osmAreaKeys () { return osmAreaKeys; },
103630                 osmSetAreaKeys: osmSetAreaKeys,
103631                 osmTagSuggestingArea: osmTagSuggestingArea,
103632                 get osmPointTags () { return osmPointTags; },
103633                 osmSetPointTags: osmSetPointTags,
103634                 get osmVertexTags () { return osmVertexTags; },
103635                 osmSetVertexTags: osmSetVertexTags,
103636                 osmNodeGeometriesForTags: osmNodeGeometriesForTags,
103637                 osmOneWayTags: osmOneWayTags,
103638                 osmPavedTags: osmPavedTags,
103639                 osmIsInterestingTag: osmIsInterestingTag,
103640                 osmRoutableHighwayTagValues: osmRoutableHighwayTagValues,
103641                 osmFlowingWaterwayTagValues: osmFlowingWaterwayTagValues,
103642                 osmRailwayTrackTagValues: osmRailwayTrackTagValues,
103643                 presetCategory: presetCategory,
103644                 presetCollection: presetCollection,
103645                 presetField: presetField,
103646                 presetPreset: presetPreset,
103647                 presetManager: _mainPresetIndex,
103648                 presetIndex: presetIndex,
103649                 rendererBackgroundSource: rendererBackgroundSource,
103650                 rendererBackground: rendererBackground,
103651                 rendererFeatures: rendererFeatures,
103652                 rendererMap: rendererMap,
103653                 rendererPhotos: rendererPhotos,
103654                 rendererTileLayer: rendererTileLayer,
103655                 services: services,
103656                 serviceKeepRight: serviceKeepRight,
103657                 serviceImproveOSM: serviceImproveOSM,
103658                 serviceOsmose: serviceOsmose,
103659                 serviceMapillary: serviceMapillary,
103660                 serviceMapRules: serviceMapRules,
103661                 serviceNominatim: serviceNominatim,
103662                 serviceNsi: serviceNsi,
103663                 serviceOpenstreetcam: serviceOpenstreetcam,
103664                 serviceOsm: serviceOsm,
103665                 serviceOsmWikibase: serviceOsmWikibase,
103666                 serviceStreetside: serviceStreetside,
103667                 serviceTaginfo: serviceTaginfo,
103668                 serviceVectorTile: serviceVectorTile,
103669                 serviceWikidata: serviceWikidata,
103670                 serviceWikipedia: serviceWikipedia,
103671                 svgAreas: svgAreas,
103672                 svgData: svgData,
103673                 svgDebug: svgDebug,
103674                 svgDefs: svgDefs,
103675                 svgKeepRight: svgKeepRight,
103676                 svgIcon: svgIcon,
103677                 svgGeolocate: svgGeolocate,
103678                 svgLabels: svgLabels,
103679                 svgLayers: svgLayers,
103680                 svgLines: svgLines,
103681                 svgMapillaryImages: svgMapillaryImages,
103682                 svgMapillarySigns: svgMapillarySigns,
103683                 svgMidpoints: svgMidpoints,
103684                 svgNotes: svgNotes,
103685                 svgMarkerSegments: svgMarkerSegments,
103686                 svgOpenstreetcamImages: svgOpenstreetcamImages,
103687                 svgOsm: svgOsm,
103688                 svgPassiveVertex: svgPassiveVertex,
103689                 svgPath: svgPath,
103690                 svgPointTransform: svgPointTransform,
103691                 svgPoints: svgPoints,
103692                 svgRelationMemberTags: svgRelationMemberTags,
103693                 svgSegmentWay: svgSegmentWay,
103694                 svgStreetside: svgStreetside,
103695                 svgTagClasses: svgTagClasses,
103696                 svgTagPattern: svgTagPattern,
103697                 svgTouch: svgTouch,
103698                 svgTurns: svgTurns,
103699                 svgVertices: svgVertices,
103700                 uiFieldDefaultCheck: uiFieldCheck,
103701                 uiFieldOnewayCheck: uiFieldCheck,
103702                 uiFieldCheck: uiFieldCheck,
103703                 uiFieldManyCombo: uiFieldCombo,
103704                 uiFieldMultiCombo: uiFieldCombo,
103705                 uiFieldNetworkCombo: uiFieldCombo,
103706                 uiFieldSemiCombo: uiFieldCombo,
103707                 uiFieldTypeCombo: uiFieldCombo,
103708                 uiFieldCombo: uiFieldCombo,
103709                 uiFieldUrl: uiFieldText,
103710                 uiFieldIdentifier: uiFieldText,
103711                 uiFieldNumber: uiFieldText,
103712                 uiFieldTel: uiFieldText,
103713                 uiFieldEmail: uiFieldText,
103714                 uiFieldText: uiFieldText,
103715                 uiFieldAccess: uiFieldAccess,
103716                 uiFieldAddress: uiFieldAddress,
103717                 uiFieldCycleway: uiFieldCycleway,
103718                 uiFieldLanes: uiFieldLanes,
103719                 uiFieldLocalized: uiFieldLocalized,
103720                 uiFieldRoadheight: uiFieldRoadheight,
103721                 uiFieldRoadspeed: uiFieldRoadspeed,
103722                 uiFieldStructureRadio: uiFieldRadio,
103723                 uiFieldRadio: uiFieldRadio,
103724                 uiFieldRestrictions: uiFieldRestrictions,
103725                 uiFieldTextarea: uiFieldTextarea,
103726                 uiFieldWikidata: uiFieldWikidata,
103727                 uiFieldWikipedia: uiFieldWikipedia,
103728                 uiFields: uiFields,
103729                 uiIntro: uiIntro,
103730                 uiPanelBackground: uiPanelBackground,
103731                 uiPanelHistory: uiPanelHistory,
103732                 uiPanelLocation: uiPanelLocation,
103733                 uiPanelMeasurement: uiPanelMeasurement,
103734                 uiInfoPanels: uiInfoPanels,
103735                 uiPaneBackground: uiPaneBackground,
103736                 uiPaneHelp: uiPaneHelp,
103737                 uiPaneIssues: uiPaneIssues,
103738                 uiPaneMapData: uiPaneMapData,
103739                 uiPanePreferences: uiPanePreferences,
103740                 uiSectionBackgroundDisplayOptions: uiSectionBackgroundDisplayOptions,
103741                 uiSectionBackgroundList: uiSectionBackgroundList,
103742                 uiSectionBackgroundOffset: uiSectionBackgroundOffset,
103743                 uiSectionChanges: uiSectionChanges,
103744                 uiSectionDataLayers: uiSectionDataLayers,
103745                 uiSectionEntityIssues: uiSectionEntityIssues,
103746                 uiSectionFeatureType: uiSectionFeatureType,
103747                 uiSectionMapFeatures: uiSectionMapFeatures,
103748                 uiSectionMapStyleOptions: uiSectionMapStyleOptions,
103749                 uiSectionOverlayList: uiSectionOverlayList,
103750                 uiSectionPhotoOverlays: uiSectionPhotoOverlays,
103751                 uiSectionPresetFields: uiSectionPresetFields,
103752                 uiSectionPrivacy: uiSectionPrivacy,
103753                 uiSectionRawMemberEditor: uiSectionRawMemberEditor,
103754                 uiSectionRawMembershipEditor: uiSectionRawMembershipEditor,
103755                 uiSectionRawTagEditor: uiSectionRawTagEditor,
103756                 uiSectionSelectionList: uiSectionSelectionList,
103757                 uiSectionValidationIssues: uiSectionValidationIssues,
103758                 uiSectionValidationOptions: uiSectionValidationOptions,
103759                 uiSectionValidationRules: uiSectionValidationRules,
103760                 uiSectionValidationStatus: uiSectionValidationStatus,
103761                 uiSettingsCustomBackground: uiSettingsCustomBackground,
103762                 uiSettingsCustomData: uiSettingsCustomData,
103763                 uiInit: uiInit,
103764                 uiAccount: uiAccount,
103765                 uiAttribution: uiAttribution,
103766                 uiChangesetEditor: uiChangesetEditor,
103767                 uiCmd: uiCmd,
103768                 uiCombobox: uiCombobox,
103769                 uiCommit: uiCommit,
103770                 uiCommitWarnings: uiCommitWarnings,
103771                 uiConfirm: uiConfirm,
103772                 uiConflicts: uiConflicts,
103773                 uiContributors: uiContributors,
103774                 uiCurtain: uiCurtain,
103775                 uiDataEditor: uiDataEditor,
103776                 uiDataHeader: uiDataHeader,
103777                 uiDisclosure: uiDisclosure,
103778                 uiEditMenu: uiEditMenu,
103779                 uiEntityEditor: uiEntityEditor,
103780                 uiFeatureInfo: uiFeatureInfo,
103781                 uiFeatureList: uiFeatureList,
103782                 uiField: uiField,
103783                 uiFieldHelp: uiFieldHelp,
103784                 uiFlash: uiFlash,
103785                 uiFormFields: uiFormFields,
103786                 uiFullScreen: uiFullScreen,
103787                 uiGeolocate: uiGeolocate,
103788                 uiImproveOsmComments: uiImproveOsmComments,
103789                 uiImproveOsmDetails: uiImproveOsmDetails,
103790                 uiImproveOsmEditor: uiImproveOsmEditor,
103791                 uiImproveOsmHeader: uiImproveOsmHeader,
103792                 uiInfo: uiInfo,
103793                 uiInspector: uiInspector,
103794                 uiIssuesInfo: uiIssuesInfo,
103795                 uiKeepRightDetails: uiKeepRightDetails,
103796                 uiKeepRightEditor: uiKeepRightEditor,
103797                 uiKeepRightHeader: uiKeepRightHeader,
103798                 uiLasso: uiLasso,
103799                 uiLoading: uiLoading,
103800                 uiMapInMap: uiMapInMap,
103801                 uiModal: uiModal,
103802                 uiNotice: uiNotice,
103803                 uiNoteComments: uiNoteComments,
103804                 uiNoteEditor: uiNoteEditor,
103805                 uiNoteHeader: uiNoteHeader,
103806                 uiNoteReport: uiNoteReport,
103807                 uiPopover: uiPopover,
103808                 uiPresetIcon: uiPresetIcon,
103809                 uiPresetList: uiPresetList,
103810                 uiRestore: uiRestore,
103811                 uiScale: uiScale,
103812                 uiSidebar: uiSidebar,
103813                 uiSourceSwitch: uiSourceSwitch,
103814                 uiSpinner: uiSpinner,
103815                 uiSplash: uiSplash,
103816                 uiStatus: uiStatus,
103817                 uiSuccess: uiSuccess,
103818                 uiTagReference: uiTagReference,
103819                 uiToggle: uiToggle,
103820                 uiTooltip: uiTooltip,
103821                 uiVersion: uiVersion,
103822                 uiViewOnOSM: uiViewOnOSM,
103823                 uiViewOnKeepRight: uiViewOnKeepRight,
103824                 uiZoom: uiZoom,
103825                 utilAesEncrypt: utilAesEncrypt,
103826                 utilAesDecrypt: utilAesDecrypt,
103827                 utilArrayChunk: utilArrayChunk,
103828                 utilArrayDifference: utilArrayDifference,
103829                 utilArrayFlatten: utilArrayFlatten,
103830                 utilArrayGroupBy: utilArrayGroupBy,
103831                 utilArrayIdentical: utilArrayIdentical,
103832                 utilArrayIntersection: utilArrayIntersection,
103833                 utilArrayUnion: utilArrayUnion,
103834                 utilArrayUniq: utilArrayUniq,
103835                 utilArrayUniqBy: utilArrayUniqBy,
103836                 utilAsyncMap: utilAsyncMap,
103837                 utilCleanTags: utilCleanTags,
103838                 utilCombinedTags: utilCombinedTags,
103839                 utilDeepMemberSelector: utilDeepMemberSelector,
103840                 utilDetect: utilDetect,
103841                 utilDisplayName: utilDisplayName,
103842                 utilDisplayNameForPath: utilDisplayNameForPath,
103843                 utilDisplayType: utilDisplayType,
103844                 utilDisplayLabel: utilDisplayLabel,
103845                 utilEntityRoot: utilEntityRoot,
103846                 utilEditDistance: utilEditDistance,
103847                 utilEntityAndDeepMemberIDs: utilEntityAndDeepMemberIDs,
103848                 utilEntityOrMemberSelector: utilEntityOrMemberSelector,
103849                 utilEntityOrDeepMemberSelector: utilEntityOrDeepMemberSelector,
103850                 utilEntitySelector: utilEntitySelector,
103851                 utilFastMouse: utilFastMouse,
103852                 utilFunctor: utilFunctor,
103853                 utilGetAllNodes: utilGetAllNodes,
103854                 utilGetSetValue: utilGetSetValue,
103855                 utilHashcode: utilHashcode,
103856                 utilHighlightEntities: utilHighlightEntities,
103857                 utilKeybinding: utilKeybinding,
103858                 utilNoAuto: utilNoAuto,
103859                 utilObjectOmit: utilObjectOmit,
103860                 utilPrefixCSSProperty: utilPrefixCSSProperty,
103861                 utilPrefixDOMProperty: utilPrefixDOMProperty,
103862                 utilQsString: utilQsString,
103863                 utilRebind: utilRebind,
103864                 utilSafeClassName: utilSafeClassName,
103865                 utilSetTransform: utilSetTransform,
103866                 utilSessionMutex: utilSessionMutex,
103867                 utilStringQs: utilStringQs,
103868                 utilTagDiff: utilTagDiff,
103869                 utilTagText: utilTagText,
103870                 utilTiler: utilTiler,
103871                 utilTotalExtent: utilTotalExtent,
103872                 utilTriggerEvent: utilTriggerEvent,
103873                 utilUnicodeCharsCount: utilUnicodeCharsCount,
103874                 utilUnicodeCharsTruncated: utilUnicodeCharsTruncated,
103875                 utilUniqueDomId: utilUniqueDomId,
103876                 utilWrap: utilWrap,
103877                 validationAlmostJunction: validationAlmostJunction,
103878                 validationCloseNodes: validationCloseNodes,
103879                 validationCrossingWays: validationCrossingWays,
103880                 validationDisconnectedWay: validationDisconnectedWay,
103881                 validationFormatting: validationFormatting,
103882                 validationHelpRequest: validationHelpRequest,
103883                 validationImpossibleOneway: validationImpossibleOneway,
103884                 validationIncompatibleSource: validationIncompatibleSource,
103885                 validationMaprules: validationMaprules,
103886                 validationMismatchedGeometry: validationMismatchedGeometry,
103887                 validationMissingRole: validationMissingRole,
103888                 validationMissingTag: validationMissingTag,
103889                 validationOutdatedTags: validationOutdatedTags,
103890                 validationPrivateData: validationPrivateData,
103891                 validationSuspiciousName: validationSuspiciousName,
103892                 validationUnsquareWay: validationUnsquareWay
103893         });
103894
103895         window.requestIdleCallback = window.requestIdleCallback || function (cb) {
103896           var start = Date.now();
103897           return window.requestAnimationFrame(function () {
103898             cb({
103899               didTimeout: false,
103900               timeRemaining: function timeRemaining() {
103901                 return Math.max(0, 50 - (Date.now() - start));
103902               }
103903             });
103904           });
103905         };
103906
103907         window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
103908           window.cancelAnimationFrame(id);
103909         };
103910         window.iD = iD;
103911
103912 }());