]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Merge remote-tracking branch 'upstream/pull/2920' into master
[rails.git] / vendor / assets / iD / iD.js
1 (function () {
2
3         var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
4
5         function getDefaultExportFromCjs (x) {
6                 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
7         }
8
9         function createCommonjsModule(fn, basedir, module) {
10                 return module = {
11                         path: basedir,
12                         exports: {},
13                         require: function (path, base) {
14                                 return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
15                         }
16                 }, fn(module, module.exports), module.exports;
17         }
18
19         function commonjsRequire () {
20                 throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
21         }
22
23         var check = function (it) {
24           return it && it.Math == Math && it;
25         };
26
27         // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
28         var global_1 =
29           // eslint-disable-next-line no-undef
30           check(typeof globalThis == 'object' && globalThis) ||
31           check(typeof window == 'object' && window) ||
32           check(typeof self == 'object' && self) ||
33           check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
34           // eslint-disable-next-line no-new-func
35           Function('return this')();
36
37         var fails = function (exec) {
38           try {
39             return !!exec();
40           } catch (error) {
41             return true;
42           }
43         };
44
45         // Thank's IE8 for his funny defineProperty
46         var descriptors = !fails(function () {
47           return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
48         });
49
50         var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
51         var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
52
53         // Nashorn ~ JDK8 bug
54         var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({ 1: 2 }, 1);
55
56         // `Object.prototype.propertyIsEnumerable` method implementation
57         // https://tc39.github.io/ecma262/#sec-object.prototype.propertyisenumerable
58         var f = NASHORN_BUG ? function propertyIsEnumerable(V) {
59           var descriptor = getOwnPropertyDescriptor(this, V);
60           return !!descriptor && descriptor.enumerable;
61         } : nativePropertyIsEnumerable;
62
63         var objectPropertyIsEnumerable = {
64                 f: f
65         };
66
67         var createPropertyDescriptor = function (bitmap, value) {
68           return {
69             enumerable: !(bitmap & 1),
70             configurable: !(bitmap & 2),
71             writable: !(bitmap & 4),
72             value: value
73           };
74         };
75
76         var toString = {}.toString;
77
78         var classofRaw = function (it) {
79           return toString.call(it).slice(8, -1);
80         };
81
82         var split = ''.split;
83
84         // fallback for non-array-like ES3 and non-enumerable old V8 strings
85         var indexedObject = fails(function () {
86           // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
87           // eslint-disable-next-line no-prototype-builtins
88           return !Object('z').propertyIsEnumerable(0);
89         }) ? function (it) {
90           return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
91         } : Object;
92
93         // `RequireObjectCoercible` abstract operation
94         // https://tc39.github.io/ecma262/#sec-requireobjectcoercible
95         var requireObjectCoercible = function (it) {
96           if (it == undefined) throw TypeError("Can't call method on " + it);
97           return it;
98         };
99
100         // toObject with fallback for non-array-like ES3 strings
101
102
103
104         var toIndexedObject = function (it) {
105           return indexedObject(requireObjectCoercible(it));
106         };
107
108         var isObject = function (it) {
109           return typeof it === 'object' ? it !== null : typeof it === 'function';
110         };
111
112         // `ToPrimitive` abstract operation
113         // https://tc39.github.io/ecma262/#sec-toprimitive
114         // instead of the ES6 spec version, we didn't implement @@toPrimitive case
115         // and the second argument - flag - preferred type is a string
116         var toPrimitive = function (input, PREFERRED_STRING) {
117           if (!isObject(input)) return input;
118           var fn, val;
119           if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
120           if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
121           if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
122           throw TypeError("Can't convert object to primitive value");
123         };
124
125         var hasOwnProperty = {}.hasOwnProperty;
126
127         var has = function (it, key) {
128           return hasOwnProperty.call(it, key);
129         };
130
131         var document$1 = global_1.document;
132         // typeof document.createElement is 'object' in old IE
133         var EXISTS = isObject(document$1) && isObject(document$1.createElement);
134
135         var documentCreateElement = function (it) {
136           return EXISTS ? document$1.createElement(it) : {};
137         };
138
139         // Thank's IE8 for his funny defineProperty
140         var ie8DomDefine = !descriptors && !fails(function () {
141           return Object.defineProperty(documentCreateElement('div'), 'a', {
142             get: function () { return 7; }
143           }).a != 7;
144         });
145
146         var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
147
148         // `Object.getOwnPropertyDescriptor` method
149         // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor
150         var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
151           O = toIndexedObject(O);
152           P = toPrimitive(P, true);
153           if (ie8DomDefine) try {
154             return nativeGetOwnPropertyDescriptor(O, P);
155           } catch (error) { /* empty */ }
156           if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
157         };
158
159         var objectGetOwnPropertyDescriptor = {
160                 f: f$1
161         };
162
163         var anObject = function (it) {
164           if (!isObject(it)) {
165             throw TypeError(String(it) + ' is not an object');
166           } return it;
167         };
168
169         var nativeDefineProperty = Object.defineProperty;
170
171         // `Object.defineProperty` method
172         // https://tc39.github.io/ecma262/#sec-object.defineproperty
173         var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
174           anObject(O);
175           P = toPrimitive(P, true);
176           anObject(Attributes);
177           if (ie8DomDefine) try {
178             return nativeDefineProperty(O, P, Attributes);
179           } catch (error) { /* empty */ }
180           if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
181           if ('value' in Attributes) O[P] = Attributes.value;
182           return O;
183         };
184
185         var objectDefineProperty = {
186                 f: f$2
187         };
188
189         var createNonEnumerableProperty = descriptors ? function (object, key, value) {
190           return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
191         } : function (object, key, value) {
192           object[key] = value;
193           return object;
194         };
195
196         var setGlobal = function (key, value) {
197           try {
198             createNonEnumerableProperty(global_1, key, value);
199           } catch (error) {
200             global_1[key] = value;
201           } return value;
202         };
203
204         var SHARED = '__core-js_shared__';
205         var store = global_1[SHARED] || setGlobal(SHARED, {});
206
207         var sharedStore = store;
208
209         var functionToString = Function.toString;
210
211         // this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper
212         if (typeof sharedStore.inspectSource != 'function') {
213           sharedStore.inspectSource = function (it) {
214             return functionToString.call(it);
215           };
216         }
217
218         var inspectSource = sharedStore.inspectSource;
219
220         var WeakMap = global_1.WeakMap;
221
222         var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap));
223
224         var isPure = false;
225
226         var shared = createCommonjsModule(function (module) {
227         (module.exports = function (key, value) {
228           return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
229         })('versions', []).push({
230           version: '3.6.5',
231           mode:  'global',
232           copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
233         });
234         });
235
236         var id = 0;
237         var postfix = Math.random();
238
239         var uid = function (key) {
240           return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
241         };
242
243         var keys = shared('keys');
244
245         var sharedKey = function (key) {
246           return keys[key] || (keys[key] = uid(key));
247         };
248
249         var hiddenKeys = {};
250
251         var WeakMap$1 = global_1.WeakMap;
252         var set, get, has$1;
253
254         var enforce = function (it) {
255           return has$1(it) ? get(it) : set(it, {});
256         };
257
258         var getterFor = function (TYPE) {
259           return function (it) {
260             var state;
261             if (!isObject(it) || (state = get(it)).type !== TYPE) {
262               throw TypeError('Incompatible receiver, ' + TYPE + ' required');
263             } return state;
264           };
265         };
266
267         if (nativeWeakMap) {
268           var store$1 = new WeakMap$1();
269           var wmget = store$1.get;
270           var wmhas = store$1.has;
271           var wmset = store$1.set;
272           set = function (it, metadata) {
273             wmset.call(store$1, it, metadata);
274             return metadata;
275           };
276           get = function (it) {
277             return wmget.call(store$1, it) || {};
278           };
279           has$1 = function (it) {
280             return wmhas.call(store$1, it);
281           };
282         } else {
283           var STATE = sharedKey('state');
284           hiddenKeys[STATE] = true;
285           set = function (it, metadata) {
286             createNonEnumerableProperty(it, STATE, metadata);
287             return metadata;
288           };
289           get = function (it) {
290             return has(it, STATE) ? it[STATE] : {};
291           };
292           has$1 = function (it) {
293             return has(it, STATE);
294           };
295         }
296
297         var internalState = {
298           set: set,
299           get: get,
300           has: has$1,
301           enforce: enforce,
302           getterFor: getterFor
303         };
304
305         var redefine = createCommonjsModule(function (module) {
306         var getInternalState = internalState.get;
307         var enforceInternalState = internalState.enforce;
308         var TEMPLATE = String(String).split('String');
309
310         (module.exports = function (O, key, value, options) {
311           var unsafe = options ? !!options.unsafe : false;
312           var simple = options ? !!options.enumerable : false;
313           var noTargetGet = options ? !!options.noTargetGet : false;
314           if (typeof value == 'function') {
315             if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key);
316             enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
317           }
318           if (O === global_1) {
319             if (simple) O[key] = value;
320             else setGlobal(key, value);
321             return;
322           } else if (!unsafe) {
323             delete O[key];
324           } else if (!noTargetGet && O[key]) {
325             simple = true;
326           }
327           if (simple) O[key] = value;
328           else createNonEnumerableProperty(O, key, value);
329         // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
330         })(Function.prototype, 'toString', function toString() {
331           return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
332         });
333         });
334
335         var path = global_1;
336
337         var aFunction = function (variable) {
338           return typeof variable == 'function' ? variable : undefined;
339         };
340
341         var getBuiltIn = function (namespace, method) {
342           return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace])
343             : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
344         };
345
346         var ceil = Math.ceil;
347         var floor = Math.floor;
348
349         // `ToInteger` abstract operation
350         // https://tc39.github.io/ecma262/#sec-tointeger
351         var toInteger = function (argument) {
352           return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
353         };
354
355         var min = Math.min;
356
357         // `ToLength` abstract operation
358         // https://tc39.github.io/ecma262/#sec-tolength
359         var toLength = function (argument) {
360           return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
361         };
362
363         var max = Math.max;
364         var min$1 = Math.min;
365
366         // Helper for a popular repeating case of the spec:
367         // Let integer be ? ToInteger(index).
368         // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
369         var toAbsoluteIndex = function (index, length) {
370           var integer = toInteger(index);
371           return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
372         };
373
374         // `Array.prototype.{ indexOf, includes }` methods implementation
375         var createMethod = function (IS_INCLUDES) {
376           return function ($this, el, fromIndex) {
377             var O = toIndexedObject($this);
378             var length = toLength(O.length);
379             var index = toAbsoluteIndex(fromIndex, length);
380             var value;
381             // Array#includes uses SameValueZero equality algorithm
382             // eslint-disable-next-line no-self-compare
383             if (IS_INCLUDES && el != el) while (length > index) {
384               value = O[index++];
385               // eslint-disable-next-line no-self-compare
386               if (value != value) return true;
387             // Array#indexOf ignores holes, Array#includes - not
388             } else for (;length > index; index++) {
389               if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
390             } return !IS_INCLUDES && -1;
391           };
392         };
393
394         var arrayIncludes = {
395           // `Array.prototype.includes` method
396           // https://tc39.github.io/ecma262/#sec-array.prototype.includes
397           includes: createMethod(true),
398           // `Array.prototype.indexOf` method
399           // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
400           indexOf: createMethod(false)
401         };
402
403         var indexOf = arrayIncludes.indexOf;
404
405
406         var objectKeysInternal = function (object, names) {
407           var O = toIndexedObject(object);
408           var i = 0;
409           var result = [];
410           var key;
411           for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key);
412           // Don't enum bug & hidden keys
413           while (names.length > i) if (has(O, key = names[i++])) {
414             ~indexOf(result, key) || result.push(key);
415           }
416           return result;
417         };
418
419         // IE8- don't enum bug keys
420         var enumBugKeys = [
421           'constructor',
422           'hasOwnProperty',
423           'isPrototypeOf',
424           'propertyIsEnumerable',
425           'toLocaleString',
426           'toString',
427           'valueOf'
428         ];
429
430         var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype');
431
432         // `Object.getOwnPropertyNames` method
433         // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
434         var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
435           return objectKeysInternal(O, hiddenKeys$1);
436         };
437
438         var objectGetOwnPropertyNames = {
439                 f: f$3
440         };
441
442         var f$4 = Object.getOwnPropertySymbols;
443
444         var objectGetOwnPropertySymbols = {
445                 f: f$4
446         };
447
448         // all object keys, includes non-enumerable and symbols
449         var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
450           var keys = objectGetOwnPropertyNames.f(anObject(it));
451           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
452           return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
453         };
454
455         var copyConstructorProperties = function (target, source) {
456           var keys = ownKeys(source);
457           var defineProperty = objectDefineProperty.f;
458           var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
459           for (var i = 0; i < keys.length; i++) {
460             var key = keys[i];
461             if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
462           }
463         };
464
465         var replacement = /#|\.prototype\./;
466
467         var isForced = function (feature, detection) {
468           var value = data[normalize(feature)];
469           return value == POLYFILL ? true
470             : value == NATIVE ? false
471             : typeof detection == 'function' ? fails(detection)
472             : !!detection;
473         };
474
475         var normalize = isForced.normalize = function (string) {
476           return String(string).replace(replacement, '.').toLowerCase();
477         };
478
479         var data = isForced.data = {};
480         var NATIVE = isForced.NATIVE = 'N';
481         var POLYFILL = isForced.POLYFILL = 'P';
482
483         var isForced_1 = isForced;
484
485         var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
486
487
488
489
490
491
492         /*
493           options.target      - name of the target object
494           options.global      - target is the global object
495           options.stat        - export as static methods of target
496           options.proto       - export as prototype methods of target
497           options.real        - real prototype method for the `pure` version
498           options.forced      - export even if the native feature is available
499           options.bind        - bind methods to the target, required for the `pure` version
500           options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
501           options.unsafe      - use the simple assignment of property instead of delete + defineProperty
502           options.sham        - add a flag to not completely full polyfills
503           options.enumerable  - export as enumerable property
504           options.noTargetGet - prevent calling a getter on target
505         */
506         var _export = function (options, source) {
507           var TARGET = options.target;
508           var GLOBAL = options.global;
509           var STATIC = options.stat;
510           var FORCED, target, key, targetProperty, sourceProperty, descriptor;
511           if (GLOBAL) {
512             target = global_1;
513           } else if (STATIC) {
514             target = global_1[TARGET] || setGlobal(TARGET, {});
515           } else {
516             target = (global_1[TARGET] || {}).prototype;
517           }
518           if (target) for (key in source) {
519             sourceProperty = source[key];
520             if (options.noTargetGet) {
521               descriptor = getOwnPropertyDescriptor$1(target, key);
522               targetProperty = descriptor && descriptor.value;
523             } else targetProperty = target[key];
524             FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
525             // contained in target
526             if (!FORCED && targetProperty !== undefined) {
527               if (typeof sourceProperty === typeof targetProperty) continue;
528               copyConstructorProperties(sourceProperty, targetProperty);
529             }
530             // add a flag to not completely full polyfills
531             if (options.sham || (targetProperty && targetProperty.sham)) {
532               createNonEnumerableProperty(sourceProperty, 'sham', true);
533             }
534             // extend global
535             redefine(target, key, sourceProperty, options);
536           }
537         };
538
539         // `Date.now` method
540         // https://tc39.github.io/ecma262/#sec-date.now
541         _export({ target: 'Date', stat: true }, {
542           now: function now() {
543             return new Date().getTime();
544           }
545         });
546
547         var DatePrototype = Date.prototype;
548         var INVALID_DATE = 'Invalid Date';
549         var TO_STRING = 'toString';
550         var nativeDateToString = DatePrototype[TO_STRING];
551         var getTime = DatePrototype.getTime;
552
553         // `Date.prototype.toString` method
554         // https://tc39.github.io/ecma262/#sec-date.prototype.tostring
555         if (new Date(NaN) + '' != INVALID_DATE) {
556           redefine(DatePrototype, TO_STRING, function toString() {
557             var value = getTime.call(this);
558             // eslint-disable-next-line no-self-compare
559             return value === value ? nativeDateToString.call(this) : INVALID_DATE;
560           });
561         }
562
563         var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
564           // Chrome 38 Symbol has incorrect toString conversion
565           // eslint-disable-next-line no-undef
566           return !String(Symbol());
567         });
568
569         var useSymbolAsUid = nativeSymbol
570           // eslint-disable-next-line no-undef
571           && !Symbol.sham
572           // eslint-disable-next-line no-undef
573           && typeof Symbol.iterator == 'symbol';
574
575         // `IsArray` abstract operation
576         // https://tc39.github.io/ecma262/#sec-isarray
577         var isArray = Array.isArray || function isArray(arg) {
578           return classofRaw(arg) == 'Array';
579         };
580
581         // `ToObject` abstract operation
582         // https://tc39.github.io/ecma262/#sec-toobject
583         var toObject = function (argument) {
584           return Object(requireObjectCoercible(argument));
585         };
586
587         // `Object.keys` method
588         // https://tc39.github.io/ecma262/#sec-object.keys
589         var objectKeys = Object.keys || function keys(O) {
590           return objectKeysInternal(O, enumBugKeys);
591         };
592
593         // `Object.defineProperties` method
594         // https://tc39.github.io/ecma262/#sec-object.defineproperties
595         var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
596           anObject(O);
597           var keys = objectKeys(Properties);
598           var length = keys.length;
599           var index = 0;
600           var key;
601           while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
602           return O;
603         };
604
605         var html = getBuiltIn('document', 'documentElement');
606
607         var GT = '>';
608         var LT = '<';
609         var PROTOTYPE = 'prototype';
610         var SCRIPT = 'script';
611         var IE_PROTO = sharedKey('IE_PROTO');
612
613         var EmptyConstructor = function () { /* empty */ };
614
615         var scriptTag = function (content) {
616           return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
617         };
618
619         // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
620         var NullProtoObjectViaActiveX = function (activeXDocument) {
621           activeXDocument.write(scriptTag(''));
622           activeXDocument.close();
623           var temp = activeXDocument.parentWindow.Object;
624           activeXDocument = null; // avoid memory leak
625           return temp;
626         };
627
628         // Create object with fake `null` prototype: use iframe Object with cleared prototype
629         var NullProtoObjectViaIFrame = function () {
630           // Thrash, waste and sodomy: IE GC bug
631           var iframe = documentCreateElement('iframe');
632           var JS = 'java' + SCRIPT + ':';
633           var iframeDocument;
634           iframe.style.display = 'none';
635           html.appendChild(iframe);
636           // https://github.com/zloirock/core-js/issues/475
637           iframe.src = String(JS);
638           iframeDocument = iframe.contentWindow.document;
639           iframeDocument.open();
640           iframeDocument.write(scriptTag('document.F=Object'));
641           iframeDocument.close();
642           return iframeDocument.F;
643         };
644
645         // Check for document.domain and active x support
646         // No need to use active x approach when document.domain is not set
647         // see https://github.com/es-shims/es5-shim/issues/150
648         // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
649         // avoid IE GC bug
650         var activeXDocument;
651         var NullProtoObject = function () {
652           try {
653             /* global ActiveXObject */
654             activeXDocument = document.domain && new ActiveXObject('htmlfile');
655           } catch (error) { /* ignore */ }
656           NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
657           var length = enumBugKeys.length;
658           while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];
659           return NullProtoObject();
660         };
661
662         hiddenKeys[IE_PROTO] = true;
663
664         // `Object.create` method
665         // https://tc39.github.io/ecma262/#sec-object.create
666         var objectCreate = Object.create || function create(O, Properties) {
667           var result;
668           if (O !== null) {
669             EmptyConstructor[PROTOTYPE] = anObject(O);
670             result = new EmptyConstructor();
671             EmptyConstructor[PROTOTYPE] = null;
672             // add "__proto__" for Object.getPrototypeOf polyfill
673             result[IE_PROTO] = O;
674           } else result = NullProtoObject();
675           return Properties === undefined ? result : objectDefineProperties(result, Properties);
676         };
677
678         var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f;
679
680         var toString$1 = {}.toString;
681
682         var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames
683           ? Object.getOwnPropertyNames(window) : [];
684
685         var getWindowNames = function (it) {
686           try {
687             return nativeGetOwnPropertyNames(it);
688           } catch (error) {
689             return windowNames.slice();
690           }
691         };
692
693         // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
694         var f$5 = function getOwnPropertyNames(it) {
695           return windowNames && toString$1.call(it) == '[object Window]'
696             ? getWindowNames(it)
697             : nativeGetOwnPropertyNames(toIndexedObject(it));
698         };
699
700         var objectGetOwnPropertyNamesExternal = {
701                 f: f$5
702         };
703
704         var WellKnownSymbolsStore = shared('wks');
705         var Symbol$1 = global_1.Symbol;
706         var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;
707
708         var wellKnownSymbol = function (name) {
709           if (!has(WellKnownSymbolsStore, name)) {
710             if (nativeSymbol && has(Symbol$1, name)) WellKnownSymbolsStore[name] = Symbol$1[name];
711             else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name);
712           } return WellKnownSymbolsStore[name];
713         };
714
715         var f$6 = wellKnownSymbol;
716
717         var wellKnownSymbolWrapped = {
718                 f: f$6
719         };
720
721         var defineProperty = objectDefineProperty.f;
722
723         var defineWellKnownSymbol = function (NAME) {
724           var Symbol = path.Symbol || (path.Symbol = {});
725           if (!has(Symbol, NAME)) defineProperty(Symbol, NAME, {
726             value: wellKnownSymbolWrapped.f(NAME)
727           });
728         };
729
730         var defineProperty$1 = objectDefineProperty.f;
731
732
733
734         var TO_STRING_TAG = wellKnownSymbol('toStringTag');
735
736         var setToStringTag = function (it, TAG, STATIC) {
737           if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG)) {
738             defineProperty$1(it, TO_STRING_TAG, { configurable: true, value: TAG });
739           }
740         };
741
742         var aFunction$1 = function (it) {
743           if (typeof it != 'function') {
744             throw TypeError(String(it) + ' is not a function');
745           } return it;
746         };
747
748         // optional / simple context binding
749         var functionBindContext = function (fn, that, length) {
750           aFunction$1(fn);
751           if (that === undefined) return fn;
752           switch (length) {
753             case 0: return function () {
754               return fn.call(that);
755             };
756             case 1: return function (a) {
757               return fn.call(that, a);
758             };
759             case 2: return function (a, b) {
760               return fn.call(that, a, b);
761             };
762             case 3: return function (a, b, c) {
763               return fn.call(that, a, b, c);
764             };
765           }
766           return function (/* ...args */) {
767             return fn.apply(that, arguments);
768           };
769         };
770
771         var SPECIES = wellKnownSymbol('species');
772
773         // `ArraySpeciesCreate` abstract operation
774         // https://tc39.github.io/ecma262/#sec-arrayspeciescreate
775         var arraySpeciesCreate = function (originalArray, length) {
776           var C;
777           if (isArray(originalArray)) {
778             C = originalArray.constructor;
779             // cross-realm fallback
780             if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;
781             else if (isObject(C)) {
782               C = C[SPECIES];
783               if (C === null) C = undefined;
784             }
785           } return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
786         };
787
788         var push = [].push;
789
790         // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex }` methods implementation
791         var createMethod$1 = function (TYPE) {
792           var IS_MAP = TYPE == 1;
793           var IS_FILTER = TYPE == 2;
794           var IS_SOME = TYPE == 3;
795           var IS_EVERY = TYPE == 4;
796           var IS_FIND_INDEX = TYPE == 6;
797           var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
798           return function ($this, callbackfn, that, specificCreate) {
799             var O = toObject($this);
800             var self = indexedObject(O);
801             var boundFunction = functionBindContext(callbackfn, that, 3);
802             var length = toLength(self.length);
803             var index = 0;
804             var create = specificCreate || arraySpeciesCreate;
805             var target = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;
806             var value, result;
807             for (;length > index; index++) if (NO_HOLES || index in self) {
808               value = self[index];
809               result = boundFunction(value, index, O);
810               if (TYPE) {
811                 if (IS_MAP) target[index] = result; // map
812                 else if (result) switch (TYPE) {
813                   case 3: return true;              // some
814                   case 5: return value;             // find
815                   case 6: return index;             // findIndex
816                   case 2: push.call(target, value); // filter
817                 } else if (IS_EVERY) return false;  // every
818               }
819             }
820             return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
821           };
822         };
823
824         var arrayIteration = {
825           // `Array.prototype.forEach` method
826           // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
827           forEach: createMethod$1(0),
828           // `Array.prototype.map` method
829           // https://tc39.github.io/ecma262/#sec-array.prototype.map
830           map: createMethod$1(1),
831           // `Array.prototype.filter` method
832           // https://tc39.github.io/ecma262/#sec-array.prototype.filter
833           filter: createMethod$1(2),
834           // `Array.prototype.some` method
835           // https://tc39.github.io/ecma262/#sec-array.prototype.some
836           some: createMethod$1(3),
837           // `Array.prototype.every` method
838           // https://tc39.github.io/ecma262/#sec-array.prototype.every
839           every: createMethod$1(4),
840           // `Array.prototype.find` method
841           // https://tc39.github.io/ecma262/#sec-array.prototype.find
842           find: createMethod$1(5),
843           // `Array.prototype.findIndex` method
844           // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
845           findIndex: createMethod$1(6)
846         };
847
848         var $forEach = arrayIteration.forEach;
849
850         var HIDDEN = sharedKey('hidden');
851         var SYMBOL = 'Symbol';
852         var PROTOTYPE$1 = 'prototype';
853         var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
854         var setInternalState = internalState.set;
855         var getInternalState = internalState.getterFor(SYMBOL);
856         var ObjectPrototype = Object[PROTOTYPE$1];
857         var $Symbol = global_1.Symbol;
858         var $stringify = getBuiltIn('JSON', 'stringify');
859         var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
860         var nativeDefineProperty$1 = objectDefineProperty.f;
861         var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;
862         var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f;
863         var AllSymbols = shared('symbols');
864         var ObjectPrototypeSymbols = shared('op-symbols');
865         var StringToSymbolRegistry = shared('string-to-symbol-registry');
866         var SymbolToStringRegistry = shared('symbol-to-string-registry');
867         var WellKnownSymbolsStore$1 = shared('wks');
868         var QObject = global_1.QObject;
869         // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
870         var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild;
871
872         // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
873         var setSymbolDescriptor = descriptors && fails(function () {
874           return objectCreate(nativeDefineProperty$1({}, 'a', {
875             get: function () { return nativeDefineProperty$1(this, 'a', { value: 7 }).a; }
876           })).a != 7;
877         }) ? function (O, P, Attributes) {
878           var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P);
879           if (ObjectPrototypeDescriptor) delete ObjectPrototype[P];
880           nativeDefineProperty$1(O, P, Attributes);
881           if (ObjectPrototypeDescriptor && O !== ObjectPrototype) {
882             nativeDefineProperty$1(ObjectPrototype, P, ObjectPrototypeDescriptor);
883           }
884         } : nativeDefineProperty$1;
885
886         var wrap = function (tag, description) {
887           var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]);
888           setInternalState(symbol, {
889             type: SYMBOL,
890             tag: tag,
891             description: description
892           });
893           if (!descriptors) symbol.description = description;
894           return symbol;
895         };
896
897         var isSymbol = useSymbolAsUid ? function (it) {
898           return typeof it == 'symbol';
899         } : function (it) {
900           return Object(it) instanceof $Symbol;
901         };
902
903         var $defineProperty = function defineProperty(O, P, Attributes) {
904           if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
905           anObject(O);
906           var key = toPrimitive(P, true);
907           anObject(Attributes);
908           if (has(AllSymbols, key)) {
909             if (!Attributes.enumerable) {
910               if (!has(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor(1, {}));
911               O[HIDDEN][key] = true;
912             } else {
913               if (has(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
914               Attributes = objectCreate(Attributes, { enumerable: createPropertyDescriptor(0, false) });
915             } return setSymbolDescriptor(O, key, Attributes);
916           } return nativeDefineProperty$1(O, key, Attributes);
917         };
918
919         var $defineProperties = function defineProperties(O, Properties) {
920           anObject(O);
921           var properties = toIndexedObject(Properties);
922           var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));
923           $forEach(keys, function (key) {
924             if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
925           });
926           return O;
927         };
928
929         var $create = function create(O, Properties) {
930           return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);
931         };
932
933         var $propertyIsEnumerable = function propertyIsEnumerable(V) {
934           var P = toPrimitive(V, true);
935           var enumerable = nativePropertyIsEnumerable$1.call(this, P);
936           if (this === ObjectPrototype && has(AllSymbols, P) && !has(ObjectPrototypeSymbols, P)) return false;
937           return enumerable || !has(this, P) || !has(AllSymbols, P) || has(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
938         };
939
940         var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
941           var it = toIndexedObject(O);
942           var key = toPrimitive(P, true);
943           if (it === ObjectPrototype && has(AllSymbols, key) && !has(ObjectPrototypeSymbols, key)) return;
944           var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
945           if (descriptor && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) {
946             descriptor.enumerable = true;
947           }
948           return descriptor;
949         };
950
951         var $getOwnPropertyNames = function getOwnPropertyNames(O) {
952           var names = nativeGetOwnPropertyNames$1(toIndexedObject(O));
953           var result = [];
954           $forEach(names, function (key) {
955             if (!has(AllSymbols, key) && !has(hiddenKeys, key)) result.push(key);
956           });
957           return result;
958         };
959
960         var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
961           var IS_OBJECT_PROTOTYPE = O === ObjectPrototype;
962           var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
963           var result = [];
964           $forEach(names, function (key) {
965             if (has(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype, key))) {
966               result.push(AllSymbols[key]);
967             }
968           });
969           return result;
970         };
971
972         // `Symbol` constructor
973         // https://tc39.github.io/ecma262/#sec-symbol-constructor
974         if (!nativeSymbol) {
975           $Symbol = function Symbol() {
976             if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
977             var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
978             var tag = uid(description);
979             var setter = function (value) {
980               if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value);
981               if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
982               setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
983             };
984             if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, { configurable: true, set: setter });
985             return wrap(tag, description);
986           };
987
988           redefine($Symbol[PROTOTYPE$1], 'toString', function toString() {
989             return getInternalState(this).tag;
990           });
991
992           redefine($Symbol, 'withoutSetter', function (description) {
993             return wrap(uid(description), description);
994           });
995
996           objectPropertyIsEnumerable.f = $propertyIsEnumerable;
997           objectDefineProperty.f = $defineProperty;
998           objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;
999           objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;
1000           objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;
1001
1002           wellKnownSymbolWrapped.f = function (name) {
1003             return wrap(wellKnownSymbol(name), name);
1004           };
1005
1006           if (descriptors) {
1007             // https://github.com/tc39/proposal-Symbol-description
1008             nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', {
1009               configurable: true,
1010               get: function description() {
1011                 return getInternalState(this).description;
1012               }
1013             });
1014             {
1015               redefine(ObjectPrototype, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true });
1016             }
1017           }
1018         }
1019
1020         _export({ global: true, wrap: true, forced: !nativeSymbol, sham: !nativeSymbol }, {
1021           Symbol: $Symbol
1022         });
1023
1024         $forEach(objectKeys(WellKnownSymbolsStore$1), function (name) {
1025           defineWellKnownSymbol(name);
1026         });
1027
1028         _export({ target: SYMBOL, stat: true, forced: !nativeSymbol }, {
1029           // `Symbol.for` method
1030           // https://tc39.github.io/ecma262/#sec-symbol.for
1031           'for': function (key) {
1032             var string = String(key);
1033             if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
1034             var symbol = $Symbol(string);
1035             StringToSymbolRegistry[string] = symbol;
1036             SymbolToStringRegistry[symbol] = string;
1037             return symbol;
1038           },
1039           // `Symbol.keyFor` method
1040           // https://tc39.github.io/ecma262/#sec-symbol.keyfor
1041           keyFor: function keyFor(sym) {
1042             if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol');
1043             if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
1044           },
1045           useSetter: function () { USE_SETTER = true; },
1046           useSimple: function () { USE_SETTER = false; }
1047         });
1048
1049         _export({ target: 'Object', stat: true, forced: !nativeSymbol, sham: !descriptors }, {
1050           // `Object.create` method
1051           // https://tc39.github.io/ecma262/#sec-object.create
1052           create: $create,
1053           // `Object.defineProperty` method
1054           // https://tc39.github.io/ecma262/#sec-object.defineproperty
1055           defineProperty: $defineProperty,
1056           // `Object.defineProperties` method
1057           // https://tc39.github.io/ecma262/#sec-object.defineproperties
1058           defineProperties: $defineProperties,
1059           // `Object.getOwnPropertyDescriptor` method
1060           // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors
1061           getOwnPropertyDescriptor: $getOwnPropertyDescriptor
1062         });
1063
1064         _export({ target: 'Object', stat: true, forced: !nativeSymbol }, {
1065           // `Object.getOwnPropertyNames` method
1066           // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
1067           getOwnPropertyNames: $getOwnPropertyNames,
1068           // `Object.getOwnPropertySymbols` method
1069           // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols
1070           getOwnPropertySymbols: $getOwnPropertySymbols
1071         });
1072
1073         // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
1074         // https://bugs.chromium.org/p/v8/issues/detail?id=3443
1075         _export({ target: 'Object', stat: true, forced: fails(function () { objectGetOwnPropertySymbols.f(1); }) }, {
1076           getOwnPropertySymbols: function getOwnPropertySymbols(it) {
1077             return objectGetOwnPropertySymbols.f(toObject(it));
1078           }
1079         });
1080
1081         // `JSON.stringify` method behavior with symbols
1082         // https://tc39.github.io/ecma262/#sec-json.stringify
1083         if ($stringify) {
1084           var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () {
1085             var symbol = $Symbol();
1086             // MS Edge converts symbol values to JSON as {}
1087             return $stringify([symbol]) != '[null]'
1088               // WebKit converts symbol values to JSON as null
1089               || $stringify({ a: symbol }) != '{}'
1090               // V8 throws on boxed symbols
1091               || $stringify(Object(symbol)) != '{}';
1092           });
1093
1094           _export({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, {
1095             // eslint-disable-next-line no-unused-vars
1096             stringify: function stringify(it, replacer, space) {
1097               var args = [it];
1098               var index = 1;
1099               var $replacer;
1100               while (arguments.length > index) args.push(arguments[index++]);
1101               $replacer = replacer;
1102               if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
1103               if (!isArray(replacer)) replacer = function (key, value) {
1104                 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
1105                 if (!isSymbol(value)) return value;
1106               };
1107               args[1] = replacer;
1108               return $stringify.apply(null, args);
1109             }
1110           });
1111         }
1112
1113         // `Symbol.prototype[@@toPrimitive]` method
1114         // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive
1115         if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
1116           createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
1117         }
1118         // `Symbol.prototype[@@toStringTag]` property
1119         // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag
1120         setToStringTag($Symbol, SYMBOL);
1121
1122         hiddenKeys[HIDDEN] = true;
1123
1124         var defineProperty$2 = objectDefineProperty.f;
1125
1126
1127         var NativeSymbol = global_1.Symbol;
1128
1129         if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) ||
1130           // Safari 12 bug
1131           NativeSymbol().description !== undefined
1132         )) {
1133           var EmptyStringDescriptionStore = {};
1134           // wrap Symbol constructor for correct work with undefined description
1135           var SymbolWrapper = function Symbol() {
1136             var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
1137             var result = this instanceof SymbolWrapper
1138               ? new NativeSymbol(description)
1139               // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
1140               : description === undefined ? NativeSymbol() : NativeSymbol(description);
1141             if (description === '') EmptyStringDescriptionStore[result] = true;
1142             return result;
1143           };
1144           copyConstructorProperties(SymbolWrapper, NativeSymbol);
1145           var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
1146           symbolPrototype.constructor = SymbolWrapper;
1147
1148           var symbolToString = symbolPrototype.toString;
1149           var native = String(NativeSymbol('test')) == 'Symbol(test)';
1150           var regexp = /^Symbol\((.*)\)[^)]+$/;
1151           defineProperty$2(symbolPrototype, 'description', {
1152             configurable: true,
1153             get: function description() {
1154               var symbol = isObject(this) ? this.valueOf() : this;
1155               var string = symbolToString.call(symbol);
1156               if (has(EmptyStringDescriptionStore, symbol)) return '';
1157               var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
1158               return desc === '' ? undefined : desc;
1159             }
1160           });
1161
1162           _export({ global: true, forced: true }, {
1163             Symbol: SymbolWrapper
1164           });
1165         }
1166
1167         // `Symbol.iterator` well-known symbol
1168         // https://tc39.github.io/ecma262/#sec-symbol.iterator
1169         defineWellKnownSymbol('iterator');
1170
1171         var arrayMethodIsStrict = function (METHOD_NAME, argument) {
1172           var method = [][METHOD_NAME];
1173           return !!method && fails(function () {
1174             // eslint-disable-next-line no-useless-call,no-throw-literal
1175             method.call(null, argument || function () { throw 1; }, 1);
1176           });
1177         };
1178
1179         var defineProperty$3 = Object.defineProperty;
1180         var cache = {};
1181
1182         var thrower = function (it) { throw it; };
1183
1184         var arrayMethodUsesToLength = function (METHOD_NAME, options) {
1185           if (has(cache, METHOD_NAME)) return cache[METHOD_NAME];
1186           if (!options) options = {};
1187           var method = [][METHOD_NAME];
1188           var ACCESSORS = has(options, 'ACCESSORS') ? options.ACCESSORS : false;
1189           var argument0 = has(options, 0) ? options[0] : thrower;
1190           var argument1 = has(options, 1) ? options[1] : undefined;
1191
1192           return cache[METHOD_NAME] = !!method && !fails(function () {
1193             if (ACCESSORS && !descriptors) return true;
1194             var O = { length: -1 };
1195
1196             if (ACCESSORS) defineProperty$3(O, 1, { enumerable: true, get: thrower });
1197             else O[1] = 1;
1198
1199             method.call(O, argument0, argument1);
1200           });
1201         };
1202
1203         var $forEach$1 = arrayIteration.forEach;
1204
1205
1206
1207         var STRICT_METHOD = arrayMethodIsStrict('forEach');
1208         var USES_TO_LENGTH = arrayMethodUsesToLength('forEach');
1209
1210         // `Array.prototype.forEach` method implementation
1211         // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
1212         var arrayForEach = (!STRICT_METHOD || !USES_TO_LENGTH) ? function forEach(callbackfn /* , thisArg */) {
1213           return $forEach$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
1214         } : [].forEach;
1215
1216         // `Array.prototype.forEach` method
1217         // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
1218         _export({ target: 'Array', proto: true, forced: [].forEach != arrayForEach }, {
1219           forEach: arrayForEach
1220         });
1221
1222         var $indexOf = arrayIncludes.indexOf;
1223
1224
1225
1226         var nativeIndexOf = [].indexOf;
1227
1228         var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
1229         var STRICT_METHOD$1 = arrayMethodIsStrict('indexOf');
1230         var USES_TO_LENGTH$1 = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });
1231
1232         // `Array.prototype.indexOf` method
1233         // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
1234         _export({ target: 'Array', proto: true, forced: NEGATIVE_ZERO || !STRICT_METHOD$1 || !USES_TO_LENGTH$1 }, {
1235           indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
1236             return NEGATIVE_ZERO
1237               // convert -0 to +0
1238               ? nativeIndexOf.apply(this, arguments) || 0
1239               : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
1240           }
1241         });
1242
1243         // `Array.isArray` method
1244         // https://tc39.github.io/ecma262/#sec-array.isarray
1245         _export({ target: 'Array', stat: true }, {
1246           isArray: isArray
1247         });
1248
1249         var UNSCOPABLES = wellKnownSymbol('unscopables');
1250         var ArrayPrototype = Array.prototype;
1251
1252         // Array.prototype[@@unscopables]
1253         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
1254         if (ArrayPrototype[UNSCOPABLES] == undefined) {
1255           objectDefineProperty.f(ArrayPrototype, UNSCOPABLES, {
1256             configurable: true,
1257             value: objectCreate(null)
1258           });
1259         }
1260
1261         // add a key to Array.prototype[@@unscopables]
1262         var addToUnscopables = function (key) {
1263           ArrayPrototype[UNSCOPABLES][key] = true;
1264         };
1265
1266         var iterators = {};
1267
1268         var correctPrototypeGetter = !fails(function () {
1269           function F() { /* empty */ }
1270           F.prototype.constructor = null;
1271           return Object.getPrototypeOf(new F()) !== F.prototype;
1272         });
1273
1274         var IE_PROTO$1 = sharedKey('IE_PROTO');
1275         var ObjectPrototype$1 = Object.prototype;
1276
1277         // `Object.getPrototypeOf` method
1278         // https://tc39.github.io/ecma262/#sec-object.getprototypeof
1279         var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
1280           O = toObject(O);
1281           if (has(O, IE_PROTO$1)) return O[IE_PROTO$1];
1282           if (typeof O.constructor == 'function' && O instanceof O.constructor) {
1283             return O.constructor.prototype;
1284           } return O instanceof Object ? ObjectPrototype$1 : null;
1285         };
1286
1287         var ITERATOR = wellKnownSymbol('iterator');
1288         var BUGGY_SAFARI_ITERATORS = false;
1289
1290         var returnThis = function () { return this; };
1291
1292         // `%IteratorPrototype%` object
1293         // https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object
1294         var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;
1295
1296         if ([].keys) {
1297           arrayIterator = [].keys();
1298           // Safari 8 has buggy iterators w/o `next`
1299           if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;
1300           else {
1301             PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
1302             if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
1303           }
1304         }
1305
1306         if (IteratorPrototype == undefined) IteratorPrototype = {};
1307
1308         // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
1309         if ( !has(IteratorPrototype, ITERATOR)) {
1310           createNonEnumerableProperty(IteratorPrototype, ITERATOR, returnThis);
1311         }
1312
1313         var iteratorsCore = {
1314           IteratorPrototype: IteratorPrototype,
1315           BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
1316         };
1317
1318         var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1319
1320
1321
1322
1323
1324         var returnThis$1 = function () { return this; };
1325
1326         var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
1327           var TO_STRING_TAG = NAME + ' Iterator';
1328           IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) });
1329           setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
1330           iterators[TO_STRING_TAG] = returnThis$1;
1331           return IteratorConstructor;
1332         };
1333
1334         var aPossiblePrototype = function (it) {
1335           if (!isObject(it) && it !== null) {
1336             throw TypeError("Can't set " + String(it) + ' as a prototype');
1337           } return it;
1338         };
1339
1340         // `Object.setPrototypeOf` method
1341         // https://tc39.github.io/ecma262/#sec-object.setprototypeof
1342         // Works with __proto__ only. Old v8 can't work with null proto objects.
1343         /* eslint-disable no-proto */
1344         var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1345           var CORRECT_SETTER = false;
1346           var test = {};
1347           var setter;
1348           try {
1349             setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1350             setter.call(test, []);
1351             CORRECT_SETTER = test instanceof Array;
1352           } catch (error) { /* empty */ }
1353           return function setPrototypeOf(O, proto) {
1354             anObject(O);
1355             aPossiblePrototype(proto);
1356             if (CORRECT_SETTER) setter.call(O, proto);
1357             else O.__proto__ = proto;
1358             return O;
1359           };
1360         }() : undefined);
1361
1362         var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
1363         var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
1364         var ITERATOR$1 = wellKnownSymbol('iterator');
1365         var KEYS = 'keys';
1366         var VALUES = 'values';
1367         var ENTRIES = 'entries';
1368
1369         var returnThis$2 = function () { return this; };
1370
1371         var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1372           createIteratorConstructor(IteratorConstructor, NAME, next);
1373
1374           var getIterationMethod = function (KIND) {
1375             if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1376             if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];
1377             switch (KIND) {
1378               case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
1379               case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
1380               case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
1381             } return function () { return new IteratorConstructor(this); };
1382           };
1383
1384           var TO_STRING_TAG = NAME + ' Iterator';
1385           var INCORRECT_VALUES_NAME = false;
1386           var IterablePrototype = Iterable.prototype;
1387           var nativeIterator = IterablePrototype[ITERATOR$1]
1388             || IterablePrototype['@@iterator']
1389             || DEFAULT && IterablePrototype[DEFAULT];
1390           var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
1391           var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1392           var CurrentIteratorPrototype, methods, KEY;
1393
1394           // fix native
1395           if (anyNativeIterator) {
1396             CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
1397             if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) {
1398               if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) {
1399                 if (objectSetPrototypeOf) {
1400                   objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2);
1401                 } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') {
1402                   createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$1, returnThis$2);
1403                 }
1404               }
1405               // Set @@toStringTag to native iterators
1406               setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
1407             }
1408           }
1409
1410           // fix Array#{values, @@iterator}.name in V8 / FF
1411           if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1412             INCORRECT_VALUES_NAME = true;
1413             defaultIterator = function values() { return nativeIterator.call(this); };
1414           }
1415
1416           // define iterator
1417           if ( IterablePrototype[ITERATOR$1] !== defaultIterator) {
1418             createNonEnumerableProperty(IterablePrototype, ITERATOR$1, defaultIterator);
1419           }
1420           iterators[NAME] = defaultIterator;
1421
1422           // export additional methods
1423           if (DEFAULT) {
1424             methods = {
1425               values: getIterationMethod(VALUES),
1426               keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1427               entries: getIterationMethod(ENTRIES)
1428             };
1429             if (FORCED) for (KEY in methods) {
1430               if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1431                 redefine(IterablePrototype, KEY, methods[KEY]);
1432               }
1433             } else _export({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME }, methods);
1434           }
1435
1436           return methods;
1437         };
1438
1439         var ARRAY_ITERATOR = 'Array Iterator';
1440         var setInternalState$1 = internalState.set;
1441         var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR);
1442
1443         // `Array.prototype.entries` method
1444         // https://tc39.github.io/ecma262/#sec-array.prototype.entries
1445         // `Array.prototype.keys` method
1446         // https://tc39.github.io/ecma262/#sec-array.prototype.keys
1447         // `Array.prototype.values` method
1448         // https://tc39.github.io/ecma262/#sec-array.prototype.values
1449         // `Array.prototype[@@iterator]` method
1450         // https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator
1451         // `CreateArrayIterator` internal method
1452         // https://tc39.github.io/ecma262/#sec-createarrayiterator
1453         var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
1454           setInternalState$1(this, {
1455             type: ARRAY_ITERATOR,
1456             target: toIndexedObject(iterated), // target
1457             index: 0,                          // next index
1458             kind: kind                         // kind
1459           });
1460         // `%ArrayIteratorPrototype%.next` method
1461         // https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next
1462         }, function () {
1463           var state = getInternalState$1(this);
1464           var target = state.target;
1465           var kind = state.kind;
1466           var index = state.index++;
1467           if (!target || index >= target.length) {
1468             state.target = undefined;
1469             return { value: undefined, done: true };
1470           }
1471           if (kind == 'keys') return { value: index, done: false };
1472           if (kind == 'values') return { value: target[index], done: false };
1473           return { value: [index, target[index]], done: false };
1474         }, 'values');
1475
1476         // argumentsList[@@iterator] is %ArrayProto_values%
1477         // https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject
1478         // https://tc39.github.io/ecma262/#sec-createmappedargumentsobject
1479         iterators.Arguments = iterators.Array;
1480
1481         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
1482         addToUnscopables('keys');
1483         addToUnscopables('values');
1484         addToUnscopables('entries');
1485
1486         var nativeJoin = [].join;
1487
1488         var ES3_STRINGS = indexedObject != Object;
1489         var STRICT_METHOD$2 = arrayMethodIsStrict('join', ',');
1490
1491         // `Array.prototype.join` method
1492         // https://tc39.github.io/ecma262/#sec-array.prototype.join
1493         _export({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$2 }, {
1494           join: function join(separator) {
1495             return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
1496           }
1497         });
1498
1499         var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';
1500
1501         var process$1 = global_1.process;
1502         var versions = process$1 && process$1.versions;
1503         var v8 = versions && versions.v8;
1504         var match, version;
1505
1506         if (v8) {
1507           match = v8.split('.');
1508           version = match[0] + match[1];
1509         } else if (engineUserAgent) {
1510           match = engineUserAgent.match(/Edge\/(\d+)/);
1511           if (!match || match[1] >= 74) {
1512             match = engineUserAgent.match(/Chrome\/(\d+)/);
1513             if (match) version = match[1];
1514           }
1515         }
1516
1517         var engineV8Version = version && +version;
1518
1519         var SPECIES$1 = wellKnownSymbol('species');
1520
1521         var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
1522           // We can't use this feature detection in V8 since it causes
1523           // deoptimization and serious performance degradation
1524           // https://github.com/zloirock/core-js/issues/677
1525           return engineV8Version >= 51 || !fails(function () {
1526             var array = [];
1527             var constructor = array.constructor = {};
1528             constructor[SPECIES$1] = function () {
1529               return { foo: 1 };
1530             };
1531             return array[METHOD_NAME](Boolean).foo !== 1;
1532           });
1533         };
1534
1535         var $map = arrayIteration.map;
1536
1537
1538
1539         var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('map');
1540         // FF49- issue
1541         var USES_TO_LENGTH$2 = arrayMethodUsesToLength('map');
1542
1543         // `Array.prototype.map` method
1544         // https://tc39.github.io/ecma262/#sec-array.prototype.map
1545         // with adding support of @@species
1546         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT || !USES_TO_LENGTH$2 }, {
1547           map: function map(callbackfn /* , thisArg */) {
1548             return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
1549           }
1550         });
1551
1552         var createProperty = function (object, key, value) {
1553           var propertyKey = toPrimitive(key);
1554           if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));
1555           else object[propertyKey] = value;
1556         };
1557
1558         var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('slice');
1559         var USES_TO_LENGTH$3 = arrayMethodUsesToLength('slice', { ACCESSORS: true, 0: 0, 1: 2 });
1560
1561         var SPECIES$2 = wellKnownSymbol('species');
1562         var nativeSlice = [].slice;
1563         var max$1 = Math.max;
1564
1565         // `Array.prototype.slice` method
1566         // https://tc39.github.io/ecma262/#sec-array.prototype.slice
1567         // fallback for not array-like ES3 strings and DOM objects
1568         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 || !USES_TO_LENGTH$3 }, {
1569           slice: function slice(start, end) {
1570             var O = toIndexedObject(this);
1571             var length = toLength(O.length);
1572             var k = toAbsoluteIndex(start, length);
1573             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
1574             // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
1575             var Constructor, result, n;
1576             if (isArray(O)) {
1577               Constructor = O.constructor;
1578               // cross-realm fallback
1579               if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
1580                 Constructor = undefined;
1581               } else if (isObject(Constructor)) {
1582                 Constructor = Constructor[SPECIES$2];
1583                 if (Constructor === null) Constructor = undefined;
1584               }
1585               if (Constructor === Array || Constructor === undefined) {
1586                 return nativeSlice.call(O, k, fin);
1587               }
1588             }
1589             result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));
1590             for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
1591             result.length = n;
1592             return result;
1593           }
1594         });
1595
1596         var arrayBufferNative = typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined';
1597
1598         var redefineAll = function (target, src, options) {
1599           for (var key in src) redefine(target, key, src[key], options);
1600           return target;
1601         };
1602
1603         var anInstance = function (it, Constructor, name) {
1604           if (!(it instanceof Constructor)) {
1605             throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
1606           } return it;
1607         };
1608
1609         // `ToIndex` abstract operation
1610         // https://tc39.github.io/ecma262/#sec-toindex
1611         var toIndex = function (it) {
1612           if (it === undefined) return 0;
1613           var number = toInteger(it);
1614           var length = toLength(number);
1615           if (number !== length) throw RangeError('Wrong length or index');
1616           return length;
1617         };
1618
1619         // IEEE754 conversions based on https://github.com/feross/ieee754
1620         // eslint-disable-next-line no-shadow-restricted-names
1621         var Infinity$1 = 1 / 0;
1622         var abs = Math.abs;
1623         var pow = Math.pow;
1624         var floor$1 = Math.floor;
1625         var log = Math.log;
1626         var LN2 = Math.LN2;
1627
1628         var pack = function (number, mantissaLength, bytes) {
1629           var buffer = new Array(bytes);
1630           var exponentLength = bytes * 8 - mantissaLength - 1;
1631           var eMax = (1 << exponentLength) - 1;
1632           var eBias = eMax >> 1;
1633           var rt = mantissaLength === 23 ? pow(2, -24) - pow(2, -77) : 0;
1634           var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
1635           var index = 0;
1636           var exponent, mantissa, c;
1637           number = abs(number);
1638           // eslint-disable-next-line no-self-compare
1639           if (number != number || number === Infinity$1) {
1640             // eslint-disable-next-line no-self-compare
1641             mantissa = number != number ? 1 : 0;
1642             exponent = eMax;
1643           } else {
1644             exponent = floor$1(log(number) / LN2);
1645             if (number * (c = pow(2, -exponent)) < 1) {
1646               exponent--;
1647               c *= 2;
1648             }
1649             if (exponent + eBias >= 1) {
1650               number += rt / c;
1651             } else {
1652               number += rt * pow(2, 1 - eBias);
1653             }
1654             if (number * c >= 2) {
1655               exponent++;
1656               c /= 2;
1657             }
1658             if (exponent + eBias >= eMax) {
1659               mantissa = 0;
1660               exponent = eMax;
1661             } else if (exponent + eBias >= 1) {
1662               mantissa = (number * c - 1) * pow(2, mantissaLength);
1663               exponent = exponent + eBias;
1664             } else {
1665               mantissa = number * pow(2, eBias - 1) * pow(2, mantissaLength);
1666               exponent = 0;
1667             }
1668           }
1669           for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);
1670           exponent = exponent << mantissaLength | mantissa;
1671           exponentLength += mantissaLength;
1672           for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);
1673           buffer[--index] |= sign * 128;
1674           return buffer;
1675         };
1676
1677         var unpack = function (buffer, mantissaLength) {
1678           var bytes = buffer.length;
1679           var exponentLength = bytes * 8 - mantissaLength - 1;
1680           var eMax = (1 << exponentLength) - 1;
1681           var eBias = eMax >> 1;
1682           var nBits = exponentLength - 7;
1683           var index = bytes - 1;
1684           var sign = buffer[index--];
1685           var exponent = sign & 127;
1686           var mantissa;
1687           sign >>= 7;
1688           for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);
1689           mantissa = exponent & (1 << -nBits) - 1;
1690           exponent >>= -nBits;
1691           nBits += mantissaLength;
1692           for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);
1693           if (exponent === 0) {
1694             exponent = 1 - eBias;
1695           } else if (exponent === eMax) {
1696             return mantissa ? NaN : sign ? -Infinity$1 : Infinity$1;
1697           } else {
1698             mantissa = mantissa + pow(2, mantissaLength);
1699             exponent = exponent - eBias;
1700           } return (sign ? -1 : 1) * mantissa * pow(2, exponent - mantissaLength);
1701         };
1702
1703         var ieee754 = {
1704           pack: pack,
1705           unpack: unpack
1706         };
1707
1708         // `Array.prototype.fill` method implementation
1709         // https://tc39.github.io/ecma262/#sec-array.prototype.fill
1710         var arrayFill = function fill(value /* , start = 0, end = @length */) {
1711           var O = toObject(this);
1712           var length = toLength(O.length);
1713           var argumentsLength = arguments.length;
1714           var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
1715           var end = argumentsLength > 2 ? arguments[2] : undefined;
1716           var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
1717           while (endPos > index) O[index++] = value;
1718           return O;
1719         };
1720
1721         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
1722         var defineProperty$4 = objectDefineProperty.f;
1723
1724
1725
1726
1727         var getInternalState$2 = internalState.get;
1728         var setInternalState$2 = internalState.set;
1729         var ARRAY_BUFFER = 'ArrayBuffer';
1730         var DATA_VIEW = 'DataView';
1731         var PROTOTYPE$2 = 'prototype';
1732         var WRONG_LENGTH = 'Wrong length';
1733         var WRONG_INDEX = 'Wrong index';
1734         var NativeArrayBuffer = global_1[ARRAY_BUFFER];
1735         var $ArrayBuffer = NativeArrayBuffer;
1736         var $DataView = global_1[DATA_VIEW];
1737         var $DataViewPrototype = $DataView && $DataView[PROTOTYPE$2];
1738         var ObjectPrototype$2 = Object.prototype;
1739         var RangeError$1 = global_1.RangeError;
1740
1741         var packIEEE754 = ieee754.pack;
1742         var unpackIEEE754 = ieee754.unpack;
1743
1744         var packInt8 = function (number) {
1745           return [number & 0xFF];
1746         };
1747
1748         var packInt16 = function (number) {
1749           return [number & 0xFF, number >> 8 & 0xFF];
1750         };
1751
1752         var packInt32 = function (number) {
1753           return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
1754         };
1755
1756         var unpackInt32 = function (buffer) {
1757           return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
1758         };
1759
1760         var packFloat32 = function (number) {
1761           return packIEEE754(number, 23, 4);
1762         };
1763
1764         var packFloat64 = function (number) {
1765           return packIEEE754(number, 52, 8);
1766         };
1767
1768         var addGetter = function (Constructor, key) {
1769           defineProperty$4(Constructor[PROTOTYPE$2], key, { get: function () { return getInternalState$2(this)[key]; } });
1770         };
1771
1772         var get$1 = function (view, count, index, isLittleEndian) {
1773           var intIndex = toIndex(index);
1774           var store = getInternalState$2(view);
1775           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1776           var bytes = getInternalState$2(store.buffer).bytes;
1777           var start = intIndex + store.byteOffset;
1778           var pack = bytes.slice(start, start + count);
1779           return isLittleEndian ? pack : pack.reverse();
1780         };
1781
1782         var set$1 = function (view, count, index, conversion, value, isLittleEndian) {
1783           var intIndex = toIndex(index);
1784           var store = getInternalState$2(view);
1785           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1786           var bytes = getInternalState$2(store.buffer).bytes;
1787           var start = intIndex + store.byteOffset;
1788           var pack = conversion(+value);
1789           for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
1790         };
1791
1792         if (!arrayBufferNative) {
1793           $ArrayBuffer = function ArrayBuffer(length) {
1794             anInstance(this, $ArrayBuffer, ARRAY_BUFFER);
1795             var byteLength = toIndex(length);
1796             setInternalState$2(this, {
1797               bytes: arrayFill.call(new Array(byteLength), 0),
1798               byteLength: byteLength
1799             });
1800             if (!descriptors) this.byteLength = byteLength;
1801           };
1802
1803           $DataView = function DataView(buffer, byteOffset, byteLength) {
1804             anInstance(this, $DataView, DATA_VIEW);
1805             anInstance(buffer, $ArrayBuffer, DATA_VIEW);
1806             var bufferLength = getInternalState$2(buffer).byteLength;
1807             var offset = toInteger(byteOffset);
1808             if (offset < 0 || offset > bufferLength) throw RangeError$1('Wrong offset');
1809             byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);
1810             if (offset + byteLength > bufferLength) throw RangeError$1(WRONG_LENGTH);
1811             setInternalState$2(this, {
1812               buffer: buffer,
1813               byteLength: byteLength,
1814               byteOffset: offset
1815             });
1816             if (!descriptors) {
1817               this.buffer = buffer;
1818               this.byteLength = byteLength;
1819               this.byteOffset = offset;
1820             }
1821           };
1822
1823           if (descriptors) {
1824             addGetter($ArrayBuffer, 'byteLength');
1825             addGetter($DataView, 'buffer');
1826             addGetter($DataView, 'byteLength');
1827             addGetter($DataView, 'byteOffset');
1828           }
1829
1830           redefineAll($DataView[PROTOTYPE$2], {
1831             getInt8: function getInt8(byteOffset) {
1832               return get$1(this, 1, byteOffset)[0] << 24 >> 24;
1833             },
1834             getUint8: function getUint8(byteOffset) {
1835               return get$1(this, 1, byteOffset)[0];
1836             },
1837             getInt16: function getInt16(byteOffset /* , littleEndian */) {
1838               var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
1839               return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
1840             },
1841             getUint16: function getUint16(byteOffset /* , littleEndian */) {
1842               var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
1843               return bytes[1] << 8 | bytes[0];
1844             },
1845             getInt32: function getInt32(byteOffset /* , littleEndian */) {
1846               return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
1847             },
1848             getUint32: function getUint32(byteOffset /* , littleEndian */) {
1849               return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
1850             },
1851             getFloat32: function getFloat32(byteOffset /* , littleEndian */) {
1852               return unpackIEEE754(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
1853             },
1854             getFloat64: function getFloat64(byteOffset /* , littleEndian */) {
1855               return unpackIEEE754(get$1(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
1856             },
1857             setInt8: function setInt8(byteOffset, value) {
1858               set$1(this, 1, byteOffset, packInt8, value);
1859             },
1860             setUint8: function setUint8(byteOffset, value) {
1861               set$1(this, 1, byteOffset, packInt8, value);
1862             },
1863             setInt16: function setInt16(byteOffset, value /* , littleEndian */) {
1864               set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
1865             },
1866             setUint16: function setUint16(byteOffset, value /* , littleEndian */) {
1867               set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
1868             },
1869             setInt32: function setInt32(byteOffset, value /* , littleEndian */) {
1870               set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
1871             },
1872             setUint32: function setUint32(byteOffset, value /* , littleEndian */) {
1873               set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
1874             },
1875             setFloat32: function setFloat32(byteOffset, value /* , littleEndian */) {
1876               set$1(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
1877             },
1878             setFloat64: function setFloat64(byteOffset, value /* , littleEndian */) {
1879               set$1(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
1880             }
1881           });
1882         } else {
1883           if (!fails(function () {
1884             NativeArrayBuffer(1);
1885           }) || !fails(function () {
1886             new NativeArrayBuffer(-1); // eslint-disable-line no-new
1887           }) || fails(function () {
1888             new NativeArrayBuffer(); // eslint-disable-line no-new
1889             new NativeArrayBuffer(1.5); // eslint-disable-line no-new
1890             new NativeArrayBuffer(NaN); // eslint-disable-line no-new
1891             return NativeArrayBuffer.name != ARRAY_BUFFER;
1892           })) {
1893             $ArrayBuffer = function ArrayBuffer(length) {
1894               anInstance(this, $ArrayBuffer);
1895               return new NativeArrayBuffer(toIndex(length));
1896             };
1897             var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE$2] = NativeArrayBuffer[PROTOTYPE$2];
1898             for (var keys$1 = getOwnPropertyNames(NativeArrayBuffer), j = 0, key; keys$1.length > j;) {
1899               if (!((key = keys$1[j++]) in $ArrayBuffer)) {
1900                 createNonEnumerableProperty($ArrayBuffer, key, NativeArrayBuffer[key]);
1901               }
1902             }
1903             ArrayBufferPrototype.constructor = $ArrayBuffer;
1904           }
1905
1906           // WebKit bug - the same parent prototype for typed arrays and data view
1907           if (objectSetPrototypeOf && objectGetPrototypeOf($DataViewPrototype) !== ObjectPrototype$2) {
1908             objectSetPrototypeOf($DataViewPrototype, ObjectPrototype$2);
1909           }
1910
1911           // iOS Safari 7.x bug
1912           var testView = new $DataView(new $ArrayBuffer(2));
1913           var nativeSetInt8 = $DataViewPrototype.setInt8;
1914           testView.setInt8(0, 2147483648);
1915           testView.setInt8(1, 2147483649);
1916           if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll($DataViewPrototype, {
1917             setInt8: function setInt8(byteOffset, value) {
1918               nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
1919             },
1920             setUint8: function setUint8(byteOffset, value) {
1921               nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
1922             }
1923           }, { unsafe: true });
1924         }
1925
1926         setToStringTag($ArrayBuffer, ARRAY_BUFFER);
1927         setToStringTag($DataView, DATA_VIEW);
1928
1929         var arrayBuffer = {
1930           ArrayBuffer: $ArrayBuffer,
1931           DataView: $DataView
1932         };
1933
1934         var SPECIES$3 = wellKnownSymbol('species');
1935
1936         var setSpecies = function (CONSTRUCTOR_NAME) {
1937           var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
1938           var defineProperty = objectDefineProperty.f;
1939
1940           if (descriptors && Constructor && !Constructor[SPECIES$3]) {
1941             defineProperty(Constructor, SPECIES$3, {
1942               configurable: true,
1943               get: function () { return this; }
1944             });
1945           }
1946         };
1947
1948         var ARRAY_BUFFER$1 = 'ArrayBuffer';
1949         var ArrayBuffer$1 = arrayBuffer[ARRAY_BUFFER$1];
1950         var NativeArrayBuffer$1 = global_1[ARRAY_BUFFER$1];
1951
1952         // `ArrayBuffer` constructor
1953         // https://tc39.github.io/ecma262/#sec-arraybuffer-constructor
1954         _export({ global: true, forced: NativeArrayBuffer$1 !== ArrayBuffer$1 }, {
1955           ArrayBuffer: ArrayBuffer$1
1956         });
1957
1958         setSpecies(ARRAY_BUFFER$1);
1959
1960         var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
1961         var test = {};
1962
1963         test[TO_STRING_TAG$1] = 'z';
1964
1965         var toStringTagSupport = String(test) === '[object z]';
1966
1967         var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');
1968         // ES3 wrong here
1969         var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
1970
1971         // fallback for IE11 Script Access Denied error
1972         var tryGet = function (it, key) {
1973           try {
1974             return it[key];
1975           } catch (error) { /* empty */ }
1976         };
1977
1978         // getting tag from ES6+ `Object.prototype.toString`
1979         var classof = toStringTagSupport ? classofRaw : function (it) {
1980           var O, tag, result;
1981           return it === undefined ? 'Undefined' : it === null ? 'Null'
1982             // @@toStringTag case
1983             : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag
1984             // builtinTag case
1985             : CORRECT_ARGUMENTS ? classofRaw(O)
1986             // ES3 arguments fallback
1987             : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
1988         };
1989
1990         var defineProperty$5 = objectDefineProperty.f;
1991
1992
1993
1994
1995
1996         var Int8Array$1 = global_1.Int8Array;
1997         var Int8ArrayPrototype = Int8Array$1 && Int8Array$1.prototype;
1998         var Uint8ClampedArray = global_1.Uint8ClampedArray;
1999         var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
2000         var TypedArray = Int8Array$1 && objectGetPrototypeOf(Int8Array$1);
2001         var TypedArrayPrototype = Int8ArrayPrototype && objectGetPrototypeOf(Int8ArrayPrototype);
2002         var ObjectPrototype$3 = Object.prototype;
2003         var isPrototypeOf = ObjectPrototype$3.isPrototypeOf;
2004
2005         var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
2006         var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');
2007         // Fixing native typed arrays in Opera Presto crashes the browser, see #595
2008         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferNative && !!objectSetPrototypeOf && classof(global_1.opera) !== 'Opera';
2009         var TYPED_ARRAY_TAG_REQIRED = false;
2010         var NAME;
2011
2012         var TypedArrayConstructorsList = {
2013           Int8Array: 1,
2014           Uint8Array: 1,
2015           Uint8ClampedArray: 1,
2016           Int16Array: 2,
2017           Uint16Array: 2,
2018           Int32Array: 4,
2019           Uint32Array: 4,
2020           Float32Array: 4,
2021           Float64Array: 8
2022         };
2023
2024         var isView = function isView(it) {
2025           var klass = classof(it);
2026           return klass === 'DataView' || has(TypedArrayConstructorsList, klass);
2027         };
2028
2029         var isTypedArray = function (it) {
2030           return isObject(it) && has(TypedArrayConstructorsList, classof(it));
2031         };
2032
2033         var aTypedArray = function (it) {
2034           if (isTypedArray(it)) return it;
2035           throw TypeError('Target is not a typed array');
2036         };
2037
2038         var aTypedArrayConstructor = function (C) {
2039           if (objectSetPrototypeOf) {
2040             if (isPrototypeOf.call(TypedArray, C)) return C;
2041           } else for (var ARRAY in TypedArrayConstructorsList) if (has(TypedArrayConstructorsList, NAME)) {
2042             var TypedArrayConstructor = global_1[ARRAY];
2043             if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
2044               return C;
2045             }
2046           } throw TypeError('Target is not a typed array constructor');
2047         };
2048
2049         var exportTypedArrayMethod = function (KEY, property, forced) {
2050           if (!descriptors) return;
2051           if (forced) for (var ARRAY in TypedArrayConstructorsList) {
2052             var TypedArrayConstructor = global_1[ARRAY];
2053             if (TypedArrayConstructor && has(TypedArrayConstructor.prototype, KEY)) {
2054               delete TypedArrayConstructor.prototype[KEY];
2055             }
2056           }
2057           if (!TypedArrayPrototype[KEY] || forced) {
2058             redefine(TypedArrayPrototype, KEY, forced ? property
2059               : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property);
2060           }
2061         };
2062
2063         var exportTypedArrayStaticMethod = function (KEY, property, forced) {
2064           var ARRAY, TypedArrayConstructor;
2065           if (!descriptors) return;
2066           if (objectSetPrototypeOf) {
2067             if (forced) for (ARRAY in TypedArrayConstructorsList) {
2068               TypedArrayConstructor = global_1[ARRAY];
2069               if (TypedArrayConstructor && has(TypedArrayConstructor, KEY)) {
2070                 delete TypedArrayConstructor[KEY];
2071               }
2072             }
2073             if (!TypedArray[KEY] || forced) {
2074               // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
2075               try {
2076                 return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8Array$1[KEY] || property);
2077               } catch (error) { /* empty */ }
2078             } else return;
2079           }
2080           for (ARRAY in TypedArrayConstructorsList) {
2081             TypedArrayConstructor = global_1[ARRAY];
2082             if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
2083               redefine(TypedArrayConstructor, KEY, property);
2084             }
2085           }
2086         };
2087
2088         for (NAME in TypedArrayConstructorsList) {
2089           if (!global_1[NAME]) NATIVE_ARRAY_BUFFER_VIEWS = false;
2090         }
2091
2092         // WebKit bug - typed arrays constructors prototype is Object.prototype
2093         if (!NATIVE_ARRAY_BUFFER_VIEWS || typeof TypedArray != 'function' || TypedArray === Function.prototype) {
2094           // eslint-disable-next-line no-shadow
2095           TypedArray = function TypedArray() {
2096             throw TypeError('Incorrect invocation');
2097           };
2098           if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
2099             if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME], TypedArray);
2100           }
2101         }
2102
2103         if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype$3) {
2104           TypedArrayPrototype = TypedArray.prototype;
2105           if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
2106             if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME].prototype, TypedArrayPrototype);
2107           }
2108         }
2109
2110         // WebKit bug - one more object in Uint8ClampedArray prototype chain
2111         if (NATIVE_ARRAY_BUFFER_VIEWS && objectGetPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
2112           objectSetPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
2113         }
2114
2115         if (descriptors && !has(TypedArrayPrototype, TO_STRING_TAG$3)) {
2116           TYPED_ARRAY_TAG_REQIRED = true;
2117           defineProperty$5(TypedArrayPrototype, TO_STRING_TAG$3, { get: function () {
2118             return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;
2119           } });
2120           for (NAME in TypedArrayConstructorsList) if (global_1[NAME]) {
2121             createNonEnumerableProperty(global_1[NAME], TYPED_ARRAY_TAG, NAME);
2122           }
2123         }
2124
2125         var arrayBufferViewCore = {
2126           NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,
2127           TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG,
2128           aTypedArray: aTypedArray,
2129           aTypedArrayConstructor: aTypedArrayConstructor,
2130           exportTypedArrayMethod: exportTypedArrayMethod,
2131           exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,
2132           isView: isView,
2133           isTypedArray: isTypedArray,
2134           TypedArray: TypedArray,
2135           TypedArrayPrototype: TypedArrayPrototype
2136         };
2137
2138         var NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
2139
2140         // `ArrayBuffer.isView` method
2141         // https://tc39.github.io/ecma262/#sec-arraybuffer.isview
2142         _export({ target: 'ArrayBuffer', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS$1 }, {
2143           isView: arrayBufferViewCore.isView
2144         });
2145
2146         var SPECIES$4 = wellKnownSymbol('species');
2147
2148         // `SpeciesConstructor` abstract operation
2149         // https://tc39.github.io/ecma262/#sec-speciesconstructor
2150         var speciesConstructor = function (O, defaultConstructor) {
2151           var C = anObject(O).constructor;
2152           var S;
2153           return C === undefined || (S = anObject(C)[SPECIES$4]) == undefined ? defaultConstructor : aFunction$1(S);
2154         };
2155
2156         var ArrayBuffer$2 = arrayBuffer.ArrayBuffer;
2157         var DataView$1 = arrayBuffer.DataView;
2158         var nativeArrayBufferSlice = ArrayBuffer$2.prototype.slice;
2159
2160         var INCORRECT_SLICE = fails(function () {
2161           return !new ArrayBuffer$2(2).slice(1, undefined).byteLength;
2162         });
2163
2164         // `ArrayBuffer.prototype.slice` method
2165         // https://tc39.github.io/ecma262/#sec-arraybuffer.prototype.slice
2166         _export({ target: 'ArrayBuffer', proto: true, unsafe: true, forced: INCORRECT_SLICE }, {
2167           slice: function slice(start, end) {
2168             if (nativeArrayBufferSlice !== undefined && end === undefined) {
2169               return nativeArrayBufferSlice.call(anObject(this), start); // FF fix
2170             }
2171             var length = anObject(this).byteLength;
2172             var first = toAbsoluteIndex(start, length);
2173             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
2174             var result = new (speciesConstructor(this, ArrayBuffer$2))(toLength(fin - first));
2175             var viewSource = new DataView$1(this);
2176             var viewTarget = new DataView$1(result);
2177             var index = 0;
2178             while (first < fin) {
2179               viewTarget.setUint8(index++, viewSource.getUint8(first++));
2180             } return result;
2181           }
2182         });
2183
2184         // `DataView` constructor
2185         // https://tc39.github.io/ecma262/#sec-dataview-constructor
2186         _export({ global: true, forced: !arrayBufferNative }, {
2187           DataView: arrayBuffer.DataView
2188         });
2189
2190         var defineProperty$6 = objectDefineProperty.f;
2191
2192         var FunctionPrototype = Function.prototype;
2193         var FunctionPrototypeToString = FunctionPrototype.toString;
2194         var nameRE = /^\s*function ([^ (]*)/;
2195         var NAME$1 = 'name';
2196
2197         // Function instances `.name` property
2198         // https://tc39.github.io/ecma262/#sec-function-instances-name
2199         if (descriptors && !(NAME$1 in FunctionPrototype)) {
2200           defineProperty$6(FunctionPrototype, NAME$1, {
2201             configurable: true,
2202             get: function () {
2203               try {
2204                 return FunctionPrototypeToString.call(this).match(nameRE)[1];
2205               } catch (error) {
2206                 return '';
2207               }
2208             }
2209           });
2210         }
2211
2212         // `Object.create` method
2213         // https://tc39.github.io/ecma262/#sec-object.create
2214         _export({ target: 'Object', stat: true, sham: !descriptors }, {
2215           create: objectCreate
2216         });
2217
2218         var nativeGetOwnPropertyNames$2 = objectGetOwnPropertyNamesExternal.f;
2219
2220         var FAILS_ON_PRIMITIVES = fails(function () { return !Object.getOwnPropertyNames(1); });
2221
2222         // `Object.getOwnPropertyNames` method
2223         // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
2224         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES }, {
2225           getOwnPropertyNames: nativeGetOwnPropertyNames$2
2226         });
2227
2228         // `Object.prototype.toString` method implementation
2229         // https://tc39.github.io/ecma262/#sec-object.prototype.tostring
2230         var objectToString = toStringTagSupport ? {}.toString : function toString() {
2231           return '[object ' + classof(this) + ']';
2232         };
2233
2234         // `Object.prototype.toString` method
2235         // https://tc39.github.io/ecma262/#sec-object.prototype.tostring
2236         if (!toStringTagSupport) {
2237           redefine(Object.prototype, 'toString', objectToString, { unsafe: true });
2238         }
2239
2240         var nativePromiseConstructor = global_1.Promise;
2241
2242         var ITERATOR$2 = wellKnownSymbol('iterator');
2243         var ArrayPrototype$1 = Array.prototype;
2244
2245         // check on default Array iterator
2246         var isArrayIteratorMethod = function (it) {
2247           return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$2] === it);
2248         };
2249
2250         var ITERATOR$3 = wellKnownSymbol('iterator');
2251
2252         var getIteratorMethod = function (it) {
2253           if (it != undefined) return it[ITERATOR$3]
2254             || it['@@iterator']
2255             || iterators[classof(it)];
2256         };
2257
2258         // call something on iterator step with safe closing on error
2259         var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
2260           try {
2261             return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
2262           // 7.4.6 IteratorClose(iterator, completion)
2263           } catch (error) {
2264             var returnMethod = iterator['return'];
2265             if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
2266             throw error;
2267           }
2268         };
2269
2270         var iterate_1 = createCommonjsModule(function (module) {
2271         var Result = function (stopped, result) {
2272           this.stopped = stopped;
2273           this.result = result;
2274         };
2275
2276         var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
2277           var boundFunction = functionBindContext(fn, that, AS_ENTRIES ? 2 : 1);
2278           var iterator, iterFn, index, length, result, next, step;
2279
2280           if (IS_ITERATOR) {
2281             iterator = iterable;
2282           } else {
2283             iterFn = getIteratorMethod(iterable);
2284             if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
2285             // optimisation for array iterators
2286             if (isArrayIteratorMethod(iterFn)) {
2287               for (index = 0, length = toLength(iterable.length); length > index; index++) {
2288                 result = AS_ENTRIES
2289                   ? boundFunction(anObject(step = iterable[index])[0], step[1])
2290                   : boundFunction(iterable[index]);
2291                 if (result && result instanceof Result) return result;
2292               } return new Result(false);
2293             }
2294             iterator = iterFn.call(iterable);
2295           }
2296
2297           next = iterator.next;
2298           while (!(step = next.call(iterator)).done) {
2299             result = callWithSafeIterationClosing(iterator, boundFunction, step.value, AS_ENTRIES);
2300             if (typeof result == 'object' && result && result instanceof Result) return result;
2301           } return new Result(false);
2302         };
2303
2304         iterate.stop = function (result) {
2305           return new Result(true, result);
2306         };
2307         });
2308
2309         var ITERATOR$4 = wellKnownSymbol('iterator');
2310         var SAFE_CLOSING = false;
2311
2312         try {
2313           var called = 0;
2314           var iteratorWithReturn = {
2315             next: function () {
2316               return { done: !!called++ };
2317             },
2318             'return': function () {
2319               SAFE_CLOSING = true;
2320             }
2321           };
2322           iteratorWithReturn[ITERATOR$4] = function () {
2323             return this;
2324           };
2325           // eslint-disable-next-line no-throw-literal
2326           Array.from(iteratorWithReturn, function () { throw 2; });
2327         } catch (error) { /* empty */ }
2328
2329         var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
2330           if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2331           var ITERATION_SUPPORT = false;
2332           try {
2333             var object = {};
2334             object[ITERATOR$4] = function () {
2335               return {
2336                 next: function () {
2337                   return { done: ITERATION_SUPPORT = true };
2338                 }
2339               };
2340             };
2341             exec(object);
2342           } catch (error) { /* empty */ }
2343           return ITERATION_SUPPORT;
2344         };
2345
2346         var engineIsIos = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);
2347
2348         var location$1 = global_1.location;
2349         var set$2 = global_1.setImmediate;
2350         var clear = global_1.clearImmediate;
2351         var process$2 = global_1.process;
2352         var MessageChannel = global_1.MessageChannel;
2353         var Dispatch = global_1.Dispatch;
2354         var counter = 0;
2355         var queue = {};
2356         var ONREADYSTATECHANGE = 'onreadystatechange';
2357         var defer, channel, port;
2358
2359         var run = function (id) {
2360           // eslint-disable-next-line no-prototype-builtins
2361           if (queue.hasOwnProperty(id)) {
2362             var fn = queue[id];
2363             delete queue[id];
2364             fn();
2365           }
2366         };
2367
2368         var runner = function (id) {
2369           return function () {
2370             run(id);
2371           };
2372         };
2373
2374         var listener = function (event) {
2375           run(event.data);
2376         };
2377
2378         var post = function (id) {
2379           // old engines have not location.origin
2380           global_1.postMessage(id + '', location$1.protocol + '//' + location$1.host);
2381         };
2382
2383         // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
2384         if (!set$2 || !clear) {
2385           set$2 = function setImmediate(fn) {
2386             var args = [];
2387             var i = 1;
2388             while (arguments.length > i) args.push(arguments[i++]);
2389             queue[++counter] = function () {
2390               // eslint-disable-next-line no-new-func
2391               (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
2392             };
2393             defer(counter);
2394             return counter;
2395           };
2396           clear = function clearImmediate(id) {
2397             delete queue[id];
2398           };
2399           // Node.js 0.8-
2400           if (classofRaw(process$2) == 'process') {
2401             defer = function (id) {
2402               process$2.nextTick(runner(id));
2403             };
2404           // Sphere (JS game engine) Dispatch API
2405           } else if (Dispatch && Dispatch.now) {
2406             defer = function (id) {
2407               Dispatch.now(runner(id));
2408             };
2409           // Browsers with MessageChannel, includes WebWorkers
2410           // except iOS - https://github.com/zloirock/core-js/issues/624
2411           } else if (MessageChannel && !engineIsIos) {
2412             channel = new MessageChannel();
2413             port = channel.port2;
2414             channel.port1.onmessage = listener;
2415             defer = functionBindContext(port.postMessage, port, 1);
2416           // Browsers with postMessage, skip WebWorkers
2417           // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
2418           } else if (
2419             global_1.addEventListener &&
2420             typeof postMessage == 'function' &&
2421             !global_1.importScripts &&
2422             !fails(post) &&
2423             location$1.protocol !== 'file:'
2424           ) {
2425             defer = post;
2426             global_1.addEventListener('message', listener, false);
2427           // IE8-
2428           } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {
2429             defer = function (id) {
2430               html.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {
2431                 html.removeChild(this);
2432                 run(id);
2433               };
2434             };
2435           // Rest old browsers
2436           } else {
2437             defer = function (id) {
2438               setTimeout(runner(id), 0);
2439             };
2440           }
2441         }
2442
2443         var task = {
2444           set: set$2,
2445           clear: clear
2446         };
2447
2448         var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
2449
2450         var macrotask = task.set;
2451
2452
2453         var MutationObserver = global_1.MutationObserver || global_1.WebKitMutationObserver;
2454         var process$3 = global_1.process;
2455         var Promise$1 = global_1.Promise;
2456         var IS_NODE = classofRaw(process$3) == 'process';
2457         // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
2458         var queueMicrotaskDescriptor = getOwnPropertyDescriptor$2(global_1, 'queueMicrotask');
2459         var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
2460
2461         var flush, head, last, notify, toggle, node, promise, then;
2462
2463         // modern engines have queueMicrotask method
2464         if (!queueMicrotask) {
2465           flush = function () {
2466             var parent, fn;
2467             if (IS_NODE && (parent = process$3.domain)) parent.exit();
2468             while (head) {
2469               fn = head.fn;
2470               head = head.next;
2471               try {
2472                 fn();
2473               } catch (error) {
2474                 if (head) notify();
2475                 else last = undefined;
2476                 throw error;
2477               }
2478             } last = undefined;
2479             if (parent) parent.enter();
2480           };
2481
2482           // Node.js
2483           if (IS_NODE) {
2484             notify = function () {
2485               process$3.nextTick(flush);
2486             };
2487           // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
2488           } else if (MutationObserver && !engineIsIos) {
2489             toggle = true;
2490             node = document.createTextNode('');
2491             new MutationObserver(flush).observe(node, { characterData: true });
2492             notify = function () {
2493               node.data = toggle = !toggle;
2494             };
2495           // environments with maybe non-completely correct, but existent Promise
2496           } else if (Promise$1 && Promise$1.resolve) {
2497             // Promise.resolve without an argument throws an error in LG WebOS 2
2498             promise = Promise$1.resolve(undefined);
2499             then = promise.then;
2500             notify = function () {
2501               then.call(promise, flush);
2502             };
2503           // for other environments - macrotask based on:
2504           // - setImmediate
2505           // - MessageChannel
2506           // - window.postMessag
2507           // - onreadystatechange
2508           // - setTimeout
2509           } else {
2510             notify = function () {
2511               // strange IE + webpack dev server bug - use .call(global)
2512               macrotask.call(global_1, flush);
2513             };
2514           }
2515         }
2516
2517         var microtask = queueMicrotask || function (fn) {
2518           var task = { fn: fn, next: undefined };
2519           if (last) last.next = task;
2520           if (!head) {
2521             head = task;
2522             notify();
2523           } last = task;
2524         };
2525
2526         var PromiseCapability = function (C) {
2527           var resolve, reject;
2528           this.promise = new C(function ($$resolve, $$reject) {
2529             if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
2530             resolve = $$resolve;
2531             reject = $$reject;
2532           });
2533           this.resolve = aFunction$1(resolve);
2534           this.reject = aFunction$1(reject);
2535         };
2536
2537         // 25.4.1.5 NewPromiseCapability(C)
2538         var f$7 = function (C) {
2539           return new PromiseCapability(C);
2540         };
2541
2542         var newPromiseCapability = {
2543                 f: f$7
2544         };
2545
2546         var promiseResolve = function (C, x) {
2547           anObject(C);
2548           if (isObject(x) && x.constructor === C) return x;
2549           var promiseCapability = newPromiseCapability.f(C);
2550           var resolve = promiseCapability.resolve;
2551           resolve(x);
2552           return promiseCapability.promise;
2553         };
2554
2555         var hostReportErrors = function (a, b) {
2556           var console = global_1.console;
2557           if (console && console.error) {
2558             arguments.length === 1 ? console.error(a) : console.error(a, b);
2559           }
2560         };
2561
2562         var perform = function (exec) {
2563           try {
2564             return { error: false, value: exec() };
2565           } catch (error) {
2566             return { error: true, value: error };
2567           }
2568         };
2569
2570         var task$1 = task.set;
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581         var SPECIES$5 = wellKnownSymbol('species');
2582         var PROMISE = 'Promise';
2583         var getInternalState$3 = internalState.get;
2584         var setInternalState$3 = internalState.set;
2585         var getInternalPromiseState = internalState.getterFor(PROMISE);
2586         var PromiseConstructor = nativePromiseConstructor;
2587         var TypeError$1 = global_1.TypeError;
2588         var document$2 = global_1.document;
2589         var process$4 = global_1.process;
2590         var $fetch = getBuiltIn('fetch');
2591         var newPromiseCapability$1 = newPromiseCapability.f;
2592         var newGenericPromiseCapability = newPromiseCapability$1;
2593         var IS_NODE$1 = classofRaw(process$4) == 'process';
2594         var DISPATCH_EVENT = !!(document$2 && document$2.createEvent && global_1.dispatchEvent);
2595         var UNHANDLED_REJECTION = 'unhandledrejection';
2596         var REJECTION_HANDLED = 'rejectionhandled';
2597         var PENDING = 0;
2598         var FULFILLED = 1;
2599         var REJECTED = 2;
2600         var HANDLED = 1;
2601         var UNHANDLED = 2;
2602         var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
2603
2604         var FORCED = isForced_1(PROMISE, function () {
2605           var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);
2606           if (!GLOBAL_CORE_JS_PROMISE) {
2607             // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
2608             // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
2609             // We can't detect it synchronously, so just check versions
2610             if (engineV8Version === 66) return true;
2611             // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
2612             if (!IS_NODE$1 && typeof PromiseRejectionEvent != 'function') return true;
2613           }
2614           // We can't use @@species feature detection in V8 since it causes
2615           // deoptimization and performance degradation
2616           // https://github.com/zloirock/core-js/issues/679
2617           if (engineV8Version >= 51 && /native code/.test(PromiseConstructor)) return false;
2618           // Detect correctness of subclassing with @@species support
2619           var promise = PromiseConstructor.resolve(1);
2620           var FakePromise = function (exec) {
2621             exec(function () { /* empty */ }, function () { /* empty */ });
2622           };
2623           var constructor = promise.constructor = {};
2624           constructor[SPECIES$5] = FakePromise;
2625           return !(promise.then(function () { /* empty */ }) instanceof FakePromise);
2626         });
2627
2628         var INCORRECT_ITERATION = FORCED || !checkCorrectnessOfIteration(function (iterable) {
2629           PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
2630         });
2631
2632         // helpers
2633         var isThenable = function (it) {
2634           var then;
2635           return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
2636         };
2637
2638         var notify$1 = function (promise, state, isReject) {
2639           if (state.notified) return;
2640           state.notified = true;
2641           var chain = state.reactions;
2642           microtask(function () {
2643             var value = state.value;
2644             var ok = state.state == FULFILLED;
2645             var index = 0;
2646             // variable length - can't use forEach
2647             while (chain.length > index) {
2648               var reaction = chain[index++];
2649               var handler = ok ? reaction.ok : reaction.fail;
2650               var resolve = reaction.resolve;
2651               var reject = reaction.reject;
2652               var domain = reaction.domain;
2653               var result, then, exited;
2654               try {
2655                 if (handler) {
2656                   if (!ok) {
2657                     if (state.rejection === UNHANDLED) onHandleUnhandled(promise, state);
2658                     state.rejection = HANDLED;
2659                   }
2660                   if (handler === true) result = value;
2661                   else {
2662                     if (domain) domain.enter();
2663                     result = handler(value); // can throw
2664                     if (domain) {
2665                       domain.exit();
2666                       exited = true;
2667                     }
2668                   }
2669                   if (result === reaction.promise) {
2670                     reject(TypeError$1('Promise-chain cycle'));
2671                   } else if (then = isThenable(result)) {
2672                     then.call(result, resolve, reject);
2673                   } else resolve(result);
2674                 } else reject(value);
2675               } catch (error) {
2676                 if (domain && !exited) domain.exit();
2677                 reject(error);
2678               }
2679             }
2680             state.reactions = [];
2681             state.notified = false;
2682             if (isReject && !state.rejection) onUnhandled(promise, state);
2683           });
2684         };
2685
2686         var dispatchEvent = function (name, promise, reason) {
2687           var event, handler;
2688           if (DISPATCH_EVENT) {
2689             event = document$2.createEvent('Event');
2690             event.promise = promise;
2691             event.reason = reason;
2692             event.initEvent(name, false, true);
2693             global_1.dispatchEvent(event);
2694           } else event = { promise: promise, reason: reason };
2695           if (handler = global_1['on' + name]) handler(event);
2696           else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
2697         };
2698
2699         var onUnhandled = function (promise, state) {
2700           task$1.call(global_1, function () {
2701             var value = state.value;
2702             var IS_UNHANDLED = isUnhandled(state);
2703             var result;
2704             if (IS_UNHANDLED) {
2705               result = perform(function () {
2706                 if (IS_NODE$1) {
2707                   process$4.emit('unhandledRejection', value, promise);
2708                 } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
2709               });
2710               // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
2711               state.rejection = IS_NODE$1 || isUnhandled(state) ? UNHANDLED : HANDLED;
2712               if (result.error) throw result.value;
2713             }
2714           });
2715         };
2716
2717         var isUnhandled = function (state) {
2718           return state.rejection !== HANDLED && !state.parent;
2719         };
2720
2721         var onHandleUnhandled = function (promise, state) {
2722           task$1.call(global_1, function () {
2723             if (IS_NODE$1) {
2724               process$4.emit('rejectionHandled', promise);
2725             } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
2726           });
2727         };
2728
2729         var bind = function (fn, promise, state, unwrap) {
2730           return function (value) {
2731             fn(promise, state, value, unwrap);
2732           };
2733         };
2734
2735         var internalReject = function (promise, state, value, unwrap) {
2736           if (state.done) return;
2737           state.done = true;
2738           if (unwrap) state = unwrap;
2739           state.value = value;
2740           state.state = REJECTED;
2741           notify$1(promise, state, true);
2742         };
2743
2744         var internalResolve = function (promise, state, value, unwrap) {
2745           if (state.done) return;
2746           state.done = true;
2747           if (unwrap) state = unwrap;
2748           try {
2749             if (promise === value) throw TypeError$1("Promise can't be resolved itself");
2750             var then = isThenable(value);
2751             if (then) {
2752               microtask(function () {
2753                 var wrapper = { done: false };
2754                 try {
2755                   then.call(value,
2756                     bind(internalResolve, promise, wrapper, state),
2757                     bind(internalReject, promise, wrapper, state)
2758                   );
2759                 } catch (error) {
2760                   internalReject(promise, wrapper, error, state);
2761                 }
2762               });
2763             } else {
2764               state.value = value;
2765               state.state = FULFILLED;
2766               notify$1(promise, state, false);
2767             }
2768           } catch (error) {
2769             internalReject(promise, { done: false }, error, state);
2770           }
2771         };
2772
2773         // constructor polyfill
2774         if (FORCED) {
2775           // 25.4.3.1 Promise(executor)
2776           PromiseConstructor = function Promise(executor) {
2777             anInstance(this, PromiseConstructor, PROMISE);
2778             aFunction$1(executor);
2779             Internal.call(this);
2780             var state = getInternalState$3(this);
2781             try {
2782               executor(bind(internalResolve, this, state), bind(internalReject, this, state));
2783             } catch (error) {
2784               internalReject(this, state, error);
2785             }
2786           };
2787           // eslint-disable-next-line no-unused-vars
2788           Internal = function Promise(executor) {
2789             setInternalState$3(this, {
2790               type: PROMISE,
2791               done: false,
2792               notified: false,
2793               parent: false,
2794               reactions: [],
2795               rejection: false,
2796               state: PENDING,
2797               value: undefined
2798             });
2799           };
2800           Internal.prototype = redefineAll(PromiseConstructor.prototype, {
2801             // `Promise.prototype.then` method
2802             // https://tc39.github.io/ecma262/#sec-promise.prototype.then
2803             then: function then(onFulfilled, onRejected) {
2804               var state = getInternalPromiseState(this);
2805               var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
2806               reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
2807               reaction.fail = typeof onRejected == 'function' && onRejected;
2808               reaction.domain = IS_NODE$1 ? process$4.domain : undefined;
2809               state.parent = true;
2810               state.reactions.push(reaction);
2811               if (state.state != PENDING) notify$1(this, state, false);
2812               return reaction.promise;
2813             },
2814             // `Promise.prototype.catch` method
2815             // https://tc39.github.io/ecma262/#sec-promise.prototype.catch
2816             'catch': function (onRejected) {
2817               return this.then(undefined, onRejected);
2818             }
2819           });
2820           OwnPromiseCapability = function () {
2821             var promise = new Internal();
2822             var state = getInternalState$3(promise);
2823             this.promise = promise;
2824             this.resolve = bind(internalResolve, promise, state);
2825             this.reject = bind(internalReject, promise, state);
2826           };
2827           newPromiseCapability.f = newPromiseCapability$1 = function (C) {
2828             return C === PromiseConstructor || C === PromiseWrapper
2829               ? new OwnPromiseCapability(C)
2830               : newGenericPromiseCapability(C);
2831           };
2832
2833           if ( typeof nativePromiseConstructor == 'function') {
2834             nativeThen = nativePromiseConstructor.prototype.then;
2835
2836             // wrap native Promise#then for native async functions
2837             redefine(nativePromiseConstructor.prototype, 'then', function then(onFulfilled, onRejected) {
2838               var that = this;
2839               return new PromiseConstructor(function (resolve, reject) {
2840                 nativeThen.call(that, resolve, reject);
2841               }).then(onFulfilled, onRejected);
2842             // https://github.com/zloirock/core-js/issues/640
2843             }, { unsafe: true });
2844
2845             // wrap fetch result
2846             if (typeof $fetch == 'function') _export({ global: true, enumerable: true, forced: true }, {
2847               // eslint-disable-next-line no-unused-vars
2848               fetch: function fetch(input /* , init */) {
2849                 return promiseResolve(PromiseConstructor, $fetch.apply(global_1, arguments));
2850               }
2851             });
2852           }
2853         }
2854
2855         _export({ global: true, wrap: true, forced: FORCED }, {
2856           Promise: PromiseConstructor
2857         });
2858
2859         setToStringTag(PromiseConstructor, PROMISE, false);
2860         setSpecies(PROMISE);
2861
2862         PromiseWrapper = getBuiltIn(PROMISE);
2863
2864         // statics
2865         _export({ target: PROMISE, stat: true, forced: FORCED }, {
2866           // `Promise.reject` method
2867           // https://tc39.github.io/ecma262/#sec-promise.reject
2868           reject: function reject(r) {
2869             var capability = newPromiseCapability$1(this);
2870             capability.reject.call(undefined, r);
2871             return capability.promise;
2872           }
2873         });
2874
2875         _export({ target: PROMISE, stat: true, forced:  FORCED }, {
2876           // `Promise.resolve` method
2877           // https://tc39.github.io/ecma262/#sec-promise.resolve
2878           resolve: function resolve(x) {
2879             return promiseResolve( this, x);
2880           }
2881         });
2882
2883         _export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION }, {
2884           // `Promise.all` method
2885           // https://tc39.github.io/ecma262/#sec-promise.all
2886           all: function all(iterable) {
2887             var C = this;
2888             var capability = newPromiseCapability$1(C);
2889             var resolve = capability.resolve;
2890             var reject = capability.reject;
2891             var result = perform(function () {
2892               var $promiseResolve = aFunction$1(C.resolve);
2893               var values = [];
2894               var counter = 0;
2895               var remaining = 1;
2896               iterate_1(iterable, function (promise) {
2897                 var index = counter++;
2898                 var alreadyCalled = false;
2899                 values.push(undefined);
2900                 remaining++;
2901                 $promiseResolve.call(C, promise).then(function (value) {
2902                   if (alreadyCalled) return;
2903                   alreadyCalled = true;
2904                   values[index] = value;
2905                   --remaining || resolve(values);
2906                 }, reject);
2907               });
2908               --remaining || resolve(values);
2909             });
2910             if (result.error) reject(result.value);
2911             return capability.promise;
2912           },
2913           // `Promise.race` method
2914           // https://tc39.github.io/ecma262/#sec-promise.race
2915           race: function race(iterable) {
2916             var C = this;
2917             var capability = newPromiseCapability$1(C);
2918             var reject = capability.reject;
2919             var result = perform(function () {
2920               var $promiseResolve = aFunction$1(C.resolve);
2921               iterate_1(iterable, function (promise) {
2922                 $promiseResolve.call(C, promise).then(capability.resolve, reject);
2923               });
2924             });
2925             if (result.error) reject(result.value);
2926             return capability.promise;
2927           }
2928         });
2929
2930         // `RegExp.prototype.flags` getter implementation
2931         // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags
2932         var regexpFlags = function () {
2933           var that = anObject(this);
2934           var result = '';
2935           if (that.global) result += 'g';
2936           if (that.ignoreCase) result += 'i';
2937           if (that.multiline) result += 'm';
2938           if (that.dotAll) result += 's';
2939           if (that.unicode) result += 'u';
2940           if (that.sticky) result += 'y';
2941           return result;
2942         };
2943
2944         // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
2945         // so we use an intermediate function.
2946         function RE(s, f) {
2947           return RegExp(s, f);
2948         }
2949
2950         var UNSUPPORTED_Y = fails(function () {
2951           // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError
2952           var re = RE('a', 'y');
2953           re.lastIndex = 2;
2954           return re.exec('abcd') != null;
2955         });
2956
2957         var BROKEN_CARET = fails(function () {
2958           // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
2959           var re = RE('^r', 'gy');
2960           re.lastIndex = 2;
2961           return re.exec('str') != null;
2962         });
2963
2964         var regexpStickyHelpers = {
2965                 UNSUPPORTED_Y: UNSUPPORTED_Y,
2966                 BROKEN_CARET: BROKEN_CARET
2967         };
2968
2969         var nativeExec = RegExp.prototype.exec;
2970         // This always refers to the native implementation, because the
2971         // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
2972         // which loads this file before patching the method.
2973         var nativeReplace = String.prototype.replace;
2974
2975         var patchedExec = nativeExec;
2976
2977         var UPDATES_LAST_INDEX_WRONG = (function () {
2978           var re1 = /a/;
2979           var re2 = /b*/g;
2980           nativeExec.call(re1, 'a');
2981           nativeExec.call(re2, 'a');
2982           return re1.lastIndex !== 0 || re2.lastIndex !== 0;
2983         })();
2984
2985         var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET;
2986
2987         // nonparticipating capturing group, copied from es5-shim's String#split patch.
2988         var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
2989
2990         var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$1;
2991
2992         if (PATCH) {
2993           patchedExec = function exec(str) {
2994             var re = this;
2995             var lastIndex, reCopy, match, i;
2996             var sticky = UNSUPPORTED_Y$1 && re.sticky;
2997             var flags = regexpFlags.call(re);
2998             var source = re.source;
2999             var charsAdded = 0;
3000             var strCopy = str;
3001
3002             if (sticky) {
3003               flags = flags.replace('y', '');
3004               if (flags.indexOf('g') === -1) {
3005                 flags += 'g';
3006               }
3007
3008               strCopy = String(str).slice(re.lastIndex);
3009               // Support anchored sticky behavior.
3010               if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
3011                 source = '(?: ' + source + ')';
3012                 strCopy = ' ' + strCopy;
3013                 charsAdded++;
3014               }
3015               // ^(? + rx + ) is needed, in combination with some str slicing, to
3016               // simulate the 'y' flag.
3017               reCopy = new RegExp('^(?:' + source + ')', flags);
3018             }
3019
3020             if (NPCG_INCLUDED) {
3021               reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
3022             }
3023             if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
3024
3025             match = nativeExec.call(sticky ? reCopy : re, strCopy);
3026
3027             if (sticky) {
3028               if (match) {
3029                 match.input = match.input.slice(charsAdded);
3030                 match[0] = match[0].slice(charsAdded);
3031                 match.index = re.lastIndex;
3032                 re.lastIndex += match[0].length;
3033               } else re.lastIndex = 0;
3034             } else if (UPDATES_LAST_INDEX_WRONG && match) {
3035               re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
3036             }
3037             if (NPCG_INCLUDED && match && match.length > 1) {
3038               // Fix browsers whose `exec` methods don't consistently return `undefined`
3039               // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
3040               nativeReplace.call(match[0], reCopy, function () {
3041                 for (i = 1; i < arguments.length - 2; i++) {
3042                   if (arguments[i] === undefined) match[i] = undefined;
3043                 }
3044               });
3045             }
3046
3047             return match;
3048           };
3049         }
3050
3051         var regexpExec = patchedExec;
3052
3053         _export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, {
3054           exec: regexpExec
3055         });
3056
3057         var TO_STRING$1 = 'toString';
3058         var RegExpPrototype = RegExp.prototype;
3059         var nativeToString = RegExpPrototype[TO_STRING$1];
3060
3061         var NOT_GENERIC = fails(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });
3062         // FF44- RegExp#toString has a wrong name
3063         var INCORRECT_NAME = nativeToString.name != TO_STRING$1;
3064
3065         // `RegExp.prototype.toString` method
3066         // https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring
3067         if (NOT_GENERIC || INCORRECT_NAME) {
3068           redefine(RegExp.prototype, TO_STRING$1, function toString() {
3069             var R = anObject(this);
3070             var p = String(R.source);
3071             var rf = R.flags;
3072             var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf);
3073             return '/' + p + '/' + f;
3074           }, { unsafe: true });
3075         }
3076
3077         // `String.prototype.{ codePointAt, at }` methods implementation
3078         var createMethod$2 = function (CONVERT_TO_STRING) {
3079           return function ($this, pos) {
3080             var S = String(requireObjectCoercible($this));
3081             var position = toInteger(pos);
3082             var size = S.length;
3083             var first, second;
3084             if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
3085             first = S.charCodeAt(position);
3086             return first < 0xD800 || first > 0xDBFF || position + 1 === size
3087               || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
3088                 ? CONVERT_TO_STRING ? S.charAt(position) : first
3089                 : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
3090           };
3091         };
3092
3093         var stringMultibyte = {
3094           // `String.prototype.codePointAt` method
3095           // https://tc39.github.io/ecma262/#sec-string.prototype.codepointat
3096           codeAt: createMethod$2(false),
3097           // `String.prototype.at` method
3098           // https://github.com/mathiasbynens/String.prototype.at
3099           charAt: createMethod$2(true)
3100         };
3101
3102         var charAt = stringMultibyte.charAt;
3103
3104
3105
3106         var STRING_ITERATOR = 'String Iterator';
3107         var setInternalState$4 = internalState.set;
3108         var getInternalState$4 = internalState.getterFor(STRING_ITERATOR);
3109
3110         // `String.prototype[@@iterator]` method
3111         // https://tc39.github.io/ecma262/#sec-string.prototype-@@iterator
3112         defineIterator(String, 'String', function (iterated) {
3113           setInternalState$4(this, {
3114             type: STRING_ITERATOR,
3115             string: String(iterated),
3116             index: 0
3117           });
3118         // `%StringIteratorPrototype%.next` method
3119         // https://tc39.github.io/ecma262/#sec-%stringiteratorprototype%.next
3120         }, function next() {
3121           var state = getInternalState$4(this);
3122           var string = state.string;
3123           var index = state.index;
3124           var point;
3125           if (index >= string.length) return { value: undefined, done: true };
3126           point = charAt(string, index);
3127           state.index += point.length;
3128           return { value: point, done: false };
3129         });
3130
3131         // TODO: Remove from `core-js@4` since it's moved to entry points
3132
3133
3134
3135
3136
3137
3138
3139         var SPECIES$6 = wellKnownSymbol('species');
3140
3141         var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
3142           // #replace needs built-in support for named groups.
3143           // #match works fine because it just return the exec results, even if it has
3144           // a "grops" property.
3145           var re = /./;
3146           re.exec = function () {
3147             var result = [];
3148             result.groups = { a: '7' };
3149             return result;
3150           };
3151           return ''.replace(re, '$<a>') !== '7';
3152         });
3153
3154         // IE <= 11 replaces $0 with the whole match, as if it was $&
3155         // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
3156         var REPLACE_KEEPS_$0 = (function () {
3157           return 'a'.replace(/./, '$0') === '$0';
3158         })();
3159
3160         var REPLACE = wellKnownSymbol('replace');
3161         // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
3162         var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
3163           if (/./[REPLACE]) {
3164             return /./[REPLACE]('a', '$0') === '';
3165           }
3166           return false;
3167         })();
3168
3169         // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
3170         // Weex JS has frozen built-in prototypes, so use try / catch wrapper
3171         var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
3172           var re = /(?:)/;
3173           var originalExec = re.exec;
3174           re.exec = function () { return originalExec.apply(this, arguments); };
3175           var result = 'ab'.split(re);
3176           return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
3177         });
3178
3179         var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
3180           var SYMBOL = wellKnownSymbol(KEY);
3181
3182           var DELEGATES_TO_SYMBOL = !fails(function () {
3183             // String methods call symbol-named RegEp methods
3184             var O = {};
3185             O[SYMBOL] = function () { return 7; };
3186             return ''[KEY](O) != 7;
3187           });
3188
3189           var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
3190             // Symbol-named RegExp methods call .exec
3191             var execCalled = false;
3192             var re = /a/;
3193
3194             if (KEY === 'split') {
3195               // We can't use real regex here since it causes deoptimization
3196               // and serious performance degradation in V8
3197               // https://github.com/zloirock/core-js/issues/306
3198               re = {};
3199               // RegExp[@@split] doesn't call the regex's exec method, but first creates
3200               // a new one. We need to return the patched regex when creating the new one.
3201               re.constructor = {};
3202               re.constructor[SPECIES$6] = function () { return re; };
3203               re.flags = '';
3204               re[SYMBOL] = /./[SYMBOL];
3205             }
3206
3207             re.exec = function () { execCalled = true; return null; };
3208
3209             re[SYMBOL]('');
3210             return !execCalled;
3211           });
3212
3213           if (
3214             !DELEGATES_TO_SYMBOL ||
3215             !DELEGATES_TO_EXEC ||
3216             (KEY === 'replace' && !(
3217               REPLACE_SUPPORTS_NAMED_GROUPS &&
3218               REPLACE_KEEPS_$0 &&
3219               !REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
3220             )) ||
3221             (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC)
3222           ) {
3223             var nativeRegExpMethod = /./[SYMBOL];
3224             var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
3225               if (regexp.exec === regexpExec) {
3226                 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
3227                   // The native String method already delegates to @@method (this
3228                   // polyfilled function), leasing to infinite recursion.
3229                   // We avoid it by directly calling the native @@method method.
3230                   return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
3231                 }
3232                 return { done: true, value: nativeMethod.call(str, regexp, arg2) };
3233               }
3234               return { done: false };
3235             }, {
3236               REPLACE_KEEPS_$0: REPLACE_KEEPS_$0,
3237               REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE: REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
3238             });
3239             var stringMethod = methods[0];
3240             var regexMethod = methods[1];
3241
3242             redefine(String.prototype, KEY, stringMethod);
3243             redefine(RegExp.prototype, SYMBOL, length == 2
3244               // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
3245               // 21.2.5.11 RegExp.prototype[@@split](string, limit)
3246               ? function (string, arg) { return regexMethod.call(string, this, arg); }
3247               // 21.2.5.6 RegExp.prototype[@@match](string)
3248               // 21.2.5.9 RegExp.prototype[@@search](string)
3249               : function (string) { return regexMethod.call(string, this); }
3250             );
3251           }
3252
3253           if (sham) createNonEnumerableProperty(RegExp.prototype[SYMBOL], 'sham', true);
3254         };
3255
3256         var charAt$1 = stringMultibyte.charAt;
3257
3258         // `AdvanceStringIndex` abstract operation
3259         // https://tc39.github.io/ecma262/#sec-advancestringindex
3260         var advanceStringIndex = function (S, index, unicode) {
3261           return index + (unicode ? charAt$1(S, index).length : 1);
3262         };
3263
3264         // `RegExpExec` abstract operation
3265         // https://tc39.github.io/ecma262/#sec-regexpexec
3266         var regexpExecAbstract = function (R, S) {
3267           var exec = R.exec;
3268           if (typeof exec === 'function') {
3269             var result = exec.call(R, S);
3270             if (typeof result !== 'object') {
3271               throw TypeError('RegExp exec method returned something other than an Object or null');
3272             }
3273             return result;
3274           }
3275
3276           if (classofRaw(R) !== 'RegExp') {
3277             throw TypeError('RegExp#exec called on incompatible receiver');
3278           }
3279
3280           return regexpExec.call(R, S);
3281         };
3282
3283         var max$2 = Math.max;
3284         var min$2 = Math.min;
3285         var floor$2 = Math.floor;
3286         var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d\d?|<[^>]*>)/g;
3287         var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d\d?)/g;
3288
3289         var maybeToString = function (it) {
3290           return it === undefined ? it : String(it);
3291         };
3292
3293         // @@replace logic
3294         fixRegexpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative, reason) {
3295           var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = reason.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE;
3296           var REPLACE_KEEPS_$0 = reason.REPLACE_KEEPS_$0;
3297           var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
3298
3299           return [
3300             // `String.prototype.replace` method
3301             // https://tc39.github.io/ecma262/#sec-string.prototype.replace
3302             function replace(searchValue, replaceValue) {
3303               var O = requireObjectCoercible(this);
3304               var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
3305               return replacer !== undefined
3306                 ? replacer.call(searchValue, O, replaceValue)
3307                 : nativeReplace.call(String(O), searchValue, replaceValue);
3308             },
3309             // `RegExp.prototype[@@replace]` method
3310             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace
3311             function (regexp, replaceValue) {
3312               if (
3313                 (!REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE && REPLACE_KEEPS_$0) ||
3314                 (typeof replaceValue === 'string' && replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1)
3315               ) {
3316                 var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
3317                 if (res.done) return res.value;
3318               }
3319
3320               var rx = anObject(regexp);
3321               var S = String(this);
3322
3323               var functionalReplace = typeof replaceValue === 'function';
3324               if (!functionalReplace) replaceValue = String(replaceValue);
3325
3326               var global = rx.global;
3327               if (global) {
3328                 var fullUnicode = rx.unicode;
3329                 rx.lastIndex = 0;
3330               }
3331               var results = [];
3332               while (true) {
3333                 var result = regexpExecAbstract(rx, S);
3334                 if (result === null) break;
3335
3336                 results.push(result);
3337                 if (!global) break;
3338
3339                 var matchStr = String(result[0]);
3340                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
3341               }
3342
3343               var accumulatedResult = '';
3344               var nextSourcePosition = 0;
3345               for (var i = 0; i < results.length; i++) {
3346                 result = results[i];
3347
3348                 var matched = String(result[0]);
3349                 var position = max$2(min$2(toInteger(result.index), S.length), 0);
3350                 var captures = [];
3351                 // NOTE: This is equivalent to
3352                 //   captures = result.slice(1).map(maybeToString)
3353                 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
3354                 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
3355                 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
3356                 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
3357                 var namedCaptures = result.groups;
3358                 if (functionalReplace) {
3359                   var replacerArgs = [matched].concat(captures, position, S);
3360                   if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
3361                   var replacement = String(replaceValue.apply(undefined, replacerArgs));
3362                 } else {
3363                   replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
3364                 }
3365                 if (position >= nextSourcePosition) {
3366                   accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
3367                   nextSourcePosition = position + matched.length;
3368                 }
3369               }
3370               return accumulatedResult + S.slice(nextSourcePosition);
3371             }
3372           ];
3373
3374           // https://tc39.github.io/ecma262/#sec-getsubstitution
3375           function getSubstitution(matched, str, position, captures, namedCaptures, replacement) {
3376             var tailPos = position + matched.length;
3377             var m = captures.length;
3378             var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
3379             if (namedCaptures !== undefined) {
3380               namedCaptures = toObject(namedCaptures);
3381               symbols = SUBSTITUTION_SYMBOLS;
3382             }
3383             return nativeReplace.call(replacement, symbols, function (match, ch) {
3384               var capture;
3385               switch (ch.charAt(0)) {
3386                 case '$': return '$';
3387                 case '&': return matched;
3388                 case '`': return str.slice(0, position);
3389                 case "'": return str.slice(tailPos);
3390                 case '<':
3391                   capture = namedCaptures[ch.slice(1, -1)];
3392                   break;
3393                 default: // \d\d?
3394                   var n = +ch;
3395                   if (n === 0) return match;
3396                   if (n > m) {
3397                     var f = floor$2(n / 10);
3398                     if (f === 0) return match;
3399                     if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
3400                     return match;
3401                   }
3402                   capture = captures[n - 1];
3403               }
3404               return capture === undefined ? '' : capture;
3405             });
3406           }
3407         });
3408
3409         var MATCH = wellKnownSymbol('match');
3410
3411         // `IsRegExp` abstract operation
3412         // https://tc39.github.io/ecma262/#sec-isregexp
3413         var isRegexp = function (it) {
3414           var isRegExp;
3415           return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
3416         };
3417
3418         var arrayPush = [].push;
3419         var min$3 = Math.min;
3420         var MAX_UINT32 = 0xFFFFFFFF;
3421
3422         // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError
3423         var SUPPORTS_Y = !fails(function () { return !RegExp(MAX_UINT32, 'y'); });
3424
3425         // @@split logic
3426         fixRegexpWellKnownSymbolLogic('split', 2, function (SPLIT, nativeSplit, maybeCallNative) {
3427           var internalSplit;
3428           if (
3429             'abbc'.split(/(b)*/)[1] == 'c' ||
3430             'test'.split(/(?:)/, -1).length != 4 ||
3431             'ab'.split(/(?:ab)*/).length != 2 ||
3432             '.'.split(/(.?)(.?)/).length != 4 ||
3433             '.'.split(/()()/).length > 1 ||
3434             ''.split(/.?/).length
3435           ) {
3436             // based on es5-shim implementation, need to rework it
3437             internalSplit = function (separator, limit) {
3438               var string = String(requireObjectCoercible(this));
3439               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
3440               if (lim === 0) return [];
3441               if (separator === undefined) return [string];
3442               // If `separator` is not a regex, use native split
3443               if (!isRegexp(separator)) {
3444                 return nativeSplit.call(string, separator, lim);
3445               }
3446               var output = [];
3447               var flags = (separator.ignoreCase ? 'i' : '') +
3448                           (separator.multiline ? 'm' : '') +
3449                           (separator.unicode ? 'u' : '') +
3450                           (separator.sticky ? 'y' : '');
3451               var lastLastIndex = 0;
3452               // Make `global` and avoid `lastIndex` issues by working with a copy
3453               var separatorCopy = new RegExp(separator.source, flags + 'g');
3454               var match, lastIndex, lastLength;
3455               while (match = regexpExec.call(separatorCopy, string)) {
3456                 lastIndex = separatorCopy.lastIndex;
3457                 if (lastIndex > lastLastIndex) {
3458                   output.push(string.slice(lastLastIndex, match.index));
3459                   if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
3460                   lastLength = match[0].length;
3461                   lastLastIndex = lastIndex;
3462                   if (output.length >= lim) break;
3463                 }
3464                 if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
3465               }
3466               if (lastLastIndex === string.length) {
3467                 if (lastLength || !separatorCopy.test('')) output.push('');
3468               } else output.push(string.slice(lastLastIndex));
3469               return output.length > lim ? output.slice(0, lim) : output;
3470             };
3471           // Chakra, V8
3472           } else if ('0'.split(undefined, 0).length) {
3473             internalSplit = function (separator, limit) {
3474               return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
3475             };
3476           } else internalSplit = nativeSplit;
3477
3478           return [
3479             // `String.prototype.split` method
3480             // https://tc39.github.io/ecma262/#sec-string.prototype.split
3481             function split(separator, limit) {
3482               var O = requireObjectCoercible(this);
3483               var splitter = separator == undefined ? undefined : separator[SPLIT];
3484               return splitter !== undefined
3485                 ? splitter.call(separator, O, limit)
3486                 : internalSplit.call(String(O), separator, limit);
3487             },
3488             // `RegExp.prototype[@@split]` method
3489             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@split
3490             //
3491             // NOTE: This cannot be properly polyfilled in engines that don't support
3492             // the 'y' flag.
3493             function (regexp, limit) {
3494               var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== nativeSplit);
3495               if (res.done) return res.value;
3496
3497               var rx = anObject(regexp);
3498               var S = String(this);
3499               var C = speciesConstructor(rx, RegExp);
3500
3501               var unicodeMatching = rx.unicode;
3502               var flags = (rx.ignoreCase ? 'i' : '') +
3503                           (rx.multiline ? 'm' : '') +
3504                           (rx.unicode ? 'u' : '') +
3505                           (SUPPORTS_Y ? 'y' : 'g');
3506
3507               // ^(? + rx + ) is needed, in combination with some S slicing, to
3508               // simulate the 'y' flag.
3509               var splitter = new C(SUPPORTS_Y ? rx : '^(?:' + rx.source + ')', flags);
3510               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
3511               if (lim === 0) return [];
3512               if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
3513               var p = 0;
3514               var q = 0;
3515               var A = [];
3516               while (q < S.length) {
3517                 splitter.lastIndex = SUPPORTS_Y ? q : 0;
3518                 var z = regexpExecAbstract(splitter, SUPPORTS_Y ? S : S.slice(q));
3519                 var e;
3520                 if (
3521                   z === null ||
3522                   (e = min$3(toLength(splitter.lastIndex + (SUPPORTS_Y ? 0 : q)), S.length)) === p
3523                 ) {
3524                   q = advanceStringIndex(S, q, unicodeMatching);
3525                 } else {
3526                   A.push(S.slice(p, q));
3527                   if (A.length === lim) return A;
3528                   for (var i = 1; i <= z.length - 1; i++) {
3529                     A.push(z[i]);
3530                     if (A.length === lim) return A;
3531                   }
3532                   q = p = e;
3533                 }
3534               }
3535               A.push(S.slice(p));
3536               return A;
3537             }
3538           ];
3539         }, !SUPPORTS_Y);
3540
3541         // a string of all valid unicode whitespaces
3542         // eslint-disable-next-line max-len
3543         var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
3544
3545         var whitespace = '[' + whitespaces + ']';
3546         var ltrim = RegExp('^' + whitespace + whitespace + '*');
3547         var rtrim = RegExp(whitespace + whitespace + '*$');
3548
3549         // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
3550         var createMethod$3 = function (TYPE) {
3551           return function ($this) {
3552             var string = String(requireObjectCoercible($this));
3553             if (TYPE & 1) string = string.replace(ltrim, '');
3554             if (TYPE & 2) string = string.replace(rtrim, '');
3555             return string;
3556           };
3557         };
3558
3559         var stringTrim = {
3560           // `String.prototype.{ trimLeft, trimStart }` methods
3561           // https://tc39.github.io/ecma262/#sec-string.prototype.trimstart
3562           start: createMethod$3(1),
3563           // `String.prototype.{ trimRight, trimEnd }` methods
3564           // https://tc39.github.io/ecma262/#sec-string.prototype.trimend
3565           end: createMethod$3(2),
3566           // `String.prototype.trim` method
3567           // https://tc39.github.io/ecma262/#sec-string.prototype.trim
3568           trim: createMethod$3(3)
3569         };
3570
3571         var non = '\u200B\u0085\u180E';
3572
3573         // check that a method works with the correct list
3574         // of whitespaces and has a correct name
3575         var stringTrimForced = function (METHOD_NAME) {
3576           return fails(function () {
3577             return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
3578           });
3579         };
3580
3581         var $trim = stringTrim.trim;
3582
3583
3584         // `String.prototype.trim` method
3585         // https://tc39.github.io/ecma262/#sec-string.prototype.trim
3586         _export({ target: 'String', proto: true, forced: stringTrimForced('trim') }, {
3587           trim: function trim() {
3588             return $trim(this);
3589           }
3590         });
3591
3592         /* eslint-disable no-new */
3593
3594
3595
3596         var NATIVE_ARRAY_BUFFER_VIEWS$2 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3597
3598         var ArrayBuffer$3 = global_1.ArrayBuffer;
3599         var Int8Array$2 = global_1.Int8Array;
3600
3601         var typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS$2 || !fails(function () {
3602           Int8Array$2(1);
3603         }) || !fails(function () {
3604           new Int8Array$2(-1);
3605         }) || !checkCorrectnessOfIteration(function (iterable) {
3606           new Int8Array$2();
3607           new Int8Array$2(null);
3608           new Int8Array$2(1.5);
3609           new Int8Array$2(iterable);
3610         }, true) || fails(function () {
3611           // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill
3612           return new Int8Array$2(new ArrayBuffer$3(2), 1, undefined).length !== 1;
3613         });
3614
3615         var toPositiveInteger = function (it) {
3616           var result = toInteger(it);
3617           if (result < 0) throw RangeError("The argument can't be less than 0");
3618           return result;
3619         };
3620
3621         var toOffset = function (it, BYTES) {
3622           var offset = toPositiveInteger(it);
3623           if (offset % BYTES) throw RangeError('Wrong offset');
3624           return offset;
3625         };
3626
3627         var aTypedArrayConstructor$1 = arrayBufferViewCore.aTypedArrayConstructor;
3628
3629         var typedArrayFrom = function from(source /* , mapfn, thisArg */) {
3630           var O = toObject(source);
3631           var argumentsLength = arguments.length;
3632           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
3633           var mapping = mapfn !== undefined;
3634           var iteratorMethod = getIteratorMethod(O);
3635           var i, length, result, step, iterator, next;
3636           if (iteratorMethod != undefined && !isArrayIteratorMethod(iteratorMethod)) {
3637             iterator = iteratorMethod.call(O);
3638             next = iterator.next;
3639             O = [];
3640             while (!(step = next.call(iterator)).done) {
3641               O.push(step.value);
3642             }
3643           }
3644           if (mapping && argumentsLength > 2) {
3645             mapfn = functionBindContext(mapfn, arguments[2], 2);
3646           }
3647           length = toLength(O.length);
3648           result = new (aTypedArrayConstructor$1(this))(length);
3649           for (i = 0; length > i; i++) {
3650             result[i] = mapping ? mapfn(O[i], i) : O[i];
3651           }
3652           return result;
3653         };
3654
3655         // makes subclassing work correct for wrapped built-ins
3656         var inheritIfRequired = function ($this, dummy, Wrapper) {
3657           var NewTarget, NewTargetPrototype;
3658           if (
3659             // it can work only with native `setPrototypeOf`
3660             objectSetPrototypeOf &&
3661             // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
3662             typeof (NewTarget = dummy.constructor) == 'function' &&
3663             NewTarget !== Wrapper &&
3664             isObject(NewTargetPrototype = NewTarget.prototype) &&
3665             NewTargetPrototype !== Wrapper.prototype
3666           ) objectSetPrototypeOf($this, NewTargetPrototype);
3667           return $this;
3668         };
3669
3670         var typedArrayConstructor = createCommonjsModule(function (module) {
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
3690
3691         var forEach = arrayIteration.forEach;
3692
3693
3694
3695
3696
3697
3698         var getInternalState = internalState.get;
3699         var setInternalState = internalState.set;
3700         var nativeDefineProperty = objectDefineProperty.f;
3701         var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
3702         var round = Math.round;
3703         var RangeError = global_1.RangeError;
3704         var ArrayBuffer = arrayBuffer.ArrayBuffer;
3705         var DataView = arrayBuffer.DataView;
3706         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3707         var TYPED_ARRAY_TAG = arrayBufferViewCore.TYPED_ARRAY_TAG;
3708         var TypedArray = arrayBufferViewCore.TypedArray;
3709         var TypedArrayPrototype = arrayBufferViewCore.TypedArrayPrototype;
3710         var aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;
3711         var isTypedArray = arrayBufferViewCore.isTypedArray;
3712         var BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';
3713         var WRONG_LENGTH = 'Wrong length';
3714
3715         var fromList = function (C, list) {
3716           var index = 0;
3717           var length = list.length;
3718           var result = new (aTypedArrayConstructor(C))(length);
3719           while (length > index) result[index] = list[index++];
3720           return result;
3721         };
3722
3723         var addGetter = function (it, key) {
3724           nativeDefineProperty(it, key, { get: function () {
3725             return getInternalState(this)[key];
3726           } });
3727         };
3728
3729         var isArrayBuffer = function (it) {
3730           var klass;
3731           return it instanceof ArrayBuffer || (klass = classof(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';
3732         };
3733
3734         var isTypedArrayIndex = function (target, key) {
3735           return isTypedArray(target)
3736             && typeof key != 'symbol'
3737             && key in target
3738             && String(+key) == String(key);
3739         };
3740
3741         var wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {
3742           return isTypedArrayIndex(target, key = toPrimitive(key, true))
3743             ? createPropertyDescriptor(2, target[key])
3744             : nativeGetOwnPropertyDescriptor(target, key);
3745         };
3746
3747         var wrappedDefineProperty = function defineProperty(target, key, descriptor) {
3748           if (isTypedArrayIndex(target, key = toPrimitive(key, true))
3749             && isObject(descriptor)
3750             && has(descriptor, 'value')
3751             && !has(descriptor, 'get')
3752             && !has(descriptor, 'set')
3753             // TODO: add validation descriptor w/o calling accessors
3754             && !descriptor.configurable
3755             && (!has(descriptor, 'writable') || descriptor.writable)
3756             && (!has(descriptor, 'enumerable') || descriptor.enumerable)
3757           ) {
3758             target[key] = descriptor.value;
3759             return target;
3760           } return nativeDefineProperty(target, key, descriptor);
3761         };
3762
3763         if (descriptors) {
3764           if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3765             objectGetOwnPropertyDescriptor.f = wrappedGetOwnPropertyDescriptor;
3766             objectDefineProperty.f = wrappedDefineProperty;
3767             addGetter(TypedArrayPrototype, 'buffer');
3768             addGetter(TypedArrayPrototype, 'byteOffset');
3769             addGetter(TypedArrayPrototype, 'byteLength');
3770             addGetter(TypedArrayPrototype, 'length');
3771           }
3772
3773           _export({ target: 'Object', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS }, {
3774             getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,
3775             defineProperty: wrappedDefineProperty
3776           });
3777
3778           module.exports = function (TYPE, wrapper, CLAMPED) {
3779             var BYTES = TYPE.match(/\d+$/)[0] / 8;
3780             var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';
3781             var GETTER = 'get' + TYPE;
3782             var SETTER = 'set' + TYPE;
3783             var NativeTypedArrayConstructor = global_1[CONSTRUCTOR_NAME];
3784             var TypedArrayConstructor = NativeTypedArrayConstructor;
3785             var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;
3786             var exported = {};
3787
3788             var getter = function (that, index) {
3789               var data = getInternalState(that);
3790               return data.view[GETTER](index * BYTES + data.byteOffset, true);
3791             };
3792
3793             var setter = function (that, index, value) {
3794               var data = getInternalState(that);
3795               if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;
3796               data.view[SETTER](index * BYTES + data.byteOffset, value, true);
3797             };
3798
3799             var addElement = function (that, index) {
3800               nativeDefineProperty(that, index, {
3801                 get: function () {
3802                   return getter(this, index);
3803                 },
3804                 set: function (value) {
3805                   return setter(this, index, value);
3806                 },
3807                 enumerable: true
3808               });
3809             };
3810
3811             if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3812               TypedArrayConstructor = wrapper(function (that, data, offset, $length) {
3813                 anInstance(that, TypedArrayConstructor, CONSTRUCTOR_NAME);
3814                 var index = 0;
3815                 var byteOffset = 0;
3816                 var buffer, byteLength, length;
3817                 if (!isObject(data)) {
3818                   length = toIndex(data);
3819                   byteLength = length * BYTES;
3820                   buffer = new ArrayBuffer(byteLength);
3821                 } else if (isArrayBuffer(data)) {
3822                   buffer = data;
3823                   byteOffset = toOffset(offset, BYTES);
3824                   var $len = data.byteLength;
3825                   if ($length === undefined) {
3826                     if ($len % BYTES) throw RangeError(WRONG_LENGTH);
3827                     byteLength = $len - byteOffset;
3828                     if (byteLength < 0) throw RangeError(WRONG_LENGTH);
3829                   } else {
3830                     byteLength = toLength($length) * BYTES;
3831                     if (byteLength + byteOffset > $len) throw RangeError(WRONG_LENGTH);
3832                   }
3833                   length = byteLength / BYTES;
3834                 } else if (isTypedArray(data)) {
3835                   return fromList(TypedArrayConstructor, data);
3836                 } else {
3837                   return typedArrayFrom.call(TypedArrayConstructor, data);
3838                 }
3839                 setInternalState(that, {
3840                   buffer: buffer,
3841                   byteOffset: byteOffset,
3842                   byteLength: byteLength,
3843                   length: length,
3844                   view: new DataView(buffer)
3845                 });
3846                 while (index < length) addElement(that, index++);
3847               });
3848
3849               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3850               TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = objectCreate(TypedArrayPrototype);
3851             } else if (typedArrayConstructorsRequireWrappers) {
3852               TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {
3853                 anInstance(dummy, TypedArrayConstructor, CONSTRUCTOR_NAME);
3854                 return inheritIfRequired(function () {
3855                   if (!isObject(data)) return new NativeTypedArrayConstructor(toIndex(data));
3856                   if (isArrayBuffer(data)) return $length !== undefined
3857                     ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES), $length)
3858                     : typedArrayOffset !== undefined
3859                       ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES))
3860                       : new NativeTypedArrayConstructor(data);
3861                   if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);
3862                   return typedArrayFrom.call(TypedArrayConstructor, data);
3863                 }(), dummy, TypedArrayConstructor);
3864               });
3865
3866               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3867               forEach(getOwnPropertyNames(NativeTypedArrayConstructor), function (key) {
3868                 if (!(key in TypedArrayConstructor)) {
3869                   createNonEnumerableProperty(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);
3870                 }
3871               });
3872               TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;
3873             }
3874
3875             if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {
3876               createNonEnumerableProperty(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);
3877             }
3878
3879             if (TYPED_ARRAY_TAG) {
3880               createNonEnumerableProperty(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);
3881             }
3882
3883             exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;
3884
3885             _export({
3886               global: true, forced: TypedArrayConstructor != NativeTypedArrayConstructor, sham: !NATIVE_ARRAY_BUFFER_VIEWS
3887             }, exported);
3888
3889             if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {
3890               createNonEnumerableProperty(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);
3891             }
3892
3893             if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {
3894               createNonEnumerableProperty(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);
3895             }
3896
3897             setSpecies(CONSTRUCTOR_NAME);
3898           };
3899         } else module.exports = function () { /* empty */ };
3900         });
3901
3902         // `Uint8Array` constructor
3903         // https://tc39.github.io/ecma262/#sec-typedarray-objects
3904         typedArrayConstructor('Uint8', function (init) {
3905           return function Uint8Array(data, byteOffset, length) {
3906             return init(this, data, byteOffset, length);
3907           };
3908         });
3909
3910         var min$4 = Math.min;
3911
3912         // `Array.prototype.copyWithin` method implementation
3913         // https://tc39.github.io/ecma262/#sec-array.prototype.copywithin
3914         var arrayCopyWithin = [].copyWithin || function copyWithin(target /* = 0 */, start /* = 0, end = @length */) {
3915           var O = toObject(this);
3916           var len = toLength(O.length);
3917           var to = toAbsoluteIndex(target, len);
3918           var from = toAbsoluteIndex(start, len);
3919           var end = arguments.length > 2 ? arguments[2] : undefined;
3920           var count = min$4((end === undefined ? len : toAbsoluteIndex(end, len)) - from, len - to);
3921           var inc = 1;
3922           if (from < to && to < from + count) {
3923             inc = -1;
3924             from += count - 1;
3925             to += count - 1;
3926           }
3927           while (count-- > 0) {
3928             if (from in O) O[to] = O[from];
3929             else delete O[to];
3930             to += inc;
3931             from += inc;
3932           } return O;
3933         };
3934
3935         var aTypedArray$1 = arrayBufferViewCore.aTypedArray;
3936         var exportTypedArrayMethod$1 = arrayBufferViewCore.exportTypedArrayMethod;
3937
3938         // `%TypedArray%.prototype.copyWithin` method
3939         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.copywithin
3940         exportTypedArrayMethod$1('copyWithin', function copyWithin(target, start /* , end */) {
3941           return arrayCopyWithin.call(aTypedArray$1(this), target, start, arguments.length > 2 ? arguments[2] : undefined);
3942         });
3943
3944         var $every = arrayIteration.every;
3945
3946         var aTypedArray$2 = arrayBufferViewCore.aTypedArray;
3947         var exportTypedArrayMethod$2 = arrayBufferViewCore.exportTypedArrayMethod;
3948
3949         // `%TypedArray%.prototype.every` method
3950         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every
3951         exportTypedArrayMethod$2('every', function every(callbackfn /* , thisArg */) {
3952           return $every(aTypedArray$2(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3953         });
3954
3955         var aTypedArray$3 = arrayBufferViewCore.aTypedArray;
3956         var exportTypedArrayMethod$3 = arrayBufferViewCore.exportTypedArrayMethod;
3957
3958         // `%TypedArray%.prototype.fill` method
3959         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.fill
3960         // eslint-disable-next-line no-unused-vars
3961         exportTypedArrayMethod$3('fill', function fill(value /* , start, end */) {
3962           return arrayFill.apply(aTypedArray$3(this), arguments);
3963         });
3964
3965         var $filter = arrayIteration.filter;
3966
3967
3968         var aTypedArray$4 = arrayBufferViewCore.aTypedArray;
3969         var aTypedArrayConstructor$2 = arrayBufferViewCore.aTypedArrayConstructor;
3970         var exportTypedArrayMethod$4 = arrayBufferViewCore.exportTypedArrayMethod;
3971
3972         // `%TypedArray%.prototype.filter` method
3973         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter
3974         exportTypedArrayMethod$4('filter', function filter(callbackfn /* , thisArg */) {
3975           var list = $filter(aTypedArray$4(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3976           var C = speciesConstructor(this, this.constructor);
3977           var index = 0;
3978           var length = list.length;
3979           var result = new (aTypedArrayConstructor$2(C))(length);
3980           while (length > index) result[index] = list[index++];
3981           return result;
3982         });
3983
3984         var $find = arrayIteration.find;
3985
3986         var aTypedArray$5 = arrayBufferViewCore.aTypedArray;
3987         var exportTypedArrayMethod$5 = arrayBufferViewCore.exportTypedArrayMethod;
3988
3989         // `%TypedArray%.prototype.find` method
3990         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.find
3991         exportTypedArrayMethod$5('find', function find(predicate /* , thisArg */) {
3992           return $find(aTypedArray$5(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
3993         });
3994
3995         var $findIndex = arrayIteration.findIndex;
3996
3997         var aTypedArray$6 = arrayBufferViewCore.aTypedArray;
3998         var exportTypedArrayMethod$6 = arrayBufferViewCore.exportTypedArrayMethod;
3999
4000         // `%TypedArray%.prototype.findIndex` method
4001         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.findindex
4002         exportTypedArrayMethod$6('findIndex', function findIndex(predicate /* , thisArg */) {
4003           return $findIndex(aTypedArray$6(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
4004         });
4005
4006         var $forEach$2 = arrayIteration.forEach;
4007
4008         var aTypedArray$7 = arrayBufferViewCore.aTypedArray;
4009         var exportTypedArrayMethod$7 = arrayBufferViewCore.exportTypedArrayMethod;
4010
4011         // `%TypedArray%.prototype.forEach` method
4012         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.foreach
4013         exportTypedArrayMethod$7('forEach', function forEach(callbackfn /* , thisArg */) {
4014           $forEach$2(aTypedArray$7(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4015         });
4016
4017         var $includes = arrayIncludes.includes;
4018
4019         var aTypedArray$8 = arrayBufferViewCore.aTypedArray;
4020         var exportTypedArrayMethod$8 = arrayBufferViewCore.exportTypedArrayMethod;
4021
4022         // `%TypedArray%.prototype.includes` method
4023         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.includes
4024         exportTypedArrayMethod$8('includes', function includes(searchElement /* , fromIndex */) {
4025           return $includes(aTypedArray$8(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4026         });
4027
4028         var $indexOf$1 = arrayIncludes.indexOf;
4029
4030         var aTypedArray$9 = arrayBufferViewCore.aTypedArray;
4031         var exportTypedArrayMethod$9 = arrayBufferViewCore.exportTypedArrayMethod;
4032
4033         // `%TypedArray%.prototype.indexOf` method
4034         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.indexof
4035         exportTypedArrayMethod$9('indexOf', function indexOf(searchElement /* , fromIndex */) {
4036           return $indexOf$1(aTypedArray$9(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4037         });
4038
4039         var ITERATOR$5 = wellKnownSymbol('iterator');
4040         var Uint8Array$1 = global_1.Uint8Array;
4041         var arrayValues = es_array_iterator.values;
4042         var arrayKeys = es_array_iterator.keys;
4043         var arrayEntries = es_array_iterator.entries;
4044         var aTypedArray$a = arrayBufferViewCore.aTypedArray;
4045         var exportTypedArrayMethod$a = arrayBufferViewCore.exportTypedArrayMethod;
4046         var nativeTypedArrayIterator = Uint8Array$1 && Uint8Array$1.prototype[ITERATOR$5];
4047
4048         var CORRECT_ITER_NAME = !!nativeTypedArrayIterator
4049           && (nativeTypedArrayIterator.name == 'values' || nativeTypedArrayIterator.name == undefined);
4050
4051         var typedArrayValues = function values() {
4052           return arrayValues.call(aTypedArray$a(this));
4053         };
4054
4055         // `%TypedArray%.prototype.entries` method
4056         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.entries
4057         exportTypedArrayMethod$a('entries', function entries() {
4058           return arrayEntries.call(aTypedArray$a(this));
4059         });
4060         // `%TypedArray%.prototype.keys` method
4061         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.keys
4062         exportTypedArrayMethod$a('keys', function keys() {
4063           return arrayKeys.call(aTypedArray$a(this));
4064         });
4065         // `%TypedArray%.prototype.values` method
4066         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.values
4067         exportTypedArrayMethod$a('values', typedArrayValues, !CORRECT_ITER_NAME);
4068         // `%TypedArray%.prototype[@@iterator]` method
4069         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype-@@iterator
4070         exportTypedArrayMethod$a(ITERATOR$5, typedArrayValues, !CORRECT_ITER_NAME);
4071
4072         var aTypedArray$b = arrayBufferViewCore.aTypedArray;
4073         var exportTypedArrayMethod$b = arrayBufferViewCore.exportTypedArrayMethod;
4074         var $join = [].join;
4075
4076         // `%TypedArray%.prototype.join` method
4077         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join
4078         // eslint-disable-next-line no-unused-vars
4079         exportTypedArrayMethod$b('join', function join(separator) {
4080           return $join.apply(aTypedArray$b(this), arguments);
4081         });
4082
4083         var min$5 = Math.min;
4084         var nativeLastIndexOf = [].lastIndexOf;
4085         var NEGATIVE_ZERO$1 = !!nativeLastIndexOf && 1 / [1].lastIndexOf(1, -0) < 0;
4086         var STRICT_METHOD$3 = arrayMethodIsStrict('lastIndexOf');
4087         // For preventing possible almost infinite loop in non-standard implementations, test the forward version of the method
4088         var USES_TO_LENGTH$4 = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });
4089         var FORCED$1 = NEGATIVE_ZERO$1 || !STRICT_METHOD$3 || !USES_TO_LENGTH$4;
4090
4091         // `Array.prototype.lastIndexOf` method implementation
4092         // https://tc39.github.io/ecma262/#sec-array.prototype.lastindexof
4093         var arrayLastIndexOf = FORCED$1 ? function lastIndexOf(searchElement /* , fromIndex = @[*-1] */) {
4094           // convert -0 to +0
4095           if (NEGATIVE_ZERO$1) return nativeLastIndexOf.apply(this, arguments) || 0;
4096           var O = toIndexedObject(this);
4097           var length = toLength(O.length);
4098           var index = length - 1;
4099           if (arguments.length > 1) index = min$5(index, toInteger(arguments[1]));
4100           if (index < 0) index = length + index;
4101           for (;index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;
4102           return -1;
4103         } : nativeLastIndexOf;
4104
4105         var aTypedArray$c = arrayBufferViewCore.aTypedArray;
4106         var exportTypedArrayMethod$c = arrayBufferViewCore.exportTypedArrayMethod;
4107
4108         // `%TypedArray%.prototype.lastIndexOf` method
4109         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.lastindexof
4110         // eslint-disable-next-line no-unused-vars
4111         exportTypedArrayMethod$c('lastIndexOf', function lastIndexOf(searchElement /* , fromIndex */) {
4112           return arrayLastIndexOf.apply(aTypedArray$c(this), arguments);
4113         });
4114
4115         var $map$1 = arrayIteration.map;
4116
4117
4118         var aTypedArray$d = arrayBufferViewCore.aTypedArray;
4119         var aTypedArrayConstructor$3 = arrayBufferViewCore.aTypedArrayConstructor;
4120         var exportTypedArrayMethod$d = arrayBufferViewCore.exportTypedArrayMethod;
4121
4122         // `%TypedArray%.prototype.map` method
4123         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.map
4124         exportTypedArrayMethod$d('map', function map(mapfn /* , thisArg */) {
4125           return $map$1(aTypedArray$d(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {
4126             return new (aTypedArrayConstructor$3(speciesConstructor(O, O.constructor)))(length);
4127           });
4128         });
4129
4130         // `Array.prototype.{ reduce, reduceRight }` methods implementation
4131         var createMethod$4 = function (IS_RIGHT) {
4132           return function (that, callbackfn, argumentsLength, memo) {
4133             aFunction$1(callbackfn);
4134             var O = toObject(that);
4135             var self = indexedObject(O);
4136             var length = toLength(O.length);
4137             var index = IS_RIGHT ? length - 1 : 0;
4138             var i = IS_RIGHT ? -1 : 1;
4139             if (argumentsLength < 2) while (true) {
4140               if (index in self) {
4141                 memo = self[index];
4142                 index += i;
4143                 break;
4144               }
4145               index += i;
4146               if (IS_RIGHT ? index < 0 : length <= index) {
4147                 throw TypeError('Reduce of empty array with no initial value');
4148               }
4149             }
4150             for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
4151               memo = callbackfn(memo, self[index], index, O);
4152             }
4153             return memo;
4154           };
4155         };
4156
4157         var arrayReduce = {
4158           // `Array.prototype.reduce` method
4159           // https://tc39.github.io/ecma262/#sec-array.prototype.reduce
4160           left: createMethod$4(false),
4161           // `Array.prototype.reduceRight` method
4162           // https://tc39.github.io/ecma262/#sec-array.prototype.reduceright
4163           right: createMethod$4(true)
4164         };
4165
4166         var $reduce = arrayReduce.left;
4167
4168         var aTypedArray$e = arrayBufferViewCore.aTypedArray;
4169         var exportTypedArrayMethod$e = arrayBufferViewCore.exportTypedArrayMethod;
4170
4171         // `%TypedArray%.prototype.reduce` method
4172         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduce
4173         exportTypedArrayMethod$e('reduce', function reduce(callbackfn /* , initialValue */) {
4174           return $reduce(aTypedArray$e(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4175         });
4176
4177         var $reduceRight = arrayReduce.right;
4178
4179         var aTypedArray$f = arrayBufferViewCore.aTypedArray;
4180         var exportTypedArrayMethod$f = arrayBufferViewCore.exportTypedArrayMethod;
4181
4182         // `%TypedArray%.prototype.reduceRicht` method
4183         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduceright
4184         exportTypedArrayMethod$f('reduceRight', function reduceRight(callbackfn /* , initialValue */) {
4185           return $reduceRight(aTypedArray$f(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4186         });
4187
4188         var aTypedArray$g = arrayBufferViewCore.aTypedArray;
4189         var exportTypedArrayMethod$g = arrayBufferViewCore.exportTypedArrayMethod;
4190         var floor$3 = Math.floor;
4191
4192         // `%TypedArray%.prototype.reverse` method
4193         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reverse
4194         exportTypedArrayMethod$g('reverse', function reverse() {
4195           var that = this;
4196           var length = aTypedArray$g(that).length;
4197           var middle = floor$3(length / 2);
4198           var index = 0;
4199           var value;
4200           while (index < middle) {
4201             value = that[index];
4202             that[index++] = that[--length];
4203             that[length] = value;
4204           } return that;
4205         });
4206
4207         var aTypedArray$h = arrayBufferViewCore.aTypedArray;
4208         var exportTypedArrayMethod$h = arrayBufferViewCore.exportTypedArrayMethod;
4209
4210         var FORCED$2 = fails(function () {
4211           // eslint-disable-next-line no-undef
4212           new Int8Array(1).set({});
4213         });
4214
4215         // `%TypedArray%.prototype.set` method
4216         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.set
4217         exportTypedArrayMethod$h('set', function set(arrayLike /* , offset */) {
4218           aTypedArray$h(this);
4219           var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
4220           var length = this.length;
4221           var src = toObject(arrayLike);
4222           var len = toLength(src.length);
4223           var index = 0;
4224           if (len + offset > length) throw RangeError('Wrong length');
4225           while (index < len) this[offset + index] = src[index++];
4226         }, FORCED$2);
4227
4228         var aTypedArray$i = arrayBufferViewCore.aTypedArray;
4229         var aTypedArrayConstructor$4 = arrayBufferViewCore.aTypedArrayConstructor;
4230         var exportTypedArrayMethod$i = arrayBufferViewCore.exportTypedArrayMethod;
4231         var $slice = [].slice;
4232
4233         var FORCED$3 = fails(function () {
4234           // eslint-disable-next-line no-undef
4235           new Int8Array(1).slice();
4236         });
4237
4238         // `%TypedArray%.prototype.slice` method
4239         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.slice
4240         exportTypedArrayMethod$i('slice', function slice(start, end) {
4241           var list = $slice.call(aTypedArray$i(this), start, end);
4242           var C = speciesConstructor(this, this.constructor);
4243           var index = 0;
4244           var length = list.length;
4245           var result = new (aTypedArrayConstructor$4(C))(length);
4246           while (length > index) result[index] = list[index++];
4247           return result;
4248         }, FORCED$3);
4249
4250         var $some = arrayIteration.some;
4251
4252         var aTypedArray$j = arrayBufferViewCore.aTypedArray;
4253         var exportTypedArrayMethod$j = arrayBufferViewCore.exportTypedArrayMethod;
4254
4255         // `%TypedArray%.prototype.some` method
4256         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.some
4257         exportTypedArrayMethod$j('some', function some(callbackfn /* , thisArg */) {
4258           return $some(aTypedArray$j(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4259         });
4260
4261         var aTypedArray$k = arrayBufferViewCore.aTypedArray;
4262         var exportTypedArrayMethod$k = arrayBufferViewCore.exportTypedArrayMethod;
4263         var $sort = [].sort;
4264
4265         // `%TypedArray%.prototype.sort` method
4266         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort
4267         exportTypedArrayMethod$k('sort', function sort(comparefn) {
4268           return $sort.call(aTypedArray$k(this), comparefn);
4269         });
4270
4271         var aTypedArray$l = arrayBufferViewCore.aTypedArray;
4272         var exportTypedArrayMethod$l = arrayBufferViewCore.exportTypedArrayMethod;
4273
4274         // `%TypedArray%.prototype.subarray` method
4275         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.subarray
4276         exportTypedArrayMethod$l('subarray', function subarray(begin, end) {
4277           var O = aTypedArray$l(this);
4278           var length = O.length;
4279           var beginIndex = toAbsoluteIndex(begin, length);
4280           return new (speciesConstructor(O, O.constructor))(
4281             O.buffer,
4282             O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT,
4283             toLength((end === undefined ? length : toAbsoluteIndex(end, length)) - beginIndex)
4284           );
4285         });
4286
4287         var Int8Array$3 = global_1.Int8Array;
4288         var aTypedArray$m = arrayBufferViewCore.aTypedArray;
4289         var exportTypedArrayMethod$m = arrayBufferViewCore.exportTypedArrayMethod;
4290         var $toLocaleString = [].toLocaleString;
4291         var $slice$1 = [].slice;
4292
4293         // iOS Safari 6.x fails here
4294         var TO_LOCALE_STRING_BUG = !!Int8Array$3 && fails(function () {
4295           $toLocaleString.call(new Int8Array$3(1));
4296         });
4297
4298         var FORCED$4 = fails(function () {
4299           return [1, 2].toLocaleString() != new Int8Array$3([1, 2]).toLocaleString();
4300         }) || !fails(function () {
4301           Int8Array$3.prototype.toLocaleString.call([1, 2]);
4302         });
4303
4304         // `%TypedArray%.prototype.toLocaleString` method
4305         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring
4306         exportTypedArrayMethod$m('toLocaleString', function toLocaleString() {
4307           return $toLocaleString.apply(TO_LOCALE_STRING_BUG ? $slice$1.call(aTypedArray$m(this)) : aTypedArray$m(this), arguments);
4308         }, FORCED$4);
4309
4310         var exportTypedArrayMethod$n = arrayBufferViewCore.exportTypedArrayMethod;
4311
4312
4313
4314         var Uint8Array$2 = global_1.Uint8Array;
4315         var Uint8ArrayPrototype = Uint8Array$2 && Uint8Array$2.prototype || {};
4316         var arrayToString = [].toString;
4317         var arrayJoin = [].join;
4318
4319         if (fails(function () { arrayToString.call({}); })) {
4320           arrayToString = function toString() {
4321             return arrayJoin.call(this);
4322           };
4323         }
4324
4325         var IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString;
4326
4327         // `%TypedArray%.prototype.toString` method
4328         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tostring
4329         exportTypedArrayMethod$n('toString', arrayToString, IS_NOT_ARRAY_METHOD);
4330
4331         // iterable DOM collections
4332         // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
4333         var domIterables = {
4334           CSSRuleList: 0,
4335           CSSStyleDeclaration: 0,
4336           CSSValueList: 0,
4337           ClientRectList: 0,
4338           DOMRectList: 0,
4339           DOMStringList: 0,
4340           DOMTokenList: 1,
4341           DataTransferItemList: 0,
4342           FileList: 0,
4343           HTMLAllCollection: 0,
4344           HTMLCollection: 0,
4345           HTMLFormElement: 0,
4346           HTMLSelectElement: 0,
4347           MediaList: 0,
4348           MimeTypeArray: 0,
4349           NamedNodeMap: 0,
4350           NodeList: 1,
4351           PaintRequestList: 0,
4352           Plugin: 0,
4353           PluginArray: 0,
4354           SVGLengthList: 0,
4355           SVGNumberList: 0,
4356           SVGPathSegList: 0,
4357           SVGPointList: 0,
4358           SVGStringList: 0,
4359           SVGTransformList: 0,
4360           SourceBufferList: 0,
4361           StyleSheetList: 0,
4362           TextTrackCueList: 0,
4363           TextTrackList: 0,
4364           TouchList: 0
4365         };
4366
4367         for (var COLLECTION_NAME in domIterables) {
4368           var Collection = global_1[COLLECTION_NAME];
4369           var CollectionPrototype = Collection && Collection.prototype;
4370           // some Chrome versions have non-configurable methods on DOMTokenList
4371           if (CollectionPrototype && CollectionPrototype.forEach !== arrayForEach) try {
4372             createNonEnumerableProperty(CollectionPrototype, 'forEach', arrayForEach);
4373           } catch (error) {
4374             CollectionPrototype.forEach = arrayForEach;
4375           }
4376         }
4377
4378         var ITERATOR$6 = wellKnownSymbol('iterator');
4379         var TO_STRING_TAG$4 = wellKnownSymbol('toStringTag');
4380         var ArrayValues = es_array_iterator.values;
4381
4382         for (var COLLECTION_NAME$1 in domIterables) {
4383           var Collection$1 = global_1[COLLECTION_NAME$1];
4384           var CollectionPrototype$1 = Collection$1 && Collection$1.prototype;
4385           if (CollectionPrototype$1) {
4386             // some Chrome versions have non-configurable methods on DOMTokenList
4387             if (CollectionPrototype$1[ITERATOR$6] !== ArrayValues) try {
4388               createNonEnumerableProperty(CollectionPrototype$1, ITERATOR$6, ArrayValues);
4389             } catch (error) {
4390               CollectionPrototype$1[ITERATOR$6] = ArrayValues;
4391             }
4392             if (!CollectionPrototype$1[TO_STRING_TAG$4]) {
4393               createNonEnumerableProperty(CollectionPrototype$1, TO_STRING_TAG$4, COLLECTION_NAME$1);
4394             }
4395             if (domIterables[COLLECTION_NAME$1]) for (var METHOD_NAME in es_array_iterator) {
4396               // some Chrome versions have non-configurable methods on DOMTokenList
4397               if (CollectionPrototype$1[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
4398                 createNonEnumerableProperty(CollectionPrototype$1, METHOD_NAME, es_array_iterator[METHOD_NAME]);
4399               } catch (error) {
4400                 CollectionPrototype$1[METHOD_NAME] = es_array_iterator[METHOD_NAME];
4401               }
4402             }
4403           }
4404         }
4405
4406         var slice = [].slice;
4407         var MSIE = /MSIE .\./.test(engineUserAgent); // <- dirty ie9- check
4408
4409         var wrap$1 = function (scheduler) {
4410           return function (handler, timeout /* , ...arguments */) {
4411             var boundArgs = arguments.length > 2;
4412             var args = boundArgs ? slice.call(arguments, 2) : undefined;
4413             return scheduler(boundArgs ? function () {
4414               // eslint-disable-next-line no-new-func
4415               (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
4416             } : handler, timeout);
4417           };
4418         };
4419
4420         // ie9- setTimeout & setInterval additional parameters fix
4421         // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
4422         _export({ global: true, bind: true, forced: MSIE }, {
4423           // `setTimeout` method
4424           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
4425           setTimeout: wrap$1(global_1.setTimeout),
4426           // `setInterval` method
4427           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
4428           setInterval: wrap$1(global_1.setInterval)
4429         });
4430
4431         var ITERATOR$7 = wellKnownSymbol('iterator');
4432
4433         var nativeUrl = !fails(function () {
4434           var url = new URL('b?a=1&b=2&c=3', 'http://a');
4435           var searchParams = url.searchParams;
4436           var result = '';
4437           url.pathname = 'c%20d';
4438           searchParams.forEach(function (value, key) {
4439             searchParams['delete']('b');
4440             result += key + value;
4441           });
4442           return (isPure && !url.toJSON)
4443             || !searchParams.sort
4444             || url.href !== 'http://a/c%20d?a=1&c=3'
4445             || searchParams.get('c') !== '3'
4446             || String(new URLSearchParams('?a=1')) !== 'a=1'
4447             || !searchParams[ITERATOR$7]
4448             // throws in Edge
4449             || new URL('https://a@b').username !== 'a'
4450             || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b'
4451             // not punycoded in Edge
4452             || new URL('http://тест').host !== 'xn--e1aybc'
4453             // not escaped in Chrome 62-
4454             || new URL('http://a#б').hash !== '#%D0%B1'
4455             // fails in Chrome 66-
4456             || result !== 'a1c3'
4457             // throws in Safari
4458             || new URL('http://x', undefined).host !== 'x';
4459         });
4460
4461         var nativeAssign = Object.assign;
4462         var defineProperty$7 = Object.defineProperty;
4463
4464         // `Object.assign` method
4465         // https://tc39.github.io/ecma262/#sec-object.assign
4466         var objectAssign = !nativeAssign || fails(function () {
4467           // should have correct order of operations (Edge bug)
4468           if (descriptors && nativeAssign({ b: 1 }, nativeAssign(defineProperty$7({}, 'a', {
4469             enumerable: true,
4470             get: function () {
4471               defineProperty$7(this, 'b', {
4472                 value: 3,
4473                 enumerable: false
4474               });
4475             }
4476           }), { b: 2 })).b !== 1) return true;
4477           // should work with symbols and should have deterministic property order (V8 bug)
4478           var A = {};
4479           var B = {};
4480           // eslint-disable-next-line no-undef
4481           var symbol = Symbol();
4482           var alphabet = 'abcdefghijklmnopqrst';
4483           A[symbol] = 7;
4484           alphabet.split('').forEach(function (chr) { B[chr] = chr; });
4485           return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
4486         }) ? function assign(target, source) { // eslint-disable-line no-unused-vars
4487           var T = toObject(target);
4488           var argumentsLength = arguments.length;
4489           var index = 1;
4490           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
4491           var propertyIsEnumerable = objectPropertyIsEnumerable.f;
4492           while (argumentsLength > index) {
4493             var S = indexedObject(arguments[index++]);
4494             var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
4495             var length = keys.length;
4496             var j = 0;
4497             var key;
4498             while (length > j) {
4499               key = keys[j++];
4500               if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
4501             }
4502           } return T;
4503         } : nativeAssign;
4504
4505         // `Array.from` method implementation
4506         // https://tc39.github.io/ecma262/#sec-array.from
4507         var arrayFrom = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {
4508           var O = toObject(arrayLike);
4509           var C = typeof this == 'function' ? this : Array;
4510           var argumentsLength = arguments.length;
4511           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
4512           var mapping = mapfn !== undefined;
4513           var iteratorMethod = getIteratorMethod(O);
4514           var index = 0;
4515           var length, result, step, iterator, next, value;
4516           if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
4517           // if the target is not iterable or it's an array with the default iterator - use a simple case
4518           if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
4519             iterator = iteratorMethod.call(O);
4520             next = iterator.next;
4521             result = new C();
4522             for (;!(step = next.call(iterator)).done; index++) {
4523               value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
4524               createProperty(result, index, value);
4525             }
4526           } else {
4527             length = toLength(O.length);
4528             result = new C(length);
4529             for (;length > index; index++) {
4530               value = mapping ? mapfn(O[index], index) : O[index];
4531               createProperty(result, index, value);
4532             }
4533           }
4534           result.length = index;
4535           return result;
4536         };
4537
4538         // based on https://github.com/bestiejs/punycode.js/blob/master/punycode.js
4539         var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
4540         var base = 36;
4541         var tMin = 1;
4542         var tMax = 26;
4543         var skew = 38;
4544         var damp = 700;
4545         var initialBias = 72;
4546         var initialN = 128; // 0x80
4547         var delimiter = '-'; // '\x2D'
4548         var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars
4549         var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
4550         var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
4551         var baseMinusTMin = base - tMin;
4552         var floor$4 = Math.floor;
4553         var stringFromCharCode = String.fromCharCode;
4554
4555         /**
4556          * Creates an array containing the numeric code points of each Unicode
4557          * character in the string. While JavaScript uses UCS-2 internally,
4558          * this function will convert a pair of surrogate halves (each of which
4559          * UCS-2 exposes as separate characters) into a single code point,
4560          * matching UTF-16.
4561          */
4562         var ucs2decode = function (string) {
4563           var output = [];
4564           var counter = 0;
4565           var length = string.length;
4566           while (counter < length) {
4567             var value = string.charCodeAt(counter++);
4568             if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
4569               // It's a high surrogate, and there is a next character.
4570               var extra = string.charCodeAt(counter++);
4571               if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
4572                 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
4573               } else {
4574                 // It's an unmatched surrogate; only append this code unit, in case the
4575                 // next code unit is the high surrogate of a surrogate pair.
4576                 output.push(value);
4577                 counter--;
4578               }
4579             } else {
4580               output.push(value);
4581             }
4582           }
4583           return output;
4584         };
4585
4586         /**
4587          * Converts a digit/integer into a basic code point.
4588          */
4589         var digitToBasic = function (digit) {
4590           //  0..25 map to ASCII a..z or A..Z
4591           // 26..35 map to ASCII 0..9
4592           return digit + 22 + 75 * (digit < 26);
4593         };
4594
4595         /**
4596          * Bias adaptation function as per section 3.4 of RFC 3492.
4597          * https://tools.ietf.org/html/rfc3492#section-3.4
4598          */
4599         var adapt = function (delta, numPoints, firstTime) {
4600           var k = 0;
4601           delta = firstTime ? floor$4(delta / damp) : delta >> 1;
4602           delta += floor$4(delta / numPoints);
4603           for (; delta > baseMinusTMin * tMax >> 1; k += base) {
4604             delta = floor$4(delta / baseMinusTMin);
4605           }
4606           return floor$4(k + (baseMinusTMin + 1) * delta / (delta + skew));
4607         };
4608
4609         /**
4610          * Converts a string of Unicode symbols (e.g. a domain name label) to a
4611          * Punycode string of ASCII-only symbols.
4612          */
4613         // eslint-disable-next-line  max-statements
4614         var encode = function (input) {
4615           var output = [];
4616
4617           // Convert the input in UCS-2 to an array of Unicode code points.
4618           input = ucs2decode(input);
4619
4620           // Cache the length.
4621           var inputLength = input.length;
4622
4623           // Initialize the state.
4624           var n = initialN;
4625           var delta = 0;
4626           var bias = initialBias;
4627           var i, currentValue;
4628
4629           // Handle the basic code points.
4630           for (i = 0; i < input.length; i++) {
4631             currentValue = input[i];
4632             if (currentValue < 0x80) {
4633               output.push(stringFromCharCode(currentValue));
4634             }
4635           }
4636
4637           var basicLength = output.length; // number of basic code points.
4638           var handledCPCount = basicLength; // number of code points that have been handled;
4639
4640           // Finish the basic string with a delimiter unless it's empty.
4641           if (basicLength) {
4642             output.push(delimiter);
4643           }
4644
4645           // Main encoding loop:
4646           while (handledCPCount < inputLength) {
4647             // All non-basic code points < n have been handled already. Find the next larger one:
4648             var m = maxInt;
4649             for (i = 0; i < input.length; i++) {
4650               currentValue = input[i];
4651               if (currentValue >= n && currentValue < m) {
4652                 m = currentValue;
4653               }
4654             }
4655
4656             // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.
4657             var handledCPCountPlusOne = handledCPCount + 1;
4658             if (m - n > floor$4((maxInt - delta) / handledCPCountPlusOne)) {
4659               throw RangeError(OVERFLOW_ERROR);
4660             }
4661
4662             delta += (m - n) * handledCPCountPlusOne;
4663             n = m;
4664
4665             for (i = 0; i < input.length; i++) {
4666               currentValue = input[i];
4667               if (currentValue < n && ++delta > maxInt) {
4668                 throw RangeError(OVERFLOW_ERROR);
4669               }
4670               if (currentValue == n) {
4671                 // Represent delta as a generalized variable-length integer.
4672                 var q = delta;
4673                 for (var k = base; /* no condition */; k += base) {
4674                   var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
4675                   if (q < t) break;
4676                   var qMinusT = q - t;
4677                   var baseMinusT = base - t;
4678                   output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
4679                   q = floor$4(qMinusT / baseMinusT);
4680                 }
4681
4682                 output.push(stringFromCharCode(digitToBasic(q)));
4683                 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
4684                 delta = 0;
4685                 ++handledCPCount;
4686               }
4687             }
4688
4689             ++delta;
4690             ++n;
4691           }
4692           return output.join('');
4693         };
4694
4695         var stringPunycodeToAscii = function (input) {
4696           var encoded = [];
4697           var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
4698           var i, label;
4699           for (i = 0; i < labels.length; i++) {
4700             label = labels[i];
4701             encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
4702           }
4703           return encoded.join('.');
4704         };
4705
4706         var getIterator = function (it) {
4707           var iteratorMethod = getIteratorMethod(it);
4708           if (typeof iteratorMethod != 'function') {
4709             throw TypeError(String(it) + ' is not iterable');
4710           } return anObject(iteratorMethod.call(it));
4711         };
4712
4713         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735         var $fetch$1 = getBuiltIn('fetch');
4736         var Headers = getBuiltIn('Headers');
4737         var ITERATOR$8 = wellKnownSymbol('iterator');
4738         var URL_SEARCH_PARAMS = 'URLSearchParams';
4739         var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
4740         var setInternalState$5 = internalState.set;
4741         var getInternalParamsState = internalState.getterFor(URL_SEARCH_PARAMS);
4742         var getInternalIteratorState = internalState.getterFor(URL_SEARCH_PARAMS_ITERATOR);
4743
4744         var plus = /\+/g;
4745         var sequences = Array(4);
4746
4747         var percentSequence = function (bytes) {
4748           return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
4749         };
4750
4751         var percentDecode = function (sequence) {
4752           try {
4753             return decodeURIComponent(sequence);
4754           } catch (error) {
4755             return sequence;
4756           }
4757         };
4758
4759         var deserialize = function (it) {
4760           var result = it.replace(plus, ' ');
4761           var bytes = 4;
4762           try {
4763             return decodeURIComponent(result);
4764           } catch (error) {
4765             while (bytes) {
4766               result = result.replace(percentSequence(bytes--), percentDecode);
4767             }
4768             return result;
4769           }
4770         };
4771
4772         var find = /[!'()~]|%20/g;
4773
4774         var replace = {
4775           '!': '%21',
4776           "'": '%27',
4777           '(': '%28',
4778           ')': '%29',
4779           '~': '%7E',
4780           '%20': '+'
4781         };
4782
4783         var replacer = function (match) {
4784           return replace[match];
4785         };
4786
4787         var serialize = function (it) {
4788           return encodeURIComponent(it).replace(find, replacer);
4789         };
4790
4791         var parseSearchParams = function (result, query) {
4792           if (query) {
4793             var attributes = query.split('&');
4794             var index = 0;
4795             var attribute, entry;
4796             while (index < attributes.length) {
4797               attribute = attributes[index++];
4798               if (attribute.length) {
4799                 entry = attribute.split('=');
4800                 result.push({
4801                   key: deserialize(entry.shift()),
4802                   value: deserialize(entry.join('='))
4803                 });
4804               }
4805             }
4806           }
4807         };
4808
4809         var updateSearchParams = function (query) {
4810           this.entries.length = 0;
4811           parseSearchParams(this.entries, query);
4812         };
4813
4814         var validateArgumentsLength = function (passed, required) {
4815           if (passed < required) throw TypeError('Not enough arguments');
4816         };
4817
4818         var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
4819           setInternalState$5(this, {
4820             type: URL_SEARCH_PARAMS_ITERATOR,
4821             iterator: getIterator(getInternalParamsState(params).entries),
4822             kind: kind
4823           });
4824         }, 'Iterator', function next() {
4825           var state = getInternalIteratorState(this);
4826           var kind = state.kind;
4827           var step = state.iterator.next();
4828           var entry = step.value;
4829           if (!step.done) {
4830             step.value = kind === 'keys' ? entry.key : kind === 'values' ? entry.value : [entry.key, entry.value];
4831           } return step;
4832         });
4833
4834         // `URLSearchParams` constructor
4835         // https://url.spec.whatwg.org/#interface-urlsearchparams
4836         var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
4837           anInstance(this, URLSearchParamsConstructor, URL_SEARCH_PARAMS);
4838           var init = arguments.length > 0 ? arguments[0] : undefined;
4839           var that = this;
4840           var entries = [];
4841           var iteratorMethod, iterator, next, step, entryIterator, entryNext, first, second, key;
4842
4843           setInternalState$5(that, {
4844             type: URL_SEARCH_PARAMS,
4845             entries: entries,
4846             updateURL: function () { /* empty */ },
4847             updateSearchParams: updateSearchParams
4848           });
4849
4850           if (init !== undefined) {
4851             if (isObject(init)) {
4852               iteratorMethod = getIteratorMethod(init);
4853               if (typeof iteratorMethod === 'function') {
4854                 iterator = iteratorMethod.call(init);
4855                 next = iterator.next;
4856                 while (!(step = next.call(iterator)).done) {
4857                   entryIterator = getIterator(anObject(step.value));
4858                   entryNext = entryIterator.next;
4859                   if (
4860                     (first = entryNext.call(entryIterator)).done ||
4861                     (second = entryNext.call(entryIterator)).done ||
4862                     !entryNext.call(entryIterator).done
4863                   ) throw TypeError('Expected sequence with length 2');
4864                   entries.push({ key: first.value + '', value: second.value + '' });
4865                 }
4866               } else for (key in init) if (has(init, key)) entries.push({ key: key, value: init[key] + '' });
4867             } else {
4868               parseSearchParams(entries, typeof init === 'string' ? init.charAt(0) === '?' ? init.slice(1) : init : init + '');
4869             }
4870           }
4871         };
4872
4873         var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
4874
4875         redefineAll(URLSearchParamsPrototype, {
4876           // `URLSearchParams.prototype.appent` method
4877           // https://url.spec.whatwg.org/#dom-urlsearchparams-append
4878           append: function append(name, value) {
4879             validateArgumentsLength(arguments.length, 2);
4880             var state = getInternalParamsState(this);
4881             state.entries.push({ key: name + '', value: value + '' });
4882             state.updateURL();
4883           },
4884           // `URLSearchParams.prototype.delete` method
4885           // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
4886           'delete': function (name) {
4887             validateArgumentsLength(arguments.length, 1);
4888             var state = getInternalParamsState(this);
4889             var entries = state.entries;
4890             var key = name + '';
4891             var index = 0;
4892             while (index < entries.length) {
4893               if (entries[index].key === key) entries.splice(index, 1);
4894               else index++;
4895             }
4896             state.updateURL();
4897           },
4898           // `URLSearchParams.prototype.get` method
4899           // https://url.spec.whatwg.org/#dom-urlsearchparams-get
4900           get: function get(name) {
4901             validateArgumentsLength(arguments.length, 1);
4902             var entries = getInternalParamsState(this).entries;
4903             var key = name + '';
4904             var index = 0;
4905             for (; index < entries.length; index++) {
4906               if (entries[index].key === key) return entries[index].value;
4907             }
4908             return null;
4909           },
4910           // `URLSearchParams.prototype.getAll` method
4911           // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
4912           getAll: function getAll(name) {
4913             validateArgumentsLength(arguments.length, 1);
4914             var entries = getInternalParamsState(this).entries;
4915             var key = name + '';
4916             var result = [];
4917             var index = 0;
4918             for (; index < entries.length; index++) {
4919               if (entries[index].key === key) result.push(entries[index].value);
4920             }
4921             return result;
4922           },
4923           // `URLSearchParams.prototype.has` method
4924           // https://url.spec.whatwg.org/#dom-urlsearchparams-has
4925           has: function has(name) {
4926             validateArgumentsLength(arguments.length, 1);
4927             var entries = getInternalParamsState(this).entries;
4928             var key = name + '';
4929             var index = 0;
4930             while (index < entries.length) {
4931               if (entries[index++].key === key) return true;
4932             }
4933             return false;
4934           },
4935           // `URLSearchParams.prototype.set` method
4936           // https://url.spec.whatwg.org/#dom-urlsearchparams-set
4937           set: function set(name, value) {
4938             validateArgumentsLength(arguments.length, 1);
4939             var state = getInternalParamsState(this);
4940             var entries = state.entries;
4941             var found = false;
4942             var key = name + '';
4943             var val = value + '';
4944             var index = 0;
4945             var entry;
4946             for (; index < entries.length; index++) {
4947               entry = entries[index];
4948               if (entry.key === key) {
4949                 if (found) entries.splice(index--, 1);
4950                 else {
4951                   found = true;
4952                   entry.value = val;
4953                 }
4954               }
4955             }
4956             if (!found) entries.push({ key: key, value: val });
4957             state.updateURL();
4958           },
4959           // `URLSearchParams.prototype.sort` method
4960           // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
4961           sort: function sort() {
4962             var state = getInternalParamsState(this);
4963             var entries = state.entries;
4964             // Array#sort is not stable in some engines
4965             var slice = entries.slice();
4966             var entry, entriesIndex, sliceIndex;
4967             entries.length = 0;
4968             for (sliceIndex = 0; sliceIndex < slice.length; sliceIndex++) {
4969               entry = slice[sliceIndex];
4970               for (entriesIndex = 0; entriesIndex < sliceIndex; entriesIndex++) {
4971                 if (entries[entriesIndex].key > entry.key) {
4972                   entries.splice(entriesIndex, 0, entry);
4973                   break;
4974                 }
4975               }
4976               if (entriesIndex === sliceIndex) entries.push(entry);
4977             }
4978             state.updateURL();
4979           },
4980           // `URLSearchParams.prototype.forEach` method
4981           forEach: function forEach(callback /* , thisArg */) {
4982             var entries = getInternalParamsState(this).entries;
4983             var boundFunction = functionBindContext(callback, arguments.length > 1 ? arguments[1] : undefined, 3);
4984             var index = 0;
4985             var entry;
4986             while (index < entries.length) {
4987               entry = entries[index++];
4988               boundFunction(entry.value, entry.key, this);
4989             }
4990           },
4991           // `URLSearchParams.prototype.keys` method
4992           keys: function keys() {
4993             return new URLSearchParamsIterator(this, 'keys');
4994           },
4995           // `URLSearchParams.prototype.values` method
4996           values: function values() {
4997             return new URLSearchParamsIterator(this, 'values');
4998           },
4999           // `URLSearchParams.prototype.entries` method
5000           entries: function entries() {
5001             return new URLSearchParamsIterator(this, 'entries');
5002           }
5003         }, { enumerable: true });
5004
5005         // `URLSearchParams.prototype[@@iterator]` method
5006         redefine(URLSearchParamsPrototype, ITERATOR$8, URLSearchParamsPrototype.entries);
5007
5008         // `URLSearchParams.prototype.toString` method
5009         // https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
5010         redefine(URLSearchParamsPrototype, 'toString', function toString() {
5011           var entries = getInternalParamsState(this).entries;
5012           var result = [];
5013           var index = 0;
5014           var entry;
5015           while (index < entries.length) {
5016             entry = entries[index++];
5017             result.push(serialize(entry.key) + '=' + serialize(entry.value));
5018           } return result.join('&');
5019         }, { enumerable: true });
5020
5021         setToStringTag(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
5022
5023         _export({ global: true, forced: !nativeUrl }, {
5024           URLSearchParams: URLSearchParamsConstructor
5025         });
5026
5027         // Wrap `fetch` for correct work with polyfilled `URLSearchParams`
5028         // https://github.com/zloirock/core-js/issues/674
5029         if (!nativeUrl && typeof $fetch$1 == 'function' && typeof Headers == 'function') {
5030           _export({ global: true, enumerable: true, forced: true }, {
5031             fetch: function fetch(input /* , init */) {
5032               var args = [input];
5033               var init, body, headers;
5034               if (arguments.length > 1) {
5035                 init = arguments[1];
5036                 if (isObject(init)) {
5037                   body = init.body;
5038                   if (classof(body) === URL_SEARCH_PARAMS) {
5039                     headers = init.headers ? new Headers(init.headers) : new Headers();
5040                     if (!headers.has('content-type')) {
5041                       headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
5042                     }
5043                     init = objectCreate(init, {
5044                       body: createPropertyDescriptor(0, String(body)),
5045                       headers: createPropertyDescriptor(0, headers)
5046                     });
5047                   }
5048                 }
5049                 args.push(init);
5050               } return $fetch$1.apply(this, args);
5051             }
5052           });
5053         }
5054
5055         var web_urlSearchParams = {
5056           URLSearchParams: URLSearchParamsConstructor,
5057           getState: getInternalParamsState
5058         };
5059
5060         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072         var codeAt = stringMultibyte.codeAt;
5073
5074
5075
5076
5077
5078         var NativeURL = global_1.URL;
5079         var URLSearchParams$1 = web_urlSearchParams.URLSearchParams;
5080         var getInternalSearchParamsState = web_urlSearchParams.getState;
5081         var setInternalState$6 = internalState.set;
5082         var getInternalURLState = internalState.getterFor('URL');
5083         var floor$5 = Math.floor;
5084         var pow$1 = Math.pow;
5085
5086         var INVALID_AUTHORITY = 'Invalid authority';
5087         var INVALID_SCHEME = 'Invalid scheme';
5088         var INVALID_HOST = 'Invalid host';
5089         var INVALID_PORT = 'Invalid port';
5090
5091         var ALPHA = /[A-Za-z]/;
5092         var ALPHANUMERIC = /[\d+-.A-Za-z]/;
5093         var DIGIT = /\d/;
5094         var HEX_START = /^(0x|0X)/;
5095         var OCT = /^[0-7]+$/;
5096         var DEC = /^\d+$/;
5097         var HEX = /^[\dA-Fa-f]+$/;
5098         // eslint-disable-next-line no-control-regex
5099         var FORBIDDEN_HOST_CODE_POINT = /[\u0000\u0009\u000A\u000D #%/:?@[\\]]/;
5100         // eslint-disable-next-line no-control-regex
5101         var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\u0000\u0009\u000A\u000D #/:?@[\\]]/;
5102         // eslint-disable-next-line no-control-regex
5103         var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
5104         // eslint-disable-next-line no-control-regex
5105         var TAB_AND_NEW_LINE = /[\u0009\u000A\u000D]/g;
5106         var EOF;
5107
5108         var parseHost = function (url, input) {
5109           var result, codePoints, index;
5110           if (input.charAt(0) == '[') {
5111             if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
5112             result = parseIPv6(input.slice(1, -1));
5113             if (!result) return INVALID_HOST;
5114             url.host = result;
5115           // opaque host
5116           } else if (!isSpecial(url)) {
5117             if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
5118             result = '';
5119             codePoints = arrayFrom(input);
5120             for (index = 0; index < codePoints.length; index++) {
5121               result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
5122             }
5123             url.host = result;
5124           } else {
5125             input = stringPunycodeToAscii(input);
5126             if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
5127             result = parseIPv4(input);
5128             if (result === null) return INVALID_HOST;
5129             url.host = result;
5130           }
5131         };
5132
5133         var parseIPv4 = function (input) {
5134           var parts = input.split('.');
5135           var partsLength, numbers, index, part, radix, number, ipv4;
5136           if (parts.length && parts[parts.length - 1] == '') {
5137             parts.pop();
5138           }
5139           partsLength = parts.length;
5140           if (partsLength > 4) return input;
5141           numbers = [];
5142           for (index = 0; index < partsLength; index++) {
5143             part = parts[index];
5144             if (part == '') return input;
5145             radix = 10;
5146             if (part.length > 1 && part.charAt(0) == '0') {
5147               radix = HEX_START.test(part) ? 16 : 8;
5148               part = part.slice(radix == 8 ? 1 : 2);
5149             }
5150             if (part === '') {
5151               number = 0;
5152             } else {
5153               if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
5154               number = parseInt(part, radix);
5155             }
5156             numbers.push(number);
5157           }
5158           for (index = 0; index < partsLength; index++) {
5159             number = numbers[index];
5160             if (index == partsLength - 1) {
5161               if (number >= pow$1(256, 5 - partsLength)) return null;
5162             } else if (number > 255) return null;
5163           }
5164           ipv4 = numbers.pop();
5165           for (index = 0; index < numbers.length; index++) {
5166             ipv4 += numbers[index] * pow$1(256, 3 - index);
5167           }
5168           return ipv4;
5169         };
5170
5171         // eslint-disable-next-line max-statements
5172         var parseIPv6 = function (input) {
5173           var address = [0, 0, 0, 0, 0, 0, 0, 0];
5174           var pieceIndex = 0;
5175           var compress = null;
5176           var pointer = 0;
5177           var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
5178
5179           var char = function () {
5180             return input.charAt(pointer);
5181           };
5182
5183           if (char() == ':') {
5184             if (input.charAt(1) != ':') return;
5185             pointer += 2;
5186             pieceIndex++;
5187             compress = pieceIndex;
5188           }
5189           while (char()) {
5190             if (pieceIndex == 8) return;
5191             if (char() == ':') {
5192               if (compress !== null) return;
5193               pointer++;
5194               pieceIndex++;
5195               compress = pieceIndex;
5196               continue;
5197             }
5198             value = length = 0;
5199             while (length < 4 && HEX.test(char())) {
5200               value = value * 16 + parseInt(char(), 16);
5201               pointer++;
5202               length++;
5203             }
5204             if (char() == '.') {
5205               if (length == 0) return;
5206               pointer -= length;
5207               if (pieceIndex > 6) return;
5208               numbersSeen = 0;
5209               while (char()) {
5210                 ipv4Piece = null;
5211                 if (numbersSeen > 0) {
5212                   if (char() == '.' && numbersSeen < 4) pointer++;
5213                   else return;
5214                 }
5215                 if (!DIGIT.test(char())) return;
5216                 while (DIGIT.test(char())) {
5217                   number = parseInt(char(), 10);
5218                   if (ipv4Piece === null) ipv4Piece = number;
5219                   else if (ipv4Piece == 0) return;
5220                   else ipv4Piece = ipv4Piece * 10 + number;
5221                   if (ipv4Piece > 255) return;
5222                   pointer++;
5223                 }
5224                 address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
5225                 numbersSeen++;
5226                 if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
5227               }
5228               if (numbersSeen != 4) return;
5229               break;
5230             } else if (char() == ':') {
5231               pointer++;
5232               if (!char()) return;
5233             } else if (char()) return;
5234             address[pieceIndex++] = value;
5235           }
5236           if (compress !== null) {
5237             swaps = pieceIndex - compress;
5238             pieceIndex = 7;
5239             while (pieceIndex != 0 && swaps > 0) {
5240               swap = address[pieceIndex];
5241               address[pieceIndex--] = address[compress + swaps - 1];
5242               address[compress + --swaps] = swap;
5243             }
5244           } else if (pieceIndex != 8) return;
5245           return address;
5246         };
5247
5248         var findLongestZeroSequence = function (ipv6) {
5249           var maxIndex = null;
5250           var maxLength = 1;
5251           var currStart = null;
5252           var currLength = 0;
5253           var index = 0;
5254           for (; index < 8; index++) {
5255             if (ipv6[index] !== 0) {
5256               if (currLength > maxLength) {
5257                 maxIndex = currStart;
5258                 maxLength = currLength;
5259               }
5260               currStart = null;
5261               currLength = 0;
5262             } else {
5263               if (currStart === null) currStart = index;
5264               ++currLength;
5265             }
5266           }
5267           if (currLength > maxLength) {
5268             maxIndex = currStart;
5269             maxLength = currLength;
5270           }
5271           return maxIndex;
5272         };
5273
5274         var serializeHost = function (host) {
5275           var result, index, compress, ignore0;
5276           // ipv4
5277           if (typeof host == 'number') {
5278             result = [];
5279             for (index = 0; index < 4; index++) {
5280               result.unshift(host % 256);
5281               host = floor$5(host / 256);
5282             } return result.join('.');
5283           // ipv6
5284           } else if (typeof host == 'object') {
5285             result = '';
5286             compress = findLongestZeroSequence(host);
5287             for (index = 0; index < 8; index++) {
5288               if (ignore0 && host[index] === 0) continue;
5289               if (ignore0) ignore0 = false;
5290               if (compress === index) {
5291                 result += index ? ':' : '::';
5292                 ignore0 = true;
5293               } else {
5294                 result += host[index].toString(16);
5295                 if (index < 7) result += ':';
5296               }
5297             }
5298             return '[' + result + ']';
5299           } return host;
5300         };
5301
5302         var C0ControlPercentEncodeSet = {};
5303         var fragmentPercentEncodeSet = objectAssign({}, C0ControlPercentEncodeSet, {
5304           ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
5305         });
5306         var pathPercentEncodeSet = objectAssign({}, fragmentPercentEncodeSet, {
5307           '#': 1, '?': 1, '{': 1, '}': 1
5308         });
5309         var userinfoPercentEncodeSet = objectAssign({}, pathPercentEncodeSet, {
5310           '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
5311         });
5312
5313         var percentEncode = function (char, set) {
5314           var code = codeAt(char, 0);
5315           return code > 0x20 && code < 0x7F && !has(set, char) ? char : encodeURIComponent(char);
5316         };
5317
5318         var specialSchemes = {
5319           ftp: 21,
5320           file: null,
5321           http: 80,
5322           https: 443,
5323           ws: 80,
5324           wss: 443
5325         };
5326
5327         var isSpecial = function (url) {
5328           return has(specialSchemes, url.scheme);
5329         };
5330
5331         var includesCredentials = function (url) {
5332           return url.username != '' || url.password != '';
5333         };
5334
5335         var cannotHaveUsernamePasswordPort = function (url) {
5336           return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
5337         };
5338
5339         var isWindowsDriveLetter = function (string, normalized) {
5340           var second;
5341           return string.length == 2 && ALPHA.test(string.charAt(0))
5342             && ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
5343         };
5344
5345         var startsWithWindowsDriveLetter = function (string) {
5346           var third;
5347           return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
5348             string.length == 2 ||
5349             ((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
5350           );
5351         };
5352
5353         var shortenURLsPath = function (url) {
5354           var path = url.path;
5355           var pathSize = path.length;
5356           if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
5357             path.pop();
5358           }
5359         };
5360
5361         var isSingleDot = function (segment) {
5362           return segment === '.' || segment.toLowerCase() === '%2e';
5363         };
5364
5365         var isDoubleDot = function (segment) {
5366           segment = segment.toLowerCase();
5367           return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
5368         };
5369
5370         // States:
5371         var SCHEME_START = {};
5372         var SCHEME = {};
5373         var NO_SCHEME = {};
5374         var SPECIAL_RELATIVE_OR_AUTHORITY = {};
5375         var PATH_OR_AUTHORITY = {};
5376         var RELATIVE = {};
5377         var RELATIVE_SLASH = {};
5378         var SPECIAL_AUTHORITY_SLASHES = {};
5379         var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
5380         var AUTHORITY = {};
5381         var HOST = {};
5382         var HOSTNAME = {};
5383         var PORT = {};
5384         var FILE = {};
5385         var FILE_SLASH = {};
5386         var FILE_HOST = {};
5387         var PATH_START = {};
5388         var PATH = {};
5389         var CANNOT_BE_A_BASE_URL_PATH = {};
5390         var QUERY = {};
5391         var FRAGMENT = {};
5392
5393         // eslint-disable-next-line max-statements
5394         var parseURL = function (url, input, stateOverride, base) {
5395           var state = stateOverride || SCHEME_START;
5396           var pointer = 0;
5397           var buffer = '';
5398           var seenAt = false;
5399           var seenBracket = false;
5400           var seenPasswordToken = false;
5401           var codePoints, char, bufferCodePoints, failure;
5402
5403           if (!stateOverride) {
5404             url.scheme = '';
5405             url.username = '';
5406             url.password = '';
5407             url.host = null;
5408             url.port = null;
5409             url.path = [];
5410             url.query = null;
5411             url.fragment = null;
5412             url.cannotBeABaseURL = false;
5413             input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
5414           }
5415
5416           input = input.replace(TAB_AND_NEW_LINE, '');
5417
5418           codePoints = arrayFrom(input);
5419
5420           while (pointer <= codePoints.length) {
5421             char = codePoints[pointer];
5422             switch (state) {
5423               case SCHEME_START:
5424                 if (char && ALPHA.test(char)) {
5425                   buffer += char.toLowerCase();
5426                   state = SCHEME;
5427                 } else if (!stateOverride) {
5428                   state = NO_SCHEME;
5429                   continue;
5430                 } else return INVALID_SCHEME;
5431                 break;
5432
5433               case SCHEME:
5434                 if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
5435                   buffer += char.toLowerCase();
5436                 } else if (char == ':') {
5437                   if (stateOverride && (
5438                     (isSpecial(url) != has(specialSchemes, buffer)) ||
5439                     (buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
5440                     (url.scheme == 'file' && !url.host)
5441                   )) return;
5442                   url.scheme = buffer;
5443                   if (stateOverride) {
5444                     if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
5445                     return;
5446                   }
5447                   buffer = '';
5448                   if (url.scheme == 'file') {
5449                     state = FILE;
5450                   } else if (isSpecial(url) && base && base.scheme == url.scheme) {
5451                     state = SPECIAL_RELATIVE_OR_AUTHORITY;
5452                   } else if (isSpecial(url)) {
5453                     state = SPECIAL_AUTHORITY_SLASHES;
5454                   } else if (codePoints[pointer + 1] == '/') {
5455                     state = PATH_OR_AUTHORITY;
5456                     pointer++;
5457                   } else {
5458                     url.cannotBeABaseURL = true;
5459                     url.path.push('');
5460                     state = CANNOT_BE_A_BASE_URL_PATH;
5461                   }
5462                 } else if (!stateOverride) {
5463                   buffer = '';
5464                   state = NO_SCHEME;
5465                   pointer = 0;
5466                   continue;
5467                 } else return INVALID_SCHEME;
5468                 break;
5469
5470               case NO_SCHEME:
5471                 if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
5472                 if (base.cannotBeABaseURL && char == '#') {
5473                   url.scheme = base.scheme;
5474                   url.path = base.path.slice();
5475                   url.query = base.query;
5476                   url.fragment = '';
5477                   url.cannotBeABaseURL = true;
5478                   state = FRAGMENT;
5479                   break;
5480                 }
5481                 state = base.scheme == 'file' ? FILE : RELATIVE;
5482                 continue;
5483
5484               case SPECIAL_RELATIVE_OR_AUTHORITY:
5485                 if (char == '/' && codePoints[pointer + 1] == '/') {
5486                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5487                   pointer++;
5488                 } else {
5489                   state = RELATIVE;
5490                   continue;
5491                 } break;
5492
5493               case PATH_OR_AUTHORITY:
5494                 if (char == '/') {
5495                   state = AUTHORITY;
5496                   break;
5497                 } else {
5498                   state = PATH;
5499                   continue;
5500                 }
5501
5502               case RELATIVE:
5503                 url.scheme = base.scheme;
5504                 if (char == EOF) {
5505                   url.username = base.username;
5506                   url.password = base.password;
5507                   url.host = base.host;
5508                   url.port = base.port;
5509                   url.path = base.path.slice();
5510                   url.query = base.query;
5511                 } else if (char == '/' || (char == '\\' && isSpecial(url))) {
5512                   state = RELATIVE_SLASH;
5513                 } else if (char == '?') {
5514                   url.username = base.username;
5515                   url.password = base.password;
5516                   url.host = base.host;
5517                   url.port = base.port;
5518                   url.path = base.path.slice();
5519                   url.query = '';
5520                   state = QUERY;
5521                 } else if (char == '#') {
5522                   url.username = base.username;
5523                   url.password = base.password;
5524                   url.host = base.host;
5525                   url.port = base.port;
5526                   url.path = base.path.slice();
5527                   url.query = base.query;
5528                   url.fragment = '';
5529                   state = FRAGMENT;
5530                 } else {
5531                   url.username = base.username;
5532                   url.password = base.password;
5533                   url.host = base.host;
5534                   url.port = base.port;
5535                   url.path = base.path.slice();
5536                   url.path.pop();
5537                   state = PATH;
5538                   continue;
5539                 } break;
5540
5541               case RELATIVE_SLASH:
5542                 if (isSpecial(url) && (char == '/' || char == '\\')) {
5543                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5544                 } else if (char == '/') {
5545                   state = AUTHORITY;
5546                 } else {
5547                   url.username = base.username;
5548                   url.password = base.password;
5549                   url.host = base.host;
5550                   url.port = base.port;
5551                   state = PATH;
5552                   continue;
5553                 } break;
5554
5555               case SPECIAL_AUTHORITY_SLASHES:
5556                 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5557                 if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
5558                 pointer++;
5559                 break;
5560
5561               case SPECIAL_AUTHORITY_IGNORE_SLASHES:
5562                 if (char != '/' && char != '\\') {
5563                   state = AUTHORITY;
5564                   continue;
5565                 } break;
5566
5567               case AUTHORITY:
5568                 if (char == '@') {
5569                   if (seenAt) buffer = '%40' + buffer;
5570                   seenAt = true;
5571                   bufferCodePoints = arrayFrom(buffer);
5572                   for (var i = 0; i < bufferCodePoints.length; i++) {
5573                     var codePoint = bufferCodePoints[i];
5574                     if (codePoint == ':' && !seenPasswordToken) {
5575                       seenPasswordToken = true;
5576                       continue;
5577                     }
5578                     var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
5579                     if (seenPasswordToken) url.password += encodedCodePoints;
5580                     else url.username += encodedCodePoints;
5581                   }
5582                   buffer = '';
5583                 } else if (
5584                   char == EOF || char == '/' || char == '?' || char == '#' ||
5585                   (char == '\\' && isSpecial(url))
5586                 ) {
5587                   if (seenAt && buffer == '') return INVALID_AUTHORITY;
5588                   pointer -= arrayFrom(buffer).length + 1;
5589                   buffer = '';
5590                   state = HOST;
5591                 } else buffer += char;
5592                 break;
5593
5594               case HOST:
5595               case HOSTNAME:
5596                 if (stateOverride && url.scheme == 'file') {
5597                   state = FILE_HOST;
5598                   continue;
5599                 } else if (char == ':' && !seenBracket) {
5600                   if (buffer == '') return INVALID_HOST;
5601                   failure = parseHost(url, buffer);
5602                   if (failure) return failure;
5603                   buffer = '';
5604                   state = PORT;
5605                   if (stateOverride == HOSTNAME) return;
5606                 } else if (
5607                   char == EOF || char == '/' || char == '?' || char == '#' ||
5608                   (char == '\\' && isSpecial(url))
5609                 ) {
5610                   if (isSpecial(url) && buffer == '') return INVALID_HOST;
5611                   if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
5612                   failure = parseHost(url, buffer);
5613                   if (failure) return failure;
5614                   buffer = '';
5615                   state = PATH_START;
5616                   if (stateOverride) return;
5617                   continue;
5618                 } else {
5619                   if (char == '[') seenBracket = true;
5620                   else if (char == ']') seenBracket = false;
5621                   buffer += char;
5622                 } break;
5623
5624               case PORT:
5625                 if (DIGIT.test(char)) {
5626                   buffer += char;
5627                 } else if (
5628                   char == EOF || char == '/' || char == '?' || char == '#' ||
5629                   (char == '\\' && isSpecial(url)) ||
5630                   stateOverride
5631                 ) {
5632                   if (buffer != '') {
5633                     var port = parseInt(buffer, 10);
5634                     if (port > 0xFFFF) return INVALID_PORT;
5635                     url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
5636                     buffer = '';
5637                   }
5638                   if (stateOverride) return;
5639                   state = PATH_START;
5640                   continue;
5641                 } else return INVALID_PORT;
5642                 break;
5643
5644               case FILE:
5645                 url.scheme = 'file';
5646                 if (char == '/' || char == '\\') state = FILE_SLASH;
5647                 else if (base && base.scheme == 'file') {
5648                   if (char == EOF) {
5649                     url.host = base.host;
5650                     url.path = base.path.slice();
5651                     url.query = base.query;
5652                   } else if (char == '?') {
5653                     url.host = base.host;
5654                     url.path = base.path.slice();
5655                     url.query = '';
5656                     state = QUERY;
5657                   } else if (char == '#') {
5658                     url.host = base.host;
5659                     url.path = base.path.slice();
5660                     url.query = base.query;
5661                     url.fragment = '';
5662                     state = FRAGMENT;
5663                   } else {
5664                     if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5665                       url.host = base.host;
5666                       url.path = base.path.slice();
5667                       shortenURLsPath(url);
5668                     }
5669                     state = PATH;
5670                     continue;
5671                   }
5672                 } else {
5673                   state = PATH;
5674                   continue;
5675                 } break;
5676
5677               case FILE_SLASH:
5678                 if (char == '/' || char == '\\') {
5679                   state = FILE_HOST;
5680                   break;
5681                 }
5682                 if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5683                   if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
5684                   else url.host = base.host;
5685                 }
5686                 state = PATH;
5687                 continue;
5688
5689               case FILE_HOST:
5690                 if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
5691                   if (!stateOverride && isWindowsDriveLetter(buffer)) {
5692                     state = PATH;
5693                   } else if (buffer == '') {
5694                     url.host = '';
5695                     if (stateOverride) return;
5696                     state = PATH_START;
5697                   } else {
5698                     failure = parseHost(url, buffer);
5699                     if (failure) return failure;
5700                     if (url.host == 'localhost') url.host = '';
5701                     if (stateOverride) return;
5702                     buffer = '';
5703                     state = PATH_START;
5704                   } continue;
5705                 } else buffer += char;
5706                 break;
5707
5708               case PATH_START:
5709                 if (isSpecial(url)) {
5710                   state = PATH;
5711                   if (char != '/' && char != '\\') continue;
5712                 } else if (!stateOverride && char == '?') {
5713                   url.query = '';
5714                   state = QUERY;
5715                 } else if (!stateOverride && char == '#') {
5716                   url.fragment = '';
5717                   state = FRAGMENT;
5718                 } else if (char != EOF) {
5719                   state = PATH;
5720                   if (char != '/') continue;
5721                 } break;
5722
5723               case PATH:
5724                 if (
5725                   char == EOF || char == '/' ||
5726                   (char == '\\' && isSpecial(url)) ||
5727                   (!stateOverride && (char == '?' || char == '#'))
5728                 ) {
5729                   if (isDoubleDot(buffer)) {
5730                     shortenURLsPath(url);
5731                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5732                       url.path.push('');
5733                     }
5734                   } else if (isSingleDot(buffer)) {
5735                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5736                       url.path.push('');
5737                     }
5738                   } else {
5739                     if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
5740                       if (url.host) url.host = '';
5741                       buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
5742                     }
5743                     url.path.push(buffer);
5744                   }
5745                   buffer = '';
5746                   if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
5747                     while (url.path.length > 1 && url.path[0] === '') {
5748                       url.path.shift();
5749                     }
5750                   }
5751                   if (char == '?') {
5752                     url.query = '';
5753                     state = QUERY;
5754                   } else if (char == '#') {
5755                     url.fragment = '';
5756                     state = FRAGMENT;
5757                   }
5758                 } else {
5759                   buffer += percentEncode(char, pathPercentEncodeSet);
5760                 } break;
5761
5762               case CANNOT_BE_A_BASE_URL_PATH:
5763                 if (char == '?') {
5764                   url.query = '';
5765                   state = QUERY;
5766                 } else if (char == '#') {
5767                   url.fragment = '';
5768                   state = FRAGMENT;
5769                 } else if (char != EOF) {
5770                   url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
5771                 } break;
5772
5773               case QUERY:
5774                 if (!stateOverride && char == '#') {
5775                   url.fragment = '';
5776                   state = FRAGMENT;
5777                 } else if (char != EOF) {
5778                   if (char == "'" && isSpecial(url)) url.query += '%27';
5779                   else if (char == '#') url.query += '%23';
5780                   else url.query += percentEncode(char, C0ControlPercentEncodeSet);
5781                 } break;
5782
5783               case FRAGMENT:
5784                 if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
5785                 break;
5786             }
5787
5788             pointer++;
5789           }
5790         };
5791
5792         // `URL` constructor
5793         // https://url.spec.whatwg.org/#url-class
5794         var URLConstructor = function URL(url /* , base */) {
5795           var that = anInstance(this, URLConstructor, 'URL');
5796           var base = arguments.length > 1 ? arguments[1] : undefined;
5797           var urlString = String(url);
5798           var state = setInternalState$6(that, { type: 'URL' });
5799           var baseState, failure;
5800           if (base !== undefined) {
5801             if (base instanceof URLConstructor) baseState = getInternalURLState(base);
5802             else {
5803               failure = parseURL(baseState = {}, String(base));
5804               if (failure) throw TypeError(failure);
5805             }
5806           }
5807           failure = parseURL(state, urlString, null, baseState);
5808           if (failure) throw TypeError(failure);
5809           var searchParams = state.searchParams = new URLSearchParams$1();
5810           var searchParamsState = getInternalSearchParamsState(searchParams);
5811           searchParamsState.updateSearchParams(state.query);
5812           searchParamsState.updateURL = function () {
5813             state.query = String(searchParams) || null;
5814           };
5815           if (!descriptors) {
5816             that.href = serializeURL.call(that);
5817             that.origin = getOrigin.call(that);
5818             that.protocol = getProtocol.call(that);
5819             that.username = getUsername.call(that);
5820             that.password = getPassword.call(that);
5821             that.host = getHost.call(that);
5822             that.hostname = getHostname.call(that);
5823             that.port = getPort.call(that);
5824             that.pathname = getPathname.call(that);
5825             that.search = getSearch.call(that);
5826             that.searchParams = getSearchParams.call(that);
5827             that.hash = getHash.call(that);
5828           }
5829         };
5830
5831         var URLPrototype = URLConstructor.prototype;
5832
5833         var serializeURL = function () {
5834           var url = getInternalURLState(this);
5835           var scheme = url.scheme;
5836           var username = url.username;
5837           var password = url.password;
5838           var host = url.host;
5839           var port = url.port;
5840           var path = url.path;
5841           var query = url.query;
5842           var fragment = url.fragment;
5843           var output = scheme + ':';
5844           if (host !== null) {
5845             output += '//';
5846             if (includesCredentials(url)) {
5847               output += username + (password ? ':' + password : '') + '@';
5848             }
5849             output += serializeHost(host);
5850             if (port !== null) output += ':' + port;
5851           } else if (scheme == 'file') output += '//';
5852           output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5853           if (query !== null) output += '?' + query;
5854           if (fragment !== null) output += '#' + fragment;
5855           return output;
5856         };
5857
5858         var getOrigin = function () {
5859           var url = getInternalURLState(this);
5860           var scheme = url.scheme;
5861           var port = url.port;
5862           if (scheme == 'blob') try {
5863             return new URL(scheme.path[0]).origin;
5864           } catch (error) {
5865             return 'null';
5866           }
5867           if (scheme == 'file' || !isSpecial(url)) return 'null';
5868           return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
5869         };
5870
5871         var getProtocol = function () {
5872           return getInternalURLState(this).scheme + ':';
5873         };
5874
5875         var getUsername = function () {
5876           return getInternalURLState(this).username;
5877         };
5878
5879         var getPassword = function () {
5880           return getInternalURLState(this).password;
5881         };
5882
5883         var getHost = function () {
5884           var url = getInternalURLState(this);
5885           var host = url.host;
5886           var port = url.port;
5887           return host === null ? ''
5888             : port === null ? serializeHost(host)
5889             : serializeHost(host) + ':' + port;
5890         };
5891
5892         var getHostname = function () {
5893           var host = getInternalURLState(this).host;
5894           return host === null ? '' : serializeHost(host);
5895         };
5896
5897         var getPort = function () {
5898           var port = getInternalURLState(this).port;
5899           return port === null ? '' : String(port);
5900         };
5901
5902         var getPathname = function () {
5903           var url = getInternalURLState(this);
5904           var path = url.path;
5905           return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5906         };
5907
5908         var getSearch = function () {
5909           var query = getInternalURLState(this).query;
5910           return query ? '?' + query : '';
5911         };
5912
5913         var getSearchParams = function () {
5914           return getInternalURLState(this).searchParams;
5915         };
5916
5917         var getHash = function () {
5918           var fragment = getInternalURLState(this).fragment;
5919           return fragment ? '#' + fragment : '';
5920         };
5921
5922         var accessorDescriptor = function (getter, setter) {
5923           return { get: getter, set: setter, configurable: true, enumerable: true };
5924         };
5925
5926         if (descriptors) {
5927           objectDefineProperties(URLPrototype, {
5928             // `URL.prototype.href` accessors pair
5929             // https://url.spec.whatwg.org/#dom-url-href
5930             href: accessorDescriptor(serializeURL, function (href) {
5931               var url = getInternalURLState(this);
5932               var urlString = String(href);
5933               var failure = parseURL(url, urlString);
5934               if (failure) throw TypeError(failure);
5935               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
5936             }),
5937             // `URL.prototype.origin` getter
5938             // https://url.spec.whatwg.org/#dom-url-origin
5939             origin: accessorDescriptor(getOrigin),
5940             // `URL.prototype.protocol` accessors pair
5941             // https://url.spec.whatwg.org/#dom-url-protocol
5942             protocol: accessorDescriptor(getProtocol, function (protocol) {
5943               var url = getInternalURLState(this);
5944               parseURL(url, String(protocol) + ':', SCHEME_START);
5945             }),
5946             // `URL.prototype.username` accessors pair
5947             // https://url.spec.whatwg.org/#dom-url-username
5948             username: accessorDescriptor(getUsername, function (username) {
5949               var url = getInternalURLState(this);
5950               var codePoints = arrayFrom(String(username));
5951               if (cannotHaveUsernamePasswordPort(url)) return;
5952               url.username = '';
5953               for (var i = 0; i < codePoints.length; i++) {
5954                 url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5955               }
5956             }),
5957             // `URL.prototype.password` accessors pair
5958             // https://url.spec.whatwg.org/#dom-url-password
5959             password: accessorDescriptor(getPassword, function (password) {
5960               var url = getInternalURLState(this);
5961               var codePoints = arrayFrom(String(password));
5962               if (cannotHaveUsernamePasswordPort(url)) return;
5963               url.password = '';
5964               for (var i = 0; i < codePoints.length; i++) {
5965                 url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5966               }
5967             }),
5968             // `URL.prototype.host` accessors pair
5969             // https://url.spec.whatwg.org/#dom-url-host
5970             host: accessorDescriptor(getHost, function (host) {
5971               var url = getInternalURLState(this);
5972               if (url.cannotBeABaseURL) return;
5973               parseURL(url, String(host), HOST);
5974             }),
5975             // `URL.prototype.hostname` accessors pair
5976             // https://url.spec.whatwg.org/#dom-url-hostname
5977             hostname: accessorDescriptor(getHostname, function (hostname) {
5978               var url = getInternalURLState(this);
5979               if (url.cannotBeABaseURL) return;
5980               parseURL(url, String(hostname), HOSTNAME);
5981             }),
5982             // `URL.prototype.port` accessors pair
5983             // https://url.spec.whatwg.org/#dom-url-port
5984             port: accessorDescriptor(getPort, function (port) {
5985               var url = getInternalURLState(this);
5986               if (cannotHaveUsernamePasswordPort(url)) return;
5987               port = String(port);
5988               if (port == '') url.port = null;
5989               else parseURL(url, port, PORT);
5990             }),
5991             // `URL.prototype.pathname` accessors pair
5992             // https://url.spec.whatwg.org/#dom-url-pathname
5993             pathname: accessorDescriptor(getPathname, function (pathname) {
5994               var url = getInternalURLState(this);
5995               if (url.cannotBeABaseURL) return;
5996               url.path = [];
5997               parseURL(url, pathname + '', PATH_START);
5998             }),
5999             // `URL.prototype.search` accessors pair
6000             // https://url.spec.whatwg.org/#dom-url-search
6001             search: accessorDescriptor(getSearch, function (search) {
6002               var url = getInternalURLState(this);
6003               search = String(search);
6004               if (search == '') {
6005                 url.query = null;
6006               } else {
6007                 if ('?' == search.charAt(0)) search = search.slice(1);
6008                 url.query = '';
6009                 parseURL(url, search, QUERY);
6010               }
6011               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
6012             }),
6013             // `URL.prototype.searchParams` getter
6014             // https://url.spec.whatwg.org/#dom-url-searchparams
6015             searchParams: accessorDescriptor(getSearchParams),
6016             // `URL.prototype.hash` accessors pair
6017             // https://url.spec.whatwg.org/#dom-url-hash
6018             hash: accessorDescriptor(getHash, function (hash) {
6019               var url = getInternalURLState(this);
6020               hash = String(hash);
6021               if (hash == '') {
6022                 url.fragment = null;
6023                 return;
6024               }
6025               if ('#' == hash.charAt(0)) hash = hash.slice(1);
6026               url.fragment = '';
6027               parseURL(url, hash, FRAGMENT);
6028             })
6029           });
6030         }
6031
6032         // `URL.prototype.toJSON` method
6033         // https://url.spec.whatwg.org/#dom-url-tojson
6034         redefine(URLPrototype, 'toJSON', function toJSON() {
6035           return serializeURL.call(this);
6036         }, { enumerable: true });
6037
6038         // `URL.prototype.toString` method
6039         // https://url.spec.whatwg.org/#URL-stringification-behavior
6040         redefine(URLPrototype, 'toString', function toString() {
6041           return serializeURL.call(this);
6042         }, { enumerable: true });
6043
6044         if (NativeURL) {
6045           var nativeCreateObjectURL = NativeURL.createObjectURL;
6046           var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
6047           // `URL.createObjectURL` method
6048           // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
6049           // eslint-disable-next-line no-unused-vars
6050           if (nativeCreateObjectURL) redefine(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
6051             return nativeCreateObjectURL.apply(NativeURL, arguments);
6052           });
6053           // `URL.revokeObjectURL` method
6054           // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
6055           // eslint-disable-next-line no-unused-vars
6056           if (nativeRevokeObjectURL) redefine(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
6057             return nativeRevokeObjectURL.apply(NativeURL, arguments);
6058           });
6059         }
6060
6061         setToStringTag(URLConstructor, 'URL');
6062
6063         _export({ global: true, forced: !nativeUrl, sham: !descriptors }, {
6064           URL: URLConstructor
6065         });
6066
6067         function _typeof(obj) {
6068           "@babel/helpers - typeof";
6069
6070           if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
6071             _typeof = function (obj) {
6072               return typeof obj;
6073             };
6074           } else {
6075             _typeof = function (obj) {
6076               return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
6077             };
6078           }
6079
6080           return _typeof(obj);
6081         }
6082
6083         function _classCallCheck(instance, Constructor) {
6084           if (!(instance instanceof Constructor)) {
6085             throw new TypeError("Cannot call a class as a function");
6086           }
6087         }
6088
6089         function _defineProperties(target, props) {
6090           for (var i = 0; i < props.length; i++) {
6091             var descriptor = props[i];
6092             descriptor.enumerable = descriptor.enumerable || false;
6093             descriptor.configurable = true;
6094             if ("value" in descriptor) descriptor.writable = true;
6095             Object.defineProperty(target, descriptor.key, descriptor);
6096           }
6097         }
6098
6099         function _createClass(Constructor, protoProps, staticProps) {
6100           if (protoProps) _defineProperties(Constructor.prototype, protoProps);
6101           if (staticProps) _defineProperties(Constructor, staticProps);
6102           return Constructor;
6103         }
6104
6105         function _defineProperty(obj, key, value) {
6106           if (key in obj) {
6107             Object.defineProperty(obj, key, {
6108               value: value,
6109               enumerable: true,
6110               configurable: true,
6111               writable: true
6112             });
6113           } else {
6114             obj[key] = value;
6115           }
6116
6117           return obj;
6118         }
6119
6120         function _slicedToArray(arr, i) {
6121           return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
6122         }
6123
6124         function _toConsumableArray(arr) {
6125           return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
6126         }
6127
6128         function _arrayWithoutHoles(arr) {
6129           if (Array.isArray(arr)) return _arrayLikeToArray(arr);
6130         }
6131
6132         function _arrayWithHoles(arr) {
6133           if (Array.isArray(arr)) return arr;
6134         }
6135
6136         function _iterableToArray(iter) {
6137           if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
6138         }
6139
6140         function _iterableToArrayLimit(arr, i) {
6141           if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
6142           var _arr = [];
6143           var _n = true;
6144           var _d = false;
6145           var _e = undefined;
6146
6147           try {
6148             for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
6149               _arr.push(_s.value);
6150
6151               if (i && _arr.length === i) break;
6152             }
6153           } catch (err) {
6154             _d = true;
6155             _e = err;
6156           } finally {
6157             try {
6158               if (!_n && _i["return"] != null) _i["return"]();
6159             } finally {
6160               if (_d) throw _e;
6161             }
6162           }
6163
6164           return _arr;
6165         }
6166
6167         function _unsupportedIterableToArray(o, minLen) {
6168           if (!o) return;
6169           if (typeof o === "string") return _arrayLikeToArray(o, minLen);
6170           var n = Object.prototype.toString.call(o).slice(8, -1);
6171           if (n === "Object" && o.constructor) n = o.constructor.name;
6172           if (n === "Map" || n === "Set") return Array.from(o);
6173           if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
6174         }
6175
6176         function _arrayLikeToArray(arr, len) {
6177           if (len == null || len > arr.length) len = arr.length;
6178
6179           for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
6180
6181           return arr2;
6182         }
6183
6184         function _nonIterableSpread() {
6185           throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
6186         }
6187
6188         function _nonIterableRest() {
6189           throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
6190         }
6191
6192         function _createForOfIteratorHelper(o, allowArrayLike) {
6193           var it;
6194
6195           if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
6196             if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
6197               if (it) o = it;
6198               var i = 0;
6199
6200               var F = function () {};
6201
6202               return {
6203                 s: F,
6204                 n: function () {
6205                   if (i >= o.length) return {
6206                     done: true
6207                   };
6208                   return {
6209                     done: false,
6210                     value: o[i++]
6211                   };
6212                 },
6213                 e: function (e) {
6214                   throw e;
6215                 },
6216                 f: F
6217               };
6218             }
6219
6220             throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
6221           }
6222
6223           var normalCompletion = true,
6224               didErr = false,
6225               err;
6226           return {
6227             s: function () {
6228               it = o[Symbol.iterator]();
6229             },
6230             n: function () {
6231               var step = it.next();
6232               normalCompletion = step.done;
6233               return step;
6234             },
6235             e: function (e) {
6236               didErr = true;
6237               err = e;
6238             },
6239             f: function () {
6240               try {
6241                 if (!normalCompletion && it.return != null) it.return();
6242               } finally {
6243                 if (didErr) throw err;
6244               }
6245             }
6246           };
6247         }
6248
6249         var global$1 = typeof globalThis !== 'undefined' && globalThis || typeof self !== 'undefined' && self || typeof global$1 !== 'undefined' && global$1;
6250         var support = {
6251           searchParams: 'URLSearchParams' in global$1,
6252           iterable: 'Symbol' in global$1 && 'iterator' in Symbol,
6253           blob: 'FileReader' in global$1 && 'Blob' in global$1 && function () {
6254             try {
6255               new Blob();
6256               return true;
6257             } catch (e) {
6258               return false;
6259             }
6260           }(),
6261           formData: 'FormData' in global$1,
6262           arrayBuffer: 'ArrayBuffer' in global$1
6263         };
6264
6265         function isDataView(obj) {
6266           return obj && DataView.prototype.isPrototypeOf(obj);
6267         }
6268
6269         if (support.arrayBuffer) {
6270           var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];
6271
6272           var isArrayBufferView = ArrayBuffer.isView || function (obj) {
6273             return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
6274           };
6275         }
6276
6277         function normalizeName(name) {
6278           if (typeof name !== 'string') {
6279             name = String(name);
6280           }
6281
6282           if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
6283             throw new TypeError('Invalid character in header field name');
6284           }
6285
6286           return name.toLowerCase();
6287         }
6288
6289         function normalizeValue(value) {
6290           if (typeof value !== 'string') {
6291             value = String(value);
6292           }
6293
6294           return value;
6295         } // Build a destructive iterator for the value list
6296
6297
6298         function iteratorFor(items) {
6299           var iterator = {
6300             next: function next() {
6301               var value = items.shift();
6302               return {
6303                 done: value === undefined,
6304                 value: value
6305               };
6306             }
6307           };
6308
6309           if (support.iterable) {
6310             iterator[Symbol.iterator] = function () {
6311               return iterator;
6312             };
6313           }
6314
6315           return iterator;
6316         }
6317
6318         function Headers$1(headers) {
6319           this.map = {};
6320
6321           if (headers instanceof Headers$1) {
6322             headers.forEach(function (value, name) {
6323               this.append(name, value);
6324             }, this);
6325           } else if (Array.isArray(headers)) {
6326             headers.forEach(function (header) {
6327               this.append(header[0], header[1]);
6328             }, this);
6329           } else if (headers) {
6330             Object.getOwnPropertyNames(headers).forEach(function (name) {
6331               this.append(name, headers[name]);
6332             }, this);
6333           }
6334         }
6335
6336         Headers$1.prototype.append = function (name, value) {
6337           name = normalizeName(name);
6338           value = normalizeValue(value);
6339           var oldValue = this.map[name];
6340           this.map[name] = oldValue ? oldValue + ', ' + value : value;
6341         };
6342
6343         Headers$1.prototype['delete'] = function (name) {
6344           delete this.map[normalizeName(name)];
6345         };
6346
6347         Headers$1.prototype.get = function (name) {
6348           name = normalizeName(name);
6349           return this.has(name) ? this.map[name] : null;
6350         };
6351
6352         Headers$1.prototype.has = function (name) {
6353           return this.map.hasOwnProperty(normalizeName(name));
6354         };
6355
6356         Headers$1.prototype.set = function (name, value) {
6357           this.map[normalizeName(name)] = normalizeValue(value);
6358         };
6359
6360         Headers$1.prototype.forEach = function (callback, thisArg) {
6361           for (var name in this.map) {
6362             if (this.map.hasOwnProperty(name)) {
6363               callback.call(thisArg, this.map[name], name, this);
6364             }
6365           }
6366         };
6367
6368         Headers$1.prototype.keys = function () {
6369           var items = [];
6370           this.forEach(function (value, name) {
6371             items.push(name);
6372           });
6373           return iteratorFor(items);
6374         };
6375
6376         Headers$1.prototype.values = function () {
6377           var items = [];
6378           this.forEach(function (value) {
6379             items.push(value);
6380           });
6381           return iteratorFor(items);
6382         };
6383
6384         Headers$1.prototype.entries = function () {
6385           var items = [];
6386           this.forEach(function (value, name) {
6387             items.push([name, value]);
6388           });
6389           return iteratorFor(items);
6390         };
6391
6392         if (support.iterable) {
6393           Headers$1.prototype[Symbol.iterator] = Headers$1.prototype.entries;
6394         }
6395
6396         function consumed(body) {
6397           if (body.bodyUsed) {
6398             return Promise.reject(new TypeError('Already read'));
6399           }
6400
6401           body.bodyUsed = true;
6402         }
6403
6404         function fileReaderReady(reader) {
6405           return new Promise(function (resolve, reject) {
6406             reader.onload = function () {
6407               resolve(reader.result);
6408             };
6409
6410             reader.onerror = function () {
6411               reject(reader.error);
6412             };
6413           });
6414         }
6415
6416         function readBlobAsArrayBuffer(blob) {
6417           var reader = new FileReader();
6418           var promise = fileReaderReady(reader);
6419           reader.readAsArrayBuffer(blob);
6420           return promise;
6421         }
6422
6423         function readBlobAsText(blob) {
6424           var reader = new FileReader();
6425           var promise = fileReaderReady(reader);
6426           reader.readAsText(blob);
6427           return promise;
6428         }
6429
6430         function readArrayBufferAsText(buf) {
6431           var view = new Uint8Array(buf);
6432           var chars = new Array(view.length);
6433
6434           for (var i = 0; i < view.length; i++) {
6435             chars[i] = String.fromCharCode(view[i]);
6436           }
6437
6438           return chars.join('');
6439         }
6440
6441         function bufferClone(buf) {
6442           if (buf.slice) {
6443             return buf.slice(0);
6444           } else {
6445             var view = new Uint8Array(buf.byteLength);
6446             view.set(new Uint8Array(buf));
6447             return view.buffer;
6448           }
6449         }
6450
6451         function Body() {
6452           this.bodyUsed = false;
6453
6454           this._initBody = function (body) {
6455             /*
6456               fetch-mock wraps the Response object in an ES6 Proxy to
6457               provide useful test harness features such as flush. However, on
6458               ES5 browsers without fetch or Proxy support pollyfills must be used;
6459               the proxy-pollyfill is unable to proxy an attribute unless it exists
6460               on the object before the Proxy is created. This change ensures
6461               Response.bodyUsed exists on the instance, while maintaining the
6462               semantic of setting Request.bodyUsed in the constructor before
6463               _initBody is called.
6464             */
6465             this.bodyUsed = this.bodyUsed;
6466             this._bodyInit = body;
6467
6468             if (!body) {
6469               this._bodyText = '';
6470             } else if (typeof body === 'string') {
6471               this._bodyText = body;
6472             } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
6473               this._bodyBlob = body;
6474             } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
6475               this._bodyFormData = body;
6476             } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6477               this._bodyText = body.toString();
6478             } else if (support.arrayBuffer && support.blob && isDataView(body)) {
6479               this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.
6480
6481               this._bodyInit = new Blob([this._bodyArrayBuffer]);
6482             } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
6483               this._bodyArrayBuffer = bufferClone(body);
6484             } else {
6485               this._bodyText = body = Object.prototype.toString.call(body);
6486             }
6487
6488             if (!this.headers.get('content-type')) {
6489               if (typeof body === 'string') {
6490                 this.headers.set('content-type', 'text/plain;charset=UTF-8');
6491               } else if (this._bodyBlob && this._bodyBlob.type) {
6492                 this.headers.set('content-type', this._bodyBlob.type);
6493               } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6494                 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
6495               }
6496             }
6497           };
6498
6499           if (support.blob) {
6500             this.blob = function () {
6501               var rejected = consumed(this);
6502
6503               if (rejected) {
6504                 return rejected;
6505               }
6506
6507               if (this._bodyBlob) {
6508                 return Promise.resolve(this._bodyBlob);
6509               } else if (this._bodyArrayBuffer) {
6510                 return Promise.resolve(new Blob([this._bodyArrayBuffer]));
6511               } else if (this._bodyFormData) {
6512                 throw new Error('could not read FormData body as blob');
6513               } else {
6514                 return Promise.resolve(new Blob([this._bodyText]));
6515               }
6516             };
6517
6518             this.arrayBuffer = function () {
6519               if (this._bodyArrayBuffer) {
6520                 var isConsumed = consumed(this);
6521
6522                 if (isConsumed) {
6523                   return isConsumed;
6524                 }
6525
6526                 if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
6527                   return Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset, this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength));
6528                 } else {
6529                   return Promise.resolve(this._bodyArrayBuffer);
6530                 }
6531               } else {
6532                 return this.blob().then(readBlobAsArrayBuffer);
6533               }
6534             };
6535           }
6536
6537           this.text = function () {
6538             var rejected = consumed(this);
6539
6540             if (rejected) {
6541               return rejected;
6542             }
6543
6544             if (this._bodyBlob) {
6545               return readBlobAsText(this._bodyBlob);
6546             } else if (this._bodyArrayBuffer) {
6547               return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
6548             } else if (this._bodyFormData) {
6549               throw new Error('could not read FormData body as text');
6550             } else {
6551               return Promise.resolve(this._bodyText);
6552             }
6553           };
6554
6555           if (support.formData) {
6556             this.formData = function () {
6557               return this.text().then(decode);
6558             };
6559           }
6560
6561           this.json = function () {
6562             return this.text().then(JSON.parse);
6563           };
6564
6565           return this;
6566         } // HTTP methods whose capitalization should be normalized
6567
6568
6569         var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
6570
6571         function normalizeMethod(method) {
6572           var upcased = method.toUpperCase();
6573           return methods.indexOf(upcased) > -1 ? upcased : method;
6574         }
6575
6576         function Request(input, options) {
6577           if (!(this instanceof Request)) {
6578             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6579           }
6580
6581           options = options || {};
6582           var body = options.body;
6583
6584           if (input instanceof Request) {
6585             if (input.bodyUsed) {
6586               throw new TypeError('Already read');
6587             }
6588
6589             this.url = input.url;
6590             this.credentials = input.credentials;
6591
6592             if (!options.headers) {
6593               this.headers = new Headers$1(input.headers);
6594             }
6595
6596             this.method = input.method;
6597             this.mode = input.mode;
6598             this.signal = input.signal;
6599
6600             if (!body && input._bodyInit != null) {
6601               body = input._bodyInit;
6602               input.bodyUsed = true;
6603             }
6604           } else {
6605             this.url = String(input);
6606           }
6607
6608           this.credentials = options.credentials || this.credentials || 'same-origin';
6609
6610           if (options.headers || !this.headers) {
6611             this.headers = new Headers$1(options.headers);
6612           }
6613
6614           this.method = normalizeMethod(options.method || this.method || 'GET');
6615           this.mode = options.mode || this.mode || null;
6616           this.signal = options.signal || this.signal;
6617           this.referrer = null;
6618
6619           if ((this.method === 'GET' || this.method === 'HEAD') && body) {
6620             throw new TypeError('Body not allowed for GET or HEAD requests');
6621           }
6622
6623           this._initBody(body);
6624
6625           if (this.method === 'GET' || this.method === 'HEAD') {
6626             if (options.cache === 'no-store' || options.cache === 'no-cache') {
6627               // Search for a '_' parameter in the query string
6628               var reParamSearch = /([?&])_=[^&]*/;
6629
6630               if (reParamSearch.test(this.url)) {
6631                 // If it already exists then set the value with the current time
6632                 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
6633               } else {
6634                 // Otherwise add a new '_' parameter to the end with the current time
6635                 var reQueryString = /\?/;
6636                 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
6637               }
6638             }
6639           }
6640         }
6641
6642         Request.prototype.clone = function () {
6643           return new Request(this, {
6644             body: this._bodyInit
6645           });
6646         };
6647
6648         function decode(body) {
6649           var form = new FormData();
6650           body.trim().split('&').forEach(function (bytes) {
6651             if (bytes) {
6652               var split = bytes.split('=');
6653               var name = split.shift().replace(/\+/g, ' ');
6654               var value = split.join('=').replace(/\+/g, ' ');
6655               form.append(decodeURIComponent(name), decodeURIComponent(value));
6656             }
6657           });
6658           return form;
6659         }
6660
6661         function parseHeaders(rawHeaders) {
6662           var headers = new Headers$1(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
6663           // https://tools.ietf.org/html/rfc7230#section-3.2
6664
6665           var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
6666           preProcessedHeaders.split(/\r?\n/).forEach(function (line) {
6667             var parts = line.split(':');
6668             var key = parts.shift().trim();
6669
6670             if (key) {
6671               var value = parts.join(':').trim();
6672               headers.append(key, value);
6673             }
6674           });
6675           return headers;
6676         }
6677
6678         Body.call(Request.prototype);
6679         function Response(bodyInit, options) {
6680           if (!(this instanceof Response)) {
6681             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6682           }
6683
6684           if (!options) {
6685             options = {};
6686           }
6687
6688           this.type = 'default';
6689           this.status = options.status === undefined ? 200 : options.status;
6690           this.ok = this.status >= 200 && this.status < 300;
6691           this.statusText = 'statusText' in options ? options.statusText : '';
6692           this.headers = new Headers$1(options.headers);
6693           this.url = options.url || '';
6694
6695           this._initBody(bodyInit);
6696         }
6697         Body.call(Response.prototype);
6698
6699         Response.prototype.clone = function () {
6700           return new Response(this._bodyInit, {
6701             status: this.status,
6702             statusText: this.statusText,
6703             headers: new Headers$1(this.headers),
6704             url: this.url
6705           });
6706         };
6707
6708         Response.error = function () {
6709           var response = new Response(null, {
6710             status: 0,
6711             statusText: ''
6712           });
6713           response.type = 'error';
6714           return response;
6715         };
6716
6717         var redirectStatuses = [301, 302, 303, 307, 308];
6718
6719         Response.redirect = function (url, status) {
6720           if (redirectStatuses.indexOf(status) === -1) {
6721             throw new RangeError('Invalid status code');
6722           }
6723
6724           return new Response(null, {
6725             status: status,
6726             headers: {
6727               location: url
6728             }
6729           });
6730         };
6731
6732         var DOMException$1 = global$1.DOMException;
6733
6734         try {
6735           new DOMException$1();
6736         } catch (err) {
6737           DOMException$1 = function DOMException(message, name) {
6738             this.message = message;
6739             this.name = name;
6740             var error = Error(message);
6741             this.stack = error.stack;
6742           };
6743
6744           DOMException$1.prototype = Object.create(Error.prototype);
6745           DOMException$1.prototype.constructor = DOMException$1;
6746         }
6747
6748         function fetch$1(input, init) {
6749           return new Promise(function (resolve, reject) {
6750             var request = new Request(input, init);
6751
6752             if (request.signal && request.signal.aborted) {
6753               return reject(new DOMException$1('Aborted', 'AbortError'));
6754             }
6755
6756             var xhr = new XMLHttpRequest();
6757
6758             function abortXhr() {
6759               xhr.abort();
6760             }
6761
6762             xhr.onload = function () {
6763               var options = {
6764                 status: xhr.status,
6765                 statusText: xhr.statusText,
6766                 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
6767               };
6768               options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
6769               var body = 'response' in xhr ? xhr.response : xhr.responseText;
6770               setTimeout(function () {
6771                 resolve(new Response(body, options));
6772               }, 0);
6773             };
6774
6775             xhr.onerror = function () {
6776               setTimeout(function () {
6777                 reject(new TypeError('Network request failed'));
6778               }, 0);
6779             };
6780
6781             xhr.ontimeout = function () {
6782               setTimeout(function () {
6783                 reject(new TypeError('Network request failed'));
6784               }, 0);
6785             };
6786
6787             xhr.onabort = function () {
6788               setTimeout(function () {
6789                 reject(new DOMException$1('Aborted', 'AbortError'));
6790               }, 0);
6791             };
6792
6793             function fixUrl(url) {
6794               try {
6795                 return url === '' && global$1.location.href ? global$1.location.href : url;
6796               } catch (e) {
6797                 return url;
6798               }
6799             }
6800
6801             xhr.open(request.method, fixUrl(request.url), true);
6802
6803             if (request.credentials === 'include') {
6804               xhr.withCredentials = true;
6805             } else if (request.credentials === 'omit') {
6806               xhr.withCredentials = false;
6807             }
6808
6809             if ('responseType' in xhr) {
6810               if (support.blob) {
6811                 xhr.responseType = 'blob';
6812               } else if (support.arrayBuffer && request.headers.get('Content-Type') && request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1) {
6813                 xhr.responseType = 'arraybuffer';
6814               }
6815             }
6816
6817             if (init && _typeof(init.headers) === 'object' && !(init.headers instanceof Headers$1)) {
6818               Object.getOwnPropertyNames(init.headers).forEach(function (name) {
6819                 xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
6820               });
6821             } else {
6822               request.headers.forEach(function (value, name) {
6823                 xhr.setRequestHeader(name, value);
6824               });
6825             }
6826
6827             if (request.signal) {
6828               request.signal.addEventListener('abort', abortXhr);
6829
6830               xhr.onreadystatechange = function () {
6831                 // DONE (success or failure)
6832                 if (xhr.readyState === 4) {
6833                   request.signal.removeEventListener('abort', abortXhr);
6834                 }
6835               };
6836             }
6837
6838             xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
6839           });
6840         }
6841         fetch$1.polyfill = true;
6842
6843         if (!global$1.fetch) {
6844           global$1.fetch = fetch$1;
6845           global$1.Headers = Headers$1;
6846           global$1.Request = Request;
6847           global$1.Response = Response;
6848         }
6849
6850         // `Symbol.toStringTag` well-known symbol
6851         // https://tc39.github.io/ecma262/#sec-symbol.tostringtag
6852         defineWellKnownSymbol('toStringTag');
6853
6854         var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('splice');
6855         var USES_TO_LENGTH$5 = arrayMethodUsesToLength('splice', { ACCESSORS: true, 0: 0, 1: 2 });
6856
6857         var max$3 = Math.max;
6858         var min$6 = Math.min;
6859         var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
6860         var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';
6861
6862         // `Array.prototype.splice` method
6863         // https://tc39.github.io/ecma262/#sec-array.prototype.splice
6864         // with adding support of @@species
6865         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 || !USES_TO_LENGTH$5 }, {
6866           splice: function splice(start, deleteCount /* , ...items */) {
6867             var O = toObject(this);
6868             var len = toLength(O.length);
6869             var actualStart = toAbsoluteIndex(start, len);
6870             var argumentsLength = arguments.length;
6871             var insertCount, actualDeleteCount, A, k, from, to;
6872             if (argumentsLength === 0) {
6873               insertCount = actualDeleteCount = 0;
6874             } else if (argumentsLength === 1) {
6875               insertCount = 0;
6876               actualDeleteCount = len - actualStart;
6877             } else {
6878               insertCount = argumentsLength - 2;
6879               actualDeleteCount = min$6(max$3(toInteger(deleteCount), 0), len - actualStart);
6880             }
6881             if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
6882               throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
6883             }
6884             A = arraySpeciesCreate(O, actualDeleteCount);
6885             for (k = 0; k < actualDeleteCount; k++) {
6886               from = actualStart + k;
6887               if (from in O) createProperty(A, k, O[from]);
6888             }
6889             A.length = actualDeleteCount;
6890             if (insertCount < actualDeleteCount) {
6891               for (k = actualStart; k < len - actualDeleteCount; k++) {
6892                 from = k + actualDeleteCount;
6893                 to = k + insertCount;
6894                 if (from in O) O[to] = O[from];
6895                 else delete O[to];
6896               }
6897               for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
6898             } else if (insertCount > actualDeleteCount) {
6899               for (k = len - actualDeleteCount; k > actualStart; k--) {
6900                 from = k + actualDeleteCount - 1;
6901                 to = k + insertCount - 1;
6902                 if (from in O) O[to] = O[from];
6903                 else delete O[to];
6904               }
6905             }
6906             for (k = 0; k < insertCount; k++) {
6907               O[k + actualStart] = arguments[k + 2];
6908             }
6909             O.length = len - actualDeleteCount + insertCount;
6910             return A;
6911           }
6912         });
6913
6914         // JSON[@@toStringTag] property
6915         // https://tc39.github.io/ecma262/#sec-json-@@tostringtag
6916         setToStringTag(global_1.JSON, 'JSON', true);
6917
6918         // Math[@@toStringTag] property
6919         // https://tc39.github.io/ecma262/#sec-math-@@tostringtag
6920         setToStringTag(Math, 'Math', true);
6921
6922         // `Object.defineProperty` method
6923         // https://tc39.github.io/ecma262/#sec-object.defineproperty
6924         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
6925           defineProperty: objectDefineProperty.f
6926         });
6927
6928         var nativeGetOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
6929
6930
6931         var FAILS_ON_PRIMITIVES$1 = fails(function () { nativeGetOwnPropertyDescriptor$2(1); });
6932         var FORCED$5 = !descriptors || FAILS_ON_PRIMITIVES$1;
6933
6934         // `Object.getOwnPropertyDescriptor` method
6935         // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor
6936         _export({ target: 'Object', stat: true, forced: FORCED$5, sham: !descriptors }, {
6937           getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
6938             return nativeGetOwnPropertyDescriptor$2(toIndexedObject(it), key);
6939           }
6940         });
6941
6942         var FAILS_ON_PRIMITIVES$2 = fails(function () { objectGetPrototypeOf(1); });
6943
6944         // `Object.getPrototypeOf` method
6945         // https://tc39.github.io/ecma262/#sec-object.getprototypeof
6946         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$2, sham: !correctPrototypeGetter }, {
6947           getPrototypeOf: function getPrototypeOf(it) {
6948             return objectGetPrototypeOf(toObject(it));
6949           }
6950         });
6951
6952         // `Object.setPrototypeOf` method
6953         // https://tc39.github.io/ecma262/#sec-object.setprototypeof
6954         _export({ target: 'Object', stat: true }, {
6955           setPrototypeOf: objectSetPrototypeOf
6956         });
6957
6958         var slice$1 = [].slice;
6959         var factories = {};
6960
6961         var construct = function (C, argsLength, args) {
6962           if (!(argsLength in factories)) {
6963             for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']';
6964             // eslint-disable-next-line no-new-func
6965             factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
6966           } return factories[argsLength](C, args);
6967         };
6968
6969         // `Function.prototype.bind` method implementation
6970         // https://tc39.github.io/ecma262/#sec-function.prototype.bind
6971         var functionBind = Function.bind || function bind(that /* , ...args */) {
6972           var fn = aFunction$1(this);
6973           var partArgs = slice$1.call(arguments, 1);
6974           var boundFunction = function bound(/* args... */) {
6975             var args = partArgs.concat(slice$1.call(arguments));
6976             return this instanceof boundFunction ? construct(fn, args.length, args) : fn.apply(that, args);
6977           };
6978           if (isObject(fn.prototype)) boundFunction.prototype = fn.prototype;
6979           return boundFunction;
6980         };
6981
6982         var nativeConstruct = getBuiltIn('Reflect', 'construct');
6983
6984         // `Reflect.construct` method
6985         // https://tc39.github.io/ecma262/#sec-reflect.construct
6986         // MS Edge supports only 2 arguments and argumentsList argument is optional
6987         // FF Nightly sets third argument as `new.target`, but does not create `this` from it
6988         var NEW_TARGET_BUG = fails(function () {
6989           function F() { /* empty */ }
6990           return !(nativeConstruct(function () { /* empty */ }, [], F) instanceof F);
6991         });
6992         var ARGS_BUG = !fails(function () {
6993           nativeConstruct(function () { /* empty */ });
6994         });
6995         var FORCED$6 = NEW_TARGET_BUG || ARGS_BUG;
6996
6997         _export({ target: 'Reflect', stat: true, forced: FORCED$6, sham: FORCED$6 }, {
6998           construct: function construct(Target, args /* , newTarget */) {
6999             aFunction$1(Target);
7000             anObject(args);
7001             var newTarget = arguments.length < 3 ? Target : aFunction$1(arguments[2]);
7002             if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
7003             if (Target == newTarget) {
7004               // w/o altered newTarget, optimization for 0-4 arguments
7005               switch (args.length) {
7006                 case 0: return new Target();
7007                 case 1: return new Target(args[0]);
7008                 case 2: return new Target(args[0], args[1]);
7009                 case 3: return new Target(args[0], args[1], args[2]);
7010                 case 4: return new Target(args[0], args[1], args[2], args[3]);
7011               }
7012               // w/o altered newTarget, lot of arguments case
7013               var $args = [null];
7014               $args.push.apply($args, args);
7015               return new (functionBind.apply(Target, $args))();
7016             }
7017             // with altered newTarget, not support built-in constructors
7018             var proto = newTarget.prototype;
7019             var instance = objectCreate(isObject(proto) ? proto : Object.prototype);
7020             var result = Function.apply.call(Target, instance, args);
7021             return isObject(result) ? result : instance;
7022           }
7023         });
7024
7025         // `Reflect.get` method
7026         // https://tc39.github.io/ecma262/#sec-reflect.get
7027         function get$2(target, propertyKey /* , receiver */) {
7028           var receiver = arguments.length < 3 ? target : arguments[2];
7029           var descriptor, prototype;
7030           if (anObject(target) === receiver) return target[propertyKey];
7031           if (descriptor = objectGetOwnPropertyDescriptor.f(target, propertyKey)) return has(descriptor, 'value')
7032             ? descriptor.value
7033             : descriptor.get === undefined
7034               ? undefined
7035               : descriptor.get.call(receiver);
7036           if (isObject(prototype = objectGetPrototypeOf(target))) return get$2(prototype, propertyKey, receiver);
7037         }
7038
7039         _export({ target: 'Reflect', stat: true }, {
7040           get: get$2
7041         });
7042
7043         (function (factory) {
7044            factory();
7045         })(function () {
7046
7047           function _classCallCheck(instance, Constructor) {
7048             if (!(instance instanceof Constructor)) {
7049               throw new TypeError("Cannot call a class as a function");
7050             }
7051           }
7052
7053           function _defineProperties(target, props) {
7054             for (var i = 0; i < props.length; i++) {
7055               var descriptor = props[i];
7056               descriptor.enumerable = descriptor.enumerable || false;
7057               descriptor.configurable = true;
7058               if ("value" in descriptor) descriptor.writable = true;
7059               Object.defineProperty(target, descriptor.key, descriptor);
7060             }
7061           }
7062
7063           function _createClass(Constructor, protoProps, staticProps) {
7064             if (protoProps) _defineProperties(Constructor.prototype, protoProps);
7065             if (staticProps) _defineProperties(Constructor, staticProps);
7066             return Constructor;
7067           }
7068
7069           function _inherits(subClass, superClass) {
7070             if (typeof superClass !== "function" && superClass !== null) {
7071               throw new TypeError("Super expression must either be null or a function");
7072             }
7073
7074             subClass.prototype = Object.create(superClass && superClass.prototype, {
7075               constructor: {
7076                 value: subClass,
7077                 writable: true,
7078                 configurable: true
7079               }
7080             });
7081             if (superClass) _setPrototypeOf(subClass, superClass);
7082           }
7083
7084           function _getPrototypeOf(o) {
7085             _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
7086               return o.__proto__ || Object.getPrototypeOf(o);
7087             };
7088             return _getPrototypeOf(o);
7089           }
7090
7091           function _setPrototypeOf(o, p) {
7092             _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
7093               o.__proto__ = p;
7094               return o;
7095             };
7096
7097             return _setPrototypeOf(o, p);
7098           }
7099
7100           function _isNativeReflectConstruct() {
7101             if (typeof Reflect === "undefined" || !Reflect.construct) return false;
7102             if (Reflect.construct.sham) return false;
7103             if (typeof Proxy === "function") return true;
7104
7105             try {
7106               Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
7107               return true;
7108             } catch (e) {
7109               return false;
7110             }
7111           }
7112
7113           function _assertThisInitialized(self) {
7114             if (self === void 0) {
7115               throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
7116             }
7117
7118             return self;
7119           }
7120
7121           function _possibleConstructorReturn(self, call) {
7122             if (call && (_typeof(call) === "object" || typeof call === "function")) {
7123               return call;
7124             }
7125
7126             return _assertThisInitialized(self);
7127           }
7128
7129           function _createSuper(Derived) {
7130             var hasNativeReflectConstruct = _isNativeReflectConstruct();
7131
7132             return function _createSuperInternal() {
7133               var Super = _getPrototypeOf(Derived),
7134                   result;
7135
7136               if (hasNativeReflectConstruct) {
7137                 var NewTarget = _getPrototypeOf(this).constructor;
7138
7139                 result = Reflect.construct(Super, arguments, NewTarget);
7140               } else {
7141                 result = Super.apply(this, arguments);
7142               }
7143
7144               return _possibleConstructorReturn(this, result);
7145             };
7146           }
7147
7148           function _superPropBase(object, property) {
7149             while (!Object.prototype.hasOwnProperty.call(object, property)) {
7150               object = _getPrototypeOf(object);
7151               if (object === null) break;
7152             }
7153
7154             return object;
7155           }
7156
7157           function _get(target, property, receiver) {
7158             if (typeof Reflect !== "undefined" && Reflect.get) {
7159               _get = Reflect.get;
7160             } else {
7161               _get = function _get(target, property, receiver) {
7162                 var base = _superPropBase(target, property);
7163
7164                 if (!base) return;
7165                 var desc = Object.getOwnPropertyDescriptor(base, property);
7166
7167                 if (desc.get) {
7168                   return desc.get.call(receiver);
7169                 }
7170
7171                 return desc.value;
7172               };
7173             }
7174
7175             return _get(target, property, receiver || target);
7176           }
7177
7178           var Emitter = /*#__PURE__*/function () {
7179             function Emitter() {
7180               _classCallCheck(this, Emitter);
7181
7182               Object.defineProperty(this, 'listeners', {
7183                 value: {},
7184                 writable: true,
7185                 configurable: true
7186               });
7187             }
7188
7189             _createClass(Emitter, [{
7190               key: "addEventListener",
7191               value: function addEventListener(type, callback) {
7192                 if (!(type in this.listeners)) {
7193                   this.listeners[type] = [];
7194                 }
7195
7196                 this.listeners[type].push(callback);
7197               }
7198             }, {
7199               key: "removeEventListener",
7200               value: function removeEventListener(type, callback) {
7201                 if (!(type in this.listeners)) {
7202                   return;
7203                 }
7204
7205                 var stack = this.listeners[type];
7206
7207                 for (var i = 0, l = stack.length; i < l; i++) {
7208                   if (stack[i] === callback) {
7209                     stack.splice(i, 1);
7210                     return;
7211                   }
7212                 }
7213               }
7214             }, {
7215               key: "dispatchEvent",
7216               value: function dispatchEvent(event) {
7217                 var _this = this;
7218
7219                 if (!(event.type in this.listeners)) {
7220                   return;
7221                 }
7222
7223                 var debounce = function debounce(callback) {
7224                   setTimeout(function () {
7225                     return callback.call(_this, event);
7226                   });
7227                 };
7228
7229                 var stack = this.listeners[event.type];
7230
7231                 for (var i = 0, l = stack.length; i < l; i++) {
7232                   debounce(stack[i]);
7233                 }
7234
7235                 return !event.defaultPrevented;
7236               }
7237             }]);
7238
7239             return Emitter;
7240           }();
7241
7242           var AbortSignal = /*#__PURE__*/function (_Emitter) {
7243             _inherits(AbortSignal, _Emitter);
7244
7245             var _super = _createSuper(AbortSignal);
7246
7247             function AbortSignal() {
7248               var _this2;
7249
7250               _classCallCheck(this, AbortSignal);
7251
7252               _this2 = _super.call(this); // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
7253               // constructor has failed to run, then "this.listeners" will still be undefined and then we call
7254               // the parent constructor directly instead as a workaround. For general details, see babel bug:
7255               // https://github.com/babel/babel/issues/3041
7256               // This hack was added as a fix for the issue described here:
7257               // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
7258
7259               if (!_this2.listeners) {
7260                 Emitter.call(_assertThisInitialized(_this2));
7261               } // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7262               // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
7263
7264
7265               Object.defineProperty(_assertThisInitialized(_this2), 'aborted', {
7266                 value: false,
7267                 writable: true,
7268                 configurable: true
7269               });
7270               Object.defineProperty(_assertThisInitialized(_this2), 'onabort', {
7271                 value: null,
7272                 writable: true,
7273                 configurable: true
7274               });
7275               return _this2;
7276             }
7277
7278             _createClass(AbortSignal, [{
7279               key: "toString",
7280               value: function toString() {
7281                 return '[object AbortSignal]';
7282               }
7283             }, {
7284               key: "dispatchEvent",
7285               value: function dispatchEvent(event) {
7286                 if (event.type === 'abort') {
7287                   this.aborted = true;
7288
7289                   if (typeof this.onabort === 'function') {
7290                     this.onabort.call(this, event);
7291                   }
7292                 }
7293
7294                 _get(_getPrototypeOf(AbortSignal.prototype), "dispatchEvent", this).call(this, event);
7295               }
7296             }]);
7297
7298             return AbortSignal;
7299           }(Emitter);
7300
7301           var AbortController = /*#__PURE__*/function () {
7302             function AbortController() {
7303               _classCallCheck(this, AbortController); // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7304               // we want Object.keys(new AbortController()) to be [] for compat with the native impl
7305
7306
7307               Object.defineProperty(this, 'signal', {
7308                 value: new AbortSignal(),
7309                 writable: true,
7310                 configurable: true
7311               });
7312             }
7313
7314             _createClass(AbortController, [{
7315               key: "abort",
7316               value: function abort() {
7317                 var event;
7318
7319                 try {
7320                   event = new Event('abort');
7321                 } catch (e) {
7322                   if (typeof document !== 'undefined') {
7323                     if (!document.createEvent) {
7324                       // For Internet Explorer 8:
7325                       event = document.createEventObject();
7326                       event.type = 'abort';
7327                     } else {
7328                       // For Internet Explorer 11:
7329                       event = document.createEvent('Event');
7330                       event.initEvent('abort', false, false);
7331                     }
7332                   } else {
7333                     // Fallback where document isn't available:
7334                     event = {
7335                       type: 'abort',
7336                       bubbles: false,
7337                       cancelable: false
7338                     };
7339                   }
7340                 }
7341
7342                 this.signal.dispatchEvent(event);
7343               }
7344             }, {
7345               key: "toString",
7346               value: function toString() {
7347                 return '[object AbortController]';
7348               }
7349             }]);
7350
7351             return AbortController;
7352           }();
7353
7354           if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
7355             // These are necessary to make sure that we get correct output for:
7356             // Object.prototype.toString.call(new AbortController())
7357             AbortController.prototype[Symbol.toStringTag] = 'AbortController';
7358             AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
7359           }
7360
7361           function polyfillNeeded(self) {
7362             if (self.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7363               console.log('__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL=true is set, will force install polyfill');
7364               return true;
7365             } // Note that the "unfetch" minimal fetch polyfill defines fetch() without
7366             // defining window.Request, and this polyfill need to work on top of unfetch
7367             // so the below feature detection needs the !self.AbortController part.
7368             // The Request.prototype check is also needed because Safari versions 11.1.2
7369             // up to and including 12.1.x has a window.AbortController present but still
7370             // does NOT correctly implement abortable fetch:
7371             // https://bugs.webkit.org/show_bug.cgi?id=174980#c2
7372
7373
7374             return typeof self.Request === 'function' && !self.Request.prototype.hasOwnProperty('signal') || !self.AbortController;
7375           }
7376           /**
7377            * Note: the "fetch.Request" default value is available for fetch imported from
7378            * the "node-fetch" package and not in browsers. This is OK since browsers
7379            * will be importing umd-polyfill.js from that path "self" is passed the
7380            * decorator so the default value will not be used (because browsers that define
7381            * fetch also has Request). One quirky setup where self.fetch exists but
7382            * self.Request does not is when the "unfetch" minimal fetch polyfill is used
7383            * on top of IE11; for this case the browser will try to use the fetch.Request
7384            * default value which in turn will be undefined but then then "if (Request)"
7385            * will ensure that you get a patched fetch but still no Request (as expected).
7386            * @param {fetch, Request = fetch.Request}
7387            * @returns {fetch: abortableFetch, Request: AbortableRequest}
7388            */
7389
7390
7391           function abortableFetchDecorator(patchTargets) {
7392             if ('function' === typeof patchTargets) {
7393               patchTargets = {
7394                 fetch: patchTargets
7395               };
7396             }
7397
7398             var _patchTargets = patchTargets,
7399                 fetch = _patchTargets.fetch,
7400                 _patchTargets$Request = _patchTargets.Request,
7401                 NativeRequest = _patchTargets$Request === void 0 ? fetch.Request : _patchTargets$Request,
7402                 NativeAbortController = _patchTargets.AbortController,
7403                 _patchTargets$__FORCE = _patchTargets.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL,
7404                 __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL = _patchTargets$__FORCE === void 0 ? false : _patchTargets$__FORCE;
7405
7406             if (!polyfillNeeded({
7407               fetch: fetch,
7408               Request: NativeRequest,
7409               AbortController: NativeAbortController,
7410               __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL: __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL
7411             })) {
7412               return {
7413                 fetch: fetch,
7414                 Request: Request
7415               };
7416             }
7417
7418             var Request = NativeRequest; // Note that the "unfetch" minimal fetch polyfill defines fetch() without
7419             // defining window.Request, and this polyfill need to work on top of unfetch
7420             // hence we only patch it if it's available. Also we don't patch it if signal
7421             // is already available on the Request prototype because in this case support
7422             // is present and the patching below can cause a crash since it assigns to
7423             // request.signal which is technically a read-only property. This latter error
7424             // happens when you run the main5.js node-fetch example in the repo
7425             // "abortcontroller-polyfill-examples". The exact error is:
7426             //   request.signal = init.signal;
7427             //   ^
7428             // TypeError: Cannot set property signal of #<Request> which has only a getter
7429
7430             if (Request && !Request.prototype.hasOwnProperty('signal') || __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7431               Request = function Request(input, init) {
7432                 var signal;
7433
7434                 if (init && init.signal) {
7435                   signal = init.signal; // Never pass init.signal to the native Request implementation when the polyfill has
7436                   // been installed because if we're running on top of a browser with a
7437                   // working native AbortController (i.e. the polyfill was installed due to
7438                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7439                   // fake AbortSignal to the native fetch will trigger:
7440                   // TypeError: Failed to construct 'Request': member signal is not of type AbortSignal.
7441
7442                   delete init.signal;
7443                 }
7444
7445                 var request = new NativeRequest(input, init);
7446
7447                 if (signal) {
7448                   Object.defineProperty(request, 'signal', {
7449                     writable: false,
7450                     enumerable: false,
7451                     configurable: true,
7452                     value: signal
7453                   });
7454                 }
7455
7456                 return request;
7457               };
7458
7459               Request.prototype = NativeRequest.prototype;
7460             }
7461
7462             var realFetch = fetch;
7463
7464             var abortableFetch = function abortableFetch(input, init) {
7465               var signal = Request && Request.prototype.isPrototypeOf(input) ? input.signal : init ? init.signal : undefined;
7466
7467               if (signal) {
7468                 var abortError;
7469
7470                 try {
7471                   abortError = new DOMException('Aborted', 'AbortError');
7472                 } catch (err) {
7473                   // IE 11 does not support calling the DOMException constructor, use a
7474                   // regular error object on it instead.
7475                   abortError = new Error('Aborted');
7476                   abortError.name = 'AbortError';
7477                 } // Return early if already aborted, thus avoiding making an HTTP request
7478
7479
7480                 if (signal.aborted) {
7481                   return Promise.reject(abortError);
7482                 } // Turn an event into a promise, reject it once `abort` is dispatched
7483
7484
7485                 var cancellation = new Promise(function (_, reject) {
7486                   signal.addEventListener('abort', function () {
7487                     return reject(abortError);
7488                   }, {
7489                     once: true
7490                   });
7491                 });
7492
7493                 if (init && init.signal) {
7494                   // Never pass .signal to the native implementation when the polyfill has
7495                   // been installed because if we're running on top of a browser with a
7496                   // working native AbortController (i.e. the polyfill was installed due to
7497                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7498                   // fake AbortSignal to the native fetch will trigger:
7499                   // TypeError: Failed to execute 'fetch' on 'Window': member signal is not of type AbortSignal.
7500                   delete init.signal;
7501                 } // Return the fastest promise (don't need to wait for request to finish)
7502
7503
7504                 return Promise.race([cancellation, realFetch(input, init)]);
7505               }
7506
7507               return realFetch(input, init);
7508             };
7509
7510             return {
7511               fetch: abortableFetch,
7512               Request: Request
7513             };
7514           }
7515
7516           (function (self) {
7517             if (!polyfillNeeded(self)) {
7518               return;
7519             }
7520
7521             if (!self.fetch) {
7522               console.warn('fetch() is not available, cannot install abortcontroller-polyfill');
7523               return;
7524             }
7525
7526             var _abortableFetch = abortableFetchDecorator(self),
7527                 fetch = _abortableFetch.fetch,
7528                 Request = _abortableFetch.Request;
7529
7530             self.fetch = fetch;
7531             self.Request = Request;
7532             Object.defineProperty(self, 'AbortController', {
7533               writable: true,
7534               enumerable: false,
7535               configurable: true,
7536               value: AbortController
7537             });
7538             Object.defineProperty(self, 'AbortSignal', {
7539               writable: true,
7540               enumerable: false,
7541               configurable: true,
7542               value: AbortSignal
7543             });
7544           })(typeof self !== 'undefined' ? self : commonjsGlobal);
7545         });
7546
7547         function actionAddEntity(way) {
7548           return function (graph) {
7549             return graph.replace(way);
7550           };
7551         }
7552
7553         var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
7554         var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
7555         var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
7556
7557         // We can't use this feature detection in V8 since it causes
7558         // deoptimization and serious performance degradation
7559         // https://github.com/zloirock/core-js/issues/679
7560         var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
7561           var array = [];
7562           array[IS_CONCAT_SPREADABLE] = false;
7563           return array.concat()[0] !== array;
7564         });
7565
7566         var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');
7567
7568         var isConcatSpreadable = function (O) {
7569           if (!isObject(O)) return false;
7570           var spreadable = O[IS_CONCAT_SPREADABLE];
7571           return spreadable !== undefined ? !!spreadable : isArray(O);
7572         };
7573
7574         var FORCED$7 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
7575
7576         // `Array.prototype.concat` method
7577         // https://tc39.github.io/ecma262/#sec-array.prototype.concat
7578         // with adding support of @@isConcatSpreadable and @@species
7579         _export({ target: 'Array', proto: true, forced: FORCED$7 }, {
7580           concat: function concat(arg) { // eslint-disable-line no-unused-vars
7581             var O = toObject(this);
7582             var A = arraySpeciesCreate(O, 0);
7583             var n = 0;
7584             var i, k, length, len, E;
7585             for (i = -1, length = arguments.length; i < length; i++) {
7586               E = i === -1 ? O : arguments[i];
7587               if (isConcatSpreadable(E)) {
7588                 len = toLength(E.length);
7589                 if (n + len > MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7590                 for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
7591               } else {
7592                 if (n >= MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7593                 createProperty(A, n++, E);
7594               }
7595             }
7596             A.length = n;
7597             return A;
7598           }
7599         });
7600
7601         // `Object.assign` method
7602         // https://tc39.github.io/ecma262/#sec-object.assign
7603         _export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, {
7604           assign: objectAssign
7605         });
7606
7607         var $filter$1 = arrayIteration.filter;
7608
7609
7610
7611         var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport('filter');
7612         // Edge 14- issue
7613         var USES_TO_LENGTH$6 = arrayMethodUsesToLength('filter');
7614
7615         // `Array.prototype.filter` method
7616         // https://tc39.github.io/ecma262/#sec-array.prototype.filter
7617         // with adding support of @@species
7618         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$3 || !USES_TO_LENGTH$6 }, {
7619           filter: function filter(callbackfn /* , thisArg */) {
7620             return $filter$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
7621           }
7622         });
7623
7624         var nativeReverse = [].reverse;
7625         var test$1 = [1, 2];
7626
7627         // `Array.prototype.reverse` method
7628         // https://tc39.github.io/ecma262/#sec-array.prototype.reverse
7629         // fix for Safari 12.0 bug
7630         // https://bugs.webkit.org/show_bug.cgi?id=188794
7631         _export({ target: 'Array', proto: true, forced: String(test$1) === String(test$1.reverse()) }, {
7632           reverse: function reverse() {
7633             // eslint-disable-next-line no-self-assign
7634             if (isArray(this)) this.length = this.length;
7635             return nativeReverse.call(this);
7636           }
7637         });
7638
7639         var FAILS_ON_PRIMITIVES$3 = fails(function () { objectKeys(1); });
7640
7641         // `Object.keys` method
7642         // https://tc39.github.io/ecma262/#sec-object.keys
7643         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$3 }, {
7644           keys: function keys(it) {
7645             return objectKeys(toObject(it));
7646           }
7647         });
7648
7649         var trim = stringTrim.trim;
7650
7651
7652         var $parseFloat = global_1.parseFloat;
7653         var FORCED$8 = 1 / $parseFloat(whitespaces + '-0') !== -Infinity;
7654
7655         // `parseFloat` method
7656         // https://tc39.github.io/ecma262/#sec-parsefloat-string
7657         var numberParseFloat = FORCED$8 ? function parseFloat(string) {
7658           var trimmedString = trim(String(string));
7659           var result = $parseFloat(trimmedString);
7660           return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
7661         } : $parseFloat;
7662
7663         // `parseFloat` method
7664         // https://tc39.github.io/ecma262/#sec-parsefloat-string
7665         _export({ global: true, forced: parseFloat != numberParseFloat }, {
7666           parseFloat: numberParseFloat
7667         });
7668
7669         /*
7670         Order the nodes of a way in reverse order and reverse any direction dependent tags
7671         other than `oneway`. (We assume that correcting a backwards oneway is the primary
7672         reason for reversing a way.)
7673
7674         In addition, numeric-valued `incline` tags are negated.
7675
7676         The JOSM implementation was used as a guide, but transformations that were of unclear benefit
7677         or adjusted tags that don't seem to be used in practice were omitted.
7678
7679         References:
7680             http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
7681             http://wiki.openstreetmap.org/wiki/Key:direction#Steps
7682             http://wiki.openstreetmap.org/wiki/Key:incline
7683             http://wiki.openstreetmap.org/wiki/Route#Members
7684             http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
7685             http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
7686             http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
7687         */
7688         function actionReverse(entityID, options) {
7689           var ignoreKey = /^.*(_|:)?(description|name|note|website|ref|source|comment|watch|attribution)(_|:)?/;
7690           var numeric = /^([+\-]?)(?=[\d.])/;
7691           var directionKey = /direction$/;
7692           var turn_lanes = /^turn:lanes:?/;
7693           var keyReplacements = [[/:right$/, ':left'], [/:left$/, ':right'], [/:forward$/, ':backward'], [/:backward$/, ':forward'], [/:right:/, ':left:'], [/:left:/, ':right:'], [/:forward:/, ':backward:'], [/:backward:/, ':forward:']];
7694           var valueReplacements = {
7695             left: 'right',
7696             right: 'left',
7697             up: 'down',
7698             down: 'up',
7699             forward: 'backward',
7700             backward: 'forward',
7701             forwards: 'backward',
7702             backwards: 'forward'
7703           };
7704           var roleReplacements = {
7705             forward: 'backward',
7706             backward: 'forward',
7707             forwards: 'backward',
7708             backwards: 'forward'
7709           };
7710           var onewayReplacements = {
7711             yes: '-1',
7712             '1': '-1',
7713             '-1': 'yes'
7714           };
7715           var compassReplacements = {
7716             N: 'S',
7717             NNE: 'SSW',
7718             NE: 'SW',
7719             ENE: 'WSW',
7720             E: 'W',
7721             ESE: 'WNW',
7722             SE: 'NW',
7723             SSE: 'NNW',
7724             S: 'N',
7725             SSW: 'NNE',
7726             SW: 'NE',
7727             WSW: 'ENE',
7728             W: 'E',
7729             WNW: 'ESE',
7730             NW: 'SE',
7731             NNW: 'SSE'
7732           };
7733
7734           function reverseKey(key) {
7735             for (var i = 0; i < keyReplacements.length; ++i) {
7736               var replacement = keyReplacements[i];
7737
7738               if (replacement[0].test(key)) {
7739                 return key.replace(replacement[0], replacement[1]);
7740               }
7741             }
7742
7743             return key;
7744           }
7745
7746           function reverseValue(key, value, includeAbsolute) {
7747             if (ignoreKey.test(key)) return value; // Turn lanes are left/right to key (not way) direction - #5674
7748
7749             if (turn_lanes.test(key)) {
7750               return value;
7751             } else if (key === 'incline' && numeric.test(value)) {
7752               return value.replace(numeric, function (_, sign) {
7753                 return sign === '-' ? '' : '-';
7754               });
7755             } else if (options && options.reverseOneway && key === 'oneway') {
7756               return onewayReplacements[value] || value;
7757             } else if (includeAbsolute && directionKey.test(key)) {
7758               if (compassReplacements[value]) return compassReplacements[value];
7759               var degrees = parseFloat(value);
7760
7761               if (typeof degrees === 'number' && !isNaN(degrees)) {
7762                 if (degrees < 180) {
7763                   degrees += 180;
7764                 } else {
7765                   degrees -= 180;
7766                 }
7767
7768                 return degrees.toString();
7769               }
7770             }
7771
7772             return valueReplacements[value] || value;
7773           } // Reverse the direction of tags attached to the nodes - #3076
7774
7775
7776           function reverseNodeTags(graph, nodeIDs) {
7777             for (var i = 0; i < nodeIDs.length; i++) {
7778               var node = graph.hasEntity(nodeIDs[i]);
7779               if (!node || !Object.keys(node.tags).length) continue;
7780               var tags = {};
7781
7782               for (var key in node.tags) {
7783                 tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID);
7784               }
7785
7786               graph = graph.replace(node.update({
7787                 tags: tags
7788               }));
7789             }
7790
7791             return graph;
7792           }
7793
7794           function reverseWay(graph, way) {
7795             var nodes = way.nodes.slice().reverse();
7796             var tags = {};
7797             var role;
7798
7799             for (var key in way.tags) {
7800               tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
7801             }
7802
7803             graph.parentRelations(way).forEach(function (relation) {
7804               relation.members.forEach(function (member, index) {
7805                 if (member.id === way.id && (role = roleReplacements[member.role])) {
7806                   relation = relation.updateMember({
7807                     role: role
7808                   }, index);
7809                   graph = graph.replace(relation);
7810                 }
7811               });
7812             }); // Reverse any associated directions on nodes on the way and then replace
7813             // the way itself with the reversed node ids and updated way tags
7814
7815             return reverseNodeTags(graph, nodes).replace(way.update({
7816               nodes: nodes,
7817               tags: tags
7818             }));
7819           }
7820
7821           var action = function action(graph) {
7822             var entity = graph.entity(entityID);
7823
7824             if (entity.type === 'way') {
7825               return reverseWay(graph, entity);
7826             }
7827
7828             return reverseNodeTags(graph, [entityID]);
7829           };
7830
7831           action.disabled = function (graph) {
7832             var entity = graph.hasEntity(entityID);
7833             if (!entity || entity.type === 'way') return false;
7834
7835             for (var key in entity.tags) {
7836               var value = entity.tags[key];
7837
7838               if (reverseKey(key) !== key || reverseValue(key, value, true) !== value) {
7839                 return false;
7840               }
7841             }
7842
7843             return 'nondirectional_node';
7844           };
7845
7846           action.entityID = function () {
7847             return entityID;
7848           };
7849
7850           return action;
7851         }
7852
7853         function osmIsInterestingTag(key) {
7854           return key !== 'attribution' && key !== 'created_by' && key !== 'source' && key !== 'odbl' && key.indexOf('source:') !== 0 && key.indexOf('source_ref') !== 0 && // purposely exclude colon
7855           key.indexOf('tiger:') !== 0;
7856         }
7857         var osmAreaKeys = {};
7858         function osmSetAreaKeys(value) {
7859           osmAreaKeys = value;
7860         } // returns an object with the tag from `tags` that implies an area geometry, if any
7861
7862         function osmTagSuggestingArea(tags) {
7863           if (tags.area === 'yes') return {
7864             area: 'yes'
7865           };
7866           if (tags.area === 'no') return null; // `highway` and `railway` are typically linear features, but there
7867           // are a few exceptions that should be treated as areas, even in the
7868           // absence of a proper `area=yes` or `areaKeys` tag.. see #4194
7869
7870           var lineKeys = {
7871             highway: {
7872               rest_area: true,
7873               services: true
7874             },
7875             railway: {
7876               roundhouse: true,
7877               station: true,
7878               traverser: true,
7879               turntable: true,
7880               wash: true
7881             }
7882           };
7883           var returnTags = {};
7884
7885           for (var key in tags) {
7886             if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
7887               returnTags[key] = tags[key];
7888               return returnTags;
7889             }
7890
7891             if (key in lineKeys && tags[key] in lineKeys[key]) {
7892               returnTags[key] = tags[key];
7893               return returnTags;
7894             }
7895           }
7896
7897           return null;
7898         } // Tags that indicate a node can be a standalone point
7899         // e.g. { amenity: { bar: true, parking: true, ... } ... }
7900
7901         var osmPointTags = {};
7902         function osmSetPointTags(value) {
7903           osmPointTags = value;
7904         } // Tags that indicate a node can be part of a way
7905         // e.g. { amenity: { parking: true, ... }, highway: { stop: true ... } ... }
7906
7907         var osmVertexTags = {};
7908         function osmSetVertexTags(value) {
7909           osmVertexTags = value;
7910         }
7911         function osmNodeGeometriesForTags(nodeTags) {
7912           var geometries = {};
7913
7914           for (var key in nodeTags) {
7915             if (osmPointTags[key] && (osmPointTags[key]['*'] || osmPointTags[key][nodeTags[key]])) {
7916               geometries.point = true;
7917             }
7918
7919             if (osmVertexTags[key] && (osmVertexTags[key]['*'] || osmVertexTags[key][nodeTags[key]])) {
7920               geometries.vertex = true;
7921             } // break early if both are already supported
7922
7923
7924             if (geometries.point && geometries.vertex) break;
7925           }
7926
7927           return geometries;
7928         }
7929         var osmOneWayTags = {
7930           'aerialway': {
7931             'chair_lift': true,
7932             'drag_lift': true,
7933             'j-bar': true,
7934             'magic_carpet': true,
7935             'mixed_lift': true,
7936             'platter': true,
7937             'rope_tow': true,
7938             't-bar': true,
7939             'zip_line': true
7940           },
7941           'highway': {
7942             'motorway': true
7943           },
7944           'junction': {
7945             'circular': true,
7946             'roundabout': true
7947           },
7948           'man_made': {
7949             'goods_conveyor': true,
7950             'piste:halfpipe': true
7951           },
7952           'piste:type': {
7953             'downhill': true,
7954             'sled': true,
7955             'yes': true
7956           },
7957           'waterway': {
7958             'canal': true,
7959             'ditch': true,
7960             'drain': true,
7961             'fish_pass': true,
7962             'river': true,
7963             'stream': true,
7964             'tidal_channel': true
7965           }
7966         }; // solid and smooth surfaces akin to the assumed default road surface in OSM
7967
7968         var osmPavedTags = {
7969           'surface': {
7970             'paved': true,
7971             'asphalt': true,
7972             'concrete': true,
7973             'concrete:lanes': true,
7974             'concrete:plates': true
7975           },
7976           'tracktype': {
7977             'grade1': true
7978           }
7979         }; // solid, if somewhat uncommon surfaces with a high range of smoothness
7980
7981         var osmSemipavedTags = {
7982           'surface': {
7983             'cobblestone': true,
7984             'cobblestone:flattened': true,
7985             'unhewn_cobblestone': true,
7986             'sett': true,
7987             'paving_stones': true,
7988             'metal': true,
7989             'wood': true
7990           }
7991         };
7992         var osmRightSideIsInsideTags = {
7993           'natural': {
7994             'cliff': true,
7995             'coastline': 'coastline'
7996           },
7997           'barrier': {
7998             'retaining_wall': true,
7999             'kerb': true,
8000             'guard_rail': true,
8001             'city_wall': true
8002           },
8003           'man_made': {
8004             'embankment': true
8005           },
8006           'waterway': {
8007             'weir': true
8008           }
8009         }; // "highway" tag values for pedestrian or vehicle right-of-ways that make up the routable network
8010         // (does not include `raceway`)
8011
8012         var osmRoutableHighwayTagValues = {
8013           motorway: true,
8014           trunk: true,
8015           primary: true,
8016           secondary: true,
8017           tertiary: true,
8018           residential: true,
8019           motorway_link: true,
8020           trunk_link: true,
8021           primary_link: true,
8022           secondary_link: true,
8023           tertiary_link: true,
8024           unclassified: true,
8025           road: true,
8026           service: true,
8027           track: true,
8028           living_street: true,
8029           bus_guideway: true,
8030           path: true,
8031           footway: true,
8032           cycleway: true,
8033           bridleway: true,
8034           pedestrian: true,
8035           corridor: true,
8036           steps: true
8037         }; // "highway" tag values that generally do not allow motor vehicles
8038
8039         var osmPathHighwayTagValues = {
8040           path: true,
8041           footway: true,
8042           cycleway: true,
8043           bridleway: true,
8044           pedestrian: true,
8045           corridor: true,
8046           steps: true
8047         }; // "railway" tag values representing existing railroad tracks (purposely does not include 'abandoned')
8048
8049         var osmRailwayTrackTagValues = {
8050           rail: true,
8051           light_rail: true,
8052           tram: true,
8053           subway: true,
8054           monorail: true,
8055           funicular: true,
8056           miniature: true,
8057           narrow_gauge: true,
8058           disused: true,
8059           preserved: true
8060         }; // "waterway" tag values for line features representing water flow
8061
8062         var osmFlowingWaterwayTagValues = {
8063           canal: true,
8064           ditch: true,
8065           drain: true,
8066           fish_pass: true,
8067           river: true,
8068           stream: true,
8069           tidal_channel: true
8070         };
8071
8072         var trim$1 = stringTrim.trim;
8073
8074
8075         var $parseInt = global_1.parseInt;
8076         var hex$1 = /^[+-]?0[Xx]/;
8077         var FORCED$9 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22;
8078
8079         // `parseInt` method
8080         // https://tc39.github.io/ecma262/#sec-parseint-string-radix
8081         var numberParseInt = FORCED$9 ? function parseInt(string, radix) {
8082           var S = trim$1(String(string));
8083           return $parseInt(S, (radix >>> 0) || (hex$1.test(S) ? 16 : 10));
8084         } : $parseInt;
8085
8086         // `parseInt` method
8087         // https://tc39.github.io/ecma262/#sec-parseint-string-radix
8088         _export({ global: true, forced: parseInt != numberParseInt }, {
8089           parseInt: numberParseInt
8090         });
8091
8092         var freezing = !fails(function () {
8093           return Object.isExtensible(Object.preventExtensions({}));
8094         });
8095
8096         var internalMetadata = createCommonjsModule(function (module) {
8097         var defineProperty = objectDefineProperty.f;
8098
8099
8100
8101         var METADATA = uid('meta');
8102         var id = 0;
8103
8104         var isExtensible = Object.isExtensible || function () {
8105           return true;
8106         };
8107
8108         var setMetadata = function (it) {
8109           defineProperty(it, METADATA, { value: {
8110             objectID: 'O' + ++id, // object ID
8111             weakData: {}          // weak collections IDs
8112           } });
8113         };
8114
8115         var fastKey = function (it, create) {
8116           // return a primitive with prefix
8117           if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
8118           if (!has(it, METADATA)) {
8119             // can't set metadata to uncaught frozen object
8120             if (!isExtensible(it)) return 'F';
8121             // not necessary to add metadata
8122             if (!create) return 'E';
8123             // add missing metadata
8124             setMetadata(it);
8125           // return object ID
8126           } return it[METADATA].objectID;
8127         };
8128
8129         var getWeakData = function (it, create) {
8130           if (!has(it, METADATA)) {
8131             // can't set metadata to uncaught frozen object
8132             if (!isExtensible(it)) return true;
8133             // not necessary to add metadata
8134             if (!create) return false;
8135             // add missing metadata
8136             setMetadata(it);
8137           // return the store of weak collections IDs
8138           } return it[METADATA].weakData;
8139         };
8140
8141         // add metadata on freeze-family methods calling
8142         var onFreeze = function (it) {
8143           if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
8144           return it;
8145         };
8146
8147         var meta = module.exports = {
8148           REQUIRED: false,
8149           fastKey: fastKey,
8150           getWeakData: getWeakData,
8151           onFreeze: onFreeze
8152         };
8153
8154         hiddenKeys[METADATA] = true;
8155         });
8156
8157         var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
8158           var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
8159           var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
8160           var ADDER = IS_MAP ? 'set' : 'add';
8161           var NativeConstructor = global_1[CONSTRUCTOR_NAME];
8162           var NativePrototype = NativeConstructor && NativeConstructor.prototype;
8163           var Constructor = NativeConstructor;
8164           var exported = {};
8165
8166           var fixMethod = function (KEY) {
8167             var nativeMethod = NativePrototype[KEY];
8168             redefine(NativePrototype, KEY,
8169               KEY == 'add' ? function add(value) {
8170                 nativeMethod.call(this, value === 0 ? 0 : value);
8171                 return this;
8172               } : KEY == 'delete' ? function (key) {
8173                 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8174               } : KEY == 'get' ? function get(key) {
8175                 return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
8176               } : KEY == 'has' ? function has(key) {
8177                 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8178               } : function set(key, value) {
8179                 nativeMethod.call(this, key === 0 ? 0 : key, value);
8180                 return this;
8181               }
8182             );
8183           };
8184
8185           // eslint-disable-next-line max-len
8186           if (isForced_1(CONSTRUCTOR_NAME, typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
8187             new NativeConstructor().entries().next();
8188           })))) {
8189             // create collection constructor
8190             Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
8191             internalMetadata.REQUIRED = true;
8192           } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
8193             var instance = new Constructor();
8194             // early implementations not supports chaining
8195             var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;
8196             // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
8197             var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });
8198             // most early implementations doesn't supports iterables, most modern - not close it correctly
8199             // eslint-disable-next-line no-new
8200             var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { new NativeConstructor(iterable); });
8201             // for early implementations -0 and +0 not the same
8202             var BUGGY_ZERO = !IS_WEAK && fails(function () {
8203               // V8 ~ Chromium 42- fails only with 5+ elements
8204               var $instance = new NativeConstructor();
8205               var index = 5;
8206               while (index--) $instance[ADDER](index, index);
8207               return !$instance.has(-0);
8208             });
8209
8210             if (!ACCEPT_ITERABLES) {
8211               Constructor = wrapper(function (dummy, iterable) {
8212                 anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
8213                 var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
8214                 if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
8215                 return that;
8216               });
8217               Constructor.prototype = NativePrototype;
8218               NativePrototype.constructor = Constructor;
8219             }
8220
8221             if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
8222               fixMethod('delete');
8223               fixMethod('has');
8224               IS_MAP && fixMethod('get');
8225             }
8226
8227             if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);
8228
8229             // weak collections should not contains .clear method
8230             if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
8231           }
8232
8233           exported[CONSTRUCTOR_NAME] = Constructor;
8234           _export({ global: true, forced: Constructor != NativeConstructor }, exported);
8235
8236           setToStringTag(Constructor, CONSTRUCTOR_NAME);
8237
8238           if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
8239
8240           return Constructor;
8241         };
8242
8243         var defineProperty$8 = objectDefineProperty.f;
8244
8245
8246
8247
8248
8249
8250
8251
8252         var fastKey = internalMetadata.fastKey;
8253
8254
8255         var setInternalState$7 = internalState.set;
8256         var internalStateGetterFor = internalState.getterFor;
8257
8258         var collectionStrong = {
8259           getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
8260             var C = wrapper(function (that, iterable) {
8261               anInstance(that, C, CONSTRUCTOR_NAME);
8262               setInternalState$7(that, {
8263                 type: CONSTRUCTOR_NAME,
8264                 index: objectCreate(null),
8265                 first: undefined,
8266                 last: undefined,
8267                 size: 0
8268               });
8269               if (!descriptors) that.size = 0;
8270               if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
8271             });
8272
8273             var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
8274
8275             var define = function (that, key, value) {
8276               var state = getInternalState(that);
8277               var entry = getEntry(that, key);
8278               var previous, index;
8279               // change existing entry
8280               if (entry) {
8281                 entry.value = value;
8282               // create new entry
8283               } else {
8284                 state.last = entry = {
8285                   index: index = fastKey(key, true),
8286                   key: key,
8287                   value: value,
8288                   previous: previous = state.last,
8289                   next: undefined,
8290                   removed: false
8291                 };
8292                 if (!state.first) state.first = entry;
8293                 if (previous) previous.next = entry;
8294                 if (descriptors) state.size++;
8295                 else that.size++;
8296                 // add to index
8297                 if (index !== 'F') state.index[index] = entry;
8298               } return that;
8299             };
8300
8301             var getEntry = function (that, key) {
8302               var state = getInternalState(that);
8303               // fast case
8304               var index = fastKey(key);
8305               var entry;
8306               if (index !== 'F') return state.index[index];
8307               // frozen object case
8308               for (entry = state.first; entry; entry = entry.next) {
8309                 if (entry.key == key) return entry;
8310               }
8311             };
8312
8313             redefineAll(C.prototype, {
8314               // 23.1.3.1 Map.prototype.clear()
8315               // 23.2.3.2 Set.prototype.clear()
8316               clear: function clear() {
8317                 var that = this;
8318                 var state = getInternalState(that);
8319                 var data = state.index;
8320                 var entry = state.first;
8321                 while (entry) {
8322                   entry.removed = true;
8323                   if (entry.previous) entry.previous = entry.previous.next = undefined;
8324                   delete data[entry.index];
8325                   entry = entry.next;
8326                 }
8327                 state.first = state.last = undefined;
8328                 if (descriptors) state.size = 0;
8329                 else that.size = 0;
8330               },
8331               // 23.1.3.3 Map.prototype.delete(key)
8332               // 23.2.3.4 Set.prototype.delete(value)
8333               'delete': function (key) {
8334                 var that = this;
8335                 var state = getInternalState(that);
8336                 var entry = getEntry(that, key);
8337                 if (entry) {
8338                   var next = entry.next;
8339                   var prev = entry.previous;
8340                   delete state.index[entry.index];
8341                   entry.removed = true;
8342                   if (prev) prev.next = next;
8343                   if (next) next.previous = prev;
8344                   if (state.first == entry) state.first = next;
8345                   if (state.last == entry) state.last = prev;
8346                   if (descriptors) state.size--;
8347                   else that.size--;
8348                 } return !!entry;
8349               },
8350               // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
8351               // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
8352               forEach: function forEach(callbackfn /* , that = undefined */) {
8353                 var state = getInternalState(this);
8354                 var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
8355                 var entry;
8356                 while (entry = entry ? entry.next : state.first) {
8357                   boundFunction(entry.value, entry.key, this);
8358                   // revert to the last existing entry
8359                   while (entry && entry.removed) entry = entry.previous;
8360                 }
8361               },
8362               // 23.1.3.7 Map.prototype.has(key)
8363               // 23.2.3.7 Set.prototype.has(value)
8364               has: function has(key) {
8365                 return !!getEntry(this, key);
8366               }
8367             });
8368
8369             redefineAll(C.prototype, IS_MAP ? {
8370               // 23.1.3.6 Map.prototype.get(key)
8371               get: function get(key) {
8372                 var entry = getEntry(this, key);
8373                 return entry && entry.value;
8374               },
8375               // 23.1.3.9 Map.prototype.set(key, value)
8376               set: function set(key, value) {
8377                 return define(this, key === 0 ? 0 : key, value);
8378               }
8379             } : {
8380               // 23.2.3.1 Set.prototype.add(value)
8381               add: function add(value) {
8382                 return define(this, value = value === 0 ? 0 : value, value);
8383               }
8384             });
8385             if (descriptors) defineProperty$8(C.prototype, 'size', {
8386               get: function () {
8387                 return getInternalState(this).size;
8388               }
8389             });
8390             return C;
8391           },
8392           setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
8393             var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
8394             var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
8395             var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
8396             // add .keys, .values, .entries, [@@iterator]
8397             // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11
8398             defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
8399               setInternalState$7(this, {
8400                 type: ITERATOR_NAME,
8401                 target: iterated,
8402                 state: getInternalCollectionState(iterated),
8403                 kind: kind,
8404                 last: undefined
8405               });
8406             }, function () {
8407               var state = getInternalIteratorState(this);
8408               var kind = state.kind;
8409               var entry = state.last;
8410               // revert to the last existing entry
8411               while (entry && entry.removed) entry = entry.previous;
8412               // get next entry
8413               if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
8414                 // or finish the iteration
8415                 state.target = undefined;
8416                 return { value: undefined, done: true };
8417               }
8418               // return step by kind
8419               if (kind == 'keys') return { value: entry.key, done: false };
8420               if (kind == 'values') return { value: entry.value, done: false };
8421               return { value: [entry.key, entry.value], done: false };
8422             }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
8423
8424             // add [@@species], 23.1.2.2, 23.2.2.2
8425             setSpecies(CONSTRUCTOR_NAME);
8426           }
8427         };
8428
8429         // `Set` constructor
8430         // https://tc39.github.io/ecma262/#sec-set-objects
8431         var es_set = collection('Set', function (init) {
8432           return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };
8433         }, collectionStrong);
8434
8435         function d3_ascending (a, b) {
8436           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
8437         }
8438
8439         function d3_bisector (f) {
8440           var delta = f;
8441           var compare = f;
8442
8443           if (f.length === 1) {
8444             delta = function delta(d, x) {
8445               return f(d) - x;
8446             };
8447
8448             compare = ascendingComparator(f);
8449           }
8450
8451           function left(a, x, lo, hi) {
8452             if (lo == null) lo = 0;
8453             if (hi == null) hi = a.length;
8454
8455             while (lo < hi) {
8456               var mid = lo + hi >>> 1;
8457               if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid;
8458             }
8459
8460             return lo;
8461           }
8462
8463           function right(a, x, lo, hi) {
8464             if (lo == null) lo = 0;
8465             if (hi == null) hi = a.length;
8466
8467             while (lo < hi) {
8468               var mid = lo + hi >>> 1;
8469               if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1;
8470             }
8471
8472             return lo;
8473           }
8474
8475           function center(a, x, lo, hi) {
8476             if (lo == null) lo = 0;
8477             if (hi == null) hi = a.length;
8478             var i = left(a, x, lo, hi - 1);
8479             return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
8480           }
8481
8482           return {
8483             left: left,
8484             center: center,
8485             right: right
8486           };
8487         }
8488
8489         function ascendingComparator(f) {
8490           return function (d, x) {
8491             return d3_ascending(f(d), x);
8492           };
8493         }
8494
8495         // `Symbol.asyncIterator` well-known symbol
8496         // https://tc39.github.io/ecma262/#sec-symbol.asynciterator
8497         defineWellKnownSymbol('asyncIterator');
8498
8499         var runtime_1 = createCommonjsModule(function (module) {
8500           /**
8501            * Copyright (c) 2014-present, Facebook, Inc.
8502            *
8503            * This source code is licensed under the MIT license found in the
8504            * LICENSE file in the root directory of this source tree.
8505            */
8506           var runtime = function (exports) {
8507
8508             var Op = Object.prototype;
8509             var hasOwn = Op.hasOwnProperty;
8510             var undefined$1; // More compressible than void 0.
8511
8512             var $Symbol = typeof Symbol === "function" ? Symbol : {};
8513             var iteratorSymbol = $Symbol.iterator || "@@iterator";
8514             var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
8515             var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
8516
8517             function define(obj, key, value) {
8518               Object.defineProperty(obj, key, {
8519                 value: value,
8520                 enumerable: true,
8521                 configurable: true,
8522                 writable: true
8523               });
8524               return obj[key];
8525             }
8526
8527             try {
8528               // IE 8 has a broken Object.defineProperty that only works on DOM objects.
8529               define({}, "");
8530             } catch (err) {
8531               define = function define(obj, key, value) {
8532                 return obj[key] = value;
8533               };
8534             }
8535
8536             function wrap(innerFn, outerFn, self, tryLocsList) {
8537               // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
8538               var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
8539               var generator = Object.create(protoGenerator.prototype);
8540               var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
8541               // .throw, and .return methods.
8542
8543               generator._invoke = makeInvokeMethod(innerFn, self, context);
8544               return generator;
8545             }
8546
8547             exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
8548             // record like context.tryEntries[i].completion. This interface could
8549             // have been (and was previously) designed to take a closure to be
8550             // invoked without arguments, but in all the cases we care about we
8551             // already have an existing method we want to call, so there's no need
8552             // to create a new function object. We can even get away with assuming
8553             // the method takes exactly one argument, since that happens to be true
8554             // in every case, so we don't have to touch the arguments object. The
8555             // only additional allocation required is the completion record, which
8556             // has a stable shape and so hopefully should be cheap to allocate.
8557
8558             function tryCatch(fn, obj, arg) {
8559               try {
8560                 return {
8561                   type: "normal",
8562                   arg: fn.call(obj, arg)
8563                 };
8564               } catch (err) {
8565                 return {
8566                   type: "throw",
8567                   arg: err
8568                 };
8569               }
8570             }
8571
8572             var GenStateSuspendedStart = "suspendedStart";
8573             var GenStateSuspendedYield = "suspendedYield";
8574             var GenStateExecuting = "executing";
8575             var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
8576             // breaking out of the dispatch switch statement.
8577
8578             var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
8579             // .constructor.prototype properties for functions that return Generator
8580             // objects. For full spec compliance, you may wish to configure your
8581             // minifier not to mangle the names of these two functions.
8582
8583             function Generator() {}
8584
8585             function GeneratorFunction() {}
8586
8587             function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
8588             // don't natively support it.
8589
8590
8591             var IteratorPrototype = {};
8592
8593             IteratorPrototype[iteratorSymbol] = function () {
8594               return this;
8595             };
8596
8597             var getProto = Object.getPrototypeOf;
8598             var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
8599
8600             if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
8601               // This environment has a native %IteratorPrototype%; use it instead
8602               // of the polyfill.
8603               IteratorPrototype = NativeIteratorPrototype;
8604             }
8605
8606             var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
8607             GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
8608             GeneratorFunctionPrototype.constructor = GeneratorFunction;
8609             GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
8610             // Iterator interface in terms of a single ._invoke method.
8611
8612             function defineIteratorMethods(prototype) {
8613               ["next", "throw", "return"].forEach(function (method) {
8614                 define(prototype, method, function (arg) {
8615                   return this._invoke(method, arg);
8616                 });
8617               });
8618             }
8619
8620             exports.isGeneratorFunction = function (genFun) {
8621               var ctor = typeof genFun === "function" && genFun.constructor;
8622               return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
8623               // do is to check its .name property.
8624               (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
8625             };
8626
8627             exports.mark = function (genFun) {
8628               if (Object.setPrototypeOf) {
8629                 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
8630               } else {
8631                 genFun.__proto__ = GeneratorFunctionPrototype;
8632                 define(genFun, toStringTagSymbol, "GeneratorFunction");
8633               }
8634
8635               genFun.prototype = Object.create(Gp);
8636               return genFun;
8637             }; // Within the body of any async function, `await x` is transformed to
8638             // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
8639             // `hasOwn.call(value, "__await")` to determine if the yielded value is
8640             // meant to be awaited.
8641
8642
8643             exports.awrap = function (arg) {
8644               return {
8645                 __await: arg
8646               };
8647             };
8648
8649             function AsyncIterator(generator, PromiseImpl) {
8650               function invoke(method, arg, resolve, reject) {
8651                 var record = tryCatch(generator[method], generator, arg);
8652
8653                 if (record.type === "throw") {
8654                   reject(record.arg);
8655                 } else {
8656                   var result = record.arg;
8657                   var value = result.value;
8658
8659                   if (value && _typeof(value) === "object" && hasOwn.call(value, "__await")) {
8660                     return PromiseImpl.resolve(value.__await).then(function (value) {
8661                       invoke("next", value, resolve, reject);
8662                     }, function (err) {
8663                       invoke("throw", err, resolve, reject);
8664                     });
8665                   }
8666
8667                   return PromiseImpl.resolve(value).then(function (unwrapped) {
8668                     // When a yielded Promise is resolved, its final value becomes
8669                     // the .value of the Promise<{value,done}> result for the
8670                     // current iteration.
8671                     result.value = unwrapped;
8672                     resolve(result);
8673                   }, function (error) {
8674                     // If a rejected Promise was yielded, throw the rejection back
8675                     // into the async generator function so it can be handled there.
8676                     return invoke("throw", error, resolve, reject);
8677                   });
8678                 }
8679               }
8680
8681               var previousPromise;
8682
8683               function enqueue(method, arg) {
8684                 function callInvokeWithMethodAndArg() {
8685                   return new PromiseImpl(function (resolve, reject) {
8686                     invoke(method, arg, resolve, reject);
8687                   });
8688                 }
8689
8690                 return previousPromise = // If enqueue has been called before, then we want to wait until
8691                 // all previous Promises have been resolved before calling invoke,
8692                 // so that results are always delivered in the correct order. If
8693                 // enqueue has not been called before, then it is important to
8694                 // call invoke immediately, without waiting on a callback to fire,
8695                 // so that the async generator function has the opportunity to do
8696                 // any necessary setup in a predictable way. This predictability
8697                 // is why the Promise constructor synchronously invokes its
8698                 // executor callback, and why async functions synchronously
8699                 // execute code before the first await. Since we implement simple
8700                 // async functions in terms of async generators, it is especially
8701                 // important to get this right, even though it requires care.
8702                 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
8703                 // invocations of the iterator.
8704                 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
8705               } // Define the unified helper method that is used to implement .next,
8706               // .throw, and .return (see defineIteratorMethods).
8707
8708
8709               this._invoke = enqueue;
8710             }
8711
8712             defineIteratorMethods(AsyncIterator.prototype);
8713
8714             AsyncIterator.prototype[asyncIteratorSymbol] = function () {
8715               return this;
8716             };
8717
8718             exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
8719             // AsyncIterator objects; they just return a Promise for the value of
8720             // the final result produced by the iterator.
8721
8722             exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
8723               if (PromiseImpl === void 0) PromiseImpl = Promise;
8724               var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
8725               return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
8726               : iter.next().then(function (result) {
8727                 return result.done ? result.value : iter.next();
8728               });
8729             };
8730
8731             function makeInvokeMethod(innerFn, self, context) {
8732               var state = GenStateSuspendedStart;
8733               return function invoke(method, arg) {
8734                 if (state === GenStateExecuting) {
8735                   throw new Error("Generator is already running");
8736                 }
8737
8738                 if (state === GenStateCompleted) {
8739                   if (method === "throw") {
8740                     throw arg;
8741                   } // Be forgiving, per 25.3.3.3.3 of the spec:
8742                   // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
8743
8744
8745                   return doneResult();
8746                 }
8747
8748                 context.method = method;
8749                 context.arg = arg;
8750
8751                 while (true) {
8752                   var delegate = context.delegate;
8753
8754                   if (delegate) {
8755                     var delegateResult = maybeInvokeDelegate(delegate, context);
8756
8757                     if (delegateResult) {
8758                       if (delegateResult === ContinueSentinel) continue;
8759                       return delegateResult;
8760                     }
8761                   }
8762
8763                   if (context.method === "next") {
8764                     // Setting context._sent for legacy support of Babel's
8765                     // function.sent implementation.
8766                     context.sent = context._sent = context.arg;
8767                   } else if (context.method === "throw") {
8768                     if (state === GenStateSuspendedStart) {
8769                       state = GenStateCompleted;
8770                       throw context.arg;
8771                     }
8772
8773                     context.dispatchException(context.arg);
8774                   } else if (context.method === "return") {
8775                     context.abrupt("return", context.arg);
8776                   }
8777
8778                   state = GenStateExecuting;
8779                   var record = tryCatch(innerFn, self, context);
8780
8781                   if (record.type === "normal") {
8782                     // If an exception is thrown from innerFn, we leave state ===
8783                     // GenStateExecuting and loop back for another invocation.
8784                     state = context.done ? GenStateCompleted : GenStateSuspendedYield;
8785
8786                     if (record.arg === ContinueSentinel) {
8787                       continue;
8788                     }
8789
8790                     return {
8791                       value: record.arg,
8792                       done: context.done
8793                     };
8794                   } else if (record.type === "throw") {
8795                     state = GenStateCompleted; // Dispatch the exception by looping back around to the
8796                     // context.dispatchException(context.arg) call above.
8797
8798                     context.method = "throw";
8799                     context.arg = record.arg;
8800                   }
8801                 }
8802               };
8803             } // Call delegate.iterator[context.method](context.arg) and handle the
8804             // result, either by returning a { value, done } result from the
8805             // delegate iterator, or by modifying context.method and context.arg,
8806             // setting context.delegate to null, and returning the ContinueSentinel.
8807
8808
8809             function maybeInvokeDelegate(delegate, context) {
8810               var method = delegate.iterator[context.method];
8811
8812               if (method === undefined$1) {
8813                 // A .throw or .return when the delegate iterator has no .throw
8814                 // method always terminates the yield* loop.
8815                 context.delegate = null;
8816
8817                 if (context.method === "throw") {
8818                   // Note: ["return"] must be used for ES3 parsing compatibility.
8819                   if (delegate.iterator["return"]) {
8820                     // If the delegate iterator has a return method, give it a
8821                     // chance to clean up.
8822                     context.method = "return";
8823                     context.arg = undefined$1;
8824                     maybeInvokeDelegate(delegate, context);
8825
8826                     if (context.method === "throw") {
8827                       // If maybeInvokeDelegate(context) changed context.method from
8828                       // "return" to "throw", let that override the TypeError below.
8829                       return ContinueSentinel;
8830                     }
8831                   }
8832
8833                   context.method = "throw";
8834                   context.arg = new TypeError("The iterator does not provide a 'throw' method");
8835                 }
8836
8837                 return ContinueSentinel;
8838               }
8839
8840               var record = tryCatch(method, delegate.iterator, context.arg);
8841
8842               if (record.type === "throw") {
8843                 context.method = "throw";
8844                 context.arg = record.arg;
8845                 context.delegate = null;
8846                 return ContinueSentinel;
8847               }
8848
8849               var info = record.arg;
8850
8851               if (!info) {
8852                 context.method = "throw";
8853                 context.arg = new TypeError("iterator result is not an object");
8854                 context.delegate = null;
8855                 return ContinueSentinel;
8856               }
8857
8858               if (info.done) {
8859                 // Assign the result of the finished delegate to the temporary
8860                 // variable specified by delegate.resultName (see delegateYield).
8861                 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
8862
8863                 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
8864                 // exception, let the outer generator proceed normally. If
8865                 // context.method was "next", forget context.arg since it has been
8866                 // "consumed" by the delegate iterator. If context.method was
8867                 // "return", allow the original .return call to continue in the
8868                 // outer generator.
8869
8870                 if (context.method !== "return") {
8871                   context.method = "next";
8872                   context.arg = undefined$1;
8873                 }
8874               } else {
8875                 // Re-yield the result returned by the delegate method.
8876                 return info;
8877               } // The delegate iterator is finished, so forget it and continue with
8878               // the outer generator.
8879
8880
8881               context.delegate = null;
8882               return ContinueSentinel;
8883             } // Define Generator.prototype.{next,throw,return} in terms of the
8884             // unified ._invoke helper method.
8885
8886
8887             defineIteratorMethods(Gp);
8888             define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
8889             // @@iterator function is called on it. Some browsers' implementations of the
8890             // iterator prototype chain incorrectly implement this, causing the Generator
8891             // object to not be returned from this call. This ensures that doesn't happen.
8892             // See https://github.com/facebook/regenerator/issues/274 for more details.
8893
8894             Gp[iteratorSymbol] = function () {
8895               return this;
8896             };
8897
8898             Gp.toString = function () {
8899               return "[object Generator]";
8900             };
8901
8902             function pushTryEntry(locs) {
8903               var entry = {
8904                 tryLoc: locs[0]
8905               };
8906
8907               if (1 in locs) {
8908                 entry.catchLoc = locs[1];
8909               }
8910
8911               if (2 in locs) {
8912                 entry.finallyLoc = locs[2];
8913                 entry.afterLoc = locs[3];
8914               }
8915
8916               this.tryEntries.push(entry);
8917             }
8918
8919             function resetTryEntry(entry) {
8920               var record = entry.completion || {};
8921               record.type = "normal";
8922               delete record.arg;
8923               entry.completion = record;
8924             }
8925
8926             function Context(tryLocsList) {
8927               // The root entry object (effectively a try statement without a catch
8928               // or a finally block) gives us a place to store values thrown from
8929               // locations where there is no enclosing try statement.
8930               this.tryEntries = [{
8931                 tryLoc: "root"
8932               }];
8933               tryLocsList.forEach(pushTryEntry, this);
8934               this.reset(true);
8935             }
8936
8937             exports.keys = function (object) {
8938               var keys = [];
8939
8940               for (var key in object) {
8941                 keys.push(key);
8942               }
8943
8944               keys.reverse(); // Rather than returning an object with a next method, we keep
8945               // things simple and return the next function itself.
8946
8947               return function next() {
8948                 while (keys.length) {
8949                   var key = keys.pop();
8950
8951                   if (key in object) {
8952                     next.value = key;
8953                     next.done = false;
8954                     return next;
8955                   }
8956                 } // To avoid creating an additional object, we just hang the .value
8957                 // and .done properties off the next function object itself. This
8958                 // also ensures that the minifier will not anonymize the function.
8959
8960
8961                 next.done = true;
8962                 return next;
8963               };
8964             };
8965
8966             function values(iterable) {
8967               if (iterable) {
8968                 var iteratorMethod = iterable[iteratorSymbol];
8969
8970                 if (iteratorMethod) {
8971                   return iteratorMethod.call(iterable);
8972                 }
8973
8974                 if (typeof iterable.next === "function") {
8975                   return iterable;
8976                 }
8977
8978                 if (!isNaN(iterable.length)) {
8979                   var i = -1,
8980                       next = function next() {
8981                     while (++i < iterable.length) {
8982                       if (hasOwn.call(iterable, i)) {
8983                         next.value = iterable[i];
8984                         next.done = false;
8985                         return next;
8986                       }
8987                     }
8988
8989                     next.value = undefined$1;
8990                     next.done = true;
8991                     return next;
8992                   };
8993
8994                   return next.next = next;
8995                 }
8996               } // Return an iterator with no values.
8997
8998
8999               return {
9000                 next: doneResult
9001               };
9002             }
9003
9004             exports.values = values;
9005
9006             function doneResult() {
9007               return {
9008                 value: undefined$1,
9009                 done: true
9010               };
9011             }
9012
9013             Context.prototype = {
9014               constructor: Context,
9015               reset: function reset(skipTempReset) {
9016                 this.prev = 0;
9017                 this.next = 0; // Resetting context._sent for legacy support of Babel's
9018                 // function.sent implementation.
9019
9020                 this.sent = this._sent = undefined$1;
9021                 this.done = false;
9022                 this.delegate = null;
9023                 this.method = "next";
9024                 this.arg = undefined$1;
9025                 this.tryEntries.forEach(resetTryEntry);
9026
9027                 if (!skipTempReset) {
9028                   for (var name in this) {
9029                     // Not sure about the optimal order of these conditions:
9030                     if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
9031                       this[name] = undefined$1;
9032                     }
9033                   }
9034                 }
9035               },
9036               stop: function stop() {
9037                 this.done = true;
9038                 var rootEntry = this.tryEntries[0];
9039                 var rootRecord = rootEntry.completion;
9040
9041                 if (rootRecord.type === "throw") {
9042                   throw rootRecord.arg;
9043                 }
9044
9045                 return this.rval;
9046               },
9047               dispatchException: function dispatchException(exception) {
9048                 if (this.done) {
9049                   throw exception;
9050                 }
9051
9052                 var context = this;
9053
9054                 function handle(loc, caught) {
9055                   record.type = "throw";
9056                   record.arg = exception;
9057                   context.next = loc;
9058
9059                   if (caught) {
9060                     // If the dispatched exception was caught by a catch block,
9061                     // then let that catch block handle the exception normally.
9062                     context.method = "next";
9063                     context.arg = undefined$1;
9064                   }
9065
9066                   return !!caught;
9067                 }
9068
9069                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9070                   var entry = this.tryEntries[i];
9071                   var record = entry.completion;
9072
9073                   if (entry.tryLoc === "root") {
9074                     // Exception thrown outside of any try block that could handle
9075                     // it, so set the completion value of the entire function to
9076                     // throw the exception.
9077                     return handle("end");
9078                   }
9079
9080                   if (entry.tryLoc <= this.prev) {
9081                     var hasCatch = hasOwn.call(entry, "catchLoc");
9082                     var hasFinally = hasOwn.call(entry, "finallyLoc");
9083
9084                     if (hasCatch && hasFinally) {
9085                       if (this.prev < entry.catchLoc) {
9086                         return handle(entry.catchLoc, true);
9087                       } else if (this.prev < entry.finallyLoc) {
9088                         return handle(entry.finallyLoc);
9089                       }
9090                     } else if (hasCatch) {
9091                       if (this.prev < entry.catchLoc) {
9092                         return handle(entry.catchLoc, true);
9093                       }
9094                     } else if (hasFinally) {
9095                       if (this.prev < entry.finallyLoc) {
9096                         return handle(entry.finallyLoc);
9097                       }
9098                     } else {
9099                       throw new Error("try statement without catch or finally");
9100                     }
9101                   }
9102                 }
9103               },
9104               abrupt: function abrupt(type, arg) {
9105                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9106                   var entry = this.tryEntries[i];
9107
9108                   if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
9109                     var finallyEntry = entry;
9110                     break;
9111                   }
9112                 }
9113
9114                 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
9115                   // Ignore the finally entry if control is not jumping to a
9116                   // location outside the try/catch block.
9117                   finallyEntry = null;
9118                 }
9119
9120                 var record = finallyEntry ? finallyEntry.completion : {};
9121                 record.type = type;
9122                 record.arg = arg;
9123
9124                 if (finallyEntry) {
9125                   this.method = "next";
9126                   this.next = finallyEntry.finallyLoc;
9127                   return ContinueSentinel;
9128                 }
9129
9130                 return this.complete(record);
9131               },
9132               complete: function complete(record, afterLoc) {
9133                 if (record.type === "throw") {
9134                   throw record.arg;
9135                 }
9136
9137                 if (record.type === "break" || record.type === "continue") {
9138                   this.next = record.arg;
9139                 } else if (record.type === "return") {
9140                   this.rval = this.arg = record.arg;
9141                   this.method = "return";
9142                   this.next = "end";
9143                 } else if (record.type === "normal" && afterLoc) {
9144                   this.next = afterLoc;
9145                 }
9146
9147                 return ContinueSentinel;
9148               },
9149               finish: function finish(finallyLoc) {
9150                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9151                   var entry = this.tryEntries[i];
9152
9153                   if (entry.finallyLoc === finallyLoc) {
9154                     this.complete(entry.completion, entry.afterLoc);
9155                     resetTryEntry(entry);
9156                     return ContinueSentinel;
9157                   }
9158                 }
9159               },
9160               "catch": function _catch(tryLoc) {
9161                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9162                   var entry = this.tryEntries[i];
9163
9164                   if (entry.tryLoc === tryLoc) {
9165                     var record = entry.completion;
9166
9167                     if (record.type === "throw") {
9168                       var thrown = record.arg;
9169                       resetTryEntry(entry);
9170                     }
9171
9172                     return thrown;
9173                   }
9174                 } // The context.catch method must only be called with a location
9175                 // argument that corresponds to a known catch block.
9176
9177
9178                 throw new Error("illegal catch attempt");
9179               },
9180               delegateYield: function delegateYield(iterable, resultName, nextLoc) {
9181                 this.delegate = {
9182                   iterator: values(iterable),
9183                   resultName: resultName,
9184                   nextLoc: nextLoc
9185                 };
9186
9187                 if (this.method === "next") {
9188                   // Deliberately forget the last sent value so that we don't
9189                   // accidentally pass it on to the delegate.
9190                   this.arg = undefined$1;
9191                 }
9192
9193                 return ContinueSentinel;
9194               }
9195             }; // Regardless of whether this script is executing as a CommonJS module
9196             // or not, return the runtime object so that we can declare the variable
9197             // regeneratorRuntime in the outer scope, which allows this module to be
9198             // injected easily by `bin/regenerator --include-runtime script.js`.
9199
9200             return exports;
9201           }( // If this script is executing as a CommonJS module, use module.exports
9202           // as the regeneratorRuntime namespace. Otherwise create a new empty
9203           // object. Either way, the resulting object will be used to initialize
9204           // the regeneratorRuntime variable at the top of this file.
9205            module.exports );
9206
9207           try {
9208             regeneratorRuntime = runtime;
9209           } catch (accidentalStrictMode) {
9210             // This module should not be running in strict mode, so the above
9211             // assignment should always work unless something is misconfigured. Just
9212             // in case runtime.js accidentally runs in strict mode, we can escape
9213             // strict mode using a global Function call. This could conceivably fail
9214             // if a Content Security Policy forbids using Function, but in that case
9215             // the proper solution is to fix the accidental strict mode problem. If
9216             // you've misconfigured your bundler to force strict mode and applied a
9217             // CSP to forbid Function, and you're not willing to fix either of those
9218             // problems, please detail your unique predicament in a GitHub issue.
9219             Function("r", "regeneratorRuntime = r")(runtime);
9220           }
9221         });
9222
9223         var _marked = /*#__PURE__*/regeneratorRuntime.mark(numbers);
9224
9225         function number (x) {
9226           return x === null ? NaN : +x;
9227         }
9228         function numbers(values, valueof) {
9229           var _iterator, _step, value, index, _iterator2, _step2, _value;
9230
9231           return regeneratorRuntime.wrap(function numbers$(_context) {
9232             while (1) {
9233               switch (_context.prev = _context.next) {
9234                 case 0:
9235                   if (!(valueof === undefined)) {
9236                     _context.next = 21;
9237                     break;
9238                   }
9239
9240                   _iterator = _createForOfIteratorHelper(values);
9241                   _context.prev = 2;
9242
9243                   _iterator.s();
9244
9245                 case 4:
9246                   if ((_step = _iterator.n()).done) {
9247                     _context.next = 11;
9248                     break;
9249                   }
9250
9251                   value = _step.value;
9252
9253                   if (!(value != null && (value = +value) >= value)) {
9254                     _context.next = 9;
9255                     break;
9256                   }
9257
9258                   _context.next = 9;
9259                   return value;
9260
9261                 case 9:
9262                   _context.next = 4;
9263                   break;
9264
9265                 case 11:
9266                   _context.next = 16;
9267                   break;
9268
9269                 case 13:
9270                   _context.prev = 13;
9271                   _context.t0 = _context["catch"](2);
9272
9273                   _iterator.e(_context.t0);
9274
9275                 case 16:
9276                   _context.prev = 16;
9277
9278                   _iterator.f();
9279
9280                   return _context.finish(16);
9281
9282                 case 19:
9283                   _context.next = 40;
9284                   break;
9285
9286                 case 21:
9287                   index = -1;
9288                   _iterator2 = _createForOfIteratorHelper(values);
9289                   _context.prev = 23;
9290
9291                   _iterator2.s();
9292
9293                 case 25:
9294                   if ((_step2 = _iterator2.n()).done) {
9295                     _context.next = 32;
9296                     break;
9297                   }
9298
9299                   _value = _step2.value;
9300
9301                   if (!((_value = valueof(_value, ++index, values)) != null && (_value = +_value) >= _value)) {
9302                     _context.next = 30;
9303                     break;
9304                   }
9305
9306                   _context.next = 30;
9307                   return _value;
9308
9309                 case 30:
9310                   _context.next = 25;
9311                   break;
9312
9313                 case 32:
9314                   _context.next = 37;
9315                   break;
9316
9317                 case 34:
9318                   _context.prev = 34;
9319                   _context.t1 = _context["catch"](23);
9320
9321                   _iterator2.e(_context.t1);
9322
9323                 case 37:
9324                   _context.prev = 37;
9325
9326                   _iterator2.f();
9327
9328                   return _context.finish(37);
9329
9330                 case 40:
9331                 case "end":
9332                   return _context.stop();
9333               }
9334             }
9335           }, _marked, null, [[2, 13, 16, 19], [23, 34, 37, 40]]);
9336         }
9337
9338         var ascendingBisect = d3_bisector(d3_ascending);
9339         var bisectRight = ascendingBisect.right;
9340         var bisectCenter = d3_bisector(number).center;
9341
9342         // `Array.prototype.fill` method
9343         // https://tc39.github.io/ecma262/#sec-array.prototype.fill
9344         _export({ target: 'Array', proto: true }, {
9345           fill: arrayFill
9346         });
9347
9348         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
9349         addToUnscopables('fill');
9350
9351         var INCORRECT_ITERATION$1 = !checkCorrectnessOfIteration(function (iterable) {
9352           Array.from(iterable);
9353         });
9354
9355         // `Array.from` method
9356         // https://tc39.github.io/ecma262/#sec-array.from
9357         _export({ target: 'Array', stat: true, forced: INCORRECT_ITERATION$1 }, {
9358           from: arrayFrom
9359         });
9360
9361         var $some$1 = arrayIteration.some;
9362
9363
9364
9365         var STRICT_METHOD$4 = arrayMethodIsStrict('some');
9366         var USES_TO_LENGTH$7 = arrayMethodUsesToLength('some');
9367
9368         // `Array.prototype.some` method
9369         // https://tc39.github.io/ecma262/#sec-array.prototype.some
9370         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$4 || !USES_TO_LENGTH$7 }, {
9371           some: function some(callbackfn /* , thisArg */) {
9372             return $some$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
9373           }
9374         });
9375
9376         // `Float64Array` constructor
9377         // https://tc39.github.io/ecma262/#sec-typedarray-objects
9378         typedArrayConstructor('Float64', function (init) {
9379           return function Float64Array(data, byteOffset, length) {
9380             return init(this, data, byteOffset, length);
9381           };
9382         });
9383
9384         var exportTypedArrayStaticMethod$1 = arrayBufferViewCore.exportTypedArrayStaticMethod;
9385
9386
9387         // `%TypedArray%.from` method
9388         // https://tc39.github.io/ecma262/#sec-%typedarray%.from
9389         exportTypedArrayStaticMethod$1('from', typedArrayFrom, typedArrayConstructorsRequireWrappers);
9390
9391         function d3_descending (a, b) {
9392           return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
9393         }
9394
9395         // https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
9396         var Adder = /*#__PURE__*/function () {
9397           function Adder() {
9398             _classCallCheck(this, Adder);
9399
9400             this._partials = new Float64Array(32);
9401             this._n = 0;
9402           }
9403
9404           _createClass(Adder, [{
9405             key: "add",
9406             value: function add(x) {
9407               var p = this._partials;
9408               var i = 0;
9409
9410               for (var j = 0; j < this._n && j < 32; j++) {
9411                 var y = p[j],
9412                     hi = x + y,
9413                     lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
9414                 if (lo) p[i++] = lo;
9415                 x = hi;
9416               }
9417
9418               p[i] = x;
9419               this._n = i + 1;
9420               return this;
9421             }
9422           }, {
9423             key: "valueOf",
9424             value: function valueOf() {
9425               var p = this._partials;
9426               var n = this._n,
9427                   x,
9428                   y,
9429                   lo,
9430                   hi = 0;
9431
9432               if (n > 0) {
9433                 hi = p[--n];
9434
9435                 while (n > 0) {
9436                   x = hi;
9437                   y = p[--n];
9438                   hi = x + y;
9439                   lo = y - (hi - x);
9440                   if (lo) break;
9441                 }
9442
9443                 if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
9444                   y = lo * 2;
9445                   x = hi + y;
9446                   if (y == x - hi) hi = x;
9447                 }
9448               }
9449
9450               return hi;
9451             }
9452           }]);
9453
9454           return Adder;
9455         }();
9456
9457         // `Map` constructor
9458         // https://tc39.github.io/ecma262/#sec-map-objects
9459         var es_map = collection('Map', function (init) {
9460           return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };
9461         }, collectionStrong);
9462
9463         var e10 = Math.sqrt(50),
9464             e5 = Math.sqrt(10),
9465             e2 = Math.sqrt(2);
9466         function ticks (start, stop, count) {
9467           var reverse,
9468               i = -1,
9469               n,
9470               ticks,
9471               step;
9472           stop = +stop, start = +start, count = +count;
9473           if (start === stop && count > 0) return [start];
9474           if (reverse = stop < start) n = start, start = stop, stop = n;
9475           if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
9476
9477           if (step > 0) {
9478             start = Math.ceil(start / step);
9479             stop = Math.floor(stop / step);
9480             ticks = new Array(n = Math.ceil(stop - start + 1));
9481
9482             while (++i < n) {
9483               ticks[i] = (start + i) * step;
9484             }
9485           } else {
9486             step = -step;
9487             start = Math.ceil(start * step);
9488             stop = Math.floor(stop * step);
9489             ticks = new Array(n = Math.ceil(stop - start + 1));
9490
9491             while (++i < n) {
9492               ticks[i] = (start + i) / step;
9493             }
9494           }
9495
9496           if (reverse) ticks.reverse();
9497           return ticks;
9498         }
9499         function tickIncrement(start, stop, count) {
9500           var step = (stop - start) / Math.max(0, count),
9501               power = Math.floor(Math.log(step) / Math.LN10),
9502               error = step / Math.pow(10, power);
9503           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);
9504         }
9505         function tickStep(start, stop, count) {
9506           var step0 = Math.abs(stop - start) / Math.max(0, count),
9507               step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
9508               error = step0 / step1;
9509           if (error >= e10) step1 *= 10;else if (error >= e5) step1 *= 5;else if (error >= e2) step1 *= 2;
9510           return stop < start ? -step1 : step1;
9511         }
9512
9513         function max$4(values, valueof) {
9514           var max;
9515
9516           if (valueof === undefined) {
9517             var _iterator = _createForOfIteratorHelper(values),
9518                 _step;
9519
9520             try {
9521               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9522                 var value = _step.value;
9523
9524                 if (value != null && (max < value || max === undefined && value >= value)) {
9525                   max = value;
9526                 }
9527               }
9528             } catch (err) {
9529               _iterator.e(err);
9530             } finally {
9531               _iterator.f();
9532             }
9533           } else {
9534             var index = -1;
9535
9536             var _iterator2 = _createForOfIteratorHelper(values),
9537                 _step2;
9538
9539             try {
9540               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9541                 var _value = _step2.value;
9542
9543                 if ((_value = valueof(_value, ++index, values)) != null && (max < _value || max === undefined && _value >= _value)) {
9544                   max = _value;
9545                 }
9546               }
9547             } catch (err) {
9548               _iterator2.e(err);
9549             } finally {
9550               _iterator2.f();
9551             }
9552           }
9553
9554           return max;
9555         }
9556
9557         function min$7(values, valueof) {
9558           var min;
9559
9560           if (valueof === undefined) {
9561             var _iterator = _createForOfIteratorHelper(values),
9562                 _step;
9563
9564             try {
9565               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9566                 var value = _step.value;
9567
9568                 if (value != null && (min > value || min === undefined && value >= value)) {
9569                   min = value;
9570                 }
9571               }
9572             } catch (err) {
9573               _iterator.e(err);
9574             } finally {
9575               _iterator.f();
9576             }
9577           } else {
9578             var index = -1;
9579
9580             var _iterator2 = _createForOfIteratorHelper(values),
9581                 _step2;
9582
9583             try {
9584               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9585                 var _value = _step2.value;
9586
9587                 if ((_value = valueof(_value, ++index, values)) != null && (min > _value || min === undefined && _value >= _value)) {
9588                   min = _value;
9589                 }
9590               }
9591             } catch (err) {
9592               _iterator2.e(err);
9593             } finally {
9594               _iterator2.f();
9595             }
9596           }
9597
9598           return min;
9599         }
9600
9601         // ISC license, Copyright 2018 Vladimir Agafonkin.
9602
9603         function quickselect(array, k) {
9604           var left = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
9605           var right = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : array.length - 1;
9606           var compare = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : d3_ascending;
9607
9608           while (right > left) {
9609             if (right - left > 600) {
9610               var n = right - left + 1;
9611               var m = k - left + 1;
9612               var z = Math.log(n);
9613               var s = 0.5 * Math.exp(2 * z / 3);
9614               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
9615               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
9616               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
9617               quickselect(array, k, newLeft, newRight, compare);
9618             }
9619
9620             var t = array[k];
9621             var i = left;
9622             var j = right;
9623             swap(array, left, k);
9624             if (compare(array[right], t) > 0) swap(array, left, right);
9625
9626             while (i < j) {
9627               swap(array, i, j), ++i, --j;
9628
9629               while (compare(array[i], t) < 0) {
9630                 ++i;
9631               }
9632
9633               while (compare(array[j], t) > 0) {
9634                 --j;
9635               }
9636             }
9637
9638             if (compare(array[left], t) === 0) swap(array, left, j);else ++j, swap(array, j, right);
9639             if (j <= k) left = j + 1;
9640             if (k <= j) right = j - 1;
9641           }
9642
9643           return array;
9644         }
9645
9646         function swap(array, i, j) {
9647           var t = array[i];
9648           array[i] = array[j];
9649           array[j] = t;
9650         }
9651
9652         function quantile(values, p, valueof) {
9653           values = Float64Array.from(numbers(values, valueof));
9654           if (!(n = values.length)) return;
9655           if ((p = +p) <= 0 || n < 2) return min$7(values);
9656           if (p >= 1) return max$4(values);
9657           var n,
9658               i = (n - 1) * p,
9659               i0 = Math.floor(i),
9660               value0 = max$4(quickselect(values, i0).subarray(0, i0 + 1)),
9661               value1 = min$7(values.subarray(i0 + 1));
9662           return value0 + (value1 - value0) * (i - i0);
9663         }
9664
9665         function d3_median (values, valueof) {
9666           return quantile(values, 0.5, valueof);
9667         }
9668
9669         var _marked$1 = /*#__PURE__*/regeneratorRuntime.mark(flatten);
9670
9671         function flatten(arrays) {
9672           var _iterator, _step, array;
9673
9674           return regeneratorRuntime.wrap(function flatten$(_context) {
9675             while (1) {
9676               switch (_context.prev = _context.next) {
9677                 case 0:
9678                   _iterator = _createForOfIteratorHelper(arrays);
9679                   _context.prev = 1;
9680
9681                   _iterator.s();
9682
9683                 case 3:
9684                   if ((_step = _iterator.n()).done) {
9685                     _context.next = 8;
9686                     break;
9687                   }
9688
9689                   array = _step.value;
9690                   return _context.delegateYield(array, "t0", 6);
9691
9692                 case 6:
9693                   _context.next = 3;
9694                   break;
9695
9696                 case 8:
9697                   _context.next = 13;
9698                   break;
9699
9700                 case 10:
9701                   _context.prev = 10;
9702                   _context.t1 = _context["catch"](1);
9703
9704                   _iterator.e(_context.t1);
9705
9706                 case 13:
9707                   _context.prev = 13;
9708
9709                   _iterator.f();
9710
9711                   return _context.finish(13);
9712
9713                 case 16:
9714                 case "end":
9715                   return _context.stop();
9716               }
9717             }
9718           }, _marked$1, null, [[1, 10, 13, 16]]);
9719         }
9720
9721         function merge(arrays) {
9722           return Array.from(flatten(arrays));
9723         }
9724
9725         function range (start, stop, step) {
9726           start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
9727           var i = -1,
9728               n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
9729               range = new Array(n);
9730
9731           while (++i < n) {
9732             range[i] = start + i * step;
9733           }
9734
9735           return range;
9736         }
9737
9738         var test$2 = [];
9739         var nativeSort = test$2.sort;
9740
9741         // IE8-
9742         var FAILS_ON_UNDEFINED = fails(function () {
9743           test$2.sort(undefined);
9744         });
9745         // V8 bug
9746         var FAILS_ON_NULL = fails(function () {
9747           test$2.sort(null);
9748         });
9749         // Old WebKit
9750         var STRICT_METHOD$5 = arrayMethodIsStrict('sort');
9751
9752         var FORCED$a = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$5;
9753
9754         // `Array.prototype.sort` method
9755         // https://tc39.github.io/ecma262/#sec-array.prototype.sort
9756         _export({ target: 'Array', proto: true, forced: FORCED$a }, {
9757           sort: function sort(comparefn) {
9758             return comparefn === undefined
9759               ? nativeSort.call(toObject(this))
9760               : nativeSort.call(toObject(this), aFunction$1(comparefn));
9761           }
9762         });
9763
9764         // `SameValue` abstract operation
9765         // https://tc39.github.io/ecma262/#sec-samevalue
9766         var sameValue = Object.is || function is(x, y) {
9767           // eslint-disable-next-line no-self-compare
9768           return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
9769         };
9770
9771         var $hypot = Math.hypot;
9772         var abs$1 = Math.abs;
9773         var sqrt = Math.sqrt;
9774
9775         // Chrome 77 bug
9776         // https://bugs.chromium.org/p/v8/issues/detail?id=9546
9777         var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity;
9778
9779         // `Math.hypot` method
9780         // https://tc39.github.io/ecma262/#sec-math.hypot
9781         _export({ target: 'Math', stat: true, forced: BUGGY }, {
9782           hypot: function hypot(value1, value2) { // eslint-disable-line no-unused-vars
9783             var sum = 0;
9784             var i = 0;
9785             var aLen = arguments.length;
9786             var larg = 0;
9787             var arg, div;
9788             while (i < aLen) {
9789               arg = abs$1(arguments[i++]);
9790               if (larg < arg) {
9791                 div = larg / arg;
9792                 sum = sum * div * div + 1;
9793                 larg = arg;
9794               } else if (arg > 0) {
9795                 div = arg / larg;
9796                 sum += div * div;
9797               } else sum += arg;
9798             }
9799             return larg === Infinity ? Infinity : larg * sqrt(sum);
9800           }
9801         });
9802
9803         // `Math.sign` method implementation
9804         // https://tc39.github.io/ecma262/#sec-math.sign
9805         var mathSign = Math.sign || function sign(x) {
9806           // eslint-disable-next-line no-self-compare
9807           return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;
9808         };
9809
9810         // `Math.sign` method
9811         // https://tc39.github.io/ecma262/#sec-math.sign
9812         _export({ target: 'Math', stat: true }, {
9813           sign: mathSign
9814         });
9815
9816         var epsilon = 1e-6;
9817         var epsilon2 = 1e-12;
9818         var pi = Math.PI;
9819         var halfPi = pi / 2;
9820         var quarterPi = pi / 4;
9821         var tau = pi * 2;
9822         var degrees = 180 / pi;
9823         var radians = pi / 180;
9824         var abs$2 = Math.abs;
9825         var atan = Math.atan;
9826         var atan2 = Math.atan2;
9827         var cos = Math.cos;
9828         var exp = Math.exp;
9829         var hypot = Math.hypot;
9830         var log$1 = Math.log;
9831         var sin = Math.sin;
9832         var sign = Math.sign || function (x) {
9833           return x > 0 ? 1 : x < 0 ? -1 : 0;
9834         };
9835         var sqrt$1 = Math.sqrt;
9836         var tan = Math.tan;
9837         function acos(x) {
9838           return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
9839         }
9840         function asin(x) {
9841           return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
9842         }
9843
9844         function noop() {}
9845
9846         function streamGeometry(geometry, stream) {
9847           if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
9848             streamGeometryType[geometry.type](geometry, stream);
9849           }
9850         }
9851
9852         var streamObjectType = {
9853           Feature: function Feature(object, stream) {
9854             streamGeometry(object.geometry, stream);
9855           },
9856           FeatureCollection: function FeatureCollection(object, stream) {
9857             var features = object.features,
9858                 i = -1,
9859                 n = features.length;
9860
9861             while (++i < n) {
9862               streamGeometry(features[i].geometry, stream);
9863             }
9864           }
9865         };
9866         var streamGeometryType = {
9867           Sphere: function Sphere(object, stream) {
9868             stream.sphere();
9869           },
9870           Point: function Point(object, stream) {
9871             object = object.coordinates;
9872             stream.point(object[0], object[1], object[2]);
9873           },
9874           MultiPoint: function MultiPoint(object, stream) {
9875             var coordinates = object.coordinates,
9876                 i = -1,
9877                 n = coordinates.length;
9878
9879             while (++i < n) {
9880               object = coordinates[i], stream.point(object[0], object[1], object[2]);
9881             }
9882           },
9883           LineString: function LineString(object, stream) {
9884             streamLine(object.coordinates, stream, 0);
9885           },
9886           MultiLineString: function MultiLineString(object, stream) {
9887             var coordinates = object.coordinates,
9888                 i = -1,
9889                 n = coordinates.length;
9890
9891             while (++i < n) {
9892               streamLine(coordinates[i], stream, 0);
9893             }
9894           },
9895           Polygon: function Polygon(object, stream) {
9896             streamPolygon(object.coordinates, stream);
9897           },
9898           MultiPolygon: function MultiPolygon(object, stream) {
9899             var coordinates = object.coordinates,
9900                 i = -1,
9901                 n = coordinates.length;
9902
9903             while (++i < n) {
9904               streamPolygon(coordinates[i], stream);
9905             }
9906           },
9907           GeometryCollection: function GeometryCollection(object, stream) {
9908             var geometries = object.geometries,
9909                 i = -1,
9910                 n = geometries.length;
9911
9912             while (++i < n) {
9913               streamGeometry(geometries[i], stream);
9914             }
9915           }
9916         };
9917
9918         function streamLine(coordinates, stream, closed) {
9919           var i = -1,
9920               n = coordinates.length - closed,
9921               coordinate;
9922           stream.lineStart();
9923
9924           while (++i < n) {
9925             coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
9926           }
9927
9928           stream.lineEnd();
9929         }
9930
9931         function streamPolygon(coordinates, stream) {
9932           var i = -1,
9933               n = coordinates.length;
9934           stream.polygonStart();
9935
9936           while (++i < n) {
9937             streamLine(coordinates[i], stream, 1);
9938           }
9939
9940           stream.polygonEnd();
9941         }
9942
9943         function d3_geoStream (object, stream) {
9944           if (object && streamObjectType.hasOwnProperty(object.type)) {
9945             streamObjectType[object.type](object, stream);
9946           } else {
9947             streamGeometry(object, stream);
9948           }
9949         }
9950
9951         var areaRingSum = new Adder(); // hello?
9952
9953         var areaSum = new Adder(),
9954             lambda00,
9955             phi00,
9956             lambda0,
9957             cosPhi0,
9958             sinPhi0;
9959         var areaStream = {
9960           point: noop,
9961           lineStart: noop,
9962           lineEnd: noop,
9963           polygonStart: function polygonStart() {
9964             areaRingSum = new Adder();
9965             areaStream.lineStart = areaRingStart;
9966             areaStream.lineEnd = areaRingEnd;
9967           },
9968           polygonEnd: function polygonEnd() {
9969             var areaRing = +areaRingSum;
9970             areaSum.add(areaRing < 0 ? tau + areaRing : areaRing);
9971             this.lineStart = this.lineEnd = this.point = noop;
9972           },
9973           sphere: function sphere() {
9974             areaSum.add(tau);
9975           }
9976         };
9977
9978         function areaRingStart() {
9979           areaStream.point = areaPointFirst;
9980         }
9981
9982         function areaRingEnd() {
9983           areaPoint(lambda00, phi00);
9984         }
9985
9986         function areaPointFirst(lambda, phi) {
9987           areaStream.point = areaPoint;
9988           lambda00 = lambda, phi00 = phi;
9989           lambda *= radians, phi *= radians;
9990           lambda0 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi);
9991         }
9992
9993         function areaPoint(lambda, phi) {
9994           lambda *= radians, phi *= radians;
9995           phi = phi / 2 + quarterPi; // half the angular distance from south pole
9996           // Spherical excess E for a spherical triangle with vertices: south pole,
9997           // previous point, current point.  Uses a formula derived from Cagnoli’s
9998           // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
9999
10000           var dLambda = lambda - lambda0,
10001               sdLambda = dLambda >= 0 ? 1 : -1,
10002               adLambda = sdLambda * dLambda,
10003               cosPhi = cos(phi),
10004               sinPhi = sin(phi),
10005               k = sinPhi0 * sinPhi,
10006               u = cosPhi0 * cosPhi + k * cos(adLambda),
10007               v = k * sdLambda * sin(adLambda);
10008           areaRingSum.add(atan2(v, u)); // Advance the previous points.
10009
10010           lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
10011         }
10012
10013         function d3_geoArea (object) {
10014           areaSum = new Adder();
10015           d3_geoStream(object, areaStream);
10016           return areaSum * 2;
10017         }
10018
10019         function spherical(cartesian) {
10020           return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
10021         }
10022         function cartesian(spherical) {
10023           var lambda = spherical[0],
10024               phi = spherical[1],
10025               cosPhi = cos(phi);
10026           return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
10027         }
10028         function cartesianDot(a, b) {
10029           return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
10030         }
10031         function cartesianCross(a, b) {
10032           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]];
10033         } // TODO return a
10034
10035         function cartesianAddInPlace(a, b) {
10036           a[0] += b[0], a[1] += b[1], a[2] += b[2];
10037         }
10038         function cartesianScale(vector, k) {
10039           return [vector[0] * k, vector[1] * k, vector[2] * k];
10040         } // TODO return d
10041
10042         function cartesianNormalizeInPlace(d) {
10043           var l = sqrt$1(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
10044           d[0] /= l, d[1] /= l, d[2] /= l;
10045         }
10046
10047         var lambda0$1, phi0, lambda1, phi1, // bounds
10048         lambda2, // previous lambda-coordinate
10049         lambda00$1, phi00$1, // first point
10050         p0, // previous 3D point
10051         deltaSum, ranges, range$1;
10052         var boundsStream = {
10053           point: boundsPoint,
10054           lineStart: boundsLineStart,
10055           lineEnd: boundsLineEnd,
10056           polygonStart: function polygonStart() {
10057             boundsStream.point = boundsRingPoint;
10058             boundsStream.lineStart = boundsRingStart;
10059             boundsStream.lineEnd = boundsRingEnd;
10060             deltaSum = new Adder();
10061             areaStream.polygonStart();
10062           },
10063           polygonEnd: function polygonEnd() {
10064             areaStream.polygonEnd();
10065             boundsStream.point = boundsPoint;
10066             boundsStream.lineStart = boundsLineStart;
10067             boundsStream.lineEnd = boundsLineEnd;
10068             if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);else if (deltaSum > epsilon) phi1 = 90;else if (deltaSum < -epsilon) phi0 = -90;
10069             range$1[0] = lambda0$1, range$1[1] = lambda1;
10070           },
10071           sphere: function sphere() {
10072             lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
10073           }
10074         };
10075
10076         function boundsPoint(lambda, phi) {
10077           ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
10078           if (phi < phi0) phi0 = phi;
10079           if (phi > phi1) phi1 = phi;
10080         }
10081
10082         function linePoint(lambda, phi) {
10083           var p = cartesian([lambda * radians, phi * radians]);
10084
10085           if (p0) {
10086             var normal = cartesianCross(p0, p),
10087                 equatorial = [normal[1], -normal[0], 0],
10088                 inflection = cartesianCross(equatorial, normal);
10089             cartesianNormalizeInPlace(inflection);
10090             inflection = spherical(inflection);
10091             var delta = lambda - lambda2,
10092                 sign = delta > 0 ? 1 : -1,
10093                 lambdai = inflection[0] * degrees * sign,
10094                 phii,
10095                 antimeridian = abs$2(delta) > 180;
10096
10097             if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10098               phii = inflection[1] * degrees;
10099               if (phii > phi1) phi1 = phii;
10100             } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10101               phii = -inflection[1] * degrees;
10102               if (phii < phi0) phi0 = phii;
10103             } else {
10104               if (phi < phi0) phi0 = phi;
10105               if (phi > phi1) phi1 = phi;
10106             }
10107
10108             if (antimeridian) {
10109               if (lambda < lambda2) {
10110                 if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10111               } else {
10112                 if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10113               }
10114             } else {
10115               if (lambda1 >= lambda0$1) {
10116                 if (lambda < lambda0$1) lambda0$1 = lambda;
10117                 if (lambda > lambda1) lambda1 = lambda;
10118               } else {
10119                 if (lambda > lambda2) {
10120                   if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10121                 } else {
10122                   if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10123                 }
10124               }
10125             }
10126           } else {
10127             ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
10128           }
10129
10130           if (phi < phi0) phi0 = phi;
10131           if (phi > phi1) phi1 = phi;
10132           p0 = p, lambda2 = lambda;
10133         }
10134
10135         function boundsLineStart() {
10136           boundsStream.point = linePoint;
10137         }
10138
10139         function boundsLineEnd() {
10140           range$1[0] = lambda0$1, range$1[1] = lambda1;
10141           boundsStream.point = boundsPoint;
10142           p0 = null;
10143         }
10144
10145         function boundsRingPoint(lambda, phi) {
10146           if (p0) {
10147             var delta = lambda - lambda2;
10148             deltaSum.add(abs$2(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
10149           } else {
10150             lambda00$1 = lambda, phi00$1 = phi;
10151           }
10152
10153           areaStream.point(lambda, phi);
10154           linePoint(lambda, phi);
10155         }
10156
10157         function boundsRingStart() {
10158           areaStream.lineStart();
10159         }
10160
10161         function boundsRingEnd() {
10162           boundsRingPoint(lambda00$1, phi00$1);
10163           areaStream.lineEnd();
10164           if (abs$2(deltaSum) > epsilon) lambda0$1 = -(lambda1 = 180);
10165           range$1[0] = lambda0$1, range$1[1] = lambda1;
10166           p0 = null;
10167         } // Finds the left-right distance between two longitudes.
10168         // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
10169         // the distance between ±180° to be 360°.
10170
10171
10172         function angle(lambda0, lambda1) {
10173           return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
10174         }
10175
10176         function rangeCompare(a, b) {
10177           return a[0] - b[0];
10178         }
10179
10180         function rangeContains(range, x) {
10181           return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
10182         }
10183
10184         function d3_geoBounds (feature) {
10185           var i, n, a, b, merged, deltaMax, delta;
10186           phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
10187           ranges = [];
10188           d3_geoStream(feature, boundsStream); // First, sort ranges by their minimum longitudes.
10189
10190           if (n = ranges.length) {
10191             ranges.sort(rangeCompare); // Then, merge any ranges that overlap.
10192
10193             for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
10194               b = ranges[i];
10195
10196               if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
10197                 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
10198                 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
10199               } else {
10200                 merged.push(a = b);
10201               }
10202             } // Finally, find the largest gap between the merged ranges.
10203             // The final bounding box will be the inverse of this gap.
10204
10205
10206             for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
10207               b = merged[i];
10208               if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
10209             }
10210           }
10211
10212           ranges = range$1 = null;
10213           return lambda0$1 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0$1, phi0], [lambda1, phi1]];
10214         }
10215
10216         var W0, W1, X0, Y0, Z0, X1, Y1, Z1, X2, Y2, Z2, lambda00$2, phi00$2, // first point
10217         x0, y0, z0; // previous point
10218
10219         var centroidStream = {
10220           sphere: noop,
10221           point: centroidPoint,
10222           lineStart: centroidLineStart,
10223           lineEnd: centroidLineEnd,
10224           polygonStart: function polygonStart() {
10225             centroidStream.lineStart = centroidRingStart;
10226             centroidStream.lineEnd = centroidRingEnd;
10227           },
10228           polygonEnd: function polygonEnd() {
10229             centroidStream.lineStart = centroidLineStart;
10230             centroidStream.lineEnd = centroidLineEnd;
10231           }
10232         }; // Arithmetic mean of Cartesian vectors.
10233
10234         function centroidPoint(lambda, phi) {
10235           lambda *= radians, phi *= radians;
10236           var cosPhi = cos(phi);
10237           centroidPointCartesian(cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi));
10238         }
10239
10240         function centroidPointCartesian(x, y, z) {
10241           ++W0;
10242           X0 += (x - X0) / W0;
10243           Y0 += (y - Y0) / W0;
10244           Z0 += (z - Z0) / W0;
10245         }
10246
10247         function centroidLineStart() {
10248           centroidStream.point = centroidLinePointFirst;
10249         }
10250
10251         function centroidLinePointFirst(lambda, phi) {
10252           lambda *= radians, phi *= radians;
10253           var cosPhi = cos(phi);
10254           x0 = cosPhi * cos(lambda);
10255           y0 = cosPhi * sin(lambda);
10256           z0 = sin(phi);
10257           centroidStream.point = centroidLinePoint;
10258           centroidPointCartesian(x0, y0, z0);
10259         }
10260
10261         function centroidLinePoint(lambda, phi) {
10262           lambda *= radians, phi *= radians;
10263           var cosPhi = cos(phi),
10264               x = cosPhi * cos(lambda),
10265               y = cosPhi * sin(lambda),
10266               z = sin(phi),
10267               w = atan2(sqrt$1((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
10268           W1 += w;
10269           X1 += w * (x0 + (x0 = x));
10270           Y1 += w * (y0 + (y0 = y));
10271           Z1 += w * (z0 + (z0 = z));
10272           centroidPointCartesian(x0, y0, z0);
10273         }
10274
10275         function centroidLineEnd() {
10276           centroidStream.point = centroidPoint;
10277         } // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
10278         // J. Applied Mechanics 42, 239 (1975).
10279
10280
10281         function centroidRingStart() {
10282           centroidStream.point = centroidRingPointFirst;
10283         }
10284
10285         function centroidRingEnd() {
10286           centroidRingPoint(lambda00$2, phi00$2);
10287           centroidStream.point = centroidPoint;
10288         }
10289
10290         function centroidRingPointFirst(lambda, phi) {
10291           lambda00$2 = lambda, phi00$2 = phi;
10292           lambda *= radians, phi *= radians;
10293           centroidStream.point = centroidRingPoint;
10294           var cosPhi = cos(phi);
10295           x0 = cosPhi * cos(lambda);
10296           y0 = cosPhi * sin(lambda);
10297           z0 = sin(phi);
10298           centroidPointCartesian(x0, y0, z0);
10299         }
10300
10301         function centroidRingPoint(lambda, phi) {
10302           lambda *= radians, phi *= radians;
10303           var cosPhi = cos(phi),
10304               x = cosPhi * cos(lambda),
10305               y = cosPhi * sin(lambda),
10306               z = sin(phi),
10307               cx = y0 * z - z0 * y,
10308               cy = z0 * x - x0 * z,
10309               cz = x0 * y - y0 * x,
10310               m = hypot(cx, cy, cz),
10311               w = asin(m),
10312               // line weight = angle
10313           v = m && -w / m; // area weight multiplier
10314
10315           X2.add(v * cx);
10316           Y2.add(v * cy);
10317           Z2.add(v * cz);
10318           W1 += w;
10319           X1 += w * (x0 + (x0 = x));
10320           Y1 += w * (y0 + (y0 = y));
10321           Z1 += w * (z0 + (z0 = z));
10322           centroidPointCartesian(x0, y0, z0);
10323         }
10324
10325         function d3_geoCentroid (object) {
10326           W0 = W1 = X0 = Y0 = Z0 = X1 = Y1 = Z1 = 0;
10327           X2 = new Adder();
10328           Y2 = new Adder();
10329           Z2 = new Adder();
10330           d3_geoStream(object, centroidStream);
10331           var x = +X2,
10332               y = +Y2,
10333               z = +Z2,
10334               m = hypot(x, y, z); // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
10335
10336           if (m < epsilon2) {
10337             x = X1, y = Y1, z = Z1; // If the feature has zero length, fall back to arithmetic mean of point vectors.
10338
10339             if (W1 < epsilon) x = X0, y = Y0, z = Z0;
10340             m = hypot(x, y, z); // If the feature still has an undefined ccentroid, then return.
10341
10342             if (m < epsilon2) return [NaN, NaN];
10343           }
10344
10345           return [atan2(y, x) * degrees, asin(z / m) * degrees];
10346         }
10347
10348         function compose (a, b) {
10349           function compose(x, y) {
10350             return x = a(x, y), b(x[0], x[1]);
10351           }
10352
10353           if (a.invert && b.invert) compose.invert = function (x, y) {
10354             return x = b.invert(x, y), x && a.invert(x[0], x[1]);
10355           };
10356           return compose;
10357         }
10358
10359         function rotationIdentity(lambda, phi) {
10360           return [abs$2(lambda) > pi ? lambda + Math.round(-lambda / tau) * tau : lambda, phi];
10361         }
10362
10363         rotationIdentity.invert = rotationIdentity;
10364         function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
10365           return (deltaLambda %= tau) ? deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) : rotationLambda(deltaLambda) : deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) : rotationIdentity;
10366         }
10367
10368         function forwardRotationLambda(deltaLambda) {
10369           return function (lambda, phi) {
10370             return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
10371           };
10372         }
10373
10374         function rotationLambda(deltaLambda) {
10375           var rotation = forwardRotationLambda(deltaLambda);
10376           rotation.invert = forwardRotationLambda(-deltaLambda);
10377           return rotation;
10378         }
10379
10380         function rotationPhiGamma(deltaPhi, deltaGamma) {
10381           var cosDeltaPhi = cos(deltaPhi),
10382               sinDeltaPhi = sin(deltaPhi),
10383               cosDeltaGamma = cos(deltaGamma),
10384               sinDeltaGamma = sin(deltaGamma);
10385
10386           function rotation(lambda, phi) {
10387             var cosPhi = cos(phi),
10388                 x = cos(lambda) * cosPhi,
10389                 y = sin(lambda) * cosPhi,
10390                 z = sin(phi),
10391                 k = z * cosDeltaPhi + x * sinDeltaPhi;
10392             return [atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), asin(k * cosDeltaGamma + y * sinDeltaGamma)];
10393           }
10394
10395           rotation.invert = function (lambda, phi) {
10396             var cosPhi = cos(phi),
10397                 x = cos(lambda) * cosPhi,
10398                 y = sin(lambda) * cosPhi,
10399                 z = sin(phi),
10400                 k = z * cosDeltaGamma - y * sinDeltaGamma;
10401             return [atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), asin(k * cosDeltaPhi - x * sinDeltaPhi)];
10402           };
10403
10404           return rotation;
10405         }
10406
10407         function rotation (rotate) {
10408           rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
10409
10410           function forward(coordinates) {
10411             coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
10412             return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
10413           }
10414
10415           forward.invert = function (coordinates) {
10416             coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
10417             return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
10418           };
10419
10420           return forward;
10421         }
10422
10423         function circleStream(stream, radius, delta, direction, t0, t1) {
10424           if (!delta) return;
10425           var cosRadius = cos(radius),
10426               sinRadius = sin(radius),
10427               step = direction * delta;
10428
10429           if (t0 == null) {
10430             t0 = radius + direction * tau;
10431             t1 = radius - step / 2;
10432           } else {
10433             t0 = circleRadius(cosRadius, t0);
10434             t1 = circleRadius(cosRadius, t1);
10435             if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
10436           }
10437
10438           for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
10439             point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
10440             stream.point(point[0], point[1]);
10441           }
10442         } // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
10443
10444         function circleRadius(cosRadius, point) {
10445           point = cartesian(point), point[0] -= cosRadius;
10446           cartesianNormalizeInPlace(point);
10447           var radius = acos(-point[1]);
10448           return ((-point[2] < 0 ? -radius : radius) + tau - epsilon) % tau;
10449         }
10450
10451         function clipBuffer () {
10452           var lines = [],
10453               line;
10454           return {
10455             point: function point(x, y, m) {
10456               line.push([x, y, m]);
10457             },
10458             lineStart: function lineStart() {
10459               lines.push(line = []);
10460             },
10461             lineEnd: noop,
10462             rejoin: function rejoin() {
10463               if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
10464             },
10465             result: function result() {
10466               var result = lines;
10467               lines = [];
10468               line = null;
10469               return result;
10470             }
10471           };
10472         }
10473
10474         function pointEqual (a, b) {
10475           return abs$2(a[0] - b[0]) < epsilon && abs$2(a[1] - b[1]) < epsilon;
10476         }
10477
10478         function Intersection(point, points, other, entry) {
10479           this.x = point;
10480           this.z = points;
10481           this.o = other; // another intersection
10482
10483           this.e = entry; // is an entry?
10484
10485           this.v = false; // visited
10486
10487           this.n = this.p = null; // next & previous
10488         } // A generalized polygon clipping algorithm: given a polygon that has been cut
10489         // into its visible line segments, and rejoins the segments by interpolating
10490         // along the clip edge.
10491
10492
10493         function clipRejoin (segments, compareIntersection, startInside, interpolate, stream) {
10494           var subject = [],
10495               clip = [],
10496               i,
10497               n;
10498           segments.forEach(function (segment) {
10499             if ((n = segment.length - 1) <= 0) return;
10500             var n,
10501                 p0 = segment[0],
10502                 p1 = segment[n],
10503                 x;
10504
10505             if (pointEqual(p0, p1)) {
10506               if (!p0[2] && !p1[2]) {
10507                 stream.lineStart();
10508
10509                 for (i = 0; i < n; ++i) {
10510                   stream.point((p0 = segment[i])[0], p0[1]);
10511                 }
10512
10513                 stream.lineEnd();
10514                 return;
10515               } // handle degenerate cases by moving the point
10516
10517
10518               p1[0] += 2 * epsilon;
10519             }
10520
10521             subject.push(x = new Intersection(p0, segment, null, true));
10522             clip.push(x.o = new Intersection(p0, null, x, false));
10523             subject.push(x = new Intersection(p1, segment, null, false));
10524             clip.push(x.o = new Intersection(p1, null, x, true));
10525           });
10526           if (!subject.length) return;
10527           clip.sort(compareIntersection);
10528           link(subject);
10529           link(clip);
10530
10531           for (i = 0, n = clip.length; i < n; ++i) {
10532             clip[i].e = startInside = !startInside;
10533           }
10534
10535           var start = subject[0],
10536               points,
10537               point;
10538
10539           while (1) {
10540             // Find first unvisited intersection.
10541             var current = start,
10542                 isSubject = true;
10543
10544             while (current.v) {
10545               if ((current = current.n) === start) return;
10546             }
10547
10548             points = current.z;
10549             stream.lineStart();
10550
10551             do {
10552               current.v = current.o.v = true;
10553
10554               if (current.e) {
10555                 if (isSubject) {
10556                   for (i = 0, n = points.length; i < n; ++i) {
10557                     stream.point((point = points[i])[0], point[1]);
10558                   }
10559                 } else {
10560                   interpolate(current.x, current.n.x, 1, stream);
10561                 }
10562
10563                 current = current.n;
10564               } else {
10565                 if (isSubject) {
10566                   points = current.p.z;
10567
10568                   for (i = points.length - 1; i >= 0; --i) {
10569                     stream.point((point = points[i])[0], point[1]);
10570                   }
10571                 } else {
10572                   interpolate(current.x, current.p.x, -1, stream);
10573                 }
10574
10575                 current = current.p;
10576               }
10577
10578               current = current.o;
10579               points = current.z;
10580               isSubject = !isSubject;
10581             } while (!current.v);
10582
10583             stream.lineEnd();
10584           }
10585         }
10586
10587         function link(array) {
10588           if (!(n = array.length)) return;
10589           var n,
10590               i = 0,
10591               a = array[0],
10592               b;
10593
10594           while (++i < n) {
10595             a.n = b = array[i];
10596             b.p = a;
10597             a = b;
10598           }
10599
10600           a.n = b = array[0];
10601           b.p = a;
10602         }
10603
10604         function longitude(point) {
10605           if (abs$2(point[0]) <= pi) return point[0];else return sign(point[0]) * ((abs$2(point[0]) + pi) % tau - pi);
10606         }
10607
10608         function polygonContains (polygon, point) {
10609           var lambda = longitude(point),
10610               phi = point[1],
10611               sinPhi = sin(phi),
10612               normal = [sin(lambda), -cos(lambda), 0],
10613               angle = 0,
10614               winding = 0;
10615           var sum = new Adder();
10616           if (sinPhi === 1) phi = halfPi + epsilon;else if (sinPhi === -1) phi = -halfPi - epsilon;
10617
10618           for (var i = 0, n = polygon.length; i < n; ++i) {
10619             if (!(m = (ring = polygon[i]).length)) continue;
10620             var ring,
10621                 m,
10622                 point0 = ring[m - 1],
10623                 lambda0 = longitude(point0),
10624                 phi0 = point0[1] / 2 + quarterPi,
10625                 sinPhi0 = sin(phi0),
10626                 cosPhi0 = cos(phi0);
10627
10628             for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
10629               var point1 = ring[j],
10630                   lambda1 = longitude(point1),
10631                   phi1 = point1[1] / 2 + quarterPi,
10632                   sinPhi1 = sin(phi1),
10633                   cosPhi1 = cos(phi1),
10634                   delta = lambda1 - lambda0,
10635                   sign = delta >= 0 ? 1 : -1,
10636                   absDelta = sign * delta,
10637                   antimeridian = absDelta > pi,
10638                   k = sinPhi0 * sinPhi1;
10639               sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
10640               angle += antimeridian ? delta + sign * tau : delta; // Are the longitudes either side of the point’s meridian (lambda),
10641               // and are the latitudes smaller than the parallel (phi)?
10642
10643               if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
10644                 var arc = cartesianCross(cartesian(point0), cartesian(point1));
10645                 cartesianNormalizeInPlace(arc);
10646                 var intersection = cartesianCross(normal, arc);
10647                 cartesianNormalizeInPlace(intersection);
10648                 var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
10649
10650                 if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
10651                   winding += antimeridian ^ delta >= 0 ? 1 : -1;
10652                 }
10653               }
10654             }
10655           } // First, determine whether the South pole is inside or outside:
10656           //
10657           // It is inside if:
10658           // * the polygon winds around it in a clockwise direction.
10659           // * the polygon does not (cumulatively) wind around it, but has a negative
10660           //   (counter-clockwise) area.
10661           //
10662           // Second, count the (signed) number of times a segment crosses a lambda
10663           // from the point to the South pole.  If it is zero, then the point is the
10664           // same side as the South pole.
10665
10666
10667           return (angle < -epsilon || angle < epsilon && sum < -epsilon2) ^ winding & 1;
10668         }
10669
10670         function clip (pointVisible, clipLine, interpolate, start) {
10671           return function (sink) {
10672             var line = clipLine(sink),
10673                 ringBuffer = clipBuffer(),
10674                 ringSink = clipLine(ringBuffer),
10675                 polygonStarted = false,
10676                 polygon,
10677                 segments,
10678                 ring;
10679             var clip = {
10680               point: point,
10681               lineStart: lineStart,
10682               lineEnd: lineEnd,
10683               polygonStart: function polygonStart() {
10684                 clip.point = pointRing;
10685                 clip.lineStart = ringStart;
10686                 clip.lineEnd = ringEnd;
10687                 segments = [];
10688                 polygon = [];
10689               },
10690               polygonEnd: function polygonEnd() {
10691                 clip.point = point;
10692                 clip.lineStart = lineStart;
10693                 clip.lineEnd = lineEnd;
10694                 segments = merge(segments);
10695                 var startInside = polygonContains(polygon, start);
10696
10697                 if (segments.length) {
10698                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10699                   clipRejoin(segments, compareIntersection, startInside, interpolate, sink);
10700                 } else if (startInside) {
10701                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10702                   sink.lineStart();
10703                   interpolate(null, null, 1, sink);
10704                   sink.lineEnd();
10705                 }
10706
10707                 if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
10708                 segments = polygon = null;
10709               },
10710               sphere: function sphere() {
10711                 sink.polygonStart();
10712                 sink.lineStart();
10713                 interpolate(null, null, 1, sink);
10714                 sink.lineEnd();
10715                 sink.polygonEnd();
10716               }
10717             };
10718
10719             function point(lambda, phi) {
10720               if (pointVisible(lambda, phi)) sink.point(lambda, phi);
10721             }
10722
10723             function pointLine(lambda, phi) {
10724               line.point(lambda, phi);
10725             }
10726
10727             function lineStart() {
10728               clip.point = pointLine;
10729               line.lineStart();
10730             }
10731
10732             function lineEnd() {
10733               clip.point = point;
10734               line.lineEnd();
10735             }
10736
10737             function pointRing(lambda, phi) {
10738               ring.push([lambda, phi]);
10739               ringSink.point(lambda, phi);
10740             }
10741
10742             function ringStart() {
10743               ringSink.lineStart();
10744               ring = [];
10745             }
10746
10747             function ringEnd() {
10748               pointRing(ring[0][0], ring[0][1]);
10749               ringSink.lineEnd();
10750               var clean = ringSink.clean(),
10751                   ringSegments = ringBuffer.result(),
10752                   i,
10753                   n = ringSegments.length,
10754                   m,
10755                   segment,
10756                   point;
10757               ring.pop();
10758               polygon.push(ring);
10759               ring = null;
10760               if (!n) return; // No intersections.
10761
10762               if (clean & 1) {
10763                 segment = ringSegments[0];
10764
10765                 if ((m = segment.length - 1) > 0) {
10766                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10767                   sink.lineStart();
10768
10769                   for (i = 0; i < m; ++i) {
10770                     sink.point((point = segment[i])[0], point[1]);
10771                   }
10772
10773                   sink.lineEnd();
10774                 }
10775
10776                 return;
10777               } // Rejoin connected segments.
10778               // TODO reuse ringBuffer.rejoin()?
10779
10780
10781               if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
10782               segments.push(ringSegments.filter(validSegment));
10783             }
10784
10785             return clip;
10786           };
10787         }
10788
10789         function validSegment(segment) {
10790           return segment.length > 1;
10791         } // Intersections are sorted along the clip edge. For both antimeridian cutting
10792         // and circle clipping, the same comparison is used.
10793
10794
10795         function compareIntersection(a, b) {
10796           return ((a = a.x)[0] < 0 ? a[1] - halfPi - epsilon : halfPi - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfPi - epsilon : halfPi - b[1]);
10797         }
10798
10799         var clipAntimeridian = clip(function () {
10800           return true;
10801         }, clipAntimeridianLine, clipAntimeridianInterpolate, [-pi, -halfPi]); // Takes a line and cuts into visible segments. Return values: 0 - there were
10802         // intersections or the line was empty; 1 - no intersections; 2 - there were
10803         // intersections, and the first and last segments should be rejoined.
10804
10805         function clipAntimeridianLine(stream) {
10806           var lambda0 = NaN,
10807               phi0 = NaN,
10808               sign0 = NaN,
10809               _clean; // no intersections
10810
10811
10812           return {
10813             lineStart: function lineStart() {
10814               stream.lineStart();
10815               _clean = 1;
10816             },
10817             point: function point(lambda1, phi1) {
10818               var sign1 = lambda1 > 0 ? pi : -pi,
10819                   delta = abs$2(lambda1 - lambda0);
10820
10821               if (abs$2(delta - pi) < epsilon) {
10822                 // line crosses a pole
10823                 stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
10824                 stream.point(sign0, phi0);
10825                 stream.lineEnd();
10826                 stream.lineStart();
10827                 stream.point(sign1, phi0);
10828                 stream.point(lambda1, phi0);
10829                 _clean = 0;
10830               } else if (sign0 !== sign1 && delta >= pi) {
10831                 // line crosses antimeridian
10832                 if (abs$2(lambda0 - sign0) < epsilon) lambda0 -= sign0 * epsilon; // handle degeneracies
10833
10834                 if (abs$2(lambda1 - sign1) < epsilon) lambda1 -= sign1 * epsilon;
10835                 phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
10836                 stream.point(sign0, phi0);
10837                 stream.lineEnd();
10838                 stream.lineStart();
10839                 stream.point(sign1, phi0);
10840                 _clean = 0;
10841               }
10842
10843               stream.point(lambda0 = lambda1, phi0 = phi1);
10844               sign0 = sign1;
10845             },
10846             lineEnd: function lineEnd() {
10847               stream.lineEnd();
10848               lambda0 = phi0 = NaN;
10849             },
10850             clean: function clean() {
10851               return 2 - _clean; // if intersections, rejoin first and last segments
10852             }
10853           };
10854         }
10855
10856         function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
10857           var cosPhi0,
10858               cosPhi1,
10859               sinLambda0Lambda1 = sin(lambda0 - lambda1);
10860           return abs$2(sinLambda0Lambda1) > epsilon ? atan((sin(phi0) * (cosPhi1 = cos(phi1)) * sin(lambda1) - sin(phi1) * (cosPhi0 = cos(phi0)) * sin(lambda0)) / (cosPhi0 * cosPhi1 * sinLambda0Lambda1)) : (phi0 + phi1) / 2;
10861         }
10862
10863         function clipAntimeridianInterpolate(from, to, direction, stream) {
10864           var phi;
10865
10866           if (from == null) {
10867             phi = direction * halfPi;
10868             stream.point(-pi, phi);
10869             stream.point(0, phi);
10870             stream.point(pi, phi);
10871             stream.point(pi, 0);
10872             stream.point(pi, -phi);
10873             stream.point(0, -phi);
10874             stream.point(-pi, -phi);
10875             stream.point(-pi, 0);
10876             stream.point(-pi, phi);
10877           } else if (abs$2(from[0] - to[0]) > epsilon) {
10878             var lambda = from[0] < to[0] ? pi : -pi;
10879             phi = direction * lambda / 2;
10880             stream.point(-lambda, phi);
10881             stream.point(0, phi);
10882             stream.point(lambda, phi);
10883           } else {
10884             stream.point(to[0], to[1]);
10885           }
10886         }
10887
10888         function clipCircle (radius) {
10889           var cr = cos(radius),
10890               delta = 6 * radians,
10891               smallRadius = cr > 0,
10892               notHemisphere = abs$2(cr) > epsilon; // TODO optimise for this common case
10893
10894           function interpolate(from, to, direction, stream) {
10895             circleStream(stream, radius, delta, direction, from, to);
10896           }
10897
10898           function visible(lambda, phi) {
10899             return cos(lambda) * cos(phi) > cr;
10900           } // Takes a line and cuts into visible segments. Return values used for polygon
10901           // clipping: 0 - there were intersections or the line was empty; 1 - no
10902           // intersections 2 - there were intersections, and the first and last segments
10903           // should be rejoined.
10904
10905
10906           function clipLine(stream) {
10907             var point0, // previous point
10908             c0, // code for previous point
10909             v0, // visibility of previous point
10910             v00, // visibility of first point
10911             _clean; // no intersections
10912
10913
10914             return {
10915               lineStart: function lineStart() {
10916                 v00 = v0 = false;
10917                 _clean = 1;
10918               },
10919               point: function point(lambda, phi) {
10920                 var point1 = [lambda, phi],
10921                     point2,
10922                     v = visible(lambda, phi),
10923                     c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
10924                 if (!point0 && (v00 = v0 = v)) stream.lineStart();
10925
10926                 if (v !== v0) {
10927                   point2 = intersect(point0, point1);
10928                   if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) point1[2] = 1;
10929                 }
10930
10931                 if (v !== v0) {
10932                   _clean = 0;
10933
10934                   if (v) {
10935                     // outside going in
10936                     stream.lineStart();
10937                     point2 = intersect(point1, point0);
10938                     stream.point(point2[0], point2[1]);
10939                   } else {
10940                     // inside going out
10941                     point2 = intersect(point0, point1);
10942                     stream.point(point2[0], point2[1], 2);
10943                     stream.lineEnd();
10944                   }
10945
10946                   point0 = point2;
10947                 } else if (notHemisphere && point0 && smallRadius ^ v) {
10948                   var t; // If the codes for two points are different, or are both zero,
10949                   // and there this segment intersects with the small circle.
10950
10951                   if (!(c & c0) && (t = intersect(point1, point0, true))) {
10952                     _clean = 0;
10953
10954                     if (smallRadius) {
10955                       stream.lineStart();
10956                       stream.point(t[0][0], t[0][1]);
10957                       stream.point(t[1][0], t[1][1]);
10958                       stream.lineEnd();
10959                     } else {
10960                       stream.point(t[1][0], t[1][1]);
10961                       stream.lineEnd();
10962                       stream.lineStart();
10963                       stream.point(t[0][0], t[0][1], 3);
10964                     }
10965                   }
10966                 }
10967
10968                 if (v && (!point0 || !pointEqual(point0, point1))) {
10969                   stream.point(point1[0], point1[1]);
10970                 }
10971
10972                 point0 = point1, v0 = v, c0 = c;
10973               },
10974               lineEnd: function lineEnd() {
10975                 if (v0) stream.lineEnd();
10976                 point0 = null;
10977               },
10978               // Rejoin first and last segments if there were intersections and the first
10979               // and last points were visible.
10980               clean: function clean() {
10981                 return _clean | (v00 && v0) << 1;
10982               }
10983             };
10984           } // Intersects the great circle between a and b with the clip circle.
10985
10986
10987           function intersect(a, b, two) {
10988             var pa = cartesian(a),
10989                 pb = cartesian(b); // We have two planes, n1.p = d1 and n2.p = d2.
10990             // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
10991
10992             var n1 = [1, 0, 0],
10993                 // normal
10994             n2 = cartesianCross(pa, pb),
10995                 n2n2 = cartesianDot(n2, n2),
10996                 n1n2 = n2[0],
10997                 // cartesianDot(n1, n2),
10998             determinant = n2n2 - n1n2 * n1n2; // Two polar points.
10999
11000             if (!determinant) return !two && a;
11001             var c1 = cr * n2n2 / determinant,
11002                 c2 = -cr * n1n2 / determinant,
11003                 n1xn2 = cartesianCross(n1, n2),
11004                 A = cartesianScale(n1, c1),
11005                 B = cartesianScale(n2, c2);
11006             cartesianAddInPlace(A, B); // Solve |p(t)|^2 = 1.
11007
11008             var u = n1xn2,
11009                 w = cartesianDot(A, u),
11010                 uu = cartesianDot(u, u),
11011                 t2 = w * w - uu * (cartesianDot(A, A) - 1);
11012             if (t2 < 0) return;
11013             var t = sqrt$1(t2),
11014                 q = cartesianScale(u, (-w - t) / uu);
11015             cartesianAddInPlace(q, A);
11016             q = spherical(q);
11017             if (!two) return q; // Two intersection points.
11018
11019             var lambda0 = a[0],
11020                 lambda1 = b[0],
11021                 phi0 = a[1],
11022                 phi1 = b[1],
11023                 z;
11024             if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
11025             var delta = lambda1 - lambda0,
11026                 polar = abs$2(delta - pi) < epsilon,
11027                 meridian = polar || delta < epsilon;
11028             if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b.
11029
11030             if (meridian ? polar ? phi0 + phi1 > 0 ^ q[1] < (abs$2(q[0] - lambda0) < epsilon ? phi0 : phi1) : phi0 <= q[1] && q[1] <= phi1 : delta > pi ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
11031               var q1 = cartesianScale(u, (-w + t) / uu);
11032               cartesianAddInPlace(q1, A);
11033               return [q, spherical(q1)];
11034             }
11035           } // Generates a 4-bit vector representing the location of a point relative to
11036           // the small circle's bounding box.
11037
11038
11039           function code(lambda, phi) {
11040             var r = smallRadius ? radius : pi - radius,
11041                 code = 0;
11042             if (lambda < -r) code |= 1; // left
11043             else if (lambda > r) code |= 2; // right
11044
11045             if (phi < -r) code |= 4; // below
11046             else if (phi > r) code |= 8; // above
11047
11048             return code;
11049           }
11050
11051           return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
11052         }
11053
11054         function clipLine (a, b, x0, y0, x1, y1) {
11055           var ax = a[0],
11056               ay = a[1],
11057               bx = b[0],
11058               by = b[1],
11059               t0 = 0,
11060               t1 = 1,
11061               dx = bx - ax,
11062               dy = by - ay,
11063               r;
11064           r = x0 - ax;
11065           if (!dx && r > 0) return;
11066           r /= dx;
11067
11068           if (dx < 0) {
11069             if (r < t0) return;
11070             if (r < t1) t1 = r;
11071           } else if (dx > 0) {
11072             if (r > t1) return;
11073             if (r > t0) t0 = r;
11074           }
11075
11076           r = x1 - ax;
11077           if (!dx && r < 0) return;
11078           r /= dx;
11079
11080           if (dx < 0) {
11081             if (r > t1) return;
11082             if (r > t0) t0 = r;
11083           } else if (dx > 0) {
11084             if (r < t0) return;
11085             if (r < t1) t1 = r;
11086           }
11087
11088           r = y0 - ay;
11089           if (!dy && r > 0) return;
11090           r /= dy;
11091
11092           if (dy < 0) {
11093             if (r < t0) return;
11094             if (r < t1) t1 = r;
11095           } else if (dy > 0) {
11096             if (r > t1) return;
11097             if (r > t0) t0 = r;
11098           }
11099
11100           r = y1 - ay;
11101           if (!dy && r < 0) return;
11102           r /= dy;
11103
11104           if (dy < 0) {
11105             if (r > t1) return;
11106             if (r > t0) t0 = r;
11107           } else if (dy > 0) {
11108             if (r < t0) return;
11109             if (r < t1) t1 = r;
11110           }
11111
11112           if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
11113           if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
11114           return true;
11115         }
11116
11117         var clipMax = 1e9,
11118             clipMin = -clipMax; // TODO Use d3-polygon’s polygonContains here for the ring check?
11119         // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
11120
11121         function clipRectangle(x0, y0, x1, y1) {
11122           function visible(x, y) {
11123             return x0 <= x && x <= x1 && y0 <= y && y <= y1;
11124           }
11125
11126           function interpolate(from, to, direction, stream) {
11127             var a = 0,
11128                 a1 = 0;
11129
11130             if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
11131               do {
11132                 stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
11133               } while ((a = (a + direction + 4) % 4) !== a1);
11134             } else {
11135               stream.point(to[0], to[1]);
11136             }
11137           }
11138
11139           function corner(p, direction) {
11140             return abs$2(p[0] - x0) < epsilon ? direction > 0 ? 0 : 3 : abs$2(p[0] - x1) < epsilon ? direction > 0 ? 2 : 1 : abs$2(p[1] - y0) < epsilon ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
11141           }
11142
11143           function compareIntersection(a, b) {
11144             return comparePoint(a.x, b.x);
11145           }
11146
11147           function comparePoint(a, b) {
11148             var ca = corner(a, 1),
11149                 cb = corner(b, 1);
11150             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];
11151           }
11152
11153           return function (stream) {
11154             var activeStream = stream,
11155                 bufferStream = clipBuffer(),
11156                 segments,
11157                 polygon,
11158                 ring,
11159                 x__,
11160                 y__,
11161                 v__,
11162                 // first point
11163             x_,
11164                 y_,
11165                 v_,
11166                 // previous point
11167             first,
11168                 clean;
11169             var clipStream = {
11170               point: point,
11171               lineStart: lineStart,
11172               lineEnd: lineEnd,
11173               polygonStart: polygonStart,
11174               polygonEnd: polygonEnd
11175             };
11176
11177             function point(x, y) {
11178               if (visible(x, y)) activeStream.point(x, y);
11179             }
11180
11181             function polygonInside() {
11182               var winding = 0;
11183
11184               for (var i = 0, n = polygon.length; i < n; ++i) {
11185                 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
11186                   a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
11187
11188                   if (a1 <= y1) {
11189                     if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding;
11190                   } else {
11191                     if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding;
11192                   }
11193                 }
11194               }
11195
11196               return winding;
11197             } // Buffer geometry within a polygon and then clip it en masse.
11198
11199
11200             function polygonStart() {
11201               activeStream = bufferStream, segments = [], polygon = [], clean = true;
11202             }
11203
11204             function polygonEnd() {
11205               var startInside = polygonInside(),
11206                   cleanInside = clean && startInside,
11207                   visible = (segments = merge(segments)).length;
11208
11209               if (cleanInside || visible) {
11210                 stream.polygonStart();
11211
11212                 if (cleanInside) {
11213                   stream.lineStart();
11214                   interpolate(null, null, 1, stream);
11215                   stream.lineEnd();
11216                 }
11217
11218                 if (visible) {
11219                   clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
11220                 }
11221
11222                 stream.polygonEnd();
11223               }
11224
11225               activeStream = stream, segments = polygon = ring = null;
11226             }
11227
11228             function lineStart() {
11229               clipStream.point = linePoint;
11230               if (polygon) polygon.push(ring = []);
11231               first = true;
11232               v_ = false;
11233               x_ = y_ = NaN;
11234             } // TODO rather than special-case polygons, simply handle them separately.
11235             // Ideally, coincident intersection points should be jittered to avoid
11236             // clipping issues.
11237
11238
11239             function lineEnd() {
11240               if (segments) {
11241                 linePoint(x__, y__);
11242                 if (v__ && v_) bufferStream.rejoin();
11243                 segments.push(bufferStream.result());
11244               }
11245
11246               clipStream.point = point;
11247               if (v_) activeStream.lineEnd();
11248             }
11249
11250             function linePoint(x, y) {
11251               var v = visible(x, y);
11252               if (polygon) ring.push([x, y]);
11253
11254               if (first) {
11255                 x__ = x, y__ = y, v__ = v;
11256                 first = false;
11257
11258                 if (v) {
11259                   activeStream.lineStart();
11260                   activeStream.point(x, y);
11261                 }
11262               } else {
11263                 if (v && v_) activeStream.point(x, y);else {
11264                   var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
11265                       b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
11266
11267                   if (clipLine(a, b, x0, y0, x1, y1)) {
11268                     if (!v_) {
11269                       activeStream.lineStart();
11270                       activeStream.point(a[0], a[1]);
11271                     }
11272
11273                     activeStream.point(b[0], b[1]);
11274                     if (!v) activeStream.lineEnd();
11275                     clean = false;
11276                   } else if (v) {
11277                     activeStream.lineStart();
11278                     activeStream.point(x, y);
11279                     clean = false;
11280                   }
11281                 }
11282               }
11283
11284               x_ = x, y_ = y, v_ = v;
11285             }
11286
11287             return clipStream;
11288           };
11289         }
11290
11291         var lengthSum, lambda0$2, sinPhi0$1, cosPhi0$1;
11292         var lengthStream = {
11293           sphere: noop,
11294           point: noop,
11295           lineStart: lengthLineStart,
11296           lineEnd: noop,
11297           polygonStart: noop,
11298           polygonEnd: noop
11299         };
11300
11301         function lengthLineStart() {
11302           lengthStream.point = lengthPointFirst;
11303           lengthStream.lineEnd = lengthLineEnd;
11304         }
11305
11306         function lengthLineEnd() {
11307           lengthStream.point = lengthStream.lineEnd = noop;
11308         }
11309
11310         function lengthPointFirst(lambda, phi) {
11311           lambda *= radians, phi *= radians;
11312           lambda0$2 = lambda, sinPhi0$1 = sin(phi), cosPhi0$1 = cos(phi);
11313           lengthStream.point = lengthPoint;
11314         }
11315
11316         function lengthPoint(lambda, phi) {
11317           lambda *= radians, phi *= radians;
11318           var sinPhi = sin(phi),
11319               cosPhi = cos(phi),
11320               delta = abs$2(lambda - lambda0$2),
11321               cosDelta = cos(delta),
11322               sinDelta = sin(delta),
11323               x = cosPhi * sinDelta,
11324               y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
11325               z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
11326           lengthSum.add(atan2(sqrt$1(x * x + y * y), z));
11327           lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
11328         }
11329
11330         function d3_geoLength (object) {
11331           lengthSum = new Adder();
11332           d3_geoStream(object, lengthStream);
11333           return +lengthSum;
11334         }
11335
11336         var identity = (function (x) {
11337           return x;
11338         });
11339
11340         var areaSum$1 = new Adder(),
11341             areaRingSum$1 = new Adder(),
11342             x00,
11343             y00,
11344             x0$1,
11345             y0$1;
11346         var areaStream$1 = {
11347           point: noop,
11348           lineStart: noop,
11349           lineEnd: noop,
11350           polygonStart: function polygonStart() {
11351             areaStream$1.lineStart = areaRingStart$1;
11352             areaStream$1.lineEnd = areaRingEnd$1;
11353           },
11354           polygonEnd: function polygonEnd() {
11355             areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop;
11356             areaSum$1.add(abs$2(areaRingSum$1));
11357             areaRingSum$1 = new Adder();
11358           },
11359           result: function result() {
11360             var area = areaSum$1 / 2;
11361             areaSum$1 = new Adder();
11362             return area;
11363           }
11364         };
11365
11366         function areaRingStart$1() {
11367           areaStream$1.point = areaPointFirst$1;
11368         }
11369
11370         function areaPointFirst$1(x, y) {
11371           areaStream$1.point = areaPoint$1;
11372           x00 = x0$1 = x, y00 = y0$1 = y;
11373         }
11374
11375         function areaPoint$1(x, y) {
11376           areaRingSum$1.add(y0$1 * x - x0$1 * y);
11377           x0$1 = x, y0$1 = y;
11378         }
11379
11380         function areaRingEnd$1() {
11381           areaPoint$1(x00, y00);
11382         }
11383
11384         var x0$2 = Infinity,
11385             y0$2 = x0$2,
11386             x1 = -x0$2,
11387             y1 = x1;
11388         var boundsStream$1 = {
11389           point: boundsPoint$1,
11390           lineStart: noop,
11391           lineEnd: noop,
11392           polygonStart: noop,
11393           polygonEnd: noop,
11394           result: function result() {
11395             var bounds = [[x0$2, y0$2], [x1, y1]];
11396             x1 = y1 = -(y0$2 = x0$2 = Infinity);
11397             return bounds;
11398           }
11399         };
11400
11401         function boundsPoint$1(x, y) {
11402           if (x < x0$2) x0$2 = x;
11403           if (x > x1) x1 = x;
11404           if (y < y0$2) y0$2 = y;
11405           if (y > y1) y1 = y;
11406         }
11407
11408         var X0$1 = 0,
11409             Y0$1 = 0,
11410             Z0$1 = 0,
11411             X1$1 = 0,
11412             Y1$1 = 0,
11413             Z1$1 = 0,
11414             X2$1 = 0,
11415             Y2$1 = 0,
11416             Z2$1 = 0,
11417             x00$1,
11418             y00$1,
11419             x0$3,
11420             y0$3;
11421         var centroidStream$1 = {
11422           point: centroidPoint$1,
11423           lineStart: centroidLineStart$1,
11424           lineEnd: centroidLineEnd$1,
11425           polygonStart: function polygonStart() {
11426             centroidStream$1.lineStart = centroidRingStart$1;
11427             centroidStream$1.lineEnd = centroidRingEnd$1;
11428           },
11429           polygonEnd: function polygonEnd() {
11430             centroidStream$1.point = centroidPoint$1;
11431             centroidStream$1.lineStart = centroidLineStart$1;
11432             centroidStream$1.lineEnd = centroidLineEnd$1;
11433           },
11434           result: function result() {
11435             var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1] : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1] : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1] : [NaN, NaN];
11436             X0$1 = Y0$1 = Z0$1 = X1$1 = Y1$1 = Z1$1 = X2$1 = Y2$1 = Z2$1 = 0;
11437             return centroid;
11438           }
11439         };
11440
11441         function centroidPoint$1(x, y) {
11442           X0$1 += x;
11443           Y0$1 += y;
11444           ++Z0$1;
11445         }
11446
11447         function centroidLineStart$1() {
11448           centroidStream$1.point = centroidPointFirstLine;
11449         }
11450
11451         function centroidPointFirstLine(x, y) {
11452           centroidStream$1.point = centroidPointLine;
11453           centroidPoint$1(x0$3 = x, y0$3 = y);
11454         }
11455
11456         function centroidPointLine(x, y) {
11457           var dx = x - x0$3,
11458               dy = y - y0$3,
11459               z = sqrt$1(dx * dx + dy * dy);
11460           X1$1 += z * (x0$3 + x) / 2;
11461           Y1$1 += z * (y0$3 + y) / 2;
11462           Z1$1 += z;
11463           centroidPoint$1(x0$3 = x, y0$3 = y);
11464         }
11465
11466         function centroidLineEnd$1() {
11467           centroidStream$1.point = centroidPoint$1;
11468         }
11469
11470         function centroidRingStart$1() {
11471           centroidStream$1.point = centroidPointFirstRing;
11472         }
11473
11474         function centroidRingEnd$1() {
11475           centroidPointRing(x00$1, y00$1);
11476         }
11477
11478         function centroidPointFirstRing(x, y) {
11479           centroidStream$1.point = centroidPointRing;
11480           centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
11481         }
11482
11483         function centroidPointRing(x, y) {
11484           var dx = x - x0$3,
11485               dy = y - y0$3,
11486               z = sqrt$1(dx * dx + dy * dy);
11487           X1$1 += z * (x0$3 + x) / 2;
11488           Y1$1 += z * (y0$3 + y) / 2;
11489           Z1$1 += z;
11490           z = y0$3 * x - x0$3 * y;
11491           X2$1 += z * (x0$3 + x);
11492           Y2$1 += z * (y0$3 + y);
11493           Z2$1 += z * 3;
11494           centroidPoint$1(x0$3 = x, y0$3 = y);
11495         }
11496
11497         function PathContext(context) {
11498           this._context = context;
11499         }
11500         PathContext.prototype = {
11501           _radius: 4.5,
11502           pointRadius: function pointRadius(_) {
11503             return this._radius = _, this;
11504           },
11505           polygonStart: function polygonStart() {
11506             this._line = 0;
11507           },
11508           polygonEnd: function polygonEnd() {
11509             this._line = NaN;
11510           },
11511           lineStart: function lineStart() {
11512             this._point = 0;
11513           },
11514           lineEnd: function lineEnd() {
11515             if (this._line === 0) this._context.closePath();
11516             this._point = NaN;
11517           },
11518           point: function point(x, y) {
11519             switch (this._point) {
11520               case 0:
11521                 {
11522                   this._context.moveTo(x, y);
11523
11524                   this._point = 1;
11525                   break;
11526                 }
11527
11528               case 1:
11529                 {
11530                   this._context.lineTo(x, y);
11531
11532                   break;
11533                 }
11534
11535               default:
11536                 {
11537                   this._context.moveTo(x + this._radius, y);
11538
11539                   this._context.arc(x, y, this._radius, 0, tau);
11540
11541                   break;
11542                 }
11543             }
11544           },
11545           result: noop
11546         };
11547
11548         var lengthSum$1 = new Adder(),
11549             lengthRing,
11550             x00$2,
11551             y00$2,
11552             x0$4,
11553             y0$4;
11554         var lengthStream$1 = {
11555           point: noop,
11556           lineStart: function lineStart() {
11557             lengthStream$1.point = lengthPointFirst$1;
11558           },
11559           lineEnd: function lineEnd() {
11560             if (lengthRing) lengthPoint$1(x00$2, y00$2);
11561             lengthStream$1.point = noop;
11562           },
11563           polygonStart: function polygonStart() {
11564             lengthRing = true;
11565           },
11566           polygonEnd: function polygonEnd() {
11567             lengthRing = null;
11568           },
11569           result: function result() {
11570             var length = +lengthSum$1;
11571             lengthSum$1 = new Adder();
11572             return length;
11573           }
11574         };
11575
11576         function lengthPointFirst$1(x, y) {
11577           lengthStream$1.point = lengthPoint$1;
11578           x00$2 = x0$4 = x, y00$2 = y0$4 = y;
11579         }
11580
11581         function lengthPoint$1(x, y) {
11582           x0$4 -= x, y0$4 -= y;
11583           lengthSum$1.add(sqrt$1(x0$4 * x0$4 + y0$4 * y0$4));
11584           x0$4 = x, y0$4 = y;
11585         }
11586
11587         function PathString() {
11588           this._string = [];
11589         }
11590         PathString.prototype = {
11591           _radius: 4.5,
11592           _circle: circle(4.5),
11593           pointRadius: function pointRadius(_) {
11594             if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
11595             return this;
11596           },
11597           polygonStart: function polygonStart() {
11598             this._line = 0;
11599           },
11600           polygonEnd: function polygonEnd() {
11601             this._line = NaN;
11602           },
11603           lineStart: function lineStart() {
11604             this._point = 0;
11605           },
11606           lineEnd: function lineEnd() {
11607             if (this._line === 0) this._string.push("Z");
11608             this._point = NaN;
11609           },
11610           point: function point(x, y) {
11611             switch (this._point) {
11612               case 0:
11613                 {
11614                   this._string.push("M", x, ",", y);
11615
11616                   this._point = 1;
11617                   break;
11618                 }
11619
11620               case 1:
11621                 {
11622                   this._string.push("L", x, ",", y);
11623
11624                   break;
11625                 }
11626
11627               default:
11628                 {
11629                   if (this._circle == null) this._circle = circle(this._radius);
11630
11631                   this._string.push("M", x, ",", y, this._circle);
11632
11633                   break;
11634                 }
11635             }
11636           },
11637           result: function result() {
11638             if (this._string.length) {
11639               var result = this._string.join("");
11640
11641               this._string = [];
11642               return result;
11643             } else {
11644               return null;
11645             }
11646           }
11647         };
11648
11649         function circle(radius) {
11650           return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
11651         }
11652
11653         function d3_geoPath (projection, context) {
11654           var pointRadius = 4.5,
11655               projectionStream,
11656               contextStream;
11657
11658           function path(object) {
11659             if (object) {
11660               if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
11661               d3_geoStream(object, projectionStream(contextStream));
11662             }
11663
11664             return contextStream.result();
11665           }
11666
11667           path.area = function (object) {
11668             d3_geoStream(object, projectionStream(areaStream$1));
11669             return areaStream$1.result();
11670           };
11671
11672           path.measure = function (object) {
11673             d3_geoStream(object, projectionStream(lengthStream$1));
11674             return lengthStream$1.result();
11675           };
11676
11677           path.bounds = function (object) {
11678             d3_geoStream(object, projectionStream(boundsStream$1));
11679             return boundsStream$1.result();
11680           };
11681
11682           path.centroid = function (object) {
11683             d3_geoStream(object, projectionStream(centroidStream$1));
11684             return centroidStream$1.result();
11685           };
11686
11687           path.projection = function (_) {
11688             return arguments.length ? (projectionStream = _ == null ? (projection = null, identity) : (projection = _).stream, path) : projection;
11689           };
11690
11691           path.context = function (_) {
11692             if (!arguments.length) return context;
11693             contextStream = _ == null ? (context = null, new PathString()) : new PathContext(context = _);
11694             if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
11695             return path;
11696           };
11697
11698           path.pointRadius = function (_) {
11699             if (!arguments.length) return pointRadius;
11700             pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
11701             return path;
11702           };
11703
11704           return path.projection(projection).context(context);
11705         }
11706
11707         function d3_geoTransform (methods) {
11708           return {
11709             stream: transformer(methods)
11710           };
11711         }
11712         function transformer(methods) {
11713           return function (stream) {
11714             var s = new TransformStream();
11715
11716             for (var key in methods) {
11717               s[key] = methods[key];
11718             }
11719
11720             s.stream = stream;
11721             return s;
11722           };
11723         }
11724
11725         function TransformStream() {}
11726
11727         TransformStream.prototype = {
11728           constructor: TransformStream,
11729           point: function point(x, y) {
11730             this.stream.point(x, y);
11731           },
11732           sphere: function sphere() {
11733             this.stream.sphere();
11734           },
11735           lineStart: function lineStart() {
11736             this.stream.lineStart();
11737           },
11738           lineEnd: function lineEnd() {
11739             this.stream.lineEnd();
11740           },
11741           polygonStart: function polygonStart() {
11742             this.stream.polygonStart();
11743           },
11744           polygonEnd: function polygonEnd() {
11745             this.stream.polygonEnd();
11746           }
11747         };
11748
11749         function fit(projection, fitBounds, object) {
11750           var clip = projection.clipExtent && projection.clipExtent();
11751           projection.scale(150).translate([0, 0]);
11752           if (clip != null) projection.clipExtent(null);
11753           d3_geoStream(object, projection.stream(boundsStream$1));
11754           fitBounds(boundsStream$1.result());
11755           if (clip != null) projection.clipExtent(clip);
11756           return projection;
11757         }
11758
11759         function fitExtent(projection, extent, object) {
11760           return fit(projection, function (b) {
11761             var w = extent[1][0] - extent[0][0],
11762                 h = extent[1][1] - extent[0][1],
11763                 k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
11764                 x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
11765                 y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
11766             projection.scale(150 * k).translate([x, y]);
11767           }, object);
11768         }
11769         function fitSize(projection, size, object) {
11770           return fitExtent(projection, [[0, 0], size], object);
11771         }
11772         function fitWidth(projection, width, object) {
11773           return fit(projection, function (b) {
11774             var w = +width,
11775                 k = w / (b[1][0] - b[0][0]),
11776                 x = (w - k * (b[1][0] + b[0][0])) / 2,
11777                 y = -k * b[0][1];
11778             projection.scale(150 * k).translate([x, y]);
11779           }, object);
11780         }
11781         function fitHeight(projection, height, object) {
11782           return fit(projection, function (b) {
11783             var h = +height,
11784                 k = h / (b[1][1] - b[0][1]),
11785                 x = -k * b[0][0],
11786                 y = (h - k * (b[1][1] + b[0][1])) / 2;
11787             projection.scale(150 * k).translate([x, y]);
11788           }, object);
11789         }
11790
11791         var maxDepth = 16,
11792             // maximum depth of subdivision
11793         cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
11794
11795         function resample (project, delta2) {
11796           return +delta2 ? resample$1(project, delta2) : resampleNone(project);
11797         }
11798
11799         function resampleNone(project) {
11800           return transformer({
11801             point: function point(x, y) {
11802               x = project(x, y);
11803               this.stream.point(x[0], x[1]);
11804             }
11805           });
11806         }
11807
11808         function resample$1(project, delta2) {
11809           function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
11810             var dx = x1 - x0,
11811                 dy = y1 - y0,
11812                 d2 = dx * dx + dy * dy;
11813
11814             if (d2 > 4 * delta2 && depth--) {
11815               var a = a0 + a1,
11816                   b = b0 + b1,
11817                   c = c0 + c1,
11818                   m = sqrt$1(a * a + b * b + c * c),
11819                   phi2 = asin(c /= m),
11820                   lambda2 = abs$2(abs$2(c) - 1) < epsilon || abs$2(lambda0 - lambda1) < epsilon ? (lambda0 + lambda1) / 2 : atan2(b, a),
11821                   p = project(lambda2, phi2),
11822                   x2 = p[0],
11823                   y2 = p[1],
11824                   dx2 = x2 - x0,
11825                   dy2 = y2 - y0,
11826                   dz = dy * dx2 - dx * dy2;
11827
11828               if (dz * dz / d2 > delta2 // perpendicular projected distance
11829               || abs$2((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
11830               || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
11831                 // angular distance
11832                 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
11833                 stream.point(x2, y2);
11834                 resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
11835               }
11836             }
11837           }
11838
11839           return function (stream) {
11840             var lambda00, x00, y00, a00, b00, c00, // first point
11841             lambda0, x0, y0, a0, b0, c0; // previous point
11842
11843             var resampleStream = {
11844               point: point,
11845               lineStart: lineStart,
11846               lineEnd: lineEnd,
11847               polygonStart: function polygonStart() {
11848                 stream.polygonStart();
11849                 resampleStream.lineStart = ringStart;
11850               },
11851               polygonEnd: function polygonEnd() {
11852                 stream.polygonEnd();
11853                 resampleStream.lineStart = lineStart;
11854               }
11855             };
11856
11857             function point(x, y) {
11858               x = project(x, y);
11859               stream.point(x[0], x[1]);
11860             }
11861
11862             function lineStart() {
11863               x0 = NaN;
11864               resampleStream.point = linePoint;
11865               stream.lineStart();
11866             }
11867
11868             function linePoint(lambda, phi) {
11869               var c = cartesian([lambda, phi]),
11870                   p = project(lambda, phi);
11871               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);
11872               stream.point(x0, y0);
11873             }
11874
11875             function lineEnd() {
11876               resampleStream.point = point;
11877               stream.lineEnd();
11878             }
11879
11880             function ringStart() {
11881               lineStart();
11882               resampleStream.point = ringPoint;
11883               resampleStream.lineEnd = ringEnd;
11884             }
11885
11886             function ringPoint(lambda, phi) {
11887               linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
11888               resampleStream.point = linePoint;
11889             }
11890
11891             function ringEnd() {
11892               resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
11893               resampleStream.lineEnd = lineEnd;
11894               lineEnd();
11895             }
11896
11897             return resampleStream;
11898           };
11899         }
11900
11901         var transformRadians = transformer({
11902           point: function point(x, y) {
11903             this.stream.point(x * radians, y * radians);
11904           }
11905         });
11906
11907         function transformRotate(rotate) {
11908           return transformer({
11909             point: function point(x, y) {
11910               var r = rotate(x, y);
11911               return this.stream.point(r[0], r[1]);
11912             }
11913           });
11914         }
11915
11916         function scaleTranslate(k, dx, dy, sx, sy) {
11917           function transform(x, y) {
11918             x *= sx;
11919             y *= sy;
11920             return [dx + k * x, dy - k * y];
11921           }
11922
11923           transform.invert = function (x, y) {
11924             return [(x - dx) / k * sx, (dy - y) / k * sy];
11925           };
11926
11927           return transform;
11928         }
11929
11930         function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
11931           if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
11932           var cosAlpha = cos(alpha),
11933               sinAlpha = sin(alpha),
11934               a = cosAlpha * k,
11935               b = sinAlpha * k,
11936               ai = cosAlpha / k,
11937               bi = sinAlpha / k,
11938               ci = (sinAlpha * dy - cosAlpha * dx) / k,
11939               fi = (sinAlpha * dx + cosAlpha * dy) / k;
11940
11941           function transform(x, y) {
11942             x *= sx;
11943             y *= sy;
11944             return [a * x - b * y + dx, dy - b * x - a * y];
11945           }
11946
11947           transform.invert = function (x, y) {
11948             return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
11949           };
11950
11951           return transform;
11952         }
11953
11954         function projection(project) {
11955           return projectionMutator(function () {
11956             return project;
11957           })();
11958         }
11959         function projectionMutator(projectAt) {
11960           var project,
11961               k = 150,
11962               // scale
11963           x = 480,
11964               y = 250,
11965               // translate
11966           lambda = 0,
11967               phi = 0,
11968               // center
11969           deltaLambda = 0,
11970               deltaPhi = 0,
11971               deltaGamma = 0,
11972               rotate,
11973               // pre-rotate
11974           alpha = 0,
11975               // post-rotate angle
11976           sx = 1,
11977               // reflectX
11978           sy = 1,
11979               // reflectX
11980           theta = null,
11981               preclip = clipAntimeridian,
11982               // pre-clip angle
11983           x0 = null,
11984               y0,
11985               x1,
11986               y1,
11987               postclip = identity,
11988               // post-clip extent
11989           delta2 = 0.5,
11990               // precision
11991           projectResample,
11992               projectTransform,
11993               projectRotateTransform,
11994               cache,
11995               cacheStream;
11996
11997           function projection(point) {
11998             return projectRotateTransform(point[0] * radians, point[1] * radians);
11999           }
12000
12001           function invert(point) {
12002             point = projectRotateTransform.invert(point[0], point[1]);
12003             return point && [point[0] * degrees, point[1] * degrees];
12004           }
12005
12006           projection.stream = function (stream) {
12007             return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
12008           };
12009
12010           projection.preclip = function (_) {
12011             return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip;
12012           };
12013
12014           projection.postclip = function (_) {
12015             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12016           };
12017
12018           projection.clipAngle = function (_) {
12019             return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees;
12020           };
12021
12022           projection.clipExtent = function (_) {
12023             return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
12024           };
12025
12026           projection.scale = function (_) {
12027             return arguments.length ? (k = +_, recenter()) : k;
12028           };
12029
12030           projection.translate = function (_) {
12031             return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
12032           };
12033
12034           projection.center = function (_) {
12035             return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
12036           };
12037
12038           projection.rotate = function (_) {
12039             return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees, deltaPhi * degrees, deltaGamma * degrees];
12040           };
12041
12042           projection.angle = function (_) {
12043             return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees;
12044           };
12045
12046           projection.reflectX = function (_) {
12047             return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
12048           };
12049
12050           projection.reflectY = function (_) {
12051             return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
12052           };
12053
12054           projection.precision = function (_) {
12055             return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$1(delta2);
12056           };
12057
12058           projection.fitExtent = function (extent, object) {
12059             return fitExtent(projection, extent, object);
12060           };
12061
12062           projection.fitSize = function (size, object) {
12063             return fitSize(projection, size, object);
12064           };
12065
12066           projection.fitWidth = function (width, object) {
12067             return fitWidth(projection, width, object);
12068           };
12069
12070           projection.fitHeight = function (height, object) {
12071             return fitHeight(projection, height, object);
12072           };
12073
12074           function recenter() {
12075             var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
12076                 transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
12077             rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
12078             projectTransform = compose(project, transform);
12079             projectRotateTransform = compose(rotate, projectTransform);
12080             projectResample = resample(projectTransform, delta2);
12081             return reset();
12082           }
12083
12084           function reset() {
12085             cache = cacheStream = null;
12086             return projection;
12087           }
12088
12089           return function () {
12090             project = projectAt.apply(this, arguments);
12091             projection.invert = project.invert && invert;
12092             return recenter();
12093           };
12094         }
12095
12096         function mercatorRaw(lambda, phi) {
12097           return [lambda, log$1(tan((halfPi + phi) / 2))];
12098         }
12099
12100         mercatorRaw.invert = function (x, y) {
12101           return [x, 2 * atan(exp(y)) - halfPi];
12102         };
12103
12104         function mercator () {
12105           return mercatorProjection(mercatorRaw).scale(961 / tau);
12106         }
12107         function mercatorProjection(project) {
12108           var m = projection(project),
12109               center = m.center,
12110               scale = m.scale,
12111               translate = m.translate,
12112               clipExtent = m.clipExtent,
12113               x0 = null,
12114               y0,
12115               x1,
12116               y1; // clip extent
12117
12118           m.scale = function (_) {
12119             return arguments.length ? (scale(_), reclip()) : scale();
12120           };
12121
12122           m.translate = function (_) {
12123             return arguments.length ? (translate(_), reclip()) : translate();
12124           };
12125
12126           m.center = function (_) {
12127             return arguments.length ? (center(_), reclip()) : center();
12128           };
12129
12130           m.clipExtent = function (_) {
12131             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]];
12132           };
12133
12134           function reclip() {
12135             var k = pi * scale(),
12136                 t = m(rotation(m.rotate()).invert([0, 0]));
12137             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)]]);
12138           }
12139
12140           return reclip();
12141         }
12142
12143         function d3_geoIdentity () {
12144           var k = 1,
12145               tx = 0,
12146               ty = 0,
12147               sx = 1,
12148               sy = 1,
12149               // scale, translate and reflect
12150           alpha = 0,
12151               ca,
12152               sa,
12153               // angle
12154           x0 = null,
12155               y0,
12156               x1,
12157               y1,
12158               // clip extent
12159           kx = 1,
12160               ky = 1,
12161               transform = transformer({
12162             point: function point(x, y) {
12163               var p = projection([x, y]);
12164               this.stream.point(p[0], p[1]);
12165             }
12166           }),
12167               postclip = identity,
12168               cache,
12169               cacheStream;
12170
12171           function reset() {
12172             kx = k * sx;
12173             ky = k * sy;
12174             cache = cacheStream = null;
12175             return projection;
12176           }
12177
12178           function projection(p) {
12179             var x = p[0] * kx,
12180                 y = p[1] * ky;
12181
12182             if (alpha) {
12183               var t = y * ca - x * sa;
12184               x = x * ca + y * sa;
12185               y = t;
12186             }
12187
12188             return [x + tx, y + ty];
12189           }
12190
12191           projection.invert = function (p) {
12192             var x = p[0] - tx,
12193                 y = p[1] - ty;
12194
12195             if (alpha) {
12196               var t = y * ca + x * sa;
12197               x = x * ca - y * sa;
12198               y = t;
12199             }
12200
12201             return [x / kx, y / ky];
12202           };
12203
12204           projection.stream = function (stream) {
12205             return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream));
12206           };
12207
12208           projection.postclip = function (_) {
12209             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12210           };
12211
12212           projection.clipExtent = function (_) {
12213             return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
12214           };
12215
12216           projection.scale = function (_) {
12217             return arguments.length ? (k = +_, reset()) : k;
12218           };
12219
12220           projection.translate = function (_) {
12221             return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
12222           };
12223
12224           projection.angle = function (_) {
12225             return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees;
12226           };
12227
12228           projection.reflectX = function (_) {
12229             return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
12230           };
12231
12232           projection.reflectY = function (_) {
12233             return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
12234           };
12235
12236           projection.fitExtent = function (extent, object) {
12237             return fitExtent(projection, extent, object);
12238           };
12239
12240           projection.fitSize = function (size, object) {
12241             return fitSize(projection, size, object);
12242           };
12243
12244           projection.fitWidth = function (width, object) {
12245             return fitWidth(projection, width, object);
12246           };
12247
12248           projection.fitHeight = function (height, object) {
12249             return fitHeight(projection, height, object);
12250           };
12251
12252           return projection;
12253         }
12254
12255         // constants
12256         var TAU = 2 * Math.PI;
12257         var EQUATORIAL_RADIUS = 6356752.314245179;
12258         var POLAR_RADIUS = 6378137.0;
12259         function geoLatToMeters(dLat) {
12260           return dLat * (TAU * POLAR_RADIUS / 360);
12261         }
12262         function geoLonToMeters(dLon, atLat) {
12263           return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
12264         }
12265         function geoMetersToLat(m) {
12266           return m / (TAU * POLAR_RADIUS / 360);
12267         }
12268         function geoMetersToLon(m, atLat) {
12269           return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
12270         }
12271         function geoMetersToOffset(meters, tileSize) {
12272           tileSize = tileSize || 256;
12273           return [meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS), -meters[1] * tileSize / (TAU * POLAR_RADIUS)];
12274         }
12275         function geoOffsetToMeters(offset, tileSize) {
12276           tileSize = tileSize || 256;
12277           return [offset[0] * TAU * EQUATORIAL_RADIUS / tileSize, -offset[1] * TAU * POLAR_RADIUS / tileSize];
12278         } // Equirectangular approximation of spherical distances on Earth
12279
12280         function geoSphericalDistance(a, b) {
12281           var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
12282           var y = geoLatToMeters(a[1] - b[1]);
12283           return Math.sqrt(x * x + y * y);
12284         } // scale to zoom
12285
12286         function geoScaleToZoom(k, tileSize) {
12287           tileSize = tileSize || 256;
12288           var log2ts = Math.log(tileSize) * Math.LOG2E;
12289           return Math.log(k * TAU) / Math.LN2 - log2ts;
12290         } // zoom to scale
12291
12292         function geoZoomToScale(z, tileSize) {
12293           tileSize = tileSize || 256;
12294           return tileSize * Math.pow(2, z) / TAU;
12295         } // returns info about the node from `nodes` closest to the given `point`
12296
12297         function geoSphericalClosestNode(nodes, point) {
12298           var minDistance = Infinity,
12299               distance;
12300           var indexOfMin;
12301
12302           for (var i in nodes) {
12303             distance = geoSphericalDistance(nodes[i].loc, point);
12304
12305             if (distance < minDistance) {
12306               minDistance = distance;
12307               indexOfMin = i;
12308             }
12309           }
12310
12311           if (indexOfMin !== undefined) {
12312             return {
12313               index: indexOfMin,
12314               distance: minDistance,
12315               node: nodes[indexOfMin]
12316             };
12317           } else {
12318             return null;
12319           }
12320         }
12321
12322         function geoExtent(min, max) {
12323           if (!(this instanceof geoExtent)) {
12324             return new geoExtent(min, max);
12325           } else if (min instanceof geoExtent) {
12326             return min;
12327           } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
12328             this[0] = min[0];
12329             this[1] = min[1];
12330           } else {
12331             this[0] = min || [Infinity, Infinity];
12332             this[1] = max || min || [-Infinity, -Infinity];
12333           }
12334         }
12335         geoExtent.prototype = new Array(2);
12336         Object.assign(geoExtent.prototype, {
12337           equals: function equals(obj) {
12338             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];
12339           },
12340           extend: function extend(obj) {
12341             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12342             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])]);
12343           },
12344           _extend: function _extend(extent) {
12345             this[0][0] = Math.min(extent[0][0], this[0][0]);
12346             this[0][1] = Math.min(extent[0][1], this[0][1]);
12347             this[1][0] = Math.max(extent[1][0], this[1][0]);
12348             this[1][1] = Math.max(extent[1][1], this[1][1]);
12349           },
12350           area: function area() {
12351             return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
12352           },
12353           center: function center() {
12354             return [(this[0][0] + this[1][0]) / 2, (this[0][1] + this[1][1]) / 2];
12355           },
12356           rectangle: function rectangle() {
12357             return [this[0][0], this[0][1], this[1][0], this[1][1]];
12358           },
12359           bbox: function bbox() {
12360             return {
12361               minX: this[0][0],
12362               minY: this[0][1],
12363               maxX: this[1][0],
12364               maxY: this[1][1]
12365             };
12366           },
12367           polygon: function polygon() {
12368             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]]];
12369           },
12370           contains: function contains(obj) {
12371             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12372             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];
12373           },
12374           intersects: function intersects(obj) {
12375             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12376             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];
12377           },
12378           intersection: function intersection(obj) {
12379             if (!this.intersects(obj)) return new geoExtent();
12380             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])]);
12381           },
12382           percentContainedIn: function percentContainedIn(obj) {
12383             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12384             var a1 = this.intersection(obj).area();
12385             var a2 = this.area();
12386
12387             if (a1 === Infinity || a2 === Infinity) {
12388               return 0;
12389             } else if (a1 === 0 || a2 === 0) {
12390               if (obj.contains(this)) {
12391                 return 1;
12392               }
12393
12394               return 0;
12395             } else {
12396               return a1 / a2;
12397             }
12398           },
12399           padByMeters: function padByMeters(meters) {
12400             var dLat = geoMetersToLat(meters);
12401             var dLon = geoMetersToLon(meters, this.center()[1]);
12402             return geoExtent([this[0][0] - dLon, this[0][1] - dLat], [this[1][0] + dLon, this[1][1] + dLat]);
12403           },
12404           toParam: function toParam() {
12405             return this.rectangle().join(',');
12406           }
12407         });
12408
12409         var $every$1 = arrayIteration.every;
12410
12411
12412
12413         var STRICT_METHOD$6 = arrayMethodIsStrict('every');
12414         var USES_TO_LENGTH$8 = arrayMethodUsesToLength('every');
12415
12416         // `Array.prototype.every` method
12417         // https://tc39.github.io/ecma262/#sec-array.prototype.every
12418         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$6 || !USES_TO_LENGTH$8 }, {
12419           every: function every(callbackfn /* , thisArg */) {
12420             return $every$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
12421           }
12422         });
12423
12424         var $reduce$1 = arrayReduce.left;
12425
12426
12427
12428         var STRICT_METHOD$7 = arrayMethodIsStrict('reduce');
12429         var USES_TO_LENGTH$9 = arrayMethodUsesToLength('reduce', { 1: 0 });
12430
12431         // `Array.prototype.reduce` method
12432         // https://tc39.github.io/ecma262/#sec-array.prototype.reduce
12433         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$7 || !USES_TO_LENGTH$9 }, {
12434           reduce: function reduce(callbackfn /* , initialValue */) {
12435             return $reduce$1(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
12436           }
12437         });
12438
12439         function d3_polygonArea (polygon) {
12440           var i = -1,
12441               n = polygon.length,
12442               a,
12443               b = polygon[n - 1],
12444               area = 0;
12445
12446           while (++i < n) {
12447             a = b;
12448             b = polygon[i];
12449             area += a[1] * b[0] - a[0] * b[1];
12450           }
12451
12452           return area / 2;
12453         }
12454
12455         function d3_polygonCentroid (polygon) {
12456           var i = -1,
12457               n = polygon.length,
12458               x = 0,
12459               y = 0,
12460               a,
12461               b = polygon[n - 1],
12462               c,
12463               k = 0;
12464
12465           while (++i < n) {
12466             a = b;
12467             b = polygon[i];
12468             k += c = a[0] * b[1] - b[0] * a[1];
12469             x += (a[0] + b[0]) * c;
12470             y += (a[1] + b[1]) * c;
12471           }
12472
12473           return k *= 3, [x / k, y / k];
12474         }
12475
12476         // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
12477         // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
12478         // right, +y is up). Returns a positive value if ABC is counter-clockwise,
12479         // negative if clockwise, and zero if the points are collinear.
12480         function cross (a, b, c) {
12481           return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
12482         }
12483
12484         function lexicographicOrder(a, b) {
12485           return a[0] - b[0] || a[1] - b[1];
12486         } // Computes the upper convex hull per the monotone chain algorithm.
12487         // Assumes points.length >= 3, is sorted by x, unique in y.
12488         // Returns an array of indices into points in left-to-right order.
12489
12490
12491         function computeUpperHullIndexes(points) {
12492           var n = points.length,
12493               indexes = [0, 1];
12494           var size = 2,
12495               i;
12496
12497           for (i = 2; i < n; ++i) {
12498             while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) {
12499               --size;
12500             }
12501
12502             indexes[size++] = i;
12503           }
12504
12505           return indexes.slice(0, size); // remove popped points
12506         }
12507
12508         function d3_polygonHull (points) {
12509           if ((n = points.length) < 3) return null;
12510           var i,
12511               n,
12512               sortedPoints = new Array(n),
12513               flippedPoints = new Array(n);
12514
12515           for (i = 0; i < n; ++i) {
12516             sortedPoints[i] = [+points[i][0], +points[i][1], i];
12517           }
12518
12519           sortedPoints.sort(lexicographicOrder);
12520
12521           for (i = 0; i < n; ++i) {
12522             flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
12523           }
12524
12525           var upperIndexes = computeUpperHullIndexes(sortedPoints),
12526               lowerIndexes = computeUpperHullIndexes(flippedPoints); // Construct the hull polygon, removing possible duplicate endpoints.
12527
12528           var skipLeft = lowerIndexes[0] === upperIndexes[0],
12529               skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
12530               hull = []; // Add upper hull in right-to-l order.
12531           // Then add lower hull in left-to-right order.
12532
12533           for (i = upperIndexes.length - 1; i >= 0; --i) {
12534             hull.push(points[sortedPoints[upperIndexes[i]][2]]);
12535           }
12536
12537           for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) {
12538             hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
12539           }
12540
12541           return hull;
12542         }
12543
12544         // vector equals
12545         function geoVecEqual(a, b, epsilon) {
12546           if (epsilon) {
12547             return Math.abs(a[0] - b[0]) <= epsilon && Math.abs(a[1] - b[1]) <= epsilon;
12548           } else {
12549             return a[0] === b[0] && a[1] === b[1];
12550           }
12551         } // vector addition
12552
12553         function geoVecAdd(a, b) {
12554           return [a[0] + b[0], a[1] + b[1]];
12555         } // vector subtraction
12556
12557         function geoVecSubtract(a, b) {
12558           return [a[0] - b[0], a[1] - b[1]];
12559         } // vector scaling
12560
12561         function geoVecScale(a, mag) {
12562           return [a[0] * mag, a[1] * mag];
12563         } // vector rounding (was: geoRoundCoordinates)
12564
12565         function geoVecFloor(a) {
12566           return [Math.floor(a[0]), Math.floor(a[1])];
12567         } // linear interpolation
12568
12569         function geoVecInterp(a, b, t) {
12570           return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
12571         } // http://jsperf.com/id-dist-optimization
12572
12573         function geoVecLength(a, b) {
12574           return Math.sqrt(geoVecLengthSquare(a, b));
12575         } // length of vector raised to the power two
12576
12577         function geoVecLengthSquare(a, b) {
12578           b = b || [0, 0];
12579           var x = a[0] - b[0];
12580           var y = a[1] - b[1];
12581           return x * x + y * y;
12582         } // get a unit vector
12583
12584         function geoVecNormalize(a) {
12585           var length = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
12586
12587           if (length !== 0) {
12588             return geoVecScale(a, 1 / length);
12589           }
12590
12591           return [0, 0];
12592         } // Return the counterclockwise angle in the range (-pi, pi)
12593         // between the positive X axis and the line intersecting a and b.
12594
12595         function geoVecAngle(a, b) {
12596           return Math.atan2(b[1] - a[1], b[0] - a[0]);
12597         } // dot product
12598
12599         function geoVecDot(a, b, origin) {
12600           origin = origin || [0, 0];
12601           var p = geoVecSubtract(a, origin);
12602           var q = geoVecSubtract(b, origin);
12603           return p[0] * q[0] + p[1] * q[1];
12604         } // normalized dot product
12605
12606         function geoVecNormalizedDot(a, b, origin) {
12607           origin = origin || [0, 0];
12608           var p = geoVecNormalize(geoVecSubtract(a, origin));
12609           var q = geoVecNormalize(geoVecSubtract(b, origin));
12610           return geoVecDot(p, q);
12611         } // 2D cross product of OA and OB vectors, returns magnitude of Z vector
12612         // Returns a positive value, if OAB makes a counter-clockwise turn,
12613         // negative for clockwise turn, and zero if the points are collinear.
12614
12615         function geoVecCross(a, b, origin) {
12616           origin = origin || [0, 0];
12617           var p = geoVecSubtract(a, origin);
12618           var q = geoVecSubtract(b, origin);
12619           return p[0] * q[1] - p[1] * q[0];
12620         } // find closest orthogonal projection of point onto points array
12621
12622         function geoVecProject(a, points) {
12623           var min = Infinity;
12624           var idx;
12625           var target;
12626
12627           for (var i = 0; i < points.length - 1; i++) {
12628             var o = points[i];
12629             var s = geoVecSubtract(points[i + 1], o);
12630             var v = geoVecSubtract(a, o);
12631             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12632             var p;
12633
12634             if (proj < 0) {
12635               p = o;
12636             } else if (proj > 1) {
12637               p = points[i + 1];
12638             } else {
12639               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12640             }
12641
12642             var dist = geoVecLength(p, a);
12643
12644             if (dist < min) {
12645               min = dist;
12646               idx = i + 1;
12647               target = p;
12648             }
12649           }
12650
12651           if (idx !== undefined) {
12652             return {
12653               index: idx,
12654               distance: min,
12655               target: target
12656             };
12657           } else {
12658             return null;
12659           }
12660         }
12661
12662         // between the positive X axis and the line intersecting a and b.
12663
12664         function geoAngle(a, b, projection) {
12665           return geoVecAngle(projection(a.loc), projection(b.loc));
12666         }
12667         function geoEdgeEqual(a, b) {
12668           return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
12669         } // Rotate all points counterclockwise around a pivot point by given angle
12670
12671         function geoRotate(points, angle, around) {
12672           return points.map(function (point) {
12673             var radial = geoVecSubtract(point, around);
12674             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]];
12675           });
12676         } // Choose the edge with the minimal distance from `point` to its orthogonal
12677         // projection onto that edge, if such a projection exists, or the distance to
12678         // the closest vertex on that edge. Returns an object with the `index` of the
12679         // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
12680
12681         function geoChooseEdge(nodes, point, projection, activeID) {
12682           var dist = geoVecLength;
12683           var points = nodes.map(function (n) {
12684             return projection(n.loc);
12685           });
12686           var ids = nodes.map(function (n) {
12687             return n.id;
12688           });
12689           var min = Infinity;
12690           var idx;
12691           var loc;
12692
12693           for (var i = 0; i < points.length - 1; i++) {
12694             if (ids[i] === activeID || ids[i + 1] === activeID) continue;
12695             var o = points[i];
12696             var s = geoVecSubtract(points[i + 1], o);
12697             var v = geoVecSubtract(point, o);
12698             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12699             var p;
12700
12701             if (proj < 0) {
12702               p = o;
12703             } else if (proj > 1) {
12704               p = points[i + 1];
12705             } else {
12706               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12707             }
12708
12709             var d = dist(p, point);
12710
12711             if (d < min) {
12712               min = d;
12713               idx = i + 1;
12714               loc = projection.invert(p);
12715             }
12716           }
12717
12718           if (idx !== undefined) {
12719             return {
12720               index: idx,
12721               distance: min,
12722               loc: loc
12723             };
12724           } else {
12725             return null;
12726           }
12727         } // Test active (dragged or drawing) segments against inactive segments
12728         // This is used to test e.g. multipolygon rings that cross
12729         // `activeNodes` is the ring containing the activeID being dragged.
12730         // `inactiveNodes` is the other ring to test against
12731
12732         function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
12733           var actives = [];
12734           var inactives = [];
12735           var j, k, n1, n2, segment; // gather active segments (only segments in activeNodes that contain the activeID)
12736
12737           for (j = 0; j < activeNodes.length - 1; j++) {
12738             n1 = activeNodes[j];
12739             n2 = activeNodes[j + 1];
12740             segment = [n1.loc, n2.loc];
12741
12742             if (n1.id === activeID || n2.id === activeID) {
12743               actives.push(segment);
12744             }
12745           } // gather inactive segments
12746
12747
12748           for (j = 0; j < inactiveNodes.length - 1; j++) {
12749             n1 = inactiveNodes[j];
12750             n2 = inactiveNodes[j + 1];
12751             segment = [n1.loc, n2.loc];
12752             inactives.push(segment);
12753           } // test
12754
12755
12756           for (j = 0; j < actives.length; j++) {
12757             for (k = 0; k < inactives.length; k++) {
12758               var p = actives[j];
12759               var q = inactives[k];
12760               var hit = geoLineIntersection(p, q);
12761
12762               if (hit) {
12763                 return true;
12764               }
12765             }
12766           }
12767
12768           return false;
12769         } // Test active (dragged or drawing) segments against inactive segments
12770         // This is used to test whether a way intersects with itself.
12771
12772         function geoHasSelfIntersections(nodes, activeID) {
12773           var actives = [];
12774           var inactives = [];
12775           var j, k; // group active and passive segments along the nodes
12776
12777           for (j = 0; j < nodes.length - 1; j++) {
12778             var n1 = nodes[j];
12779             var n2 = nodes[j + 1];
12780             var segment = [n1.loc, n2.loc];
12781
12782             if (n1.id === activeID || n2.id === activeID) {
12783               actives.push(segment);
12784             } else {
12785               inactives.push(segment);
12786             }
12787           } // test
12788
12789
12790           for (j = 0; j < actives.length; j++) {
12791             for (k = 0; k < inactives.length; k++) {
12792               var p = actives[j];
12793               var q = inactives[k]; // skip if segments share an endpoint
12794
12795               if (geoVecEqual(p[1], q[0]) || geoVecEqual(p[0], q[1]) || geoVecEqual(p[0], q[0]) || geoVecEqual(p[1], q[1])) {
12796                 continue;
12797               }
12798
12799               var hit = geoLineIntersection(p, q);
12800
12801               if (hit) {
12802                 var epsilon = 1e-8; // skip if the hit is at the segment's endpoint
12803
12804                 if (geoVecEqual(p[1], hit, epsilon) || geoVecEqual(p[0], hit, epsilon) || geoVecEqual(q[1], hit, epsilon) || geoVecEqual(q[0], hit, epsilon)) {
12805                   continue;
12806                 } else {
12807                   return true;
12808                 }
12809               }
12810             }
12811           }
12812
12813           return false;
12814         } // Return the intersection point of 2 line segments.
12815         // From https://github.com/pgkelley4/line-segments-intersect
12816         // This uses the vector cross product approach described below:
12817         //  http://stackoverflow.com/a/565282/786339
12818
12819         function geoLineIntersection(a, b) {
12820           var p = [a[0][0], a[0][1]];
12821           var p2 = [a[1][0], a[1][1]];
12822           var q = [b[0][0], b[0][1]];
12823           var q2 = [b[1][0], b[1][1]];
12824           var r = geoVecSubtract(p2, p);
12825           var s = geoVecSubtract(q2, q);
12826           var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
12827           var denominator = geoVecCross(r, s);
12828
12829           if (uNumerator && denominator) {
12830             var u = uNumerator / denominator;
12831             var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
12832
12833             if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
12834               return geoVecInterp(p, p2, t);
12835             }
12836           }
12837
12838           return null;
12839         }
12840         function geoPathIntersections(path1, path2) {
12841           var intersections = [];
12842
12843           for (var i = 0; i < path1.length - 1; i++) {
12844             for (var j = 0; j < path2.length - 1; j++) {
12845               var a = [path1[i], path1[i + 1]];
12846               var b = [path2[j], path2[j + 1]];
12847               var hit = geoLineIntersection(a, b);
12848
12849               if (hit) {
12850                 intersections.push(hit);
12851               }
12852             }
12853           }
12854
12855           return intersections;
12856         }
12857         function geoPathHasIntersections(path1, path2) {
12858           for (var i = 0; i < path1.length - 1; i++) {
12859             for (var j = 0; j < path2.length - 1; j++) {
12860               var a = [path1[i], path1[i + 1]];
12861               var b = [path2[j], path2[j + 1]];
12862               var hit = geoLineIntersection(a, b);
12863
12864               if (hit) {
12865                 return true;
12866               }
12867             }
12868           }
12869
12870           return false;
12871         } // Return whether point is contained in polygon.
12872         //
12873         // `point` should be a 2-item array of coordinates.
12874         // `polygon` should be an array of 2-item arrays of coordinates.
12875         //
12876         // From https://github.com/substack/point-in-polygon.
12877         // ray-casting algorithm based on
12878         // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
12879         //
12880
12881         function geoPointInPolygon(point, polygon) {
12882           var x = point[0];
12883           var y = point[1];
12884           var inside = false;
12885
12886           for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
12887             var xi = polygon[i][0];
12888             var yi = polygon[i][1];
12889             var xj = polygon[j][0];
12890             var yj = polygon[j][1];
12891             var intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
12892             if (intersect) inside = !inside;
12893           }
12894
12895           return inside;
12896         }
12897         function geoPolygonContainsPolygon(outer, inner) {
12898           return inner.every(function (point) {
12899             return geoPointInPolygon(point, outer);
12900           });
12901         }
12902         function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
12903           function testPoints(outer, inner) {
12904             return inner.some(function (point) {
12905               return geoPointInPolygon(point, outer);
12906             });
12907           }
12908
12909           return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
12910         } // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
12911         // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
12912
12913         function geoGetSmallestSurroundingRectangle(points) {
12914           var hull = d3_polygonHull(points);
12915           var centroid = d3_polygonCentroid(hull);
12916           var minArea = Infinity;
12917           var ssrExtent = [];
12918           var ssrAngle = 0;
12919           var c1 = hull[0];
12920
12921           for (var i = 0; i <= hull.length - 1; i++) {
12922             var c2 = i === hull.length - 1 ? hull[0] : hull[i + 1];
12923             var angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
12924             var poly = geoRotate(hull, -angle, centroid);
12925             var extent = poly.reduce(function (extent, point) {
12926               return extent.extend(geoExtent(point));
12927             }, geoExtent());
12928             var area = extent.area();
12929
12930             if (area < minArea) {
12931               minArea = area;
12932               ssrExtent = extent;
12933               ssrAngle = angle;
12934             }
12935
12936             c1 = c2;
12937           }
12938
12939           return {
12940             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
12941             angle: ssrAngle
12942           };
12943         }
12944         function geoPathLength(path) {
12945           var length = 0;
12946
12947           for (var i = 0; i < path.length - 1; i++) {
12948             length += geoVecLength(path[i], path[i + 1]);
12949           }
12950
12951           return length;
12952         } // If the given point is at the edge of the padded viewport,
12953         // return a vector that will nudge the viewport in that direction
12954
12955         function geoViewportEdge(point, dimensions) {
12956           var pad = [80, 20, 50, 20]; // top, right, bottom, left
12957
12958           var x = 0;
12959           var y = 0;
12960           if (point[0] > dimensions[0] - pad[1]) x = -10;
12961           if (point[0] < pad[3]) x = 10;
12962           if (point[1] > dimensions[1] - pad[2]) y = -10;
12963           if (point[1] < pad[0]) y = 10;
12964
12965           if (x || y) {
12966             return [x, y];
12967           } else {
12968             return null;
12969           }
12970         }
12971
12972         var noop$1 = {
12973           value: function value() {}
12974         };
12975
12976         function dispatch() {
12977           for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
12978             if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
12979             _[t] = [];
12980           }
12981
12982           return new Dispatch$1(_);
12983         }
12984
12985         function Dispatch$1(_) {
12986           this._ = _;
12987         }
12988
12989         function parseTypenames(typenames, types) {
12990           return typenames.trim().split(/^|\s+/).map(function (t) {
12991             var name = "",
12992                 i = t.indexOf(".");
12993             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
12994             if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
12995             return {
12996               type: t,
12997               name: name
12998             };
12999           });
13000         }
13001
13002         Dispatch$1.prototype = dispatch.prototype = {
13003           constructor: Dispatch$1,
13004           on: function on(typename, callback) {
13005             var _ = this._,
13006                 T = parseTypenames(typename + "", _),
13007                 t,
13008                 i = -1,
13009                 n = T.length; // If no callback was specified, return the callback of the given type and name.
13010
13011             if (arguments.length < 2) {
13012               while (++i < n) {
13013                 if ((t = (typename = T[i]).type) && (t = get$3(_[t], typename.name))) return t;
13014               }
13015
13016               return;
13017             } // If a type was specified, set the callback for the given type and name.
13018             // Otherwise, if a null callback was specified, remove callbacks of the given name.
13019
13020
13021             if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
13022
13023             while (++i < n) {
13024               if (t = (typename = T[i]).type) _[t] = set$3(_[t], typename.name, callback);else if (callback == null) for (t in _) {
13025                 _[t] = set$3(_[t], typename.name, null);
13026               }
13027             }
13028
13029             return this;
13030           },
13031           copy: function copy() {
13032             var copy = {},
13033                 _ = this._;
13034
13035             for (var t in _) {
13036               copy[t] = _[t].slice();
13037             }
13038
13039             return new Dispatch$1(copy);
13040           },
13041           call: function call(type, that) {
13042             if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) {
13043               args[i] = arguments[i + 2];
13044             }
13045             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13046
13047             for (t = this._[type], i = 0, n = t.length; i < n; ++i) {
13048               t[i].value.apply(that, args);
13049             }
13050           },
13051           apply: function apply(type, that, args) {
13052             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13053
13054             for (var t = this._[type], i = 0, n = t.length; i < n; ++i) {
13055               t[i].value.apply(that, args);
13056             }
13057           }
13058         };
13059
13060         function get$3(type, name) {
13061           for (var i = 0, n = type.length, c; i < n; ++i) {
13062             if ((c = type[i]).name === name) {
13063               return c.value;
13064             }
13065           }
13066         }
13067
13068         function set$3(type, name, callback) {
13069           for (var i = 0, n = type.length; i < n; ++i) {
13070             if (type[i].name === name) {
13071               type[i] = noop$1, type = type.slice(0, i).concat(type.slice(i + 1));
13072               break;
13073             }
13074           }
13075
13076           if (callback != null) type.push({
13077             name: name,
13078             value: callback
13079           });
13080           return type;
13081         }
13082
13083         var xhtml = "http://www.w3.org/1999/xhtml";
13084         var namespaces = {
13085           svg: "http://www.w3.org/2000/svg",
13086           xhtml: xhtml,
13087           xlink: "http://www.w3.org/1999/xlink",
13088           xml: "http://www.w3.org/XML/1998/namespace",
13089           xmlns: "http://www.w3.org/2000/xmlns/"
13090         };
13091
13092         function namespace (name) {
13093           var prefix = name += "",
13094               i = prefix.indexOf(":");
13095           if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
13096           return namespaces.hasOwnProperty(prefix) ? {
13097             space: namespaces[prefix],
13098             local: name
13099           } : name; // eslint-disable-line no-prototype-builtins
13100         }
13101
13102         function creatorInherit(name) {
13103           return function () {
13104             var document = this.ownerDocument,
13105                 uri = this.namespaceURI;
13106             return uri === xhtml && document.documentElement.namespaceURI === xhtml ? document.createElement(name) : document.createElementNS(uri, name);
13107           };
13108         }
13109
13110         function creatorFixed(fullname) {
13111           return function () {
13112             return this.ownerDocument.createElementNS(fullname.space, fullname.local);
13113           };
13114         }
13115
13116         function creator (name) {
13117           var fullname = namespace(name);
13118           return (fullname.local ? creatorFixed : creatorInherit)(fullname);
13119         }
13120
13121         function none() {}
13122
13123         function selector (selector) {
13124           return selector == null ? none : function () {
13125             return this.querySelector(selector);
13126           };
13127         }
13128
13129         function selection_select (select) {
13130           if (typeof select !== "function") select = selector(select);
13131
13132           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13133             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
13134               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
13135                 if ("__data__" in node) subnode.__data__ = node.__data__;
13136                 subgroup[i] = subnode;
13137               }
13138             }
13139           }
13140
13141           return new Selection(subgroups, this._parents);
13142         }
13143
13144         function array (x) {
13145           return _typeof(x) === "object" && "length" in x ? x // Array, TypedArray, NodeList, array-like
13146           : Array.from(x); // Map, Set, iterable, string, or anything else
13147         }
13148
13149         function empty() {
13150           return [];
13151         }
13152
13153         function selectorAll (selector) {
13154           return selector == null ? empty : function () {
13155             return this.querySelectorAll(selector);
13156           };
13157         }
13158
13159         function arrayAll(select) {
13160           return function () {
13161             var group = select.apply(this, arguments);
13162             return group == null ? [] : array(group);
13163           };
13164         }
13165
13166         function selection_selectAll (select) {
13167           if (typeof select === "function") select = arrayAll(select);else select = selectorAll(select);
13168
13169           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
13170             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
13171               if (node = group[i]) {
13172                 subgroups.push(select.call(node, node.__data__, i, group));
13173                 parents.push(node);
13174               }
13175             }
13176           }
13177
13178           return new Selection(subgroups, parents);
13179         }
13180
13181         var $find$1 = arrayIteration.find;
13182
13183
13184
13185         var FIND = 'find';
13186         var SKIPS_HOLES = true;
13187
13188         var USES_TO_LENGTH$a = arrayMethodUsesToLength(FIND);
13189
13190         // Shouldn't skip holes
13191         if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES = false; });
13192
13193         // `Array.prototype.find` method
13194         // https://tc39.github.io/ecma262/#sec-array.prototype.find
13195         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES || !USES_TO_LENGTH$a }, {
13196           find: function find(callbackfn /* , that = undefined */) {
13197             return $find$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
13198           }
13199         });
13200
13201         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
13202         addToUnscopables(FIND);
13203
13204         function matcher (selector) {
13205           return function () {
13206             return this.matches(selector);
13207           };
13208         }
13209         function childMatcher(selector) {
13210           return function (node) {
13211             return node.matches(selector);
13212           };
13213         }
13214
13215         var find$1 = Array.prototype.find;
13216
13217         function childFind(match) {
13218           return function () {
13219             return find$1.call(this.children, match);
13220           };
13221         }
13222
13223         function childFirst() {
13224           return this.firstElementChild;
13225         }
13226
13227         function selection_selectChild (match) {
13228           return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
13229         }
13230
13231         var filter = Array.prototype.filter;
13232
13233         function children() {
13234           return this.children;
13235         }
13236
13237         function childrenFilter(match) {
13238           return function () {
13239             return filter.call(this.children, match);
13240           };
13241         }
13242
13243         function selection_selectChildren (match) {
13244           return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
13245         }
13246
13247         function selection_filter (match) {
13248           if (typeof match !== "function") match = matcher(match);
13249
13250           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13251             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
13252               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
13253                 subgroup.push(node);
13254               }
13255             }
13256           }
13257
13258           return new Selection(subgroups, this._parents);
13259         }
13260
13261         function sparse (update) {
13262           return new Array(update.length);
13263         }
13264
13265         function selection_enter () {
13266           return new Selection(this._enter || this._groups.map(sparse), this._parents);
13267         }
13268         function EnterNode(parent, datum) {
13269           this.ownerDocument = parent.ownerDocument;
13270           this.namespaceURI = parent.namespaceURI;
13271           this._next = null;
13272           this._parent = parent;
13273           this.__data__ = datum;
13274         }
13275         EnterNode.prototype = {
13276           constructor: EnterNode,
13277           appendChild: function appendChild(child) {
13278             return this._parent.insertBefore(child, this._next);
13279           },
13280           insertBefore: function insertBefore(child, next) {
13281             return this._parent.insertBefore(child, next);
13282           },
13283           querySelector: function querySelector(selector) {
13284             return this._parent.querySelector(selector);
13285           },
13286           querySelectorAll: function querySelectorAll(selector) {
13287             return this._parent.querySelectorAll(selector);
13288           }
13289         };
13290
13291         function constant (x) {
13292           return function () {
13293             return x;
13294           };
13295         }
13296
13297         function bindIndex(parent, group, enter, update, exit, data) {
13298           var i = 0,
13299               node,
13300               groupLength = group.length,
13301               dataLength = data.length; // Put any non-null nodes that fit into update.
13302           // Put any null nodes into enter.
13303           // Put any remaining data into enter.
13304
13305           for (; i < dataLength; ++i) {
13306             if (node = group[i]) {
13307               node.__data__ = data[i];
13308               update[i] = node;
13309             } else {
13310               enter[i] = new EnterNode(parent, data[i]);
13311             }
13312           } // Put any non-null nodes that don’t fit into exit.
13313
13314
13315           for (; i < groupLength; ++i) {
13316             if (node = group[i]) {
13317               exit[i] = node;
13318             }
13319           }
13320         }
13321
13322         function bindKey(parent, group, enter, update, exit, data, key) {
13323           var i,
13324               node,
13325               nodeByKeyValue = new Map(),
13326               groupLength = group.length,
13327               dataLength = data.length,
13328               keyValues = new Array(groupLength),
13329               keyValue; // Compute the key for each node.
13330           // If multiple nodes have the same key, the duplicates are added to exit.
13331
13332           for (i = 0; i < groupLength; ++i) {
13333             if (node = group[i]) {
13334               keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
13335
13336               if (nodeByKeyValue.has(keyValue)) {
13337                 exit[i] = node;
13338               } else {
13339                 nodeByKeyValue.set(keyValue, node);
13340               }
13341             }
13342           } // Compute the key for each datum.
13343           // If there a node associated with this key, join and add it to update.
13344           // If there is not (or the key is a duplicate), add it to enter.
13345
13346
13347           for (i = 0; i < dataLength; ++i) {
13348             keyValue = key.call(parent, data[i], i, data) + "";
13349
13350             if (node = nodeByKeyValue.get(keyValue)) {
13351               update[i] = node;
13352               node.__data__ = data[i];
13353               nodeByKeyValue["delete"](keyValue);
13354             } else {
13355               enter[i] = new EnterNode(parent, data[i]);
13356             }
13357           } // Add any remaining nodes that were not bound to data to exit.
13358
13359
13360           for (i = 0; i < groupLength; ++i) {
13361             if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
13362               exit[i] = node;
13363             }
13364           }
13365         }
13366
13367         function datum(node) {
13368           return node.__data__;
13369         }
13370
13371         function selection_data (value, key) {
13372           if (!arguments.length) return Array.from(this, datum);
13373           var bind = key ? bindKey : bindIndex,
13374               parents = this._parents,
13375               groups = this._groups;
13376           if (typeof value !== "function") value = constant(value);
13377
13378           for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
13379             var parent = parents[j],
13380                 group = groups[j],
13381                 groupLength = group.length,
13382                 data = array(value.call(parent, parent && parent.__data__, j, parents)),
13383                 dataLength = data.length,
13384                 enterGroup = enter[j] = new Array(dataLength),
13385                 updateGroup = update[j] = new Array(dataLength),
13386                 exitGroup = exit[j] = new Array(groupLength);
13387             bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); // Now connect the enter nodes to their following update node, such that
13388             // appendChild can insert the materialized enter node before this node,
13389             // rather than at the end of the parent node.
13390
13391             for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
13392               if (previous = enterGroup[i0]) {
13393                 if (i0 >= i1) i1 = i0 + 1;
13394
13395                 while (!(next = updateGroup[i1]) && ++i1 < dataLength) {
13396                 }
13397
13398                 previous._next = next || null;
13399               }
13400             }
13401           }
13402
13403           update = new Selection(update, parents);
13404           update._enter = enter;
13405           update._exit = exit;
13406           return update;
13407         }
13408
13409         function selection_exit () {
13410           return new Selection(this._exit || this._groups.map(sparse), this._parents);
13411         }
13412
13413         function selection_join (onenter, onupdate, onexit) {
13414           var enter = this.enter(),
13415               update = this,
13416               exit = this.exit();
13417           enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
13418           if (onupdate != null) update = onupdate(update);
13419           if (onexit == null) exit.remove();else onexit(exit);
13420           return enter && update ? enter.merge(update).order() : update;
13421         }
13422
13423         function selection_merge (selection) {
13424           if (!(selection instanceof Selection)) throw new Error("invalid merge");
13425
13426           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) {
13427             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
13428               if (node = group0[i] || group1[i]) {
13429                 merge[i] = node;
13430               }
13431             }
13432           }
13433
13434           for (; j < m0; ++j) {
13435             merges[j] = groups0[j];
13436           }
13437
13438           return new Selection(merges, this._parents);
13439         }
13440
13441         function selection_order () {
13442           for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
13443             for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
13444               if (node = group[i]) {
13445                 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
13446                 next = node;
13447               }
13448             }
13449           }
13450
13451           return this;
13452         }
13453
13454         function selection_sort (compare) {
13455           if (!compare) compare = ascending;
13456
13457           function compareNode(a, b) {
13458             return a && b ? compare(a.__data__, b.__data__) : !a - !b;
13459           }
13460
13461           for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
13462             for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
13463               if (node = group[i]) {
13464                 sortgroup[i] = node;
13465               }
13466             }
13467
13468             sortgroup.sort(compareNode);
13469           }
13470
13471           return new Selection(sortgroups, this._parents).order();
13472         }
13473
13474         function ascending(a, b) {
13475           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
13476         }
13477
13478         function selection_call () {
13479           var callback = arguments[0];
13480           arguments[0] = this;
13481           callback.apply(null, arguments);
13482           return this;
13483         }
13484
13485         function selection_nodes () {
13486           return Array.from(this);
13487         }
13488
13489         function selection_node () {
13490           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13491             for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
13492               var node = group[i];
13493               if (node) return node;
13494             }
13495           }
13496
13497           return null;
13498         }
13499
13500         function selection_size () {
13501           var size = 0;
13502
13503           var _iterator = _createForOfIteratorHelper(this),
13504               _step;
13505
13506           try {
13507             for (_iterator.s(); !(_step = _iterator.n()).done;) {
13508               var node = _step.value;
13509               ++size;
13510             } // eslint-disable-line no-unused-vars
13511
13512           } catch (err) {
13513             _iterator.e(err);
13514           } finally {
13515             _iterator.f();
13516           }
13517
13518           return size;
13519         }
13520
13521         function selection_empty () {
13522           return !this.node();
13523         }
13524
13525         function selection_each (callback) {
13526           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13527             for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
13528               if (node = group[i]) callback.call(node, node.__data__, i, group);
13529             }
13530           }
13531
13532           return this;
13533         }
13534
13535         function attrRemove(name) {
13536           return function () {
13537             this.removeAttribute(name);
13538           };
13539         }
13540
13541         function attrRemoveNS(fullname) {
13542           return function () {
13543             this.removeAttributeNS(fullname.space, fullname.local);
13544           };
13545         }
13546
13547         function attrConstant(name, value) {
13548           return function () {
13549             this.setAttribute(name, value);
13550           };
13551         }
13552
13553         function attrConstantNS(fullname, value) {
13554           return function () {
13555             this.setAttributeNS(fullname.space, fullname.local, value);
13556           };
13557         }
13558
13559         function attrFunction(name, value) {
13560           return function () {
13561             var v = value.apply(this, arguments);
13562             if (v == null) this.removeAttribute(name);else this.setAttribute(name, v);
13563           };
13564         }
13565
13566         function attrFunctionNS(fullname, value) {
13567           return function () {
13568             var v = value.apply(this, arguments);
13569             if (v == null) this.removeAttributeNS(fullname.space, fullname.local);else this.setAttributeNS(fullname.space, fullname.local, v);
13570           };
13571         }
13572
13573         function selection_attr (name, value) {
13574           var fullname = namespace(name);
13575
13576           if (arguments.length < 2) {
13577             var node = this.node();
13578             return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
13579           }
13580
13581           return this.each((value == null ? fullname.local ? attrRemoveNS : attrRemove : typeof value === "function" ? fullname.local ? attrFunctionNS : attrFunction : fullname.local ? attrConstantNS : attrConstant)(fullname, value));
13582         }
13583
13584         function defaultView (node) {
13585           return node.ownerDocument && node.ownerDocument.defaultView || // node is a Node
13586           node.document && node // node is a Window
13587           || node.defaultView; // node is a Document
13588         }
13589
13590         function styleRemove(name) {
13591           return function () {
13592             this.style.removeProperty(name);
13593           };
13594         }
13595
13596         function styleConstant(name, value, priority) {
13597           return function () {
13598             this.style.setProperty(name, value, priority);
13599           };
13600         }
13601
13602         function styleFunction(name, value, priority) {
13603           return function () {
13604             var v = value.apply(this, arguments);
13605             if (v == null) this.style.removeProperty(name);else this.style.setProperty(name, v, priority);
13606           };
13607         }
13608
13609         function selection_style (name, value, priority) {
13610           return arguments.length > 1 ? this.each((value == null ? styleRemove : typeof value === "function" ? styleFunction : styleConstant)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
13611         }
13612         function styleValue(node, name) {
13613           return node.style.getPropertyValue(name) || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
13614         }
13615
13616         function propertyRemove(name) {
13617           return function () {
13618             delete this[name];
13619           };
13620         }
13621
13622         function propertyConstant(name, value) {
13623           return function () {
13624             this[name] = value;
13625           };
13626         }
13627
13628         function propertyFunction(name, value) {
13629           return function () {
13630             var v = value.apply(this, arguments);
13631             if (v == null) delete this[name];else this[name] = v;
13632           };
13633         }
13634
13635         function selection_property (name, value) {
13636           return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
13637         }
13638
13639         function classArray(string) {
13640           return string.trim().split(/^|\s+/);
13641         }
13642
13643         function classList(node) {
13644           return node.classList || new ClassList(node);
13645         }
13646
13647         function ClassList(node) {
13648           this._node = node;
13649           this._names = classArray(node.getAttribute("class") || "");
13650         }
13651
13652         ClassList.prototype = {
13653           add: function add(name) {
13654             var i = this._names.indexOf(name);
13655
13656             if (i < 0) {
13657               this._names.push(name);
13658
13659               this._node.setAttribute("class", this._names.join(" "));
13660             }
13661           },
13662           remove: function remove(name) {
13663             var i = this._names.indexOf(name);
13664
13665             if (i >= 0) {
13666               this._names.splice(i, 1);
13667
13668               this._node.setAttribute("class", this._names.join(" "));
13669             }
13670           },
13671           contains: function contains(name) {
13672             return this._names.indexOf(name) >= 0;
13673           }
13674         };
13675
13676         function classedAdd(node, names) {
13677           var list = classList(node),
13678               i = -1,
13679               n = names.length;
13680
13681           while (++i < n) {
13682             list.add(names[i]);
13683           }
13684         }
13685
13686         function classedRemove(node, names) {
13687           var list = classList(node),
13688               i = -1,
13689               n = names.length;
13690
13691           while (++i < n) {
13692             list.remove(names[i]);
13693           }
13694         }
13695
13696         function classedTrue(names) {
13697           return function () {
13698             classedAdd(this, names);
13699           };
13700         }
13701
13702         function classedFalse(names) {
13703           return function () {
13704             classedRemove(this, names);
13705           };
13706         }
13707
13708         function classedFunction(names, value) {
13709           return function () {
13710             (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
13711           };
13712         }
13713
13714         function selection_classed (name, value) {
13715           var names = classArray(name + "");
13716
13717           if (arguments.length < 2) {
13718             var list = classList(this.node()),
13719                 i = -1,
13720                 n = names.length;
13721
13722             while (++i < n) {
13723               if (!list.contains(names[i])) return false;
13724             }
13725
13726             return true;
13727           }
13728
13729           return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
13730         }
13731
13732         function textRemove() {
13733           this.textContent = "";
13734         }
13735
13736         function textConstant(value) {
13737           return function () {
13738             this.textContent = value;
13739           };
13740         }
13741
13742         function textFunction(value) {
13743           return function () {
13744             var v = value.apply(this, arguments);
13745             this.textContent = v == null ? "" : v;
13746           };
13747         }
13748
13749         function selection_text (value) {
13750           return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction : textConstant)(value)) : this.node().textContent;
13751         }
13752
13753         function htmlRemove() {
13754           this.innerHTML = "";
13755         }
13756
13757         function htmlConstant(value) {
13758           return function () {
13759             this.innerHTML = value;
13760           };
13761         }
13762
13763         function htmlFunction(value) {
13764           return function () {
13765             var v = value.apply(this, arguments);
13766             this.innerHTML = v == null ? "" : v;
13767           };
13768         }
13769
13770         function selection_html (value) {
13771           return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
13772         }
13773
13774         function raise() {
13775           if (this.nextSibling) this.parentNode.appendChild(this);
13776         }
13777
13778         function selection_raise () {
13779           return this.each(raise);
13780         }
13781
13782         function lower() {
13783           if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
13784         }
13785
13786         function selection_lower () {
13787           return this.each(lower);
13788         }
13789
13790         function selection_append (name) {
13791           var create = typeof name === "function" ? name : creator(name);
13792           return this.select(function () {
13793             return this.appendChild(create.apply(this, arguments));
13794           });
13795         }
13796
13797         function constantNull() {
13798           return null;
13799         }
13800
13801         function selection_insert (name, before) {
13802           var create = typeof name === "function" ? name : creator(name),
13803               select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
13804           return this.select(function () {
13805             return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
13806           });
13807         }
13808
13809         function remove() {
13810           var parent = this.parentNode;
13811           if (parent) parent.removeChild(this);
13812         }
13813
13814         function selection_remove () {
13815           return this.each(remove);
13816         }
13817
13818         function selection_cloneShallow() {
13819           var clone = this.cloneNode(false),
13820               parent = this.parentNode;
13821           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
13822         }
13823
13824         function selection_cloneDeep() {
13825           var clone = this.cloneNode(true),
13826               parent = this.parentNode;
13827           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
13828         }
13829
13830         function selection_clone (deep) {
13831           return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
13832         }
13833
13834         function selection_datum (value) {
13835           return arguments.length ? this.property("__data__", value) : this.node().__data__;
13836         }
13837
13838         function contextListener(listener) {
13839           return function (event) {
13840             listener.call(this, event, this.__data__);
13841           };
13842         }
13843
13844         function parseTypenames$1(typenames) {
13845           return typenames.trim().split(/^|\s+/).map(function (t) {
13846             var name = "",
13847                 i = t.indexOf(".");
13848             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13849             return {
13850               type: t,
13851               name: name
13852             };
13853           });
13854         }
13855
13856         function onRemove(typename) {
13857           return function () {
13858             var on = this.__on;
13859             if (!on) return;
13860
13861             for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
13862               if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
13863                 this.removeEventListener(o.type, o.listener, o.options);
13864               } else {
13865                 on[++i] = o;
13866               }
13867             }
13868
13869             if (++i) on.length = i;else delete this.__on;
13870           };
13871         }
13872
13873         function onAdd(typename, value, options) {
13874           return function () {
13875             var on = this.__on,
13876                 o,
13877                 listener = contextListener(value);
13878             if (on) for (var j = 0, m = on.length; j < m; ++j) {
13879               if ((o = on[j]).type === typename.type && o.name === typename.name) {
13880                 this.removeEventListener(o.type, o.listener, o.options);
13881                 this.addEventListener(o.type, o.listener = listener, o.options = options);
13882                 o.value = value;
13883                 return;
13884               }
13885             }
13886             this.addEventListener(typename.type, listener, options);
13887             o = {
13888               type: typename.type,
13889               name: typename.name,
13890               value: value,
13891               listener: listener,
13892               options: options
13893             };
13894             if (!on) this.__on = [o];else on.push(o);
13895           };
13896         }
13897
13898         function selection_on (typename, value, options) {
13899           var typenames = parseTypenames$1(typename + ""),
13900               i,
13901               n = typenames.length,
13902               t;
13903
13904           if (arguments.length < 2) {
13905             var on = this.node().__on;
13906
13907             if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
13908               for (i = 0, o = on[j]; i < n; ++i) {
13909                 if ((t = typenames[i]).type === o.type && t.name === o.name) {
13910                   return o.value;
13911                 }
13912               }
13913             }
13914             return;
13915           }
13916
13917           on = value ? onAdd : onRemove;
13918
13919           for (i = 0; i < n; ++i) {
13920             this.each(on(typenames[i], value, options));
13921           }
13922
13923           return this;
13924         }
13925
13926         function dispatchEvent$1(node, type, params) {
13927           var window = defaultView(node),
13928               event = window.CustomEvent;
13929
13930           if (typeof event === "function") {
13931             event = new event(type, params);
13932           } else {
13933             event = window.document.createEvent("Event");
13934             if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;else event.initEvent(type, false, false);
13935           }
13936
13937           node.dispatchEvent(event);
13938         }
13939
13940         function dispatchConstant(type, params) {
13941           return function () {
13942             return dispatchEvent$1(this, type, params);
13943           };
13944         }
13945
13946         function dispatchFunction(type, params) {
13947           return function () {
13948             return dispatchEvent$1(this, type, params.apply(this, arguments));
13949           };
13950         }
13951
13952         function selection_dispatch (type, params) {
13953           return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
13954         }
13955
13956         var _marked$2 = /*#__PURE__*/regeneratorRuntime.mark(_callee);
13957
13958         function _callee() {
13959           var groups, j, m, group, i, n, node;
13960           return regeneratorRuntime.wrap(function _callee$(_context) {
13961             while (1) {
13962               switch (_context.prev = _context.next) {
13963                 case 0:
13964                   groups = this._groups, j = 0, m = groups.length;
13965
13966                 case 1:
13967                   if (!(j < m)) {
13968                     _context.next = 13;
13969                     break;
13970                   }
13971
13972                   group = groups[j], i = 0, n = group.length;
13973
13974                 case 3:
13975                   if (!(i < n)) {
13976                     _context.next = 10;
13977                     break;
13978                   }
13979
13980                   if (!(node = group[i])) {
13981                     _context.next = 7;
13982                     break;
13983                   }
13984
13985                   _context.next = 7;
13986                   return node;
13987
13988                 case 7:
13989                   ++i;
13990                   _context.next = 3;
13991                   break;
13992
13993                 case 10:
13994                   ++j;
13995                   _context.next = 1;
13996                   break;
13997
13998                 case 13:
13999                 case "end":
14000                   return _context.stop();
14001               }
14002             }
14003           }, _marked$2, this);
14004         }
14005
14006         var root = [null];
14007         function Selection(groups, parents) {
14008           this._groups = groups;
14009           this._parents = parents;
14010         }
14011
14012         function selection() {
14013           return new Selection([[document.documentElement]], root);
14014         }
14015
14016         function selection_selection() {
14017           return this;
14018         }
14019
14020         Selection.prototype = selection.prototype = _defineProperty({
14021           constructor: Selection,
14022           select: selection_select,
14023           selectAll: selection_selectAll,
14024           selectChild: selection_selectChild,
14025           selectChildren: selection_selectChildren,
14026           filter: selection_filter,
14027           data: selection_data,
14028           enter: selection_enter,
14029           exit: selection_exit,
14030           join: selection_join,
14031           merge: selection_merge,
14032           selection: selection_selection,
14033           order: selection_order,
14034           sort: selection_sort,
14035           call: selection_call,
14036           nodes: selection_nodes,
14037           node: selection_node,
14038           size: selection_size,
14039           empty: selection_empty,
14040           each: selection_each,
14041           attr: selection_attr,
14042           style: selection_style,
14043           property: selection_property,
14044           classed: selection_classed,
14045           text: selection_text,
14046           html: selection_html,
14047           raise: selection_raise,
14048           lower: selection_lower,
14049           append: selection_append,
14050           insert: selection_insert,
14051           remove: selection_remove,
14052           clone: selection_clone,
14053           datum: selection_datum,
14054           on: selection_on,
14055           dispatch: selection_dispatch
14056         }, Symbol.iterator, _callee);
14057
14058         function select (selector) {
14059           return typeof selector === "string" ? new Selection([[document.querySelector(selector)]], [document.documentElement]) : new Selection([[selector]], root);
14060         }
14061
14062         function sourceEvent (event) {
14063           var sourceEvent;
14064
14065           while (sourceEvent = event.sourceEvent) {
14066             event = sourceEvent;
14067           }
14068
14069           return event;
14070         }
14071
14072         function pointer (event, node) {
14073           event = sourceEvent(event);
14074           if (node === undefined) node = event.currentTarget;
14075
14076           if (node) {
14077             var svg = node.ownerSVGElement || node;
14078
14079             if (svg.createSVGPoint) {
14080               var point = svg.createSVGPoint();
14081               point.x = event.clientX, point.y = event.clientY;
14082               point = point.matrixTransform(node.getScreenCTM().inverse());
14083               return [point.x, point.y];
14084             }
14085
14086             if (node.getBoundingClientRect) {
14087               var rect = node.getBoundingClientRect();
14088               return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
14089             }
14090           }
14091
14092           return [event.pageX, event.pageY];
14093         }
14094
14095         function selectAll (selector) {
14096           return typeof selector === "string" ? new Selection([document.querySelectorAll(selector)], [document.documentElement]) : new Selection([selector == null ? [] : array(selector)], root);
14097         }
14098
14099         function nopropagation(event) {
14100           event.stopImmediatePropagation();
14101         }
14102         function noevent (event) {
14103           event.preventDefault();
14104           event.stopImmediatePropagation();
14105         }
14106
14107         function dragDisable (view) {
14108           var root = view.document.documentElement,
14109               selection = select(view).on("dragstart.drag", noevent, true);
14110
14111           if ("onselectstart" in root) {
14112             selection.on("selectstart.drag", noevent, true);
14113           } else {
14114             root.__noselect = root.style.MozUserSelect;
14115             root.style.MozUserSelect = "none";
14116           }
14117         }
14118         function yesdrag(view, noclick) {
14119           var root = view.document.documentElement,
14120               selection = select(view).on("dragstart.drag", null);
14121
14122           if (noclick) {
14123             selection.on("click.drag", noevent, true);
14124             setTimeout(function () {
14125               selection.on("click.drag", null);
14126             }, 0);
14127           }
14128
14129           if ("onselectstart" in root) {
14130             selection.on("selectstart.drag", null);
14131           } else {
14132             root.style.MozUserSelect = root.__noselect;
14133             delete root.__noselect;
14134           }
14135         }
14136
14137         var constant$1 = (function (x) {
14138           return function () {
14139             return x;
14140           };
14141         });
14142
14143         // `Object.defineProperties` method
14144         // https://tc39.github.io/ecma262/#sec-object.defineproperties
14145         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
14146           defineProperties: objectDefineProperties
14147         });
14148
14149         function DragEvent(type, _ref) {
14150           var sourceEvent = _ref.sourceEvent,
14151               subject = _ref.subject,
14152               target = _ref.target,
14153               identifier = _ref.identifier,
14154               active = _ref.active,
14155               x = _ref.x,
14156               y = _ref.y,
14157               dx = _ref.dx,
14158               dy = _ref.dy,
14159               dispatch = _ref.dispatch;
14160           Object.defineProperties(this, {
14161             type: {
14162               value: type,
14163               enumerable: true,
14164               configurable: true
14165             },
14166             sourceEvent: {
14167               value: sourceEvent,
14168               enumerable: true,
14169               configurable: true
14170             },
14171             subject: {
14172               value: subject,
14173               enumerable: true,
14174               configurable: true
14175             },
14176             target: {
14177               value: target,
14178               enumerable: true,
14179               configurable: true
14180             },
14181             identifier: {
14182               value: identifier,
14183               enumerable: true,
14184               configurable: true
14185             },
14186             active: {
14187               value: active,
14188               enumerable: true,
14189               configurable: true
14190             },
14191             x: {
14192               value: x,
14193               enumerable: true,
14194               configurable: true
14195             },
14196             y: {
14197               value: y,
14198               enumerable: true,
14199               configurable: true
14200             },
14201             dx: {
14202               value: dx,
14203               enumerable: true,
14204               configurable: true
14205             },
14206             dy: {
14207               value: dy,
14208               enumerable: true,
14209               configurable: true
14210             },
14211             _: {
14212               value: dispatch
14213             }
14214           });
14215         }
14216
14217         DragEvent.prototype.on = function () {
14218           var value = this._.on.apply(this._, arguments);
14219
14220           return value === this._ ? this : value;
14221         };
14222
14223         function defaultFilter(event) {
14224           return !event.ctrlKey && !event.button;
14225         }
14226
14227         function defaultContainer() {
14228           return this.parentNode;
14229         }
14230
14231         function defaultSubject(event, d) {
14232           return d == null ? {
14233             x: event.x,
14234             y: event.y
14235           } : d;
14236         }
14237
14238         function defaultTouchable() {
14239           return navigator.maxTouchPoints || "ontouchstart" in this;
14240         }
14241
14242         function d3_drag () {
14243           var filter = defaultFilter,
14244               container = defaultContainer,
14245               subject = defaultSubject,
14246               touchable = defaultTouchable,
14247               gestures = {},
14248               listeners = dispatch("start", "drag", "end"),
14249               active = 0,
14250               mousedownx,
14251               mousedowny,
14252               mousemoving,
14253               touchending,
14254               clickDistance2 = 0;
14255
14256           function drag(selection) {
14257             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)");
14258           }
14259
14260           function mousedowned(event, d) {
14261             if (touchending || !filter.call(this, event, d)) return;
14262             var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
14263             if (!gesture) return;
14264             select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
14265             dragDisable(event.view);
14266             nopropagation(event);
14267             mousemoving = false;
14268             mousedownx = event.clientX;
14269             mousedowny = event.clientY;
14270             gesture("start", event);
14271           }
14272
14273           function mousemoved(event) {
14274             noevent(event);
14275
14276             if (!mousemoving) {
14277               var dx = event.clientX - mousedownx,
14278                   dy = event.clientY - mousedowny;
14279               mousemoving = dx * dx + dy * dy > clickDistance2;
14280             }
14281
14282             gestures.mouse("drag", event);
14283           }
14284
14285           function mouseupped(event) {
14286             select(event.view).on("mousemove.drag mouseup.drag", null);
14287             yesdrag(event.view, mousemoving);
14288             noevent(event);
14289             gestures.mouse("end", event);
14290           }
14291
14292           function touchstarted(event, d) {
14293             if (!filter.call(this, event, d)) return;
14294             var touches = event.changedTouches,
14295                 c = container.call(this, event, d),
14296                 n = touches.length,
14297                 i,
14298                 gesture;
14299
14300             for (i = 0; i < n; ++i) {
14301               if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
14302                 nopropagation(event);
14303                 gesture("start", event, touches[i]);
14304               }
14305             }
14306           }
14307
14308           function touchmoved(event) {
14309             var touches = event.changedTouches,
14310                 n = touches.length,
14311                 i,
14312                 gesture;
14313
14314             for (i = 0; i < n; ++i) {
14315               if (gesture = gestures[touches[i].identifier]) {
14316                 noevent(event);
14317                 gesture("drag", event, touches[i]);
14318               }
14319             }
14320           }
14321
14322           function touchended(event) {
14323             var touches = event.changedTouches,
14324                 n = touches.length,
14325                 i,
14326                 gesture;
14327             if (touchending) clearTimeout(touchending);
14328             touchending = setTimeout(function () {
14329               touchending = null;
14330             }, 500); // Ghost clicks are delayed!
14331
14332             for (i = 0; i < n; ++i) {
14333               if (gesture = gestures[touches[i].identifier]) {
14334                 nopropagation(event);
14335                 gesture("end", event, touches[i]);
14336               }
14337             }
14338           }
14339
14340           function beforestart(that, container, event, d, identifier, touch) {
14341             var dispatch = listeners.copy(),
14342                 p = pointer(touch || event, container),
14343                 dx,
14344                 dy,
14345                 s;
14346             if ((s = subject.call(that, new DragEvent("beforestart", {
14347               sourceEvent: event,
14348               target: drag,
14349               identifier: identifier,
14350               active: active,
14351               x: p[0],
14352               y: p[1],
14353               dx: 0,
14354               dy: 0,
14355               dispatch: dispatch
14356             }), d)) == null) return;
14357             dx = s.x - p[0] || 0;
14358             dy = s.y - p[1] || 0;
14359             return function gesture(type, event, touch) {
14360               var p0 = p,
14361                   n;
14362
14363               switch (type) {
14364                 case "start":
14365                   gestures[identifier] = gesture, n = active++;
14366                   break;
14367
14368                 case "end":
14369                   delete gestures[identifier], --active;
14370                 // nobreak
14371
14372                 case "drag":
14373                   p = pointer(touch || event, container), n = active;
14374                   break;
14375               }
14376
14377               dispatch.call(type, that, new DragEvent(type, {
14378                 sourceEvent: event,
14379                 subject: s,
14380                 target: drag,
14381                 identifier: identifier,
14382                 active: n,
14383                 x: p[0] + dx,
14384                 y: p[1] + dy,
14385                 dx: p[0] - p0[0],
14386                 dy: p[1] - p0[1],
14387                 dispatch: dispatch
14388               }), d);
14389             };
14390           }
14391
14392           drag.filter = function (_) {
14393             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$1(!!_), drag) : filter;
14394           };
14395
14396           drag.container = function (_) {
14397             return arguments.length ? (container = typeof _ === "function" ? _ : constant$1(_), drag) : container;
14398           };
14399
14400           drag.subject = function (_) {
14401             return arguments.length ? (subject = typeof _ === "function" ? _ : constant$1(_), drag) : subject;
14402           };
14403
14404           drag.touchable = function (_) {
14405             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$1(!!_), drag) : touchable;
14406           };
14407
14408           drag.on = function () {
14409             var value = listeners.on.apply(listeners, arguments);
14410             return value === listeners ? drag : value;
14411           };
14412
14413           drag.clickDistance = function (_) {
14414             return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
14415           };
14416
14417           return drag;
14418         }
14419
14420         var defineProperty$9 = objectDefineProperty.f;
14421         var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
14422
14423
14424
14425
14426
14427         var setInternalState$8 = internalState.set;
14428
14429
14430
14431         var MATCH$1 = wellKnownSymbol('match');
14432         var NativeRegExp = global_1.RegExp;
14433         var RegExpPrototype$1 = NativeRegExp.prototype;
14434         var re1 = /a/g;
14435         var re2 = /a/g;
14436
14437         // "new" should create a new object, old webkit bug
14438         var CORRECT_NEW = new NativeRegExp(re1) !== re1;
14439
14440         var UNSUPPORTED_Y$2 = regexpStickyHelpers.UNSUPPORTED_Y;
14441
14442         var FORCED$b = descriptors && isForced_1('RegExp', (!CORRECT_NEW || UNSUPPORTED_Y$2 || fails(function () {
14443           re2[MATCH$1] = false;
14444           // RegExp constructor can alter flags and IsRegExp works correct with @@match
14445           return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
14446         })));
14447
14448         // `RegExp` constructor
14449         // https://tc39.github.io/ecma262/#sec-regexp-constructor
14450         if (FORCED$b) {
14451           var RegExpWrapper = function RegExp(pattern, flags) {
14452             var thisIsRegExp = this instanceof RegExpWrapper;
14453             var patternIsRegExp = isRegexp(pattern);
14454             var flagsAreUndefined = flags === undefined;
14455             var sticky;
14456
14457             if (!thisIsRegExp && patternIsRegExp && pattern.constructor === RegExpWrapper && flagsAreUndefined) {
14458               return pattern;
14459             }
14460
14461             if (CORRECT_NEW) {
14462               if (patternIsRegExp && !flagsAreUndefined) pattern = pattern.source;
14463             } else if (pattern instanceof RegExpWrapper) {
14464               if (flagsAreUndefined) flags = regexpFlags.call(pattern);
14465               pattern = pattern.source;
14466             }
14467
14468             if (UNSUPPORTED_Y$2) {
14469               sticky = !!flags && flags.indexOf('y') > -1;
14470               if (sticky) flags = flags.replace(/y/g, '');
14471             }
14472
14473             var result = inheritIfRequired(
14474               CORRECT_NEW ? new NativeRegExp(pattern, flags) : NativeRegExp(pattern, flags),
14475               thisIsRegExp ? this : RegExpPrototype$1,
14476               RegExpWrapper
14477             );
14478
14479             if (UNSUPPORTED_Y$2 && sticky) setInternalState$8(result, { sticky: sticky });
14480
14481             return result;
14482           };
14483           var proxy = function (key) {
14484             key in RegExpWrapper || defineProperty$9(RegExpWrapper, key, {
14485               configurable: true,
14486               get: function () { return NativeRegExp[key]; },
14487               set: function (it) { NativeRegExp[key] = it; }
14488             });
14489           };
14490           var keys$2 = getOwnPropertyNames$1(NativeRegExp);
14491           var index = 0;
14492           while (keys$2.length > index) proxy(keys$2[index++]);
14493           RegExpPrototype$1.constructor = RegExpWrapper;
14494           RegExpWrapper.prototype = RegExpPrototype$1;
14495           redefine(global_1, 'RegExp', RegExpWrapper);
14496         }
14497
14498         // https://tc39.github.io/ecma262/#sec-get-regexp-@@species
14499         setSpecies('RegExp');
14500
14501         function define (constructor, factory, prototype) {
14502           constructor.prototype = factory.prototype = prototype;
14503           prototype.constructor = constructor;
14504         }
14505         function extend(parent, definition) {
14506           var prototype = Object.create(parent.prototype);
14507
14508           for (var key in definition) {
14509             prototype[key] = definition[key];
14510           }
14511
14512           return prototype;
14513         }
14514
14515         function Color() {}
14516         var _darker = 0.7;
14517
14518         var _brighter = 1 / _darker;
14519         var reI = "\\s*([+-]?\\d+)\\s*",
14520             reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
14521             reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
14522             reHex = /^#([0-9a-f]{3,8})$/,
14523             reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
14524             reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
14525             reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
14526             reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
14527             reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
14528             reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
14529         var named = {
14530           aliceblue: 0xf0f8ff,
14531           antiquewhite: 0xfaebd7,
14532           aqua: 0x00ffff,
14533           aquamarine: 0x7fffd4,
14534           azure: 0xf0ffff,
14535           beige: 0xf5f5dc,
14536           bisque: 0xffe4c4,
14537           black: 0x000000,
14538           blanchedalmond: 0xffebcd,
14539           blue: 0x0000ff,
14540           blueviolet: 0x8a2be2,
14541           brown: 0xa52a2a,
14542           burlywood: 0xdeb887,
14543           cadetblue: 0x5f9ea0,
14544           chartreuse: 0x7fff00,
14545           chocolate: 0xd2691e,
14546           coral: 0xff7f50,
14547           cornflowerblue: 0x6495ed,
14548           cornsilk: 0xfff8dc,
14549           crimson: 0xdc143c,
14550           cyan: 0x00ffff,
14551           darkblue: 0x00008b,
14552           darkcyan: 0x008b8b,
14553           darkgoldenrod: 0xb8860b,
14554           darkgray: 0xa9a9a9,
14555           darkgreen: 0x006400,
14556           darkgrey: 0xa9a9a9,
14557           darkkhaki: 0xbdb76b,
14558           darkmagenta: 0x8b008b,
14559           darkolivegreen: 0x556b2f,
14560           darkorange: 0xff8c00,
14561           darkorchid: 0x9932cc,
14562           darkred: 0x8b0000,
14563           darksalmon: 0xe9967a,
14564           darkseagreen: 0x8fbc8f,
14565           darkslateblue: 0x483d8b,
14566           darkslategray: 0x2f4f4f,
14567           darkslategrey: 0x2f4f4f,
14568           darkturquoise: 0x00ced1,
14569           darkviolet: 0x9400d3,
14570           deeppink: 0xff1493,
14571           deepskyblue: 0x00bfff,
14572           dimgray: 0x696969,
14573           dimgrey: 0x696969,
14574           dodgerblue: 0x1e90ff,
14575           firebrick: 0xb22222,
14576           floralwhite: 0xfffaf0,
14577           forestgreen: 0x228b22,
14578           fuchsia: 0xff00ff,
14579           gainsboro: 0xdcdcdc,
14580           ghostwhite: 0xf8f8ff,
14581           gold: 0xffd700,
14582           goldenrod: 0xdaa520,
14583           gray: 0x808080,
14584           green: 0x008000,
14585           greenyellow: 0xadff2f,
14586           grey: 0x808080,
14587           honeydew: 0xf0fff0,
14588           hotpink: 0xff69b4,
14589           indianred: 0xcd5c5c,
14590           indigo: 0x4b0082,
14591           ivory: 0xfffff0,
14592           khaki: 0xf0e68c,
14593           lavender: 0xe6e6fa,
14594           lavenderblush: 0xfff0f5,
14595           lawngreen: 0x7cfc00,
14596           lemonchiffon: 0xfffacd,
14597           lightblue: 0xadd8e6,
14598           lightcoral: 0xf08080,
14599           lightcyan: 0xe0ffff,
14600           lightgoldenrodyellow: 0xfafad2,
14601           lightgray: 0xd3d3d3,
14602           lightgreen: 0x90ee90,
14603           lightgrey: 0xd3d3d3,
14604           lightpink: 0xffb6c1,
14605           lightsalmon: 0xffa07a,
14606           lightseagreen: 0x20b2aa,
14607           lightskyblue: 0x87cefa,
14608           lightslategray: 0x778899,
14609           lightslategrey: 0x778899,
14610           lightsteelblue: 0xb0c4de,
14611           lightyellow: 0xffffe0,
14612           lime: 0x00ff00,
14613           limegreen: 0x32cd32,
14614           linen: 0xfaf0e6,
14615           magenta: 0xff00ff,
14616           maroon: 0x800000,
14617           mediumaquamarine: 0x66cdaa,
14618           mediumblue: 0x0000cd,
14619           mediumorchid: 0xba55d3,
14620           mediumpurple: 0x9370db,
14621           mediumseagreen: 0x3cb371,
14622           mediumslateblue: 0x7b68ee,
14623           mediumspringgreen: 0x00fa9a,
14624           mediumturquoise: 0x48d1cc,
14625           mediumvioletred: 0xc71585,
14626           midnightblue: 0x191970,
14627           mintcream: 0xf5fffa,
14628           mistyrose: 0xffe4e1,
14629           moccasin: 0xffe4b5,
14630           navajowhite: 0xffdead,
14631           navy: 0x000080,
14632           oldlace: 0xfdf5e6,
14633           olive: 0x808000,
14634           olivedrab: 0x6b8e23,
14635           orange: 0xffa500,
14636           orangered: 0xff4500,
14637           orchid: 0xda70d6,
14638           palegoldenrod: 0xeee8aa,
14639           palegreen: 0x98fb98,
14640           paleturquoise: 0xafeeee,
14641           palevioletred: 0xdb7093,
14642           papayawhip: 0xffefd5,
14643           peachpuff: 0xffdab9,
14644           peru: 0xcd853f,
14645           pink: 0xffc0cb,
14646           plum: 0xdda0dd,
14647           powderblue: 0xb0e0e6,
14648           purple: 0x800080,
14649           rebeccapurple: 0x663399,
14650           red: 0xff0000,
14651           rosybrown: 0xbc8f8f,
14652           royalblue: 0x4169e1,
14653           saddlebrown: 0x8b4513,
14654           salmon: 0xfa8072,
14655           sandybrown: 0xf4a460,
14656           seagreen: 0x2e8b57,
14657           seashell: 0xfff5ee,
14658           sienna: 0xa0522d,
14659           silver: 0xc0c0c0,
14660           skyblue: 0x87ceeb,
14661           slateblue: 0x6a5acd,
14662           slategray: 0x708090,
14663           slategrey: 0x708090,
14664           snow: 0xfffafa,
14665           springgreen: 0x00ff7f,
14666           steelblue: 0x4682b4,
14667           tan: 0xd2b48c,
14668           teal: 0x008080,
14669           thistle: 0xd8bfd8,
14670           tomato: 0xff6347,
14671           turquoise: 0x40e0d0,
14672           violet: 0xee82ee,
14673           wheat: 0xf5deb3,
14674           white: 0xffffff,
14675           whitesmoke: 0xf5f5f5,
14676           yellow: 0xffff00,
14677           yellowgreen: 0x9acd32
14678         };
14679         define(Color, color, {
14680           copy: function copy(channels) {
14681             return Object.assign(new this.constructor(), this, channels);
14682           },
14683           displayable: function displayable() {
14684             return this.rgb().displayable();
14685           },
14686           hex: color_formatHex,
14687           // Deprecated! Use color.formatHex.
14688           formatHex: color_formatHex,
14689           formatHsl: color_formatHsl,
14690           formatRgb: color_formatRgb,
14691           toString: color_formatRgb
14692         });
14693
14694         function color_formatHex() {
14695           return this.rgb().formatHex();
14696         }
14697
14698         function color_formatHsl() {
14699           return hslConvert(this).formatHsl();
14700         }
14701
14702         function color_formatRgb() {
14703           return this.rgb().formatRgb();
14704         }
14705
14706         function color(format) {
14707           var m, l;
14708           format = (format + "").trim().toLowerCase();
14709           return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
14710           : l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
14711           : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
14712           : 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
14713           : null // invalid hex
14714           ) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
14715           : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
14716           : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
14717           : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
14718           : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
14719           : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
14720           : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
14721           : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
14722         }
14723
14724         function rgbn(n) {
14725           return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
14726         }
14727
14728         function rgba(r, g, b, a) {
14729           if (a <= 0) r = g = b = NaN;
14730           return new Rgb(r, g, b, a);
14731         }
14732
14733         function rgbConvert(o) {
14734           if (!(o instanceof Color)) o = color(o);
14735           if (!o) return new Rgb();
14736           o = o.rgb();
14737           return new Rgb(o.r, o.g, o.b, o.opacity);
14738         }
14739         function rgb(r, g, b, opacity) {
14740           return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
14741         }
14742         function Rgb(r, g, b, opacity) {
14743           this.r = +r;
14744           this.g = +g;
14745           this.b = +b;
14746           this.opacity = +opacity;
14747         }
14748         define(Rgb, rgb, extend(Color, {
14749           brighter: function brighter(k) {
14750             k = k == null ? _brighter : Math.pow(_brighter, k);
14751             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
14752           },
14753           darker: function darker(k) {
14754             k = k == null ? _darker : Math.pow(_darker, k);
14755             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
14756           },
14757           rgb: function rgb() {
14758             return this;
14759           },
14760           displayable: function displayable() {
14761             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;
14762           },
14763           hex: rgb_formatHex,
14764           // Deprecated! Use color.formatHex.
14765           formatHex: rgb_formatHex,
14766           formatRgb: rgb_formatRgb,
14767           toString: rgb_formatRgb
14768         }));
14769
14770         function rgb_formatHex() {
14771           return "#" + hex$2(this.r) + hex$2(this.g) + hex$2(this.b);
14772         }
14773
14774         function rgb_formatRgb() {
14775           var a = this.opacity;
14776           a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
14777           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 + ")");
14778         }
14779
14780         function hex$2(value) {
14781           value = Math.max(0, Math.min(255, Math.round(value) || 0));
14782           return (value < 16 ? "0" : "") + value.toString(16);
14783         }
14784
14785         function hsla(h, s, l, a) {
14786           if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
14787           return new Hsl(h, s, l, a);
14788         }
14789
14790         function hslConvert(o) {
14791           if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
14792           if (!(o instanceof Color)) o = color(o);
14793           if (!o) return new Hsl();
14794           if (o instanceof Hsl) return o;
14795           o = o.rgb();
14796           var r = o.r / 255,
14797               g = o.g / 255,
14798               b = o.b / 255,
14799               min = Math.min(r, g, b),
14800               max = Math.max(r, g, b),
14801               h = NaN,
14802               s = max - min,
14803               l = (max + min) / 2;
14804
14805           if (s) {
14806             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;
14807             s /= l < 0.5 ? max + min : 2 - max - min;
14808             h *= 60;
14809           } else {
14810             s = l > 0 && l < 1 ? 0 : h;
14811           }
14812
14813           return new Hsl(h, s, l, o.opacity);
14814         }
14815         function hsl(h, s, l, opacity) {
14816           return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
14817         }
14818
14819         function Hsl(h, s, l, opacity) {
14820           this.h = +h;
14821           this.s = +s;
14822           this.l = +l;
14823           this.opacity = +opacity;
14824         }
14825
14826         define(Hsl, hsl, extend(Color, {
14827           brighter: function brighter(k) {
14828             k = k == null ? _brighter : Math.pow(_brighter, k);
14829             return new Hsl(this.h, this.s, this.l * k, this.opacity);
14830           },
14831           darker: function darker(k) {
14832             k = k == null ? _darker : Math.pow(_darker, k);
14833             return new Hsl(this.h, this.s, this.l * k, this.opacity);
14834           },
14835           rgb: function rgb() {
14836             var h = this.h % 360 + (this.h < 0) * 360,
14837                 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
14838                 l = this.l,
14839                 m2 = l + (l < 0.5 ? l : 1 - l) * s,
14840                 m1 = 2 * l - m2;
14841             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);
14842           },
14843           displayable: function displayable() {
14844             return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
14845           },
14846           formatHsl: function formatHsl() {
14847             var a = this.opacity;
14848             a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
14849             return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
14850           }
14851         }));
14852         /* From FvD 13.37, CSS Color Module Level 3 */
14853
14854         function hsl2rgb(h, m1, m2) {
14855           return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
14856         }
14857
14858         var constant$2 = (function (x) {
14859           return function () {
14860             return x;
14861           };
14862         });
14863
14864         function linear(a, d) {
14865           return function (t) {
14866             return a + t * d;
14867           };
14868         }
14869
14870         function exponential(a, b, y) {
14871           return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function (t) {
14872             return Math.pow(a + t * b, y);
14873           };
14874         }
14875         function gamma(y) {
14876           return (y = +y) === 1 ? nogamma : function (a, b) {
14877             return b - a ? exponential(a, b, y) : constant$2(isNaN(a) ? b : a);
14878           };
14879         }
14880         function nogamma(a, b) {
14881           var d = b - a;
14882           return d ? linear(a, d) : constant$2(isNaN(a) ? b : a);
14883         }
14884
14885         var d3_interpolateRgb = (function rgbGamma(y) {
14886           var color = gamma(y);
14887
14888           function rgb$1(start, end) {
14889             var r = color((start = rgb(start)).r, (end = rgb(end)).r),
14890                 g = color(start.g, end.g),
14891                 b = color(start.b, end.b),
14892                 opacity = nogamma(start.opacity, end.opacity);
14893             return function (t) {
14894               start.r = r(t);
14895               start.g = g(t);
14896               start.b = b(t);
14897               start.opacity = opacity(t);
14898               return start + "";
14899             };
14900           }
14901
14902           rgb$1.gamma = rgbGamma;
14903           return rgb$1;
14904         })(1);
14905
14906         function numberArray (a, b) {
14907           if (!b) b = [];
14908           var n = a ? Math.min(b.length, a.length) : 0,
14909               c = b.slice(),
14910               i;
14911           return function (t) {
14912             for (i = 0; i < n; ++i) {
14913               c[i] = a[i] * (1 - t) + b[i] * t;
14914             }
14915
14916             return c;
14917           };
14918         }
14919         function isNumberArray(x) {
14920           return ArrayBuffer.isView(x) && !(x instanceof DataView);
14921         }
14922
14923         function genericArray(a, b) {
14924           var nb = b ? b.length : 0,
14925               na = a ? Math.min(nb, a.length) : 0,
14926               x = new Array(na),
14927               c = new Array(nb),
14928               i;
14929
14930           for (i = 0; i < na; ++i) {
14931             x[i] = interpolate(a[i], b[i]);
14932           }
14933
14934           for (; i < nb; ++i) {
14935             c[i] = b[i];
14936           }
14937
14938           return function (t) {
14939             for (i = 0; i < na; ++i) {
14940               c[i] = x[i](t);
14941             }
14942
14943             return c;
14944           };
14945         }
14946
14947         function date (a, b) {
14948           var d = new Date();
14949           return a = +a, b = +b, function (t) {
14950             return d.setTime(a * (1 - t) + b * t), d;
14951           };
14952         }
14953
14954         function d3_interpolateNumber (a, b) {
14955           return a = +a, b = +b, function (t) {
14956             return a * (1 - t) + b * t;
14957           };
14958         }
14959
14960         function object (a, b) {
14961           var i = {},
14962               c = {},
14963               k;
14964           if (a === null || _typeof(a) !== "object") a = {};
14965           if (b === null || _typeof(b) !== "object") b = {};
14966
14967           for (k in b) {
14968             if (k in a) {
14969               i[k] = interpolate(a[k], b[k]);
14970             } else {
14971               c[k] = b[k];
14972             }
14973           }
14974
14975           return function (t) {
14976             for (k in i) {
14977               c[k] = i[k](t);
14978             }
14979
14980             return c;
14981           };
14982         }
14983
14984         var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
14985             reB = new RegExp(reA.source, "g");
14986
14987         function zero(b) {
14988           return function () {
14989             return b;
14990           };
14991         }
14992
14993         function one(b) {
14994           return function (t) {
14995             return b(t) + "";
14996           };
14997         }
14998
14999         function interpolateString (a, b) {
15000           var bi = reA.lastIndex = reB.lastIndex = 0,
15001               // scan index for next number in b
15002           am,
15003               // current match in a
15004           bm,
15005               // current match in b
15006           bs,
15007               // string preceding current number in b, if any
15008           i = -1,
15009               // index in s
15010           s = [],
15011               // string constants and placeholders
15012           q = []; // number interpolators
15013           // Coerce inputs to strings.
15014
15015           a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b.
15016
15017           while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
15018             if ((bs = bm.index) > bi) {
15019               // a string precedes the next number in b
15020               bs = b.slice(bi, bs);
15021               if (s[i]) s[i] += bs; // coalesce with previous string
15022               else s[++i] = bs;
15023             }
15024
15025             if ((am = am[0]) === (bm = bm[0])) {
15026               // numbers in a & b match
15027               if (s[i]) s[i] += bm; // coalesce with previous string
15028               else s[++i] = bm;
15029             } else {
15030               // interpolate non-matching numbers
15031               s[++i] = null;
15032               q.push({
15033                 i: i,
15034                 x: d3_interpolateNumber(am, bm)
15035               });
15036             }
15037
15038             bi = reB.lastIndex;
15039           } // Add remains of b.
15040
15041
15042           if (bi < b.length) {
15043             bs = b.slice(bi);
15044             if (s[i]) s[i] += bs; // coalesce with previous string
15045             else s[++i] = bs;
15046           } // Special optimization for only a single match.
15047           // Otherwise, interpolate each of the numbers and rejoin the string.
15048
15049
15050           return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function (t) {
15051             for (var i = 0, o; i < b; ++i) {
15052               s[(o = q[i]).i] = o.x(t);
15053             }
15054
15055             return s.join("");
15056           });
15057         }
15058
15059         function interpolate (a, b) {
15060           var t = _typeof(b),
15061               c;
15062
15063           return b == null || t === "boolean" ? constant$2(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);
15064         }
15065
15066         function interpolateRound (a, b) {
15067           return a = +a, b = +b, function (t) {
15068             return Math.round(a * (1 - t) + b * t);
15069           };
15070         }
15071
15072         var degrees$1 = 180 / Math.PI;
15073         var identity$1 = {
15074           translateX: 0,
15075           translateY: 0,
15076           rotate: 0,
15077           skewX: 0,
15078           scaleX: 1,
15079           scaleY: 1
15080         };
15081         function decompose (a, b, c, d, e, f) {
15082           var scaleX, scaleY, skewX;
15083           if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
15084           if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
15085           if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
15086           if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
15087           return {
15088             translateX: e,
15089             translateY: f,
15090             rotate: Math.atan2(b, a) * degrees$1,
15091             skewX: Math.atan(skewX) * degrees$1,
15092             scaleX: scaleX,
15093             scaleY: scaleY
15094           };
15095         }
15096
15097         var svgNode;
15098         /* eslint-disable no-undef */
15099
15100         function parseCss(value) {
15101           var m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
15102           return m.isIdentity ? identity$1 : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
15103         }
15104         function parseSvg(value) {
15105           if (value == null) return identity$1;
15106           if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
15107           svgNode.setAttribute("transform", value);
15108           if (!(value = svgNode.transform.baseVal.consolidate())) return identity$1;
15109           value = value.matrix;
15110           return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
15111         }
15112
15113         function interpolateTransform(parse, pxComma, pxParen, degParen) {
15114           function pop(s) {
15115             return s.length ? s.pop() + " " : "";
15116           }
15117
15118           function translate(xa, ya, xb, yb, s, q) {
15119             if (xa !== xb || ya !== yb) {
15120               var i = s.push("translate(", null, pxComma, null, pxParen);
15121               q.push({
15122                 i: i - 4,
15123                 x: d3_interpolateNumber(xa, xb)
15124               }, {
15125                 i: i - 2,
15126                 x: d3_interpolateNumber(ya, yb)
15127               });
15128             } else if (xb || yb) {
15129               s.push("translate(" + xb + pxComma + yb + pxParen);
15130             }
15131           }
15132
15133           function rotate(a, b, s, q) {
15134             if (a !== b) {
15135               if (a - b > 180) b += 360;else if (b - a > 180) a += 360; // shortest path
15136
15137               q.push({
15138                 i: s.push(pop(s) + "rotate(", null, degParen) - 2,
15139                 x: d3_interpolateNumber(a, b)
15140               });
15141             } else if (b) {
15142               s.push(pop(s) + "rotate(" + b + degParen);
15143             }
15144           }
15145
15146           function skewX(a, b, s, q) {
15147             if (a !== b) {
15148               q.push({
15149                 i: s.push(pop(s) + "skewX(", null, degParen) - 2,
15150                 x: d3_interpolateNumber(a, b)
15151               });
15152             } else if (b) {
15153               s.push(pop(s) + "skewX(" + b + degParen);
15154             }
15155           }
15156
15157           function scale(xa, ya, xb, yb, s, q) {
15158             if (xa !== xb || ya !== yb) {
15159               var i = s.push(pop(s) + "scale(", null, ",", null, ")");
15160               q.push({
15161                 i: i - 4,
15162                 x: d3_interpolateNumber(xa, xb)
15163               }, {
15164                 i: i - 2,
15165                 x: d3_interpolateNumber(ya, yb)
15166               });
15167             } else if (xb !== 1 || yb !== 1) {
15168               s.push(pop(s) + "scale(" + xb + "," + yb + ")");
15169             }
15170           }
15171
15172           return function (a, b) {
15173             var s = [],
15174                 // string constants and placeholders
15175             q = []; // number interpolators
15176
15177             a = parse(a), b = parse(b);
15178             translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
15179             rotate(a.rotate, b.rotate, s, q);
15180             skewX(a.skewX, b.skewX, s, q);
15181             scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
15182             a = b = null; // gc
15183
15184             return function (t) {
15185               var i = -1,
15186                   n = q.length,
15187                   o;
15188
15189               while (++i < n) {
15190                 s[(o = q[i]).i] = o.x(t);
15191               }
15192
15193               return s.join("");
15194             };
15195           };
15196         }
15197
15198         var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
15199         var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
15200
15201         var epsilon2$1 = 1e-12;
15202
15203         function cosh(x) {
15204           return ((x = Math.exp(x)) + 1 / x) / 2;
15205         }
15206
15207         function sinh(x) {
15208           return ((x = Math.exp(x)) - 1 / x) / 2;
15209         }
15210
15211         function tanh(x) {
15212           return ((x = Math.exp(2 * x)) - 1) / (x + 1);
15213         }
15214
15215         var interpolateZoom = (function zoomRho(rho, rho2, rho4) {
15216           // p0 = [ux0, uy0, w0]
15217           // p1 = [ux1, uy1, w1]
15218           function zoom(p0, p1) {
15219             var ux0 = p0[0],
15220                 uy0 = p0[1],
15221                 w0 = p0[2],
15222                 ux1 = p1[0],
15223                 uy1 = p1[1],
15224                 w1 = p1[2],
15225                 dx = ux1 - ux0,
15226                 dy = uy1 - uy0,
15227                 d2 = dx * dx + dy * dy,
15228                 i,
15229                 S; // Special case for u0 ≅ u1.
15230
15231             if (d2 < epsilon2$1) {
15232               S = Math.log(w1 / w0) / rho;
15233
15234               i = function i(t) {
15235                 return [ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(rho * t * S)];
15236               };
15237             } // General case.
15238             else {
15239                 var d1 = Math.sqrt(d2),
15240                     b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
15241                     b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
15242                     r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
15243                     r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
15244                 S = (r1 - r0) / rho;
15245
15246                 i = function i(t) {
15247                   var s = t * S,
15248                       coshr0 = cosh(r0),
15249                       u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
15250                   return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(rho * s + r0)];
15251                 };
15252               }
15253
15254             i.duration = S * 1000 * rho / Math.SQRT2;
15255             return i;
15256           }
15257
15258           zoom.rho = function (_) {
15259             var _1 = Math.max(1e-3, +_),
15260                 _2 = _1 * _1,
15261                 _4 = _2 * _2;
15262
15263             return zoomRho(_1, _2, _4);
15264           };
15265
15266           return zoom;
15267         })(Math.SQRT2, 2, 4);
15268
15269         function d3_quantize (interpolator, n) {
15270           var samples = new Array(n);
15271
15272           for (var i = 0; i < n; ++i) {
15273             samples[i] = interpolator(i / (n - 1));
15274           }
15275
15276           return samples;
15277         }
15278
15279         // `Function.prototype.bind` method
15280         // https://tc39.github.io/ecma262/#sec-function.prototype.bind
15281         _export({ target: 'Function', proto: true }, {
15282           bind: functionBind
15283         });
15284
15285         var frame = 0,
15286             // is an animation frame pending?
15287         timeout = 0,
15288             // is a timeout pending?
15289         interval = 0,
15290             // are any timers active?
15291         pokeDelay = 1000,
15292             // how frequently we check for clock skew
15293         taskHead,
15294             taskTail,
15295             clockLast = 0,
15296             clockNow = 0,
15297             clockSkew = 0,
15298             clock = (typeof performance === "undefined" ? "undefined" : _typeof(performance)) === "object" && performance.now ? performance : Date,
15299             setFrame = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function (f) {
15300           setTimeout(f, 17);
15301         };
15302         function now() {
15303           return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
15304         }
15305
15306         function clearNow() {
15307           clockNow = 0;
15308         }
15309
15310         function Timer() {
15311           this._call = this._time = this._next = null;
15312         }
15313         Timer.prototype = timer.prototype = {
15314           constructor: Timer,
15315           restart: function restart(callback, delay, time) {
15316             if (typeof callback !== "function") throw new TypeError("callback is not a function");
15317             time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
15318
15319             if (!this._next && taskTail !== this) {
15320               if (taskTail) taskTail._next = this;else taskHead = this;
15321               taskTail = this;
15322             }
15323
15324             this._call = callback;
15325             this._time = time;
15326             sleep();
15327           },
15328           stop: function stop() {
15329             if (this._call) {
15330               this._call = null;
15331               this._time = Infinity;
15332               sleep();
15333             }
15334           }
15335         };
15336         function timer(callback, delay, time) {
15337           var t = new Timer();
15338           t.restart(callback, delay, time);
15339           return t;
15340         }
15341         function timerFlush() {
15342           now(); // Get the current time, if not already set.
15343
15344           ++frame; // Pretend we’ve set an alarm, if we haven’t already.
15345
15346           var t = taskHead,
15347               e;
15348
15349           while (t) {
15350             if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
15351             t = t._next;
15352           }
15353
15354           --frame;
15355         }
15356
15357         function wake() {
15358           clockNow = (clockLast = clock.now()) + clockSkew;
15359           frame = timeout = 0;
15360
15361           try {
15362             timerFlush();
15363           } finally {
15364             frame = 0;
15365             nap();
15366             clockNow = 0;
15367           }
15368         }
15369
15370         function poke() {
15371           var now = clock.now(),
15372               delay = now - clockLast;
15373           if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
15374         }
15375
15376         function nap() {
15377           var t0,
15378               t1 = taskHead,
15379               t2,
15380               time = Infinity;
15381
15382           while (t1) {
15383             if (t1._call) {
15384               if (time > t1._time) time = t1._time;
15385               t0 = t1, t1 = t1._next;
15386             } else {
15387               t2 = t1._next, t1._next = null;
15388               t1 = t0 ? t0._next = t2 : taskHead = t2;
15389             }
15390           }
15391
15392           taskTail = t0;
15393           sleep(time);
15394         }
15395
15396         function sleep(time) {
15397           if (frame) return; // Soonest alarm already set, or will be.
15398
15399           if (timeout) timeout = clearTimeout(timeout);
15400           var delay = time - clockNow; // Strictly less than if we recomputed clockNow.
15401
15402           if (delay > 24) {
15403             if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
15404             if (interval) interval = clearInterval(interval);
15405           } else {
15406             if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
15407             frame = 1, setFrame(wake);
15408           }
15409         }
15410
15411         function d3_timeout (callback, delay, time) {
15412           var t = new Timer();
15413           delay = delay == null ? 0 : +delay;
15414           t.restart(function (elapsed) {
15415             t.stop();
15416             callback(elapsed + delay);
15417           }, delay, time);
15418           return t;
15419         }
15420
15421         var emptyOn = dispatch("start", "end", "cancel", "interrupt");
15422         var emptyTween = [];
15423         var CREATED = 0;
15424         var SCHEDULED = 1;
15425         var STARTING = 2;
15426         var STARTED = 3;
15427         var RUNNING = 4;
15428         var ENDING = 5;
15429         var ENDED = 6;
15430         function schedule (node, name, id, index, group, timing) {
15431           var schedules = node.__transition;
15432           if (!schedules) node.__transition = {};else if (id in schedules) return;
15433           create(node, id, {
15434             name: name,
15435             index: index,
15436             // For context during callback.
15437             group: group,
15438             // For context during callback.
15439             on: emptyOn,
15440             tween: emptyTween,
15441             time: timing.time,
15442             delay: timing.delay,
15443             duration: timing.duration,
15444             ease: timing.ease,
15445             timer: null,
15446             state: CREATED
15447           });
15448         }
15449         function init(node, id) {
15450           var schedule = get$4(node, id);
15451           if (schedule.state > CREATED) throw new Error("too late; already scheduled");
15452           return schedule;
15453         }
15454         function set$4(node, id) {
15455           var schedule = get$4(node, id);
15456           if (schedule.state > STARTED) throw new Error("too late; already running");
15457           return schedule;
15458         }
15459         function get$4(node, id) {
15460           var schedule = node.__transition;
15461           if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
15462           return schedule;
15463         }
15464
15465         function create(node, id, self) {
15466           var schedules = node.__transition,
15467               tween; // Initialize the self timer when the transition is created.
15468           // Note the actual delay is not known until the first callback!
15469
15470           schedules[id] = self;
15471           self.timer = timer(schedule, 0, self.time);
15472
15473           function schedule(elapsed) {
15474             self.state = SCHEDULED;
15475             self.timer.restart(start, self.delay, self.time); // If the elapsed delay is less than our first sleep, start immediately.
15476
15477             if (self.delay <= elapsed) start(elapsed - self.delay);
15478           }
15479
15480           function start(elapsed) {
15481             var i, j, n, o; // If the state is not SCHEDULED, then we previously errored on start.
15482
15483             if (self.state !== SCHEDULED) return stop();
15484
15485             for (i in schedules) {
15486               o = schedules[i];
15487               if (o.name !== self.name) continue; // While this element already has a starting transition during this frame,
15488               // defer starting an interrupting transition until that transition has a
15489               // chance to tick (and possibly end); see d3/d3-transition#54!
15490
15491               if (o.state === STARTED) return d3_timeout(start); // Interrupt the active transition, if any.
15492
15493               if (o.state === RUNNING) {
15494                 o.state = ENDED;
15495                 o.timer.stop();
15496                 o.on.call("interrupt", node, node.__data__, o.index, o.group);
15497                 delete schedules[i];
15498               } // Cancel any pre-empted transitions.
15499               else if (+i < id) {
15500                   o.state = ENDED;
15501                   o.timer.stop();
15502                   o.on.call("cancel", node, node.__data__, o.index, o.group);
15503                   delete schedules[i];
15504                 }
15505             } // Defer the first tick to end of the current frame; see d3/d3#1576.
15506             // Note the transition may be canceled after start and before the first tick!
15507             // Note this must be scheduled before the start event; see d3/d3-transition#16!
15508             // Assuming this is successful, subsequent callbacks go straight to tick.
15509
15510
15511             d3_timeout(function () {
15512               if (self.state === STARTED) {
15513                 self.state = RUNNING;
15514                 self.timer.restart(tick, self.delay, self.time);
15515                 tick(elapsed);
15516               }
15517             }); // Dispatch the start event.
15518             // Note this must be done before the tween are initialized.
15519
15520             self.state = STARTING;
15521             self.on.call("start", node, node.__data__, self.index, self.group);
15522             if (self.state !== STARTING) return; // interrupted
15523
15524             self.state = STARTED; // Initialize the tween, deleting null tween.
15525
15526             tween = new Array(n = self.tween.length);
15527
15528             for (i = 0, j = -1; i < n; ++i) {
15529               if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
15530                 tween[++j] = o;
15531               }
15532             }
15533
15534             tween.length = j + 1;
15535           }
15536
15537           function tick(elapsed) {
15538             var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
15539                 i = -1,
15540                 n = tween.length;
15541
15542             while (++i < n) {
15543               tween[i].call(node, t);
15544             } // Dispatch the end event.
15545
15546
15547             if (self.state === ENDING) {
15548               self.on.call("end", node, node.__data__, self.index, self.group);
15549               stop();
15550             }
15551           }
15552
15553           function stop() {
15554             self.state = ENDED;
15555             self.timer.stop();
15556             delete schedules[id];
15557
15558             for (var i in schedules) {
15559               return;
15560             } // eslint-disable-line no-unused-vars
15561
15562
15563             delete node.__transition;
15564           }
15565         }
15566
15567         function interrupt (node, name) {
15568           var schedules = node.__transition,
15569               schedule,
15570               active,
15571               empty = true,
15572               i;
15573           if (!schedules) return;
15574           name = name == null ? null : name + "";
15575
15576           for (i in schedules) {
15577             if ((schedule = schedules[i]).name !== name) {
15578               empty = false;
15579               continue;
15580             }
15581
15582             active = schedule.state > STARTING && schedule.state < ENDING;
15583             schedule.state = ENDED;
15584             schedule.timer.stop();
15585             schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
15586             delete schedules[i];
15587           }
15588
15589           if (empty) delete node.__transition;
15590         }
15591
15592         function selection_interrupt (name) {
15593           return this.each(function () {
15594             interrupt(this, name);
15595           });
15596         }
15597
15598         function tweenRemove(id, name) {
15599           var tween0, tween1;
15600           return function () {
15601             var schedule = set$4(this, id),
15602                 tween = schedule.tween; // If this node shared tween with the previous node,
15603             // just assign the updated shared tween and we’re done!
15604             // Otherwise, copy-on-write.
15605
15606             if (tween !== tween0) {
15607               tween1 = tween0 = tween;
15608
15609               for (var i = 0, n = tween1.length; i < n; ++i) {
15610                 if (tween1[i].name === name) {
15611                   tween1 = tween1.slice();
15612                   tween1.splice(i, 1);
15613                   break;
15614                 }
15615               }
15616             }
15617
15618             schedule.tween = tween1;
15619           };
15620         }
15621
15622         function tweenFunction(id, name, value) {
15623           var tween0, tween1;
15624           if (typeof value !== "function") throw new Error();
15625           return function () {
15626             var schedule = set$4(this, id),
15627                 tween = schedule.tween; // If this node shared tween with the previous node,
15628             // just assign the updated shared tween and we’re done!
15629             // Otherwise, copy-on-write.
15630
15631             if (tween !== tween0) {
15632               tween1 = (tween0 = tween).slice();
15633
15634               for (var t = {
15635                 name: name,
15636                 value: value
15637               }, i = 0, n = tween1.length; i < n; ++i) {
15638                 if (tween1[i].name === name) {
15639                   tween1[i] = t;
15640                   break;
15641                 }
15642               }
15643
15644               if (i === n) tween1.push(t);
15645             }
15646
15647             schedule.tween = tween1;
15648           };
15649         }
15650
15651         function transition_tween (name, value) {
15652           var id = this._id;
15653           name += "";
15654
15655           if (arguments.length < 2) {
15656             var tween = get$4(this.node(), id).tween;
15657
15658             for (var i = 0, n = tween.length, t; i < n; ++i) {
15659               if ((t = tween[i]).name === name) {
15660                 return t.value;
15661               }
15662             }
15663
15664             return null;
15665           }
15666
15667           return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
15668         }
15669         function tweenValue(transition, name, value) {
15670           var id = transition._id;
15671           transition.each(function () {
15672             var schedule = set$4(this, id);
15673             (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
15674           });
15675           return function (node) {
15676             return get$4(node, id).value[name];
15677           };
15678         }
15679
15680         function interpolate$1 (a, b) {
15681           var c;
15682           return (typeof b === "number" ? d3_interpolateNumber : b instanceof color ? d3_interpolateRgb : (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString)(a, b);
15683         }
15684
15685         function attrRemove$1(name) {
15686           return function () {
15687             this.removeAttribute(name);
15688           };
15689         }
15690
15691         function attrRemoveNS$1(fullname) {
15692           return function () {
15693             this.removeAttributeNS(fullname.space, fullname.local);
15694           };
15695         }
15696
15697         function attrConstant$1(name, interpolate, value1) {
15698           var string00,
15699               string1 = value1 + "",
15700               interpolate0;
15701           return function () {
15702             var string0 = this.getAttribute(name);
15703             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
15704           };
15705         }
15706
15707         function attrConstantNS$1(fullname, interpolate, value1) {
15708           var string00,
15709               string1 = value1 + "",
15710               interpolate0;
15711           return function () {
15712             var string0 = this.getAttributeNS(fullname.space, fullname.local);
15713             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
15714           };
15715         }
15716
15717         function attrFunction$1(name, interpolate, value) {
15718           var string00, string10, interpolate0;
15719           return function () {
15720             var string0,
15721                 value1 = value(this),
15722                 string1;
15723             if (value1 == null) return void this.removeAttribute(name);
15724             string0 = this.getAttribute(name);
15725             string1 = value1 + "";
15726             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
15727           };
15728         }
15729
15730         function attrFunctionNS$1(fullname, interpolate, value) {
15731           var string00, string10, interpolate0;
15732           return function () {
15733             var string0,
15734                 value1 = value(this),
15735                 string1;
15736             if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
15737             string0 = this.getAttributeNS(fullname.space, fullname.local);
15738             string1 = value1 + "";
15739             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
15740           };
15741         }
15742
15743         function transition_attr (name, value) {
15744           var fullname = namespace(name),
15745               i = fullname === "transform" ? interpolateTransformSvg : interpolate$1;
15746           return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname) : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value));
15747         }
15748
15749         function attrInterpolate(name, i) {
15750           return function (t) {
15751             this.setAttribute(name, i.call(this, t));
15752           };
15753         }
15754
15755         function attrInterpolateNS(fullname, i) {
15756           return function (t) {
15757             this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));
15758           };
15759         }
15760
15761         function attrTweenNS(fullname, value) {
15762           var t0, i0;
15763
15764           function tween() {
15765             var i = value.apply(this, arguments);
15766             if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
15767             return t0;
15768           }
15769
15770           tween._value = value;
15771           return tween;
15772         }
15773
15774         function attrTween(name, value) {
15775           var t0, i0;
15776
15777           function tween() {
15778             var i = value.apply(this, arguments);
15779             if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
15780             return t0;
15781           }
15782
15783           tween._value = value;
15784           return tween;
15785         }
15786
15787         function transition_attrTween (name, value) {
15788           var key = "attr." + name;
15789           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
15790           if (value == null) return this.tween(key, null);
15791           if (typeof value !== "function") throw new Error();
15792           var fullname = namespace(name);
15793           return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
15794         }
15795
15796         function delayFunction(id, value) {
15797           return function () {
15798             init(this, id).delay = +value.apply(this, arguments);
15799           };
15800         }
15801
15802         function delayConstant(id, value) {
15803           return value = +value, function () {
15804             init(this, id).delay = value;
15805           };
15806         }
15807
15808         function transition_delay (value) {
15809           var id = this._id;
15810           return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id, value)) : get$4(this.node(), id).delay;
15811         }
15812
15813         function durationFunction(id, value) {
15814           return function () {
15815             set$4(this, id).duration = +value.apply(this, arguments);
15816           };
15817         }
15818
15819         function durationConstant(id, value) {
15820           return value = +value, function () {
15821             set$4(this, id).duration = value;
15822           };
15823         }
15824
15825         function transition_duration (value) {
15826           var id = this._id;
15827           return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id, value)) : get$4(this.node(), id).duration;
15828         }
15829
15830         function easeConstant(id, value) {
15831           if (typeof value !== "function") throw new Error();
15832           return function () {
15833             set$4(this, id).ease = value;
15834           };
15835         }
15836
15837         function transition_ease (value) {
15838           var id = this._id;
15839           return arguments.length ? this.each(easeConstant(id, value)) : get$4(this.node(), id).ease;
15840         }
15841
15842         function easeVarying(id, value) {
15843           return function () {
15844             var v = value.apply(this, arguments);
15845             if (typeof v !== "function") throw new Error();
15846             set$4(this, id).ease = v;
15847           };
15848         }
15849
15850         function transition_easeVarying (value) {
15851           if (typeof value !== "function") throw new Error();
15852           return this.each(easeVarying(this._id, value));
15853         }
15854
15855         function transition_filter (match) {
15856           if (typeof match !== "function") match = matcher(match);
15857
15858           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
15859             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
15860               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
15861                 subgroup.push(node);
15862               }
15863             }
15864           }
15865
15866           return new Transition(subgroups, this._parents, this._name, this._id);
15867         }
15868
15869         function transition_merge (transition) {
15870           if (transition._id !== this._id) throw new Error();
15871
15872           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) {
15873             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
15874               if (node = group0[i] || group1[i]) {
15875                 merge[i] = node;
15876               }
15877             }
15878           }
15879
15880           for (; j < m0; ++j) {
15881             merges[j] = groups0[j];
15882           }
15883
15884           return new Transition(merges, this._parents, this._name, this._id);
15885         }
15886
15887         function start(name) {
15888           return (name + "").trim().split(/^|\s+/).every(function (t) {
15889             var i = t.indexOf(".");
15890             if (i >= 0) t = t.slice(0, i);
15891             return !t || t === "start";
15892           });
15893         }
15894
15895         function onFunction(id, name, listener) {
15896           var on0,
15897               on1,
15898               sit = start(name) ? init : set$4;
15899           return function () {
15900             var schedule = sit(this, id),
15901                 on = schedule.on; // If this node shared a dispatch with the previous node,
15902             // just assign the updated shared dispatch and we’re done!
15903             // Otherwise, copy-on-write.
15904
15905             if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
15906             schedule.on = on1;
15907           };
15908         }
15909
15910         function transition_on (name, listener) {
15911           var id = this._id;
15912           return arguments.length < 2 ? get$4(this.node(), id).on.on(name) : this.each(onFunction(id, name, listener));
15913         }
15914
15915         function removeFunction(id) {
15916           return function () {
15917             var parent = this.parentNode;
15918
15919             for (var i in this.__transition) {
15920               if (+i !== id) return;
15921             }
15922
15923             if (parent) parent.removeChild(this);
15924           };
15925         }
15926
15927         function transition_remove () {
15928           return this.on("end.remove", removeFunction(this._id));
15929         }
15930
15931         function transition_select (select) {
15932           var name = this._name,
15933               id = this._id;
15934           if (typeof select !== "function") select = selector(select);
15935
15936           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
15937             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
15938               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
15939                 if ("__data__" in node) subnode.__data__ = node.__data__;
15940                 subgroup[i] = subnode;
15941                 schedule(subgroup[i], name, id, i, subgroup, get$4(node, id));
15942               }
15943             }
15944           }
15945
15946           return new Transition(subgroups, this._parents, name, id);
15947         }
15948
15949         function transition_selectAll (select) {
15950           var name = this._name,
15951               id = this._id;
15952           if (typeof select !== "function") select = selectorAll(select);
15953
15954           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
15955             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
15956               if (node = group[i]) {
15957                 for (var children = select.call(node, node.__data__, i, group), child, inherit = get$4(node, id), k = 0, l = children.length; k < l; ++k) {
15958                   if (child = children[k]) {
15959                     schedule(child, name, id, k, children, inherit);
15960                   }
15961                 }
15962
15963                 subgroups.push(children);
15964                 parents.push(node);
15965               }
15966             }
15967           }
15968
15969           return new Transition(subgroups, parents, name, id);
15970         }
15971
15972         var Selection$1 = selection.prototype.constructor;
15973         function transition_selection () {
15974           return new Selection$1(this._groups, this._parents);
15975         }
15976
15977         function styleNull(name, interpolate) {
15978           var string00, string10, interpolate0;
15979           return function () {
15980             var string0 = styleValue(this, name),
15981                 string1 = (this.style.removeProperty(name), styleValue(this, name));
15982             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
15983           };
15984         }
15985
15986         function styleRemove$1(name) {
15987           return function () {
15988             this.style.removeProperty(name);
15989           };
15990         }
15991
15992         function styleConstant$1(name, interpolate, value1) {
15993           var string00,
15994               string1 = value1 + "",
15995               interpolate0;
15996           return function () {
15997             var string0 = styleValue(this, name);
15998             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
15999           };
16000         }
16001
16002         function styleFunction$1(name, interpolate, value) {
16003           var string00, string10, interpolate0;
16004           return function () {
16005             var string0 = styleValue(this, name),
16006                 value1 = value(this),
16007                 string1 = value1 + "";
16008             if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
16009             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16010           };
16011         }
16012
16013         function styleMaybeRemove(id, name) {
16014           var on0,
16015               on1,
16016               listener0,
16017               key = "style." + name,
16018               event = "end." + key,
16019               remove;
16020           return function () {
16021             var schedule = set$4(this, id),
16022                 on = schedule.on,
16023                 listener = schedule.value[key] == null ? remove || (remove = styleRemove$1(name)) : undefined; // If this node shared a dispatch with the previous node,
16024             // just assign the updated shared dispatch and we’re done!
16025             // Otherwise, copy-on-write.
16026
16027             if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
16028             schedule.on = on1;
16029           };
16030         }
16031
16032         function transition_style (name, value, priority) {
16033           var i = (name += "") === "transform" ? interpolateTransformCss : interpolate$1;
16034           return value == null ? this.styleTween(name, styleNull(name, i)).on("end.style." + name, styleRemove$1(name)) : typeof value === "function" ? this.styleTween(name, styleFunction$1(name, i, tweenValue(this, "style." + name, value))).each(styleMaybeRemove(this._id, name)) : this.styleTween(name, styleConstant$1(name, i, value), priority).on("end.style." + name, null);
16035         }
16036
16037         function styleInterpolate(name, i, priority) {
16038           return function (t) {
16039             this.style.setProperty(name, i.call(this, t), priority);
16040           };
16041         }
16042
16043         function styleTween(name, value, priority) {
16044           var t, i0;
16045
16046           function tween() {
16047             var i = value.apply(this, arguments);
16048             if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);
16049             return t;
16050           }
16051
16052           tween._value = value;
16053           return tween;
16054         }
16055
16056         function transition_styleTween (name, value, priority) {
16057           var key = "style." + (name += "");
16058           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
16059           if (value == null) return this.tween(key, null);
16060           if (typeof value !== "function") throw new Error();
16061           return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
16062         }
16063
16064         function textConstant$1(value) {
16065           return function () {
16066             this.textContent = value;
16067           };
16068         }
16069
16070         function textFunction$1(value) {
16071           return function () {
16072             var value1 = value(this);
16073             this.textContent = value1 == null ? "" : value1;
16074           };
16075         }
16076
16077         function transition_text (value) {
16078           return this.tween("text", typeof value === "function" ? textFunction$1(tweenValue(this, "text", value)) : textConstant$1(value == null ? "" : value + ""));
16079         }
16080
16081         function textInterpolate(i) {
16082           return function (t) {
16083             this.textContent = i.call(this, t);
16084           };
16085         }
16086
16087         function textTween(value) {
16088           var t0, i0;
16089
16090           function tween() {
16091             var i = value.apply(this, arguments);
16092             if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
16093             return t0;
16094           }
16095
16096           tween._value = value;
16097           return tween;
16098         }
16099
16100         function transition_textTween (value) {
16101           var key = "text";
16102           if (arguments.length < 1) return (key = this.tween(key)) && key._value;
16103           if (value == null) return this.tween(key, null);
16104           if (typeof value !== "function") throw new Error();
16105           return this.tween(key, textTween(value));
16106         }
16107
16108         function transition_transition () {
16109           var name = this._name,
16110               id0 = this._id,
16111               id1 = newId();
16112
16113           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16114             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16115               if (node = group[i]) {
16116                 var inherit = get$4(node, id0);
16117                 schedule(node, name, id1, i, group, {
16118                   time: inherit.time + inherit.delay + inherit.duration,
16119                   delay: 0,
16120                   duration: inherit.duration,
16121                   ease: inherit.ease
16122                 });
16123               }
16124             }
16125           }
16126
16127           return new Transition(groups, this._parents, name, id1);
16128         }
16129
16130         function transition_end () {
16131           var on0,
16132               on1,
16133               that = this,
16134               id = that._id,
16135               size = that.size();
16136           return new Promise(function (resolve, reject) {
16137             var cancel = {
16138               value: reject
16139             },
16140                 end = {
16141               value: function value() {
16142                 if (--size === 0) resolve();
16143               }
16144             };
16145             that.each(function () {
16146               var schedule = set$4(this, id),
16147                   on = schedule.on; // If this node shared a dispatch with the previous node,
16148               // just assign the updated shared dispatch and we’re done!
16149               // Otherwise, copy-on-write.
16150
16151               if (on !== on0) {
16152                 on1 = (on0 = on).copy();
16153
16154                 on1._.cancel.push(cancel);
16155
16156                 on1._.interrupt.push(cancel);
16157
16158                 on1._.end.push(end);
16159               }
16160
16161               schedule.on = on1;
16162             }); // The selection was empty, resolve end immediately
16163
16164             if (size === 0) resolve();
16165           });
16166         }
16167
16168         var id$1 = 0;
16169         function Transition(groups, parents, name, id) {
16170           this._groups = groups;
16171           this._parents = parents;
16172           this._name = name;
16173           this._id = id;
16174         }
16175         function transition(name) {
16176           return selection().transition(name);
16177         }
16178         function newId() {
16179           return ++id$1;
16180         }
16181         var selection_prototype = selection.prototype;
16182         Transition.prototype = transition.prototype = _defineProperty({
16183           constructor: Transition,
16184           select: transition_select,
16185           selectAll: transition_selectAll,
16186           filter: transition_filter,
16187           merge: transition_merge,
16188           selection: transition_selection,
16189           transition: transition_transition,
16190           call: selection_prototype.call,
16191           nodes: selection_prototype.nodes,
16192           node: selection_prototype.node,
16193           size: selection_prototype.size,
16194           empty: selection_prototype.empty,
16195           each: selection_prototype.each,
16196           on: transition_on,
16197           attr: transition_attr,
16198           attrTween: transition_attrTween,
16199           style: transition_style,
16200           styleTween: transition_styleTween,
16201           text: transition_text,
16202           textTween: transition_textTween,
16203           remove: transition_remove,
16204           tween: transition_tween,
16205           delay: transition_delay,
16206           duration: transition_duration,
16207           ease: transition_ease,
16208           easeVarying: transition_easeVarying,
16209           end: transition_end
16210         }, Symbol.iterator, selection_prototype[Symbol.iterator]);
16211
16212         var linear$1 = function linear(t) {
16213           return +t;
16214         };
16215
16216         function cubicInOut(t) {
16217           return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
16218         }
16219
16220         var defaultTiming = {
16221           time: null,
16222           // Set on use.
16223           delay: 0,
16224           duration: 250,
16225           ease: cubicInOut
16226         };
16227
16228         function inherit(node, id) {
16229           var timing;
16230
16231           while (!(timing = node.__transition) || !(timing = timing[id])) {
16232             if (!(node = node.parentNode)) {
16233               throw new Error("transition ".concat(id, " not found"));
16234             }
16235           }
16236
16237           return timing;
16238         }
16239
16240         function selection_transition (name) {
16241           var id, timing;
16242
16243           if (name instanceof Transition) {
16244             id = name._id, name = name._name;
16245           } else {
16246             id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
16247           }
16248
16249           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16250             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16251               if (node = group[i]) {
16252                 schedule(node, name, id, i, group, timing || inherit(node, id));
16253               }
16254             }
16255           }
16256
16257           return new Transition(groups, this._parents, name, id);
16258         }
16259
16260         selection.prototype.interrupt = selection_interrupt;
16261         selection.prototype.transition = selection_transition;
16262
16263         var constant$3 = (function (x) {
16264           return function () {
16265             return x;
16266           };
16267         });
16268
16269         function ZoomEvent(type, _ref) {
16270           var sourceEvent = _ref.sourceEvent,
16271               target = _ref.target,
16272               transform = _ref.transform,
16273               dispatch = _ref.dispatch;
16274           Object.defineProperties(this, {
16275             type: {
16276               value: type,
16277               enumerable: true,
16278               configurable: true
16279             },
16280             sourceEvent: {
16281               value: sourceEvent,
16282               enumerable: true,
16283               configurable: true
16284             },
16285             target: {
16286               value: target,
16287               enumerable: true,
16288               configurable: true
16289             },
16290             transform: {
16291               value: transform,
16292               enumerable: true,
16293               configurable: true
16294             },
16295             _: {
16296               value: dispatch
16297             }
16298           });
16299         }
16300
16301         function Transform(k, x, y) {
16302           this.k = k;
16303           this.x = x;
16304           this.y = y;
16305         }
16306         Transform.prototype = {
16307           constructor: Transform,
16308           scale: function scale(k) {
16309             return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
16310           },
16311           translate: function translate(x, y) {
16312             return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
16313           },
16314           apply: function apply(point) {
16315             return [point[0] * this.k + this.x, point[1] * this.k + this.y];
16316           },
16317           applyX: function applyX(x) {
16318             return x * this.k + this.x;
16319           },
16320           applyY: function applyY(y) {
16321             return y * this.k + this.y;
16322           },
16323           invert: function invert(location) {
16324             return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
16325           },
16326           invertX: function invertX(x) {
16327             return (x - this.x) / this.k;
16328           },
16329           invertY: function invertY(y) {
16330             return (y - this.y) / this.k;
16331           },
16332           rescaleX: function rescaleX(x) {
16333             return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
16334           },
16335           rescaleY: function rescaleY(y) {
16336             return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
16337           },
16338           toString: function toString() {
16339             return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
16340           }
16341         };
16342         var identity$2 = new Transform(1, 0, 0);
16343
16344         function nopropagation$1(event) {
16345           event.stopImmediatePropagation();
16346         }
16347         function noevent$1 (event) {
16348           event.preventDefault();
16349           event.stopImmediatePropagation();
16350         }
16351
16352         // except for pinch-to-zoom, which is sent as a wheel+ctrlKey event
16353
16354         function defaultFilter$1(event) {
16355           return (!event.ctrlKey || event.type === 'wheel') && !event.button;
16356         }
16357
16358         function defaultExtent() {
16359           var e = this;
16360
16361           if (e instanceof SVGElement) {
16362             e = e.ownerSVGElement || e;
16363
16364             if (e.hasAttribute("viewBox")) {
16365               e = e.viewBox.baseVal;
16366               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
16367             }
16368
16369             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
16370           }
16371
16372           return [[0, 0], [e.clientWidth, e.clientHeight]];
16373         }
16374
16375         function defaultTransform() {
16376           return this.__zoom || identity$2;
16377         }
16378
16379         function defaultWheelDelta(event) {
16380           return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);
16381         }
16382
16383         function defaultTouchable$1() {
16384           return navigator.maxTouchPoints || "ontouchstart" in this;
16385         }
16386
16387         function defaultConstrain(transform, extent, translateExtent) {
16388           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
16389               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
16390               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
16391               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
16392           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));
16393         }
16394
16395         function d3_zoom () {
16396           var filter = defaultFilter$1,
16397               extent = defaultExtent,
16398               constrain = defaultConstrain,
16399               wheelDelta = defaultWheelDelta,
16400               touchable = defaultTouchable$1,
16401               scaleExtent = [0, Infinity],
16402               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
16403               duration = 250,
16404               interpolate = interpolateZoom,
16405               listeners = dispatch("start", "zoom", "end"),
16406               touchstarting,
16407               touchfirst,
16408               touchending,
16409               touchDelay = 500,
16410               wheelDelay = 150,
16411               clickDistance2 = 0,
16412               tapDistance = 10;
16413
16414           function zoom(selection) {
16415             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)");
16416           }
16417
16418           zoom.transform = function (collection, transform, point, event) {
16419             var selection = collection.selection ? collection.selection() : collection;
16420             selection.property("__zoom", defaultTransform);
16421
16422             if (collection !== selection) {
16423               schedule(collection, transform, point, event);
16424             } else {
16425               selection.interrupt().each(function () {
16426                 gesture(this, arguments).event(event).start().zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform).end();
16427               });
16428             }
16429           };
16430
16431           zoom.scaleBy = function (selection, k, p, event) {
16432             zoom.scaleTo(selection, function () {
16433               var k0 = this.__zoom.k,
16434                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16435               return k0 * k1;
16436             }, p, event);
16437           };
16438
16439           zoom.scaleTo = function (selection, k, p, event) {
16440             zoom.transform(selection, function () {
16441               var e = extent.apply(this, arguments),
16442                   t0 = this.__zoom,
16443                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p,
16444                   p1 = t0.invert(p0),
16445                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16446               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
16447             }, p, event);
16448           };
16449
16450           zoom.translateBy = function (selection, x, y, event) {
16451             zoom.transform(selection, function () {
16452               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);
16453             }, null, event);
16454           };
16455
16456           zoom.translateTo = function (selection, x, y, p, event) {
16457             zoom.transform(selection, function () {
16458               var e = extent.apply(this, arguments),
16459                   t = this.__zoom,
16460                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
16461               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);
16462             }, p, event);
16463           };
16464
16465           function scale(transform, k) {
16466             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
16467             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
16468           }
16469
16470           function translate(transform, p0, p1) {
16471             var x = p0[0] - p1[0] * transform.k,
16472                 y = p0[1] - p1[1] * transform.k;
16473             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
16474           }
16475
16476           function centroid(extent) {
16477             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
16478           }
16479
16480           function schedule(transition, transform, point, event) {
16481             transition.on("start.zoom", function () {
16482               gesture(this, arguments).event(event).start();
16483             }).on("interrupt.zoom end.zoom", function () {
16484               gesture(this, arguments).event(event).end();
16485             }).tween("zoom", function () {
16486               var that = this,
16487                   args = arguments,
16488                   g = gesture(that, args).event(event),
16489                   e = extent.apply(that, args),
16490                   p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point,
16491                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
16492                   a = that.__zoom,
16493                   b = typeof transform === "function" ? transform.apply(that, args) : transform,
16494                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
16495               return function (t) {
16496                 if (t === 1) t = b; // Avoid rounding error on end.
16497                 else {
16498                     var l = i(t),
16499                         k = w / l[2];
16500                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
16501                   }
16502                 g.zoom(null, t);
16503               };
16504             });
16505           }
16506
16507           function gesture(that, args, clean) {
16508             return !clean && that.__zooming || new Gesture(that, args);
16509           }
16510
16511           function Gesture(that, args) {
16512             this.that = that;
16513             this.args = args;
16514             this.active = 0;
16515             this.sourceEvent = null;
16516             this.extent = extent.apply(that, args);
16517             this.taps = 0;
16518           }
16519
16520           Gesture.prototype = {
16521             event: function event(_event) {
16522               if (_event) this.sourceEvent = _event;
16523               return this;
16524             },
16525             start: function start() {
16526               if (++this.active === 1) {
16527                 this.that.__zooming = this;
16528                 this.emit("start");
16529               }
16530
16531               return this;
16532             },
16533             zoom: function zoom(key, transform) {
16534               if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
16535               if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
16536               if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
16537               this.that.__zoom = transform;
16538               this.emit("zoom");
16539               return this;
16540             },
16541             end: function end() {
16542               if (--this.active === 0) {
16543                 delete this.that.__zooming;
16544                 this.emit("end");
16545               }
16546
16547               return this;
16548             },
16549             emit: function emit(type) {
16550               var d = select(this.that).datum();
16551               listeners.call(type, this.that, new ZoomEvent(type, {
16552                 sourceEvent: this.sourceEvent,
16553                 target: zoom,
16554                 type: type,
16555                 transform: this.that.__zoom,
16556                 dispatch: listeners
16557               }), d);
16558             }
16559           };
16560
16561           function wheeled(event) {
16562             for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
16563               args[_key - 1] = arguments[_key];
16564             }
16565
16566             if (!filter.apply(this, arguments)) return;
16567             var g = gesture(this, args).event(event),
16568                 t = this.__zoom,
16569                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
16570                 p = pointer(event); // If the mouse is in the same location as before, reuse it.
16571             // If there were recent wheel events, reset the wheel idle timeout.
16572
16573             if (g.wheel) {
16574               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
16575                 g.mouse[1] = t.invert(g.mouse[0] = p);
16576               }
16577
16578               clearTimeout(g.wheel);
16579             } // If this wheel event won’t trigger a transform change, ignore it.
16580             else if (t.k === k) return; // Otherwise, capture the mouse point and location at the start.
16581               else {
16582                   g.mouse = [p, t.invert(p)];
16583                   interrupt(this);
16584                   g.start();
16585                 }
16586
16587             noevent$1(event);
16588             g.wheel = setTimeout(wheelidled, wheelDelay);
16589             g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
16590
16591             function wheelidled() {
16592               g.wheel = null;
16593               g.end();
16594             }
16595           }
16596
16597           function mousedowned(event) {
16598             for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
16599               args[_key2 - 1] = arguments[_key2];
16600             }
16601
16602             if (touchending || !filter.apply(this, arguments)) return;
16603             var g = gesture(this, args, true).event(event),
16604                 v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
16605                 p = pointer(event, currentTarget),
16606                 currentTarget = event.currentTarget,
16607                 x0 = event.clientX,
16608                 y0 = event.clientY;
16609             dragDisable(event.view);
16610             nopropagation$1(event);
16611             g.mouse = [p, this.__zoom.invert(p)];
16612             interrupt(this);
16613             g.start();
16614
16615             function mousemoved(event) {
16616               noevent$1(event);
16617
16618               if (!g.moved) {
16619                 var dx = event.clientX - x0,
16620                     dy = event.clientY - y0;
16621                 g.moved = dx * dx + dy * dy > clickDistance2;
16622               }
16623
16624               g.event(event).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
16625             }
16626
16627             function mouseupped(event) {
16628               v.on("mousemove.zoom mouseup.zoom", null);
16629               yesdrag(event.view, g.moved);
16630               noevent$1(event);
16631               g.event(event).end();
16632             }
16633           }
16634
16635           function dblclicked(event) {
16636             for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
16637               args[_key3 - 1] = arguments[_key3];
16638             }
16639
16640             if (!filter.apply(this, arguments)) return;
16641             var t0 = this.__zoom,
16642                 p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),
16643                 p1 = t0.invert(p0),
16644                 k1 = t0.k * (event.shiftKey ? 0.5 : 2),
16645                 t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
16646             noevent$1(event);
16647             if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);else select(this).call(zoom.transform, t1, p0, event);
16648           }
16649
16650           function touchstarted(event) {
16651             for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
16652               args[_key4 - 1] = arguments[_key4];
16653             }
16654
16655             if (!filter.apply(this, arguments)) return;
16656             var touches = event.touches,
16657                 n = touches.length,
16658                 g = gesture(this, args, event.changedTouches.length === n).event(event),
16659                 started,
16660                 i,
16661                 t,
16662                 p;
16663             nopropagation$1(event);
16664
16665             for (i = 0; i < n; ++i) {
16666               t = touches[i], p = pointer(t, this);
16667               p = [p, this.__zoom.invert(p), t.identifier];
16668               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;
16669             }
16670
16671             if (touchstarting) touchstarting = clearTimeout(touchstarting);
16672
16673             if (started) {
16674               if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function () {
16675                 touchstarting = null;
16676               }, touchDelay);
16677               interrupt(this);
16678               g.start();
16679             }
16680           }
16681
16682           function touchmoved(event) {
16683             if (!this.__zooming) return;
16684
16685             for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
16686               args[_key5 - 1] = arguments[_key5];
16687             }
16688
16689             var g = gesture(this, args).event(event),
16690                 touches = event.changedTouches,
16691                 n = touches.length,
16692                 i,
16693                 t,
16694                 p,
16695                 l;
16696             noevent$1(event);
16697
16698             for (i = 0; i < n; ++i) {
16699               t = touches[i], p = pointer(t, this);
16700               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;
16701             }
16702
16703             t = g.that.__zoom;
16704
16705             if (g.touch1) {
16706               var p0 = g.touch0[0],
16707                   l0 = g.touch0[1],
16708                   p1 = g.touch1[0],
16709                   l1 = g.touch1[1],
16710                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
16711                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
16712               t = scale(t, Math.sqrt(dp / dl));
16713               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
16714               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
16715             } else if (g.touch0) p = g.touch0[0], l = g.touch0[1];else return;
16716
16717             g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
16718           }
16719
16720           function touchended(event) {
16721             for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
16722               args[_key6 - 1] = arguments[_key6];
16723             }
16724
16725             if (!this.__zooming) return;
16726             var g = gesture(this, args).event(event),
16727                 touches = event.changedTouches,
16728                 n = touches.length,
16729                 i,
16730                 t;
16731             nopropagation$1(event);
16732             if (touchending) clearTimeout(touchending);
16733             touchending = setTimeout(function () {
16734               touchending = null;
16735             }, touchDelay);
16736
16737             for (i = 0; i < n; ++i) {
16738               t = touches[i];
16739               if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
16740             }
16741
16742             if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
16743             if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);else {
16744               g.end(); // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.
16745
16746               if (g.taps === 2) {
16747                 t = pointer(t, this);
16748
16749                 if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
16750                   var p = select(this).on("dblclick.zoom");
16751                   if (p) p.apply(this, arguments);
16752                 }
16753               }
16754             }
16755           }
16756
16757           zoom.wheelDelta = function (_) {
16758             return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant$3(+_), zoom) : wheelDelta;
16759           };
16760
16761           zoom.filter = function (_) {
16762             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$3(!!_), zoom) : filter;
16763           };
16764
16765           zoom.touchable = function (_) {
16766             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$3(!!_), zoom) : touchable;
16767           };
16768
16769           zoom.extent = function (_) {
16770             return arguments.length ? (extent = typeof _ === "function" ? _ : constant$3([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
16771           };
16772
16773           zoom.scaleExtent = function (_) {
16774             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
16775           };
16776
16777           zoom.translateExtent = function (_) {
16778             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]]];
16779           };
16780
16781           zoom.constrain = function (_) {
16782             return arguments.length ? (constrain = _, zoom) : constrain;
16783           };
16784
16785           zoom.duration = function (_) {
16786             return arguments.length ? (duration = +_, zoom) : duration;
16787           };
16788
16789           zoom.interpolate = function (_) {
16790             return arguments.length ? (interpolate = _, zoom) : interpolate;
16791           };
16792
16793           zoom.on = function () {
16794             var value = listeners.on.apply(listeners, arguments);
16795             return value === listeners ? zoom : value;
16796           };
16797
16798           zoom.clickDistance = function (_) {
16799             return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
16800           };
16801
16802           zoom.tapDistance = function (_) {
16803             return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
16804           };
16805
16806           return zoom;
16807         }
16808
16809         /*
16810             Bypasses features of D3's default projection stream pipeline that are unnecessary:
16811             * Antimeridian clipping
16812             * Spherical rotation
16813             * Resampling
16814         */
16815
16816         function geoRawMercator() {
16817           var project = mercatorRaw;
16818           var k = 512 / Math.PI; // scale
16819
16820           var x = 0;
16821           var y = 0; // translate
16822
16823           var clipExtent = [[0, 0], [0, 0]];
16824
16825           function projection(point) {
16826             point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
16827             return [point[0] * k + x, y - point[1] * k];
16828           }
16829
16830           projection.invert = function (point) {
16831             point = project.invert((point[0] - x) / k, (y - point[1]) / k);
16832             return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
16833           };
16834
16835           projection.scale = function (_) {
16836             if (!arguments.length) return k;
16837             k = +_;
16838             return projection;
16839           };
16840
16841           projection.translate = function (_) {
16842             if (!arguments.length) return [x, y];
16843             x = +_[0];
16844             y = +_[1];
16845             return projection;
16846           };
16847
16848           projection.clipExtent = function (_) {
16849             if (!arguments.length) return clipExtent;
16850             clipExtent = _;
16851             return projection;
16852           };
16853
16854           projection.transform = function (obj) {
16855             if (!arguments.length) return identity$2.translate(x, y).scale(k);
16856             x = +obj.x;
16857             y = +obj.y;
16858             k = +obj.k;
16859             return projection;
16860           };
16861
16862           projection.stream = d3_geoTransform({
16863             point: function point(x, y) {
16864               var vec = projection([x, y]);
16865               this.stream.point(vec[0], vec[1]);
16866             }
16867           }).stream;
16868           return projection;
16869         }
16870
16871         function geoOrthoNormalizedDotProduct(a, b, origin) {
16872           if (geoVecEqual(origin, a) || geoVecEqual(origin, b)) {
16873             return 1; // coincident points, treat as straight and try to remove
16874           }
16875
16876           return geoVecNormalizedDot(a, b, origin);
16877         }
16878
16879         function geoOrthoFilterDotProduct(dotp, epsilon, lowerThreshold, upperThreshold, allowStraightAngles) {
16880           var val = Math.abs(dotp);
16881
16882           if (val < epsilon) {
16883             return 0; // already orthogonal
16884           } else if (allowStraightAngles && Math.abs(val - 1) < epsilon) {
16885             return 0; // straight angle, which is okay in this case
16886           } else if (val < lowerThreshold || val > upperThreshold) {
16887             return dotp; // can be adjusted
16888           } else {
16889             return null; // ignore vertex
16890           }
16891         }
16892
16893         function geoOrthoCalcScore(points, isClosed, epsilon, threshold) {
16894           var score = 0;
16895           var first = isClosed ? 0 : 1;
16896           var last = isClosed ? points.length : points.length - 1;
16897           var coords = points.map(function (p) {
16898             return p.coord;
16899           });
16900           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
16901           var upperThreshold = Math.cos(threshold * Math.PI / 180);
16902
16903           for (var i = first; i < last; i++) {
16904             var a = coords[(i - 1 + coords.length) % coords.length];
16905             var origin = coords[i];
16906             var b = coords[(i + 1) % coords.length];
16907             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold);
16908             if (dotp === null) continue; // ignore vertex
16909
16910             score = score + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
16911           }
16912
16913           return score;
16914         } // returns the maximum angle less than `lessThan` between the actual corner and a 0° or 90° corner
16915
16916         function geoOrthoMaxOffsetAngle(coords, isClosed, lessThan) {
16917           var max = -Infinity;
16918           var first = isClosed ? 0 : 1;
16919           var last = isClosed ? coords.length : coords.length - 1;
16920
16921           for (var i = first; i < last; i++) {
16922             var a = coords[(i - 1 + coords.length) % coords.length];
16923             var origin = coords[i];
16924             var b = coords[(i + 1) % coords.length];
16925             var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin);
16926             var angle = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
16927             if (angle > 45) angle = 90 - angle;
16928             if (angle >= lessThan) continue;
16929             if (angle > max) max = angle;
16930           }
16931
16932           if (max === -Infinity) return null;
16933           return max;
16934         } // similar to geoOrthoCalcScore, but returns quickly if there is something to do
16935
16936         function geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles) {
16937           var score = null;
16938           var first = isClosed ? 0 : 1;
16939           var last = isClosed ? coords.length : coords.length - 1;
16940           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
16941           var upperThreshold = Math.cos(threshold * Math.PI / 180);
16942
16943           for (var i = first; i < last; i++) {
16944             var a = coords[(i - 1 + coords.length) % coords.length];
16945             var origin = coords[i];
16946             var b = coords[(i + 1) % coords.length];
16947             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold, allowStraightAngles);
16948             if (dotp === null) continue; // ignore vertex
16949
16950             if (Math.abs(dotp) > 0) return 1; // something to do
16951
16952             score = 0; // already square
16953           }
16954
16955           return score;
16956         }
16957
16958         var onFreeze = internalMetadata.onFreeze;
16959
16960         var nativeFreeze = Object.freeze;
16961         var FAILS_ON_PRIMITIVES$4 = fails(function () { nativeFreeze(1); });
16962
16963         // `Object.freeze` method
16964         // https://tc39.github.io/ecma262/#sec-object.freeze
16965         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$4, sham: !freezing }, {
16966           freeze: function freeze(it) {
16967             return nativeFreeze && isObject(it) ? nativeFreeze(onFreeze(it)) : it;
16968           }
16969         });
16970
16971         // Returns true if a and b have the same elements at the same indices.
16972         function utilArrayIdentical(a, b) {
16973           // an array is always identical to itself
16974           if (a === b) return true;
16975           var i = a.length;
16976           if (i !== b.length) return false;
16977
16978           while (i--) {
16979             if (a[i] !== b[i]) return false;
16980           }
16981
16982           return true;
16983         } // http://2ality.com/2015/01/es6-set-operations.html
16984         // Difference (a \ b): create a set that contains those elements of set a that are not in set b.
16985         // This operation is also sometimes called minus (-).
16986         // var a = [1,2,3];
16987         // var b = [4,3,2];
16988         // utilArrayDifference(a, b)
16989         //   [1]
16990         // utilArrayDifference(b, a)
16991         //   [4]
16992
16993         function utilArrayDifference(a, b) {
16994           var other = new Set(b);
16995           return Array.from(new Set(a)).filter(function (v) {
16996             return !other.has(v);
16997           });
16998         } // Intersection (a ∩ b): create a set that contains those elements of set a that are also in set b.
16999         // var a = [1,2,3];
17000         // var b = [4,3,2];
17001         // utilArrayIntersection(a, b)
17002         //   [2,3]
17003
17004         function utilArrayIntersection(a, b) {
17005           var other = new Set(b);
17006           return Array.from(new Set(a)).filter(function (v) {
17007             return other.has(v);
17008           });
17009         } // Union (a ∪ b): create a set that contains the elements of both set a and set b.
17010         // var a = [1,2,3];
17011         // var b = [4,3,2];
17012         // utilArrayUnion(a, b)
17013         //   [1,2,3,4]
17014
17015         function utilArrayUnion(a, b) {
17016           var result = new Set(a);
17017           b.forEach(function (v) {
17018             result.add(v);
17019           });
17020           return Array.from(result);
17021         } // Returns an Array with all the duplicates removed
17022         // var a = [1,1,2,3,3];
17023         // utilArrayUniq(a)
17024         //   [1,2,3]
17025
17026         function utilArrayUniq(a) {
17027           return Array.from(new Set(a));
17028         } // Splits array into chunks of given chunk size
17029         // var a = [1,2,3,4,5,6,7];
17030         // utilArrayChunk(a, 3);
17031         //   [[1,2,3],[4,5,6],[7]];
17032
17033         function utilArrayChunk(a, chunkSize) {
17034           if (!chunkSize || chunkSize < 0) return [a.slice()];
17035           var result = new Array(Math.ceil(a.length / chunkSize));
17036           return Array.from(result, function (item, i) {
17037             return a.slice(i * chunkSize, i * chunkSize + chunkSize);
17038           });
17039         } // Flattens two level array into a single level
17040         // var a = [[1,2,3],[4,5,6],[7]];
17041         // utilArrayFlatten(a);
17042         //   [1,2,3,4,5,6,7];
17043
17044         function utilArrayFlatten(a) {
17045           return a.reduce(function (acc, val) {
17046             return acc.concat(val);
17047           }, []);
17048         } // Groups the items of the Array according to the given key
17049         // `key` can be passed as a property or as a key function
17050         //
17051         // var pets = [
17052         //     { type: 'Dog', name: 'Spot' },
17053         //     { type: 'Cat', name: 'Tiger' },
17054         //     { type: 'Dog', name: 'Rover' },
17055         //     { type: 'Cat', name: 'Leo' }
17056         // ];
17057         //
17058         // utilArrayGroupBy(pets, 'type')
17059         //   {
17060         //     'Dog': [{type: 'Dog', name: 'Spot'}, {type: 'Dog', name: 'Rover'}],
17061         //     'Cat': [{type: 'Cat', name: 'Tiger'}, {type: 'Cat', name: 'Leo'}]
17062         //   }
17063         //
17064         // utilArrayGroupBy(pets, function(item) { return item.name.length; })
17065         //   {
17066         //     3: [{type: 'Cat', name: 'Leo'}],
17067         //     4: [{type: 'Dog', name: 'Spot'}],
17068         //     5: [{type: 'Cat', name: 'Tiger'}, {type: 'Dog', name: 'Rover'}]
17069         //   }
17070
17071         function utilArrayGroupBy(a, key) {
17072           return a.reduce(function (acc, item) {
17073             var group = typeof key === 'function' ? key(item) : item[key];
17074             (acc[group] = acc[group] || []).push(item);
17075             return acc;
17076           }, {});
17077         } // Returns an Array with all the duplicates removed
17078         // where uniqueness determined by the given key
17079         // `key` can be passed as a property or as a key function
17080         //
17081         // var pets = [
17082         //     { type: 'Dog', name: 'Spot' },
17083         //     { type: 'Cat', name: 'Tiger' },
17084         //     { type: 'Dog', name: 'Rover' },
17085         //     { type: 'Cat', name: 'Leo' }
17086         // ];
17087         //
17088         // utilArrayUniqBy(pets, 'type')
17089         //   [
17090         //     { type: 'Dog', name: 'Spot' },
17091         //     { type: 'Cat', name: 'Tiger' }
17092         //   ]
17093         //
17094         // utilArrayUniqBy(pets, function(item) { return item.name.length; })
17095         //   [
17096         //     { type: 'Dog', name: 'Spot' },
17097         //     { type: 'Cat', name: 'Tiger' },
17098         //     { type: 'Cat', name: 'Leo' }
17099         //   }
17100
17101         function utilArrayUniqBy(a, key) {
17102           var seen = new Set();
17103           return a.reduce(function (acc, item) {
17104             var val = typeof key === 'function' ? key(item) : item[key];
17105
17106             if (val && !seen.has(val)) {
17107               seen.add(val);
17108               acc.push(item);
17109             }
17110
17111             return acc;
17112           }, []);
17113         }
17114
17115         // @@match logic
17116         fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
17117           return [
17118             // `String.prototype.match` method
17119             // https://tc39.github.io/ecma262/#sec-string.prototype.match
17120             function match(regexp) {
17121               var O = requireObjectCoercible(this);
17122               var matcher = regexp == undefined ? undefined : regexp[MATCH];
17123               return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
17124             },
17125             // `RegExp.prototype[@@match]` method
17126             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@match
17127             function (regexp) {
17128               var res = maybeCallNative(nativeMatch, regexp, this);
17129               if (res.done) return res.value;
17130
17131               var rx = anObject(regexp);
17132               var S = String(this);
17133
17134               if (!rx.global) return regexpExecAbstract(rx, S);
17135
17136               var fullUnicode = rx.unicode;
17137               rx.lastIndex = 0;
17138               var A = [];
17139               var n = 0;
17140               var result;
17141               while ((result = regexpExecAbstract(rx, S)) !== null) {
17142                 var matchStr = String(result[0]);
17143                 A[n] = matchStr;
17144                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
17145                 n++;
17146               }
17147               return n === 0 ? null : A;
17148             }
17149           ];
17150         });
17151
17152         var remove$1 = removeDiacritics;
17153         var replacementList = [{
17154           base: ' ',
17155           chars: "\xA0"
17156         }, {
17157           base: '0',
17158           chars: "\u07C0"
17159         }, {
17160           base: 'A',
17161           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"
17162         }, {
17163           base: 'AA',
17164           chars: "\uA732"
17165         }, {
17166           base: 'AE',
17167           chars: "\xC6\u01FC\u01E2"
17168         }, {
17169           base: 'AO',
17170           chars: "\uA734"
17171         }, {
17172           base: 'AU',
17173           chars: "\uA736"
17174         }, {
17175           base: 'AV',
17176           chars: "\uA738\uA73A"
17177         }, {
17178           base: 'AY',
17179           chars: "\uA73C"
17180         }, {
17181           base: 'B',
17182           chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181"
17183         }, {
17184           base: 'C',
17185           chars: "\u24B8\uFF23\uA73E\u1E08\u0106C\u0108\u010A\u010C\xC7\u0187\u023B"
17186         }, {
17187           base: 'D',
17188           chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779"
17189         }, {
17190           base: 'Dh',
17191           chars: "\xD0"
17192         }, {
17193           base: 'DZ',
17194           chars: "\u01F1\u01C4"
17195         }, {
17196           base: 'Dz',
17197           chars: "\u01F2\u01C5"
17198         }, {
17199           base: 'E',
17200           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"
17201         }, {
17202           base: 'F',
17203           chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B"
17204         }, {
17205           base: 'G',
17206           chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262"
17207         }, {
17208           base: 'H',
17209           chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"
17210         }, {
17211           base: 'I',
17212           chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"
17213         }, {
17214           base: 'J',
17215           chars: "\u24BF\uFF2A\u0134\u0248\u0237"
17216         }, {
17217           base: 'K',
17218           chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"
17219         }, {
17220           base: 'L',
17221           chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"
17222         }, {
17223           base: 'LJ',
17224           chars: "\u01C7"
17225         }, {
17226           base: 'Lj',
17227           chars: "\u01C8"
17228         }, {
17229           base: 'M',
17230           chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB"
17231         }, {
17232           base: 'N',
17233           chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E"
17234         }, {
17235           base: 'NJ',
17236           chars: "\u01CA"
17237         }, {
17238           base: 'Nj',
17239           chars: "\u01CB"
17240         }, {
17241           base: 'O',
17242           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"
17243         }, {
17244           base: 'OE',
17245           chars: "\u0152"
17246         }, {
17247           base: 'OI',
17248           chars: "\u01A2"
17249         }, {
17250           base: 'OO',
17251           chars: "\uA74E"
17252         }, {
17253           base: 'OU',
17254           chars: "\u0222"
17255         }, {
17256           base: 'P',
17257           chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"
17258         }, {
17259           base: 'Q',
17260           chars: "\u24C6\uFF31\uA756\uA758\u024A"
17261         }, {
17262           base: 'R',
17263           chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"
17264         }, {
17265           base: 'S',
17266           chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"
17267         }, {
17268           base: 'T',
17269           chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"
17270         }, {
17271           base: 'Th',
17272           chars: "\xDE"
17273         }, {
17274           base: 'TZ',
17275           chars: "\uA728"
17276         }, {
17277           base: 'U',
17278           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"
17279         }, {
17280           base: 'V',
17281           chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"
17282         }, {
17283           base: 'VY',
17284           chars: "\uA760"
17285         }, {
17286           base: 'W',
17287           chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"
17288         }, {
17289           base: 'X',
17290           chars: "\u24CD\uFF38\u1E8A\u1E8C"
17291         }, {
17292           base: 'Y',
17293           chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"
17294         }, {
17295           base: 'Z',
17296           chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"
17297         }, {
17298           base: 'a',
17299           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"
17300         }, {
17301           base: 'aa',
17302           chars: "\uA733"
17303         }, {
17304           base: 'ae',
17305           chars: "\xE6\u01FD\u01E3"
17306         }, {
17307           base: 'ao',
17308           chars: "\uA735"
17309         }, {
17310           base: 'au',
17311           chars: "\uA737"
17312         }, {
17313           base: 'av',
17314           chars: "\uA739\uA73B"
17315         }, {
17316           base: 'ay',
17317           chars: "\uA73D"
17318         }, {
17319           base: 'b',
17320           chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182"
17321         }, {
17322           base: 'c',
17323           chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\xE7\u1E09\u0188\u023C\uA73F\u2184"
17324         }, {
17325           base: 'd',
17326           chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA"
17327         }, {
17328           base: 'dh',
17329           chars: "\xF0"
17330         }, {
17331           base: 'dz',
17332           chars: "\u01F3\u01C6"
17333         }, {
17334           base: 'e',
17335           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"
17336         }, {
17337           base: 'f',
17338           chars: "\u24D5\uFF46\u1E1F\u0192"
17339         }, {
17340           base: 'ff',
17341           chars: "\uFB00"
17342         }, {
17343           base: 'fi',
17344           chars: "\uFB01"
17345         }, {
17346           base: 'fl',
17347           chars: "\uFB02"
17348         }, {
17349           base: 'ffi',
17350           chars: "\uFB03"
17351         }, {
17352           base: 'ffl',
17353           chars: "\uFB04"
17354         }, {
17355           base: 'g',
17356           chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79"
17357         }, {
17358           base: 'h',
17359           chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"
17360         }, {
17361           base: 'hv',
17362           chars: "\u0195"
17363         }, {
17364           base: 'i',
17365           chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"
17366         }, {
17367           base: 'j',
17368           chars: "\u24D9\uFF4A\u0135\u01F0\u0249"
17369         }, {
17370           base: 'k',
17371           chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"
17372         }, {
17373           base: 'l',
17374           chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D"
17375         }, {
17376           base: 'lj',
17377           chars: "\u01C9"
17378         }, {
17379           base: 'm',
17380           chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"
17381         }, {
17382           base: 'n',
17383           chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509"
17384         }, {
17385           base: 'nj',
17386           chars: "\u01CC"
17387         }, {
17388           base: 'o',
17389           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"
17390         }, {
17391           base: 'oe',
17392           chars: "\u0153"
17393         }, {
17394           base: 'oi',
17395           chars: "\u01A3"
17396         }, {
17397           base: 'oo',
17398           chars: "\uA74F"
17399         }, {
17400           base: 'ou',
17401           chars: "\u0223"
17402         }, {
17403           base: 'p',
17404           chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1"
17405         }, {
17406           base: 'q',
17407           chars: "\u24E0\uFF51\u024B\uA757\uA759"
17408         }, {
17409           base: 'r',
17410           chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"
17411         }, {
17412           base: 's',
17413           chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282"
17414         }, {
17415           base: 'ss',
17416           chars: "\xDF"
17417         }, {
17418           base: 't',
17419           chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"
17420         }, {
17421           base: 'th',
17422           chars: "\xFE"
17423         }, {
17424           base: 'tz',
17425           chars: "\uA729"
17426         }, {
17427           base: 'u',
17428           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"
17429         }, {
17430           base: 'v',
17431           chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"
17432         }, {
17433           base: 'vy',
17434           chars: "\uA761"
17435         }, {
17436           base: 'w',
17437           chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"
17438         }, {
17439           base: 'x',
17440           chars: "\u24E7\uFF58\u1E8B\u1E8D"
17441         }, {
17442           base: 'y',
17443           chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"
17444         }, {
17445           base: 'z',
17446           chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"
17447         }];
17448         var diacriticsMap = {};
17449
17450         for (var i = 0; i < replacementList.length; i += 1) {
17451           var chars = replacementList[i].chars;
17452
17453           for (var j$1 = 0; j$1 < chars.length; j$1 += 1) {
17454             diacriticsMap[chars[j$1]] = replacementList[i].base;
17455           }
17456         }
17457
17458         function removeDiacritics(str) {
17459           return str.replace(/[^\u0000-\u007e]/g, function (c) {
17460             return diacriticsMap[c] || c;
17461           });
17462         }
17463
17464         var replacementList_1 = replacementList;
17465         var diacriticsMap_1 = diacriticsMap;
17466         var diacritics = {
17467           remove: remove$1,
17468           replacementList: replacementList_1,
17469           diacriticsMap: diacriticsMap_1
17470         };
17471
17472         var isArabic_1 = createCommonjsModule(function (module, exports) {
17473
17474           Object.defineProperty(exports, "__esModule", {
17475             value: true
17476           });
17477           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
17478           ];
17479
17480           function isArabic(_char) {
17481             if (_char.length > 1) {
17482               // allow the newer chars?
17483               throw new Error('isArabic works on only one-character strings');
17484             }
17485
17486             var code = _char.charCodeAt(0);
17487
17488             for (var i = 0; i < arabicBlocks.length; i++) {
17489               var block = arabicBlocks[i];
17490
17491               if (code >= block[0] && code <= block[1]) {
17492                 return true;
17493               }
17494             }
17495
17496             return false;
17497           }
17498
17499           exports.isArabic = isArabic;
17500
17501           function isMath(_char2) {
17502             if (_char2.length > 2) {
17503               // allow the newer chars?
17504               throw new Error('isMath works on only one-character strings');
17505             }
17506
17507             var code = _char2.charCodeAt(0);
17508
17509             return code >= 0x660 && code <= 0x66C || code >= 0x6F0 && code <= 0x6F9;
17510           }
17511
17512           exports.isMath = isMath;
17513         });
17514
17515         var unicodeArabic = createCommonjsModule(function (module, exports) {
17516
17517           Object.defineProperty(exports, "__esModule", {
17518             value: true
17519           });
17520           var arabicReference = {
17521             "alef": {
17522               "normal": ["\u0627"],
17523               "madda_above": {
17524                 "normal": ["\u0627\u0653", "\u0622"],
17525                 "isolated": "\uFE81",
17526                 "final": "\uFE82"
17527               },
17528               "hamza_above": {
17529                 "normal": ["\u0627\u0654", "\u0623"],
17530                 "isolated": "\uFE83",
17531                 "final": "\uFE84"
17532               },
17533               "hamza_below": {
17534                 "normal": ["\u0627\u0655", "\u0625"],
17535                 "isolated": "\uFE87",
17536                 "final": "\uFE88"
17537               },
17538               "wasla": {
17539                 "normal": "\u0671",
17540                 "isolated": "\uFB50",
17541                 "final": "\uFB51"
17542               },
17543               "wavy_hamza_above": ["\u0672"],
17544               "wavy_hamza_below": ["\u0627\u065F", "\u0673"],
17545               "high_hamza": ["\u0675", "\u0627\u0674"],
17546               "indic_two_above": ["\u0773"],
17547               "indic_three_above": ["\u0774"],
17548               "fathatan": {
17549                 "normal": ["\u0627\u064B"],
17550                 "final": "\uFD3C",
17551                 "isolated": "\uFD3D"
17552               },
17553               "isolated": "\uFE8D",
17554               "final": "\uFE8E"
17555             },
17556             "beh": {
17557               "normal": ["\u0628"],
17558               "dotless": ["\u066E"],
17559               "three_dots_horizontally_below": ["\u0750"],
17560               "dot_below_three_dots_above": ["\u0751"],
17561               "three_dots_pointing_upwards_below": ["\u0752"],
17562               "three_dots_pointing_upwards_below_two_dots_above": ["\u0753"],
17563               "two_dots_below_dot_above": ["\u0754"],
17564               "inverted_small_v_below": ["\u0755"],
17565               "small_v": ["\u0756"],
17566               "small_v_below": ["\u08A0"],
17567               "hamza_above": ["\u08A1"],
17568               "small_meem_above": ["\u08B6"],
17569               "isolated": "\uFE8F",
17570               "final": "\uFE90",
17571               "initial": "\uFE91",
17572               "medial": "\uFE92"
17573             },
17574             "teh marbuta": {
17575               "normal": ["\u0629"],
17576               "isolated": "\uFE93",
17577               "final": "\uFE94"
17578             },
17579             "teh": {
17580               "normal": ["\u062A"],
17581               "ring": ["\u067C"],
17582               "three_dots_above_downwards": ["\u067D"],
17583               "small_teh_above": ["\u08B8"],
17584               "isolated": "\uFE95",
17585               "final": "\uFE96",
17586               "initial": "\uFE97",
17587               "medial": "\uFE98"
17588             },
17589             "theh": {
17590               "normal": ["\u062B"],
17591               "isolated": "\uFE99",
17592               "final": "\uFE9A",
17593               "initial": "\uFE9B",
17594               "medial": "\uFE9C"
17595             },
17596             "jeem": {
17597               "normal": ["\u062C"],
17598               "two_dots_above": ["\u08A2"],
17599               "isolated": "\uFE9D",
17600               "final": "\uFE9E",
17601               "initial": "\uFE9F",
17602               "medial": "\uFEA0"
17603             },
17604             "hah": {
17605               "normal": ["\u062D"],
17606               "hamza_above": ["\u0681"],
17607               "two_dots_vertical_above": ["\u0682"],
17608               "three_dots_above": ["\u0685"],
17609               "two_dots_above": ["\u0757"],
17610               "three_dots_pointing_upwards_below": ["\u0758"],
17611               "small_tah_below": ["\u076E"],
17612               "small_tah_two_dots": ["\u076F"],
17613               "small_tah_above": ["\u0772"],
17614               "indic_four_below": ["\u077C"],
17615               "isolated": "\uFEA1",
17616               "final": "\uFEA2",
17617               "initial": "\uFEA3",
17618               "medial": "\uFEA4"
17619             },
17620             "khah": {
17621               "normal": ["\u062E"],
17622               "isolated": "\uFEA5",
17623               "final": "\uFEA6",
17624               "initial": "\uFEA7",
17625               "medial": "\uFEA8"
17626             },
17627             "dal": {
17628               "normal": ["\u062F"],
17629               "ring": ["\u0689"],
17630               "dot_below": ["\u068A"],
17631               "dot_below_small_tah": ["\u068B"],
17632               "three_dots_above_downwards": ["\u068F"],
17633               "four_dots_above": ["\u0690"],
17634               "inverted_v": ["\u06EE"],
17635               "two_dots_vertically_below_small_tah": ["\u0759"],
17636               "inverted_small_v_below": ["\u075A"],
17637               "three_dots_below": ["\u08AE"],
17638               "isolated": "\uFEA9",
17639               "final": "\uFEAA"
17640             },
17641             "thal": {
17642               "normal": ["\u0630"],
17643               "isolated": "\uFEAB",
17644               "final": "\uFEAC"
17645             },
17646             "reh": {
17647               "normal": ["\u0631"],
17648               "small_v": ["\u0692"],
17649               "ring": ["\u0693"],
17650               "dot_below": ["\u0694"],
17651               "small_v_below": ["\u0695"],
17652               "dot_below_dot_above": ["\u0696"],
17653               "two_dots_above": ["\u0697"],
17654               "four_dots_above": ["\u0699"],
17655               "inverted_v": ["\u06EF"],
17656               "stroke": ["\u075B"],
17657               "two_dots_vertically_above": ["\u076B"],
17658               "hamza_above": ["\u076C"],
17659               "small_tah_two_dots": ["\u0771"],
17660               "loop": ["\u08AA"],
17661               "small_noon_above": ["\u08B9"],
17662               "isolated": "\uFEAD",
17663               "final": "\uFEAE"
17664             },
17665             "zain": {
17666               "normal": ["\u0632"],
17667               "inverted_v_above": ["\u08B2"],
17668               "isolated": "\uFEAF",
17669               "final": "\uFEB0"
17670             },
17671             "seen": {
17672               "normal": ["\u0633"],
17673               "dot_below_dot_above": ["\u069A"],
17674               "three_dots_below": ["\u069B"],
17675               "three_dots_below_three_dots_above": ["\u069C"],
17676               "four_dots_above": ["\u075C"],
17677               "two_dots_vertically_above": ["\u076D"],
17678               "small_tah_two_dots": ["\u0770"],
17679               "indic_four_above": ["\u077D"],
17680               "inverted_v": ["\u077E"],
17681               "isolated": "\uFEB1",
17682               "final": "\uFEB2",
17683               "initial": "\uFEB3",
17684               "medial": "\uFEB4"
17685             },
17686             "sheen": {
17687               "normal": ["\u0634"],
17688               "dot_below": ["\u06FA"],
17689               "isolated": "\uFEB5",
17690               "final": "\uFEB6",
17691               "initial": "\uFEB7",
17692               "medial": "\uFEB8"
17693             },
17694             "sad": {
17695               "normal": ["\u0635"],
17696               "two_dots_below": ["\u069D"],
17697               "three_dots_above": ["\u069E"],
17698               "three_dots_below": ["\u08AF"],
17699               "isolated": "\uFEB9",
17700               "final": "\uFEBA",
17701               "initial": "\uFEBB",
17702               "medial": "\uFEBC"
17703             },
17704             "dad": {
17705               "normal": ["\u0636"],
17706               "dot_below": ["\u06FB"],
17707               "isolated": "\uFEBD",
17708               "final": "\uFEBE",
17709               "initial": "\uFEBF",
17710               "medial": "\uFEC0"
17711             },
17712             "tah": {
17713               "normal": ["\u0637"],
17714               "three_dots_above": ["\u069F"],
17715               "two_dots_above": ["\u08A3"],
17716               "isolated": "\uFEC1",
17717               "final": "\uFEC2",
17718               "initial": "\uFEC3",
17719               "medial": "\uFEC4"
17720             },
17721             "zah": {
17722               "normal": ["\u0638"],
17723               "isolated": "\uFEC5",
17724               "final": "\uFEC6",
17725               "initial": "\uFEC7",
17726               "medial": "\uFEC8"
17727             },
17728             "ain": {
17729               "normal": ["\u0639"],
17730               "three_dots_above": ["\u06A0"],
17731               "two_dots_above": ["\u075D"],
17732               "three_dots_pointing_downwards_above": ["\u075E"],
17733               "two_dots_vertically_above": ["\u075F"],
17734               "three_dots_below": ["\u08B3"],
17735               "isolated": "\uFEC9",
17736               "final": "\uFECA",
17737               "initial": "\uFECB",
17738               "medial": "\uFECC"
17739             },
17740             "ghain": {
17741               "normal": ["\u063A"],
17742               "dot_below": ["\u06FC"],
17743               "isolated": "\uFECD",
17744               "final": "\uFECE",
17745               "initial": "\uFECF",
17746               "medial": "\uFED0"
17747             },
17748             "feh": {
17749               "normal": ["\u0641"],
17750               "dotless": ["\u06A1"],
17751               "dot_moved_below": ["\u06A2"],
17752               "dot_below": ["\u06A3"],
17753               "three_dots_below": ["\u06A5"],
17754               "two_dots_below": ["\u0760"],
17755               "three_dots_pointing_upwards_below": ["\u0761"],
17756               "dot_below_three_dots_above": ["\u08A4"],
17757               "isolated": "\uFED1",
17758               "final": "\uFED2",
17759               "initial": "\uFED3",
17760               "medial": "\uFED4"
17761             },
17762             "qaf": {
17763               "normal": ["\u0642"],
17764               "dotless": ["\u066F"],
17765               "dot_above": ["\u06A7"],
17766               "three_dots_above": ["\u06A8"],
17767               "dot_below": ["\u08A5"],
17768               "isolated": "\uFED5",
17769               "final": "\uFED6",
17770               "initial": "\uFED7",
17771               "medial": "\uFED8"
17772             },
17773             "kaf": {
17774               "normal": ["\u0643"],
17775               "swash": ["\u06AA"],
17776               "ring": ["\u06AB"],
17777               "dot_above": ["\u06AC"],
17778               "three_dots_below": ["\u06AE"],
17779               "two_dots_above": ["\u077F"],
17780               "dot_below": ["\u08B4"],
17781               "isolated": "\uFED9",
17782               "final": "\uFEDA",
17783               "initial": "\uFEDB",
17784               "medial": "\uFEDC"
17785             },
17786             "lam": {
17787               "normal": ["\u0644"],
17788               "small_v": ["\u06B5"],
17789               "dot_above": ["\u06B6"],
17790               "three_dots_above": ["\u06B7"],
17791               "three_dots_below": ["\u06B8"],
17792               "bar": ["\u076A"],
17793               "double_bar": ["\u08A6"],
17794               "isolated": "\uFEDD",
17795               "final": "\uFEDE",
17796               "initial": "\uFEDF",
17797               "medial": "\uFEE0"
17798             },
17799             "meem": {
17800               "normal": ["\u0645"],
17801               "dot_above": ["\u0765"],
17802               "dot_below": ["\u0766"],
17803               "three_dots_above": ["\u08A7"],
17804               "isolated": "\uFEE1",
17805               "final": "\uFEE2",
17806               "initial": "\uFEE3",
17807               "medial": "\uFEE4"
17808             },
17809             "noon": {
17810               "normal": ["\u0646"],
17811               "dot_below": ["\u06B9"],
17812               "ring": ["\u06BC"],
17813               "three_dots_above": ["\u06BD"],
17814               "two_dots_below": ["\u0767"],
17815               "small_tah": ["\u0768"],
17816               "small_v": ["\u0769"],
17817               "isolated": "\uFEE5",
17818               "final": "\uFEE6",
17819               "initial": "\uFEE7",
17820               "medial": "\uFEE8"
17821             },
17822             "heh": {
17823               "normal": ["\u0647"],
17824               "isolated": "\uFEE9",
17825               "final": "\uFEEA",
17826               "initial": "\uFEEB",
17827               "medial": "\uFEEC"
17828             },
17829             "waw": {
17830               "normal": ["\u0648"],
17831               "hamza_above": {
17832                 "normal": ["\u0624", "\u0648\u0654"],
17833                 "isolated": "\uFE85",
17834                 "final": "\uFE86"
17835               },
17836               "high_hamza": ["\u0676", "\u0648\u0674"],
17837               "ring": ["\u06C4"],
17838               "two_dots_above": ["\u06CA"],
17839               "dot_above": ["\u06CF"],
17840               "indic_two_above": ["\u0778"],
17841               "indic_three_above": ["\u0779"],
17842               "dot_within": ["\u08AB"],
17843               "isolated": "\uFEED",
17844               "final": "\uFEEE"
17845             },
17846             "alef_maksura": {
17847               "normal": ["\u0649"],
17848               "hamza_above": ["\u0626", "\u064A\u0654"],
17849               "initial": "\uFBE8",
17850               "medial": "\uFBE9",
17851               "isolated": "\uFEEF",
17852               "final": "\uFEF0"
17853             },
17854             "yeh": {
17855               "normal": ["\u064A"],
17856               "hamza_above": {
17857                 "normal": ["\u0626", "\u0649\u0654"],
17858                 "isolated": "\uFE89",
17859                 "final": "\uFE8A",
17860                 "initial": "\uFE8B",
17861                 "medial": "\uFE8C"
17862               },
17863               "two_dots_below_hamza_above": ["\u08A8"],
17864               "high_hamza": ["\u0678", "\u064A\u0674"],
17865               "tail": ["\u06CD"],
17866               "small_v": ["\u06CE"],
17867               "three_dots_below": ["\u06D1"],
17868               "two_dots_below_dot_above": ["\u08A9"],
17869               "two_dots_below_small_noon_above": ["\u08BA"],
17870               "isolated": "\uFEF1",
17871               "final": "\uFEF2",
17872               "initial": "\uFEF3",
17873               "medial": "\uFEF4"
17874             },
17875             "tteh": {
17876               "normal": ["\u0679"],
17877               "isolated": "\uFB66",
17878               "final": "\uFB67",
17879               "initial": "\uFB68",
17880               "medial": "\uFB69"
17881             },
17882             "tteheh": {
17883               "normal": ["\u067A"],
17884               "isolated": "\uFB5E",
17885               "final": "\uFB5F",
17886               "initial": "\uFB60",
17887               "medial": "\uFB61"
17888             },
17889             "beeh": {
17890               "normal": ["\u067B"],
17891               "isolated": "\uFB52",
17892               "final": "\uFB53",
17893               "initial": "\uFB54",
17894               "medial": "\uFB55"
17895             },
17896             "peh": {
17897               "normal": ["\u067E"],
17898               "small_meem_above": ["\u08B7"],
17899               "isolated": "\uFB56",
17900               "final": "\uFB57",
17901               "initial": "\uFB58",
17902               "medial": "\uFB59"
17903             },
17904             "teheh": {
17905               "normal": ["\u067F"],
17906               "isolated": "\uFB62",
17907               "final": "\uFB63",
17908               "initial": "\uFB64",
17909               "medial": "\uFB65"
17910             },
17911             "beheh": {
17912               "normal": ["\u0680"],
17913               "isolated": "\uFB5A",
17914               "final": "\uFB5B",
17915               "initial": "\uFB5C",
17916               "medial": "\uFB5D"
17917             },
17918             "nyeh": {
17919               "normal": ["\u0683"],
17920               "isolated": "\uFB76",
17921               "final": "\uFB77",
17922               "initial": "\uFB78",
17923               "medial": "\uFB79"
17924             },
17925             "dyeh": {
17926               "normal": ["\u0684"],
17927               "isolated": "\uFB72",
17928               "final": "\uFB73",
17929               "initial": "\uFB74",
17930               "medial": "\uFB75"
17931             },
17932             "tcheh": {
17933               "normal": ["\u0686"],
17934               "dot_above": ["\u06BF"],
17935               "isolated": "\uFB7A",
17936               "final": "\uFB7B",
17937               "initial": "\uFB7C",
17938               "medial": "\uFB7D"
17939             },
17940             "tcheheh": {
17941               "normal": ["\u0687"],
17942               "isolated": "\uFB7E",
17943               "final": "\uFB7F",
17944               "initial": "\uFB80",
17945               "medial": "\uFB81"
17946             },
17947             "ddal": {
17948               "normal": ["\u0688"],
17949               "isolated": "\uFB88",
17950               "final": "\uFB89"
17951             },
17952             "dahal": {
17953               "normal": ["\u068C"],
17954               "isolated": "\uFB84",
17955               "final": "\uFB85"
17956             },
17957             "ddahal": {
17958               "normal": ["\u068D"],
17959               "isolated": "\uFB82",
17960               "final": "\uFB83"
17961             },
17962             "dul": {
17963               "normal": ["\u068F", "\u068E"],
17964               "isolated": "\uFB86",
17965               "final": "\uFB87"
17966             },
17967             "rreh": {
17968               "normal": ["\u0691"],
17969               "isolated": "\uFB8C",
17970               "final": "\uFB8D"
17971             },
17972             "jeh": {
17973               "normal": ["\u0698"],
17974               "isolated": "\uFB8A",
17975               "final": "\uFB8B"
17976             },
17977             "veh": {
17978               "normal": ["\u06A4"],
17979               "isolated": "\uFB6A",
17980               "final": "\uFB6B",
17981               "initial": "\uFB6C",
17982               "medial": "\uFB6D"
17983             },
17984             "peheh": {
17985               "normal": ["\u06A6"],
17986               "isolated": "\uFB6E",
17987               "final": "\uFB6F",
17988               "initial": "\uFB70",
17989               "medial": "\uFB71"
17990             },
17991             "keheh": {
17992               "normal": ["\u06A9"],
17993               "dot_above": ["\u0762"],
17994               "three_dots_above": ["\u0763"],
17995               "three_dots_pointing_upwards_below": ["\u0764"],
17996               "isolated": "\uFB8E",
17997               "final": "\uFB8F",
17998               "initial": "\uFB90",
17999               "medial": "\uFB91"
18000             },
18001             "ng": {
18002               "normal": ["\u06AD"],
18003               "isolated": "\uFBD3",
18004               "final": "\uFBD4",
18005               "initial": "\uFBD5",
18006               "medial": "\uFBD6"
18007             },
18008             "gaf": {
18009               "normal": ["\u06AF"],
18010               "ring": ["\u06B0"],
18011               "two_dots_below": ["\u06B2"],
18012               "three_dots_above": ["\u06B4"],
18013               "inverted_stroke": ["\u08B0"],
18014               "isolated": "\uFB92",
18015               "final": "\uFB93",
18016               "initial": "\uFB94",
18017               "medial": "\uFB95"
18018             },
18019             "ngoeh": {
18020               "normal": ["\u06B1"],
18021               "isolated": "\uFB9A",
18022               "final": "\uFB9B",
18023               "initial": "\uFB9C",
18024               "medial": "\uFB9D"
18025             },
18026             "gueh": {
18027               "normal": ["\u06B3"],
18028               "isolated": "\uFB96",
18029               "final": "\uFB97",
18030               "initial": "\uFB98",
18031               "medial": "\uFB99"
18032             },
18033             "noon ghunna": {
18034               "normal": ["\u06BA"],
18035               "isolated": "\uFB9E",
18036               "final": "\uFB9F"
18037             },
18038             "rnoon": {
18039               "normal": ["\u06BB"],
18040               "isolated": "\uFBA0",
18041               "final": "\uFBA1",
18042               "initial": "\uFBA2",
18043               "medial": "\uFBA3"
18044             },
18045             "heh doachashmee": {
18046               "normal": ["\u06BE"],
18047               "isolated": "\uFBAA",
18048               "final": "\uFBAB",
18049               "initial": "\uFBAC",
18050               "medial": "\uFBAD"
18051             },
18052             "heh goal": {
18053               "normal": ["\u06C1"],
18054               "hamza_above": ["\u06C1\u0654", "\u06C2"],
18055               "isolated": "\uFBA6",
18056               "final": "\uFBA7",
18057               "initial": "\uFBA8",
18058               "medial": "\uFBA9"
18059             },
18060             "teh marbuta goal": {
18061               "normal": ["\u06C3"]
18062             },
18063             "kirghiz oe": {
18064               "normal": ["\u06C5"],
18065               "isolated": "\uFBE0",
18066               "final": "\uFBE1"
18067             },
18068             "oe": {
18069               "normal": ["\u06C6"],
18070               "isolated": "\uFBD9",
18071               "final": "\uFBDA"
18072             },
18073             "u": {
18074               "normal": ["\u06C7"],
18075               "hamza_above": {
18076                 "normal": ["\u0677", "\u06C7\u0674"],
18077                 "isolated": "\uFBDD"
18078               },
18079               "isolated": "\uFBD7",
18080               "final": "\uFBD8"
18081             },
18082             "yu": {
18083               "normal": ["\u06C8"],
18084               "isolated": "\uFBDB",
18085               "final": "\uFBDC"
18086             },
18087             "kirghiz yu": {
18088               "normal": ["\u06C9"],
18089               "isolated": "\uFBE2",
18090               "final": "\uFBE3"
18091             },
18092             "ve": {
18093               "normal": ["\u06CB"],
18094               "isolated": "\uFBDE",
18095               "final": "\uFBDF"
18096             },
18097             "farsi yeh": {
18098               "normal": ["\u06CC"],
18099               "indic_two_above": ["\u0775"],
18100               "indic_three_above": ["\u0776"],
18101               "indic_four_above": ["\u0777"],
18102               "isolated": "\uFBFC",
18103               "final": "\uFBFD",
18104               "initial": "\uFBFE",
18105               "medial": "\uFBFF"
18106             },
18107             "e": {
18108               "normal": ["\u06D0"],
18109               "isolated": "\uFBE4",
18110               "final": "\uFBE5",
18111               "initial": "\uFBE6",
18112               "medial": "\uFBE7"
18113             },
18114             "yeh barree": {
18115               "normal": ["\u06D2"],
18116               "hamza_above": {
18117                 "normal": ["\u06D2\u0654", "\u06D3"],
18118                 "isolated": "\uFBB0",
18119                 "final": "\uFBB1"
18120               },
18121               "indic_two_above": ["\u077A"],
18122               "indic_three_above": ["\u077B"],
18123               "isolated": "\uFBAE",
18124               "final": "\uFBAF"
18125             },
18126             "ae": {
18127               "normal": ["\u06D5"],
18128               "isolated": "\u06D5",
18129               "final": "\uFEEA",
18130               "yeh_above": {
18131                 "normal": ["\u06C0", "\u06D5\u0654"],
18132                 "isolated": "\uFBA4",
18133                 "final": "\uFBA5"
18134               }
18135             },
18136             "rohingya yeh": {
18137               "normal": ["\u08AC"]
18138             },
18139             "low alef": {
18140               "normal": ["\u08AD"]
18141             },
18142             "straight waw": {
18143               "normal": ["\u08B1"]
18144             },
18145             "african feh": {
18146               "normal": ["\u08BB"]
18147             },
18148             "african qaf": {
18149               "normal": ["\u08BC"]
18150             },
18151             "african noon": {
18152               "normal": ["\u08BD"]
18153             }
18154           };
18155           exports["default"] = arabicReference;
18156         });
18157
18158         var unicodeLigatures = createCommonjsModule(function (module, exports) {
18159
18160           Object.defineProperty(exports, "__esModule", {
18161             value: true
18162           });
18163           var ligatureReference = {
18164             "\u0626\u0627": {
18165               "isolated": "\uFBEA",
18166               "final": "\uFBEB"
18167             },
18168             "\u0626\u06D5": {
18169               "isolated": "\uFBEC",
18170               "final": "\uFBED"
18171             },
18172             "\u0626\u0648": {
18173               "isolated": "\uFBEE",
18174               "final": "\uFBEF"
18175             },
18176             "\u0626\u06C7": {
18177               "isolated": "\uFBF0",
18178               "final": "\uFBF1"
18179             },
18180             "\u0626\u06C6": {
18181               "isolated": "\uFBF2",
18182               "final": "\uFBF3"
18183             },
18184             "\u0626\u06C8": {
18185               "isolated": "\uFBF4",
18186               "final": "\uFBF5"
18187             },
18188             "\u0626\u06D0": {
18189               "isolated": "\uFBF6",
18190               "final": "\uFBF7",
18191               "initial": "\uFBF8"
18192             },
18193             "\u0626\u0649": {
18194               "uighur_kirghiz": {
18195                 "isolated": "\uFBF9",
18196                 "final": "\uFBFA",
18197                 "initial": "\uFBFB"
18198               },
18199               "isolated": "\uFC03",
18200               "final": "\uFC68"
18201             },
18202             "\u0626\u062C": {
18203               "isolated": "\uFC00",
18204               "initial": "\uFC97"
18205             },
18206             "\u0626\u062D": {
18207               "isolated": "\uFC01",
18208               "initial": "\uFC98"
18209             },
18210             "\u0626\u0645": {
18211               "isolated": "\uFC02",
18212               "final": "\uFC66",
18213               "initial": "\uFC9A",
18214               "medial": "\uFCDF"
18215             },
18216             "\u0626\u064A": {
18217               "isolated": "\uFC04",
18218               "final": "\uFC69"
18219             },
18220             "\u0628\u062C": {
18221               "isolated": "\uFC05",
18222               "initial": "\uFC9C"
18223             },
18224             "\u0628\u062D": {
18225               "isolated": "\uFC06",
18226               "initial": "\uFC9D"
18227             },
18228             "\u0628\u062E": {
18229               "isolated": "\uFC07",
18230               "initial": "\uFC9E"
18231             },
18232             "\u0628\u0645": {
18233               "isolated": "\uFC08",
18234               "final": "\uFC6C",
18235               "initial": "\uFC9F",
18236               "medial": "\uFCE1"
18237             },
18238             "\u0628\u0649": {
18239               "isolated": "\uFC09",
18240               "final": "\uFC6E"
18241             },
18242             "\u0628\u064A": {
18243               "isolated": "\uFC0A",
18244               "final": "\uFC6F"
18245             },
18246             "\u062A\u062C": {
18247               "isolated": "\uFC0B",
18248               "initial": "\uFCA1"
18249             },
18250             "\u062A\u062D": {
18251               "isolated": "\uFC0C",
18252               "initial": "\uFCA2"
18253             },
18254             "\u062A\u062E": {
18255               "isolated": "\uFC0D",
18256               "initial": "\uFCA3"
18257             },
18258             "\u062A\u0645": {
18259               "isolated": "\uFC0E",
18260               "final": "\uFC72",
18261               "initial": "\uFCA4",
18262               "medial": "\uFCE3"
18263             },
18264             "\u062A\u0649": {
18265               "isolated": "\uFC0F",
18266               "final": "\uFC74"
18267             },
18268             "\u062A\u064A": {
18269               "isolated": "\uFC10",
18270               "final": "\uFC75"
18271             },
18272             "\u062B\u062C": {
18273               "isolated": "\uFC11"
18274             },
18275             "\u062B\u0645": {
18276               "isolated": "\uFC12",
18277               "final": "\uFC78",
18278               "initial": "\uFCA6",
18279               "medial": "\uFCE5"
18280             },
18281             "\u062B\u0649": {
18282               "isolated": "\uFC13",
18283               "final": "\uFC7A"
18284             },
18285             "\u062B\u0648": {
18286               "isolated": "\uFC14"
18287             },
18288             "\u062C\u062D": {
18289               "isolated": "\uFC15",
18290               "initial": "\uFCA7"
18291             },
18292             "\u062C\u0645": {
18293               "isolated": "\uFC16",
18294               "initial": "\uFCA8"
18295             },
18296             "\u062D\u062C": {
18297               "isolated": "\uFC17",
18298               "initial": "\uFCA9"
18299             },
18300             "\u062D\u0645": {
18301               "isolated": "\uFC18",
18302               "initial": "\uFCAA"
18303             },
18304             "\u062E\u062C": {
18305               "isolated": "\uFC19",
18306               "initial": "\uFCAB"
18307             },
18308             "\u062E\u062D": {
18309               "isolated": "\uFC1A"
18310             },
18311             "\u062E\u0645": {
18312               "isolated": "\uFC1B",
18313               "initial": "\uFCAC"
18314             },
18315             "\u0633\u062C": {
18316               "isolated": "\uFC1C",
18317               "initial": "\uFCAD",
18318               "medial": "\uFD34"
18319             },
18320             "\u0633\u062D": {
18321               "isolated": "\uFC1D",
18322               "initial": "\uFCAE",
18323               "medial": "\uFD35"
18324             },
18325             "\u0633\u062E": {
18326               "isolated": "\uFC1E",
18327               "initial": "\uFCAF",
18328               "medial": "\uFD36"
18329             },
18330             "\u0633\u0645": {
18331               "isolated": "\uFC1F",
18332               "initial": "\uFCB0",
18333               "medial": "\uFCE7"
18334             },
18335             "\u0635\u062D": {
18336               "isolated": "\uFC20",
18337               "initial": "\uFCB1"
18338             },
18339             "\u0635\u0645": {
18340               "isolated": "\uFC21",
18341               "initial": "\uFCB3"
18342             },
18343             "\u0636\u062C": {
18344               "isolated": "\uFC22",
18345               "initial": "\uFCB4"
18346             },
18347             "\u0636\u062D": {
18348               "isolated": "\uFC23",
18349               "initial": "\uFCB5"
18350             },
18351             "\u0636\u062E": {
18352               "isolated": "\uFC24",
18353               "initial": "\uFCB6"
18354             },
18355             "\u0636\u0645": {
18356               "isolated": "\uFC25",
18357               "initial": "\uFCB7"
18358             },
18359             "\u0637\u062D": {
18360               "isolated": "\uFC26",
18361               "initial": "\uFCB8"
18362             },
18363             "\u0637\u0645": {
18364               "isolated": "\uFC27",
18365               "initial": "\uFD33",
18366               "medial": "\uFD3A"
18367             },
18368             "\u0638\u0645": {
18369               "isolated": "\uFC28",
18370               "initial": "\uFCB9",
18371               "medial": "\uFD3B"
18372             },
18373             "\u0639\u062C": {
18374               "isolated": "\uFC29",
18375               "initial": "\uFCBA"
18376             },
18377             "\u0639\u0645": {
18378               "isolated": "\uFC2A",
18379               "initial": "\uFCBB"
18380             },
18381             "\u063A\u062C": {
18382               "isolated": "\uFC2B",
18383               "initial": "\uFCBC"
18384             },
18385             "\u063A\u0645": {
18386               "isolated": "\uFC2C",
18387               "initial": "\uFCBD"
18388             },
18389             "\u0641\u062C": {
18390               "isolated": "\uFC2D",
18391               "initial": "\uFCBE"
18392             },
18393             "\u0641\u062D": {
18394               "isolated": "\uFC2E",
18395               "initial": "\uFCBF"
18396             },
18397             "\u0641\u062E": {
18398               "isolated": "\uFC2F",
18399               "initial": "\uFCC0"
18400             },
18401             "\u0641\u0645": {
18402               "isolated": "\uFC30",
18403               "initial": "\uFCC1"
18404             },
18405             "\u0641\u0649": {
18406               "isolated": "\uFC31",
18407               "final": "\uFC7C"
18408             },
18409             "\u0641\u064A": {
18410               "isolated": "\uFC32",
18411               "final": "\uFC7D"
18412             },
18413             "\u0642\u062D": {
18414               "isolated": "\uFC33",
18415               "initial": "\uFCC2"
18416             },
18417             "\u0642\u0645": {
18418               "isolated": "\uFC34",
18419               "initial": "\uFCC3"
18420             },
18421             "\u0642\u0649": {
18422               "isolated": "\uFC35",
18423               "final": "\uFC7E"
18424             },
18425             "\u0642\u064A": {
18426               "isolated": "\uFC36",
18427               "final": "\uFC7F"
18428             },
18429             "\u0643\u0627": {
18430               "isolated": "\uFC37",
18431               "final": "\uFC80"
18432             },
18433             "\u0643\u062C": {
18434               "isolated": "\uFC38",
18435               "initial": "\uFCC4"
18436             },
18437             "\u0643\u062D": {
18438               "isolated": "\uFC39",
18439               "initial": "\uFCC5"
18440             },
18441             "\u0643\u062E": {
18442               "isolated": "\uFC3A",
18443               "initial": "\uFCC6"
18444             },
18445             "\u0643\u0644": {
18446               "isolated": "\uFC3B",
18447               "final": "\uFC81",
18448               "initial": "\uFCC7",
18449               "medial": "\uFCEB"
18450             },
18451             "\u0643\u0645": {
18452               "isolated": "\uFC3C",
18453               "final": "\uFC82",
18454               "initial": "\uFCC8",
18455               "medial": "\uFCEC"
18456             },
18457             "\u0643\u0649": {
18458               "isolated": "\uFC3D",
18459               "final": "\uFC83"
18460             },
18461             "\u0643\u064A": {
18462               "isolated": "\uFC3E",
18463               "final": "\uFC84"
18464             },
18465             "\u0644\u062C": {
18466               "isolated": "\uFC3F",
18467               "initial": "\uFCC9"
18468             },
18469             "\u0644\u062D": {
18470               "isolated": "\uFC40",
18471               "initial": "\uFCCA"
18472             },
18473             "\u0644\u062E": {
18474               "isolated": "\uFC41",
18475               "initial": "\uFCCB"
18476             },
18477             "\u0644\u0645": {
18478               "isolated": "\uFC42",
18479               "final": "\uFC85",
18480               "initial": "\uFCCC",
18481               "medial": "\uFCED"
18482             },
18483             "\u0644\u0649": {
18484               "isolated": "\uFC43",
18485               "final": "\uFC86"
18486             },
18487             "\u0644\u064A": {
18488               "isolated": "\uFC44",
18489               "final": "\uFC87"
18490             },
18491             "\u0645\u062C": {
18492               "isolated": "\uFC45",
18493               "initial": "\uFCCE"
18494             },
18495             "\u0645\u062D": {
18496               "isolated": "\uFC46",
18497               "initial": "\uFCCF"
18498             },
18499             "\u0645\u062E": {
18500               "isolated": "\uFC47",
18501               "initial": "\uFCD0"
18502             },
18503             "\u0645\u0645": {
18504               "isolated": "\uFC48",
18505               "final": "\uFC89",
18506               "initial": "\uFCD1"
18507             },
18508             "\u0645\u0649": {
18509               "isolated": "\uFC49"
18510             },
18511             "\u0645\u064A": {
18512               "isolated": "\uFC4A"
18513             },
18514             "\u0646\u062C": {
18515               "isolated": "\uFC4B",
18516               "initial": "\uFCD2"
18517             },
18518             "\u0646\u062D": {
18519               "isolated": "\uFC4C",
18520               "initial": "\uFCD3"
18521             },
18522             "\u0646\u062E": {
18523               "isolated": "\uFC4D",
18524               "initial": "\uFCD4"
18525             },
18526             "\u0646\u0645": {
18527               "isolated": "\uFC4E",
18528               "final": "\uFC8C",
18529               "initial": "\uFCD5",
18530               "medial": "\uFCEE"
18531             },
18532             "\u0646\u0649": {
18533               "isolated": "\uFC4F",
18534               "final": "\uFC8E"
18535             },
18536             "\u0646\u064A": {
18537               "isolated": "\uFC50",
18538               "final": "\uFC8F"
18539             },
18540             "\u0647\u062C": {
18541               "isolated": "\uFC51",
18542               "initial": "\uFCD7"
18543             },
18544             "\u0647\u0645": {
18545               "isolated": "\uFC52",
18546               "initial": "\uFCD8"
18547             },
18548             "\u0647\u0649": {
18549               "isolated": "\uFC53"
18550             },
18551             "\u0647\u064A": {
18552               "isolated": "\uFC54"
18553             },
18554             "\u064A\u062C": {
18555               "isolated": "\uFC55",
18556               "initial": "\uFCDA"
18557             },
18558             "\u064A\u062D": {
18559               "isolated": "\uFC56",
18560               "initial": "\uFCDB"
18561             },
18562             "\u064A\u062E": {
18563               "isolated": "\uFC57",
18564               "initial": "\uFCDC"
18565             },
18566             "\u064A\u0645": {
18567               "isolated": "\uFC58",
18568               "final": "\uFC93",
18569               "initial": "\uFCDD",
18570               "medial": "\uFCF0"
18571             },
18572             "\u064A\u0649": {
18573               "isolated": "\uFC59",
18574               "final": "\uFC95"
18575             },
18576             "\u064A\u064A": {
18577               "isolated": "\uFC5A",
18578               "final": "\uFC96"
18579             },
18580             "\u0630\u0670": {
18581               "isolated": "\uFC5B"
18582             },
18583             "\u0631\u0670": {
18584               "isolated": "\uFC5C"
18585             },
18586             "\u0649\u0670": {
18587               "isolated": "\uFC5D",
18588               "final": "\uFC90"
18589             },
18590             "\u064C\u0651": {
18591               "isolated": "\uFC5E"
18592             },
18593             "\u064D\u0651": {
18594               "isolated": "\uFC5F"
18595             },
18596             "\u064E\u0651": {
18597               "isolated": "\uFC60"
18598             },
18599             "\u064F\u0651": {
18600               "isolated": "\uFC61"
18601             },
18602             "\u0650\u0651": {
18603               "isolated": "\uFC62"
18604             },
18605             "\u0651\u0670": {
18606               "isolated": "\uFC63"
18607             },
18608             "\u0626\u0631": {
18609               "final": "\uFC64"
18610             },
18611             "\u0626\u0632": {
18612               "final": "\uFC65"
18613             },
18614             "\u0626\u0646": {
18615               "final": "\uFC67"
18616             },
18617             "\u0628\u0631": {
18618               "final": "\uFC6A"
18619             },
18620             "\u0628\u0632": {
18621               "final": "\uFC6B"
18622             },
18623             "\u0628\u0646": {
18624               "final": "\uFC6D"
18625             },
18626             "\u062A\u0631": {
18627               "final": "\uFC70"
18628             },
18629             "\u062A\u0632": {
18630               "final": "\uFC71"
18631             },
18632             "\u062A\u0646": {
18633               "final": "\uFC73"
18634             },
18635             "\u062B\u0631": {
18636               "final": "\uFC76"
18637             },
18638             "\u062B\u0632": {
18639               "final": "\uFC77"
18640             },
18641             "\u062B\u0646": {
18642               "final": "\uFC79"
18643             },
18644             "\u062B\u064A": {
18645               "final": "\uFC7B"
18646             },
18647             "\u0645\u0627": {
18648               "final": "\uFC88"
18649             },
18650             "\u0646\u0631": {
18651               "final": "\uFC8A"
18652             },
18653             "\u0646\u0632": {
18654               "final": "\uFC8B"
18655             },
18656             "\u0646\u0646": {
18657               "final": "\uFC8D"
18658             },
18659             "\u064A\u0631": {
18660               "final": "\uFC91"
18661             },
18662             "\u064A\u0632": {
18663               "final": "\uFC92"
18664             },
18665             "\u064A\u0646": {
18666               "final": "\uFC94"
18667             },
18668             "\u0626\u062E": {
18669               "initial": "\uFC99"
18670             },
18671             "\u0626\u0647": {
18672               "initial": "\uFC9B",
18673               "medial": "\uFCE0"
18674             },
18675             "\u0628\u0647": {
18676               "initial": "\uFCA0",
18677               "medial": "\uFCE2"
18678             },
18679             "\u062A\u0647": {
18680               "initial": "\uFCA5",
18681               "medial": "\uFCE4"
18682             },
18683             "\u0635\u062E": {
18684               "initial": "\uFCB2"
18685             },
18686             "\u0644\u0647": {
18687               "initial": "\uFCCD"
18688             },
18689             "\u0646\u0647": {
18690               "initial": "\uFCD6",
18691               "medial": "\uFCEF"
18692             },
18693             "\u0647\u0670": {
18694               "initial": "\uFCD9"
18695             },
18696             "\u064A\u0647": {
18697               "initial": "\uFCDE",
18698               "medial": "\uFCF1"
18699             },
18700             "\u062B\u0647": {
18701               "medial": "\uFCE6"
18702             },
18703             "\u0633\u0647": {
18704               "medial": "\uFCE8",
18705               "initial": "\uFD31"
18706             },
18707             "\u0634\u0645": {
18708               "medial": "\uFCE9",
18709               "isolated": "\uFD0C",
18710               "final": "\uFD28",
18711               "initial": "\uFD30"
18712             },
18713             "\u0634\u0647": {
18714               "medial": "\uFCEA",
18715               "initial": "\uFD32"
18716             },
18717             "\u0640\u064E\u0651": {
18718               "medial": "\uFCF2"
18719             },
18720             "\u0640\u064F\u0651": {
18721               "medial": "\uFCF3"
18722             },
18723             "\u0640\u0650\u0651": {
18724               "medial": "\uFCF4"
18725             },
18726             "\u0637\u0649": {
18727               "isolated": "\uFCF5",
18728               "final": "\uFD11"
18729             },
18730             "\u0637\u064A": {
18731               "isolated": "\uFCF6",
18732               "final": "\uFD12"
18733             },
18734             "\u0639\u0649": {
18735               "isolated": "\uFCF7",
18736               "final": "\uFD13"
18737             },
18738             "\u0639\u064A": {
18739               "isolated": "\uFCF8",
18740               "final": "\uFD14"
18741             },
18742             "\u063A\u0649": {
18743               "isolated": "\uFCF9",
18744               "final": "\uFD15"
18745             },
18746             "\u063A\u064A": {
18747               "isolated": "\uFCFA",
18748               "final": "\uFD16"
18749             },
18750             "\u0633\u0649": {
18751               "isolated": "\uFCFB"
18752             },
18753             "\u0633\u064A": {
18754               "isolated": "\uFCFC",
18755               "final": "\uFD18"
18756             },
18757             "\u0634\u0649": {
18758               "isolated": "\uFCFD",
18759               "final": "\uFD19"
18760             },
18761             "\u0634\u064A": {
18762               "isolated": "\uFCFE",
18763               "final": "\uFD1A"
18764             },
18765             "\u062D\u0649": {
18766               "isolated": "\uFCFF",
18767               "final": "\uFD1B"
18768             },
18769             "\u062D\u064A": {
18770               "isolated": "\uFD00",
18771               "final": "\uFD1C"
18772             },
18773             "\u062C\u0649": {
18774               "isolated": "\uFD01",
18775               "final": "\uFD1D"
18776             },
18777             "\u062C\u064A": {
18778               "isolated": "\uFD02",
18779               "final": "\uFD1E"
18780             },
18781             "\u062E\u0649": {
18782               "isolated": "\uFD03",
18783               "final": "\uFD1F"
18784             },
18785             "\u062E\u064A": {
18786               "isolated": "\uFD04",
18787               "final": "\uFD20"
18788             },
18789             "\u0635\u0649": {
18790               "isolated": "\uFD05",
18791               "final": "\uFD21"
18792             },
18793             "\u0635\u064A": {
18794               "isolated": "\uFD06",
18795               "final": "\uFD22"
18796             },
18797             "\u0636\u0649": {
18798               "isolated": "\uFD07",
18799               "final": "\uFD23"
18800             },
18801             "\u0636\u064A": {
18802               "isolated": "\uFD08",
18803               "final": "\uFD24"
18804             },
18805             "\u0634\u062C": {
18806               "isolated": "\uFD09",
18807               "final": "\uFD25",
18808               "initial": "\uFD2D",
18809               "medial": "\uFD37"
18810             },
18811             "\u0634\u062D": {
18812               "isolated": "\uFD0A",
18813               "final": "\uFD26",
18814               "initial": "\uFD2E",
18815               "medial": "\uFD38"
18816             },
18817             "\u0634\u062E": {
18818               "isolated": "\uFD0B",
18819               "final": "\uFD27",
18820               "initial": "\uFD2F",
18821               "medial": "\uFD39"
18822             },
18823             "\u0634\u0631": {
18824               "isolated": "\uFD0D",
18825               "final": "\uFD29"
18826             },
18827             "\u0633\u0631": {
18828               "isolated": "\uFD0E",
18829               "final": "\uFD2A"
18830             },
18831             "\u0635\u0631": {
18832               "isolated": "\uFD0F",
18833               "final": "\uFD2B"
18834             },
18835             "\u0636\u0631": {
18836               "isolated": "\uFD10",
18837               "final": "\uFD2C"
18838             },
18839             "\u0633\u0639": {
18840               "final": "\uFD17"
18841             },
18842             "\u062A\u062C\u0645": {
18843               "initial": "\uFD50"
18844             },
18845             "\u062A\u062D\u062C": {
18846               "final": "\uFD51",
18847               "initial": "\uFD52"
18848             },
18849             "\u062A\u062D\u0645": {
18850               "initial": "\uFD53"
18851             },
18852             "\u062A\u062E\u0645": {
18853               "initial": "\uFD54"
18854             },
18855             "\u062A\u0645\u062C": {
18856               "initial": "\uFD55"
18857             },
18858             "\u062A\u0645\u062D": {
18859               "initial": "\uFD56"
18860             },
18861             "\u062A\u0645\u062E": {
18862               "initial": "\uFD57"
18863             },
18864             "\u062C\u0645\u062D": {
18865               "final": "\uFD58",
18866               "initial": "\uFD59"
18867             },
18868             "\u062D\u0645\u064A": {
18869               "final": "\uFD5A"
18870             },
18871             "\u062D\u0645\u0649": {
18872               "final": "\uFD5B"
18873             },
18874             "\u0633\u062D\u062C": {
18875               "initial": "\uFD5C"
18876             },
18877             "\u0633\u062C\u062D": {
18878               "initial": "\uFD5D"
18879             },
18880             "\u0633\u062C\u0649": {
18881               "final": "\uFD5E"
18882             },
18883             "\u0633\u0645\u062D": {
18884               "final": "\uFD5F",
18885               "initial": "\uFD60"
18886             },
18887             "\u0633\u0645\u062C": {
18888               "initial": "\uFD61"
18889             },
18890             "\u0633\u0645\u0645": {
18891               "final": "\uFD62",
18892               "initial": "\uFD63"
18893             },
18894             "\u0635\u062D\u062D": {
18895               "final": "\uFD64",
18896               "initial": "\uFD65"
18897             },
18898             "\u0635\u0645\u0645": {
18899               "final": "\uFD66",
18900               "initial": "\uFDC5"
18901             },
18902             "\u0634\u062D\u0645": {
18903               "final": "\uFD67",
18904               "initial": "\uFD68"
18905             },
18906             "\u0634\u062C\u064A": {
18907               "final": "\uFD69"
18908             },
18909             "\u0634\u0645\u062E": {
18910               "final": "\uFD6A",
18911               "initial": "\uFD6B"
18912             },
18913             "\u0634\u0645\u0645": {
18914               "final": "\uFD6C",
18915               "initial": "\uFD6D"
18916             },
18917             "\u0636\u062D\u0649": {
18918               "final": "\uFD6E"
18919             },
18920             "\u0636\u062E\u0645": {
18921               "final": "\uFD6F",
18922               "initial": "\uFD70"
18923             },
18924             "\u0636\u0645\u062D": {
18925               "final": "\uFD71"
18926             },
18927             "\u0637\u0645\u062D": {
18928               "initial": "\uFD72"
18929             },
18930             "\u0637\u0645\u0645": {
18931               "initial": "\uFD73"
18932             },
18933             "\u0637\u0645\u064A": {
18934               "final": "\uFD74"
18935             },
18936             "\u0639\u062C\u0645": {
18937               "final": "\uFD75",
18938               "initial": "\uFDC4"
18939             },
18940             "\u0639\u0645\u0645": {
18941               "final": "\uFD76",
18942               "initial": "\uFD77"
18943             },
18944             "\u0639\u0645\u0649": {
18945               "final": "\uFD78"
18946             },
18947             "\u063A\u0645\u0645": {
18948               "final": "\uFD79"
18949             },
18950             "\u063A\u0645\u064A": {
18951               "final": "\uFD7A"
18952             },
18953             "\u063A\u0645\u0649": {
18954               "final": "\uFD7B"
18955             },
18956             "\u0641\u062E\u0645": {
18957               "final": "\uFD7C",
18958               "initial": "\uFD7D"
18959             },
18960             "\u0642\u0645\u062D": {
18961               "final": "\uFD7E",
18962               "initial": "\uFDB4"
18963             },
18964             "\u0642\u0645\u0645": {
18965               "final": "\uFD7F"
18966             },
18967             "\u0644\u062D\u0645": {
18968               "final": "\uFD80",
18969               "initial": "\uFDB5"
18970             },
18971             "\u0644\u062D\u064A": {
18972               "final": "\uFD81"
18973             },
18974             "\u0644\u062D\u0649": {
18975               "final": "\uFD82"
18976             },
18977             "\u0644\u062C\u062C": {
18978               "initial": "\uFD83",
18979               "final": "\uFD84"
18980             },
18981             "\u0644\u062E\u0645": {
18982               "final": "\uFD85",
18983               "initial": "\uFD86"
18984             },
18985             "\u0644\u0645\u062D": {
18986               "final": "\uFD87",
18987               "initial": "\uFD88"
18988             },
18989             "\u0645\u062D\u062C": {
18990               "initial": "\uFD89"
18991             },
18992             "\u0645\u062D\u0645": {
18993               "initial": "\uFD8A"
18994             },
18995             "\u0645\u062D\u064A": {
18996               "final": "\uFD8B"
18997             },
18998             "\u0645\u062C\u062D": {
18999               "initial": "\uFD8C"
19000             },
19001             "\u0645\u062C\u0645": {
19002               "initial": "\uFD8D"
19003             },
19004             "\u0645\u062E\u062C": {
19005               "initial": "\uFD8E"
19006             },
19007             "\u0645\u062E\u0645": {
19008               "initial": "\uFD8F"
19009             },
19010             "\u0645\u062C\u062E": {
19011               "initial": "\uFD92"
19012             },
19013             "\u0647\u0645\u062C": {
19014               "initial": "\uFD93"
19015             },
19016             "\u0647\u0645\u0645": {
19017               "initial": "\uFD94"
19018             },
19019             "\u0646\u062D\u0645": {
19020               "initial": "\uFD95"
19021             },
19022             "\u0646\u062D\u0649": {
19023               "final": "\uFD96"
19024             },
19025             "\u0646\u062C\u0645": {
19026               "final": "\uFD97",
19027               "initial": "\uFD98"
19028             },
19029             "\u0646\u062C\u0649": {
19030               "final": "\uFD99"
19031             },
19032             "\u0646\u0645\u064A": {
19033               "final": "\uFD9A"
19034             },
19035             "\u0646\u0645\u0649": {
19036               "final": "\uFD9B"
19037             },
19038             "\u064A\u0645\u0645": {
19039               "final": "\uFD9C",
19040               "initial": "\uFD9D"
19041             },
19042             "\u0628\u062E\u064A": {
19043               "final": "\uFD9E"
19044             },
19045             "\u062A\u062C\u064A": {
19046               "final": "\uFD9F"
19047             },
19048             "\u062A\u062C\u0649": {
19049               "final": "\uFDA0"
19050             },
19051             "\u062A\u062E\u064A": {
19052               "final": "\uFDA1"
19053             },
19054             "\u062A\u062E\u0649": {
19055               "final": "\uFDA2"
19056             },
19057             "\u062A\u0645\u064A": {
19058               "final": "\uFDA3"
19059             },
19060             "\u062A\u0645\u0649": {
19061               "final": "\uFDA4"
19062             },
19063             "\u062C\u0645\u064A": {
19064               "final": "\uFDA5"
19065             },
19066             "\u062C\u062D\u0649": {
19067               "final": "\uFDA6"
19068             },
19069             "\u062C\u0645\u0649": {
19070               "final": "\uFDA7"
19071             },
19072             "\u0633\u062E\u0649": {
19073               "final": "\uFDA8"
19074             },
19075             "\u0635\u062D\u064A": {
19076               "final": "\uFDA9"
19077             },
19078             "\u0634\u062D\u064A": {
19079               "final": "\uFDAA"
19080             },
19081             "\u0636\u062D\u064A": {
19082               "final": "\uFDAB"
19083             },
19084             "\u0644\u062C\u064A": {
19085               "final": "\uFDAC"
19086             },
19087             "\u0644\u0645\u064A": {
19088               "final": "\uFDAD"
19089             },
19090             "\u064A\u062D\u064A": {
19091               "final": "\uFDAE"
19092             },
19093             "\u064A\u062C\u064A": {
19094               "final": "\uFDAF"
19095             },
19096             "\u064A\u0645\u064A": {
19097               "final": "\uFDB0"
19098             },
19099             "\u0645\u0645\u064A": {
19100               "final": "\uFDB1"
19101             },
19102             "\u0642\u0645\u064A": {
19103               "final": "\uFDB2"
19104             },
19105             "\u0646\u062D\u064A": {
19106               "final": "\uFDB3"
19107             },
19108             "\u0639\u0645\u064A": {
19109               "final": "\uFDB6"
19110             },
19111             "\u0643\u0645\u064A": {
19112               "final": "\uFDB7"
19113             },
19114             "\u0646\u062C\u062D": {
19115               "initial": "\uFDB8",
19116               "final": "\uFDBD"
19117             },
19118             "\u0645\u062E\u064A": {
19119               "final": "\uFDB9"
19120             },
19121             "\u0644\u062C\u0645": {
19122               "initial": "\uFDBA",
19123               "final": "\uFDBC"
19124             },
19125             "\u0643\u0645\u0645": {
19126               "final": "\uFDBB",
19127               "initial": "\uFDC3"
19128             },
19129             "\u062C\u062D\u064A": {
19130               "final": "\uFDBE"
19131             },
19132             "\u062D\u062C\u064A": {
19133               "final": "\uFDBF"
19134             },
19135             "\u0645\u062C\u064A": {
19136               "final": "\uFDC0"
19137             },
19138             "\u0641\u0645\u064A": {
19139               "final": "\uFDC1"
19140             },
19141             "\u0628\u062D\u064A": {
19142               "final": "\uFDC2"
19143             },
19144             "\u0633\u062E\u064A": {
19145               "final": "\uFDC6"
19146             },
19147             "\u0646\u062C\u064A": {
19148               "final": "\uFDC7"
19149             },
19150             "\u0644\u0622": {
19151               "isolated": "\uFEF5",
19152               "final": "\uFEF6"
19153             },
19154             "\u0644\u0623": {
19155               "isolated": "\uFEF7",
19156               "final": "\uFEF8"
19157             },
19158             "\u0644\u0625": {
19159               "isolated": "\uFEF9",
19160               "final": "\uFEFA"
19161             },
19162             "\u0644\u0627": {
19163               "isolated": "\uFEFB",
19164               "final": "\uFEFC"
19165             },
19166             "words": {
19167               "\u0635\u0644\u06D2": "\uFDF0",
19168               "\u0642\u0644\u06D2": "\uFDF1",
19169               "\u0627\u0644\u0644\u0647": "\uFDF2",
19170               "\u0627\u0643\u0628\u0631": "\uFDF3",
19171               "\u0645\u062D\u0645\u062F": "\uFDF4",
19172               "\u0635\u0644\u0639\u0645": "\uFDF5",
19173               "\u0631\u0633\u0648\u0644": "\uFDF6",
19174               "\u0639\u0644\u064A\u0647": "\uFDF7",
19175               "\u0648\u0633\u0644\u0645": "\uFDF8",
19176               "\u0635\u0644\u0649": "\uFDF9",
19177               "\u0635\u0644\u0649\u0627\u0644\u0644\u0647\u0639\u0644\u064A\u0647\u0648\u0633\u0644\u0645": "\uFDFA",
19178               "\u062C\u0644\u062C\u0644\u0627\u0644\u0647": "\uFDFB",
19179               "\u0631\u06CC\u0627\u0644": "\uFDFC"
19180             }
19181           };
19182           exports["default"] = ligatureReference;
19183         });
19184
19185         var reference = createCommonjsModule(function (module, exports) {
19186
19187           Object.defineProperty(exports, "__esModule", {
19188             value: true
19189           });
19190           var letterList = Object.keys(unicodeArabic["default"]);
19191           exports.letterList = letterList;
19192           var ligatureList = Object.keys(unicodeLigatures["default"]);
19193           exports.ligatureList = ligatureList;
19194           var ligatureWordList = Object.keys(unicodeLigatures["default"].words);
19195           exports.ligatureWordList = ligatureWordList;
19196           var lams = "\u0644\u06B5\u06B6\u06B7\u06B8";
19197           exports.lams = lams;
19198           var alefs = "\u0627\u0622\u0623\u0625\u0671\u0672\u0673\u0675\u0773\u0774";
19199           exports.alefs = alefs; // for (var l = 1; l < lams.length; l++) {
19200           //   console.log('-');
19201           //   for (var a = 0; a < alefs.length; a++) {
19202           //     console.log(a + ': ' + lams[l] + alefs[a]);
19203           //   }
19204           // }
19205
19206           var tashkeel = "\u0605\u0640\u0670\u0674\u06DF\u06E7\u06E8";
19207           exports.tashkeel = tashkeel;
19208
19209           function addToTashkeel(start, finish) {
19210             for (var i = start; i <= finish; i++) {
19211               exports.tashkeel = tashkeel += String.fromCharCode(i);
19212             }
19213           }
19214
19215           addToTashkeel(0x0610, 0x061A);
19216           addToTashkeel(0x064B, 0x065F);
19217           addToTashkeel(0x06D6, 0x06DC);
19218           addToTashkeel(0x06E0, 0x06E4);
19219           addToTashkeel(0x06EA, 0x06ED);
19220           addToTashkeel(0x08D3, 0x08E1);
19221           addToTashkeel(0x08E3, 0x08FF);
19222           addToTashkeel(0xFE70, 0xFE7F);
19223           var lineBreakers = "\u0627\u0629\u0648\u06C0\u06CF\u06FD\u06FE\u076B\u076C\u0771\u0773\u0774\u0778\u0779\u08E2\u08B1\u08B2\u08B9";
19224           exports.lineBreakers = lineBreakers;
19225
19226           function addToLineBreakers(start, finish) {
19227             for (var i = start; i <= finish; i++) {
19228               exports.lineBreakers = lineBreakers += String.fromCharCode(i);
19229             }
19230           }
19231
19232           addToLineBreakers(0x0600, 0x061F); // it's OK to include tashkeel in this range as it is ignored
19233
19234           addToLineBreakers(0x0621, 0x0625);
19235           addToLineBreakers(0x062F, 0x0632);
19236           addToLineBreakers(0x0660, 0x066D); // numerals, math
19237
19238           addToLineBreakers(0x0671, 0x0677);
19239           addToLineBreakers(0x0688, 0x0699);
19240           addToLineBreakers(0x06C3, 0x06CB);
19241           addToLineBreakers(0x06D2, 0x06F9);
19242           addToLineBreakers(0x0759, 0x075B);
19243           addToLineBreakers(0x08AA, 0x08AE);
19244           addToLineBreakers(0xFB50, 0xFDFD); // presentation forms look like they could connect, but never do
19245           // Presentation Forms A includes diacritics but they are meant to stand alone
19246
19247           addToLineBreakers(0xFE80, 0xFEFC); // presentation forms look like they could connect, but never do
19248           // numerals, math
19249
19250           addToLineBreakers(0x10E60, 0x10E7F);
19251           addToLineBreakers(0x1EC70, 0x1ECBF);
19252           addToLineBreakers(0x1EE00, 0x1EEFF);
19253         });
19254
19255         var GlyphSplitter_1 = createCommonjsModule(function (module, exports) {
19256
19257           Object.defineProperty(exports, "__esModule", {
19258             value: true
19259           });
19260
19261           function GlyphSplitter(word) {
19262             var letters = [];
19263             var lastLetter = '';
19264             word.split('').forEach(function (letter) {
19265               if (isArabic_1.isArabic(letter)) {
19266                 if (reference.tashkeel.indexOf(letter) > -1) {
19267                   letters[letters.length - 1] += letter;
19268                 } else if (lastLetter.length && (reference.lams.indexOf(lastLetter) === 0 && reference.alefs.indexOf(letter) > -1 || reference.lams.indexOf(lastLetter) > 0 && reference.alefs.indexOf(letter) === 0)) {
19269                   // valid LA forms
19270                   letters[letters.length - 1] += letter;
19271                 } else {
19272                   letters.push(letter);
19273                 }
19274               } else {
19275                 letters.push(letter);
19276               }
19277
19278               if (reference.tashkeel.indexOf(letter) === -1) {
19279                 lastLetter = letter;
19280               }
19281             });
19282             return letters;
19283           }
19284
19285           exports.GlyphSplitter = GlyphSplitter;
19286         });
19287
19288         var BaselineSplitter_1 = createCommonjsModule(function (module, exports) {
19289
19290           Object.defineProperty(exports, "__esModule", {
19291             value: true
19292           });
19293
19294           function BaselineSplitter(word) {
19295             var letters = [];
19296             var lastLetter = '';
19297             word.split('').forEach(function (letter) {
19298               if (isArabic_1.isArabic(letter) && isArabic_1.isArabic(lastLetter)) {
19299                 if (lastLetter.length && reference.tashkeel.indexOf(letter) > -1) {
19300                   letters[letters.length - 1] += letter;
19301                 } else if (reference.lineBreakers.indexOf(lastLetter) > -1) {
19302                   letters.push(letter);
19303                 } else {
19304                   letters[letters.length - 1] += letter;
19305                 }
19306               } else {
19307                 letters.push(letter);
19308               }
19309
19310               if (reference.tashkeel.indexOf(letter) === -1) {
19311                 // don't allow tashkeel to hide line break
19312                 lastLetter = letter;
19313               }
19314             });
19315             return letters;
19316           }
19317
19318           exports.BaselineSplitter = BaselineSplitter;
19319         });
19320
19321         var Normalization = createCommonjsModule(function (module, exports) {
19322
19323           Object.defineProperty(exports, "__esModule", {
19324             value: true
19325           });
19326
19327           function Normal(word, breakPresentationForm) {
19328             // default is to turn initial/isolated/medial/final presentation form to generic
19329             if (typeof breakPresentationForm === 'undefined') {
19330               breakPresentationForm = true;
19331             }
19332
19333             var returnable = '';
19334             word.split('').forEach(function (letter) {
19335               if (!isArabic_1.isArabic(letter)) {
19336                 returnable += letter;
19337                 return;
19338               }
19339
19340               for (var w = 0; w < reference.letterList.length; w++) {
19341                 // ok so we are checking this potential lettertron
19342                 var letterForms = unicodeArabic["default"][reference.letterList[w]];
19343                 var versions = Object.keys(letterForms);
19344
19345                 for (var v = 0; v < versions.length; v++) {
19346                   var localVersion = letterForms[versions[v]];
19347
19348                   if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19349                     // look at this embedded object
19350                     var embeddedForms = Object.keys(localVersion);
19351
19352                     for (var ef = 0; ef < embeddedForms.length; ef++) {
19353                       var form = localVersion[embeddedForms[ef]];
19354
19355                       if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19356                         // match
19357                         // console.log('embedded match');
19358                         if (form === letter) {
19359                           // match exact
19360                           if (breakPresentationForm && localVersion['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(embeddedForms[ef]) > -1) {
19361                             // replace presentation form
19362                             // console.log('keeping normal form of the letter');
19363                             if (_typeof(localVersion['normal']) === 'object') {
19364                               returnable += localVersion['normal'][0];
19365                             } else {
19366                               returnable += localVersion['normal'];
19367                             }
19368
19369                             return;
19370                           } // console.log('keeping this letter');
19371
19372
19373                           returnable += letter;
19374                           return;
19375                         } else if (_typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19376                           // match
19377                           returnable += form[0]; // console.log('added the first letter from the same array');
19378
19379                           return;
19380                         }
19381                       }
19382                     }
19383                   } else if (localVersion === letter) {
19384                     // match exact
19385                     if (breakPresentationForm && letterForms['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(versions[v]) > -1) {
19386                       // replace presentation form
19387                       // console.log('keeping normal form of the letter');
19388                       if (_typeof(letterForms['normal']) === 'object') {
19389                         returnable += letterForms['normal'][0];
19390                       } else {
19391                         returnable += letterForms['normal'];
19392                       }
19393
19394                       return;
19395                     } // console.log('keeping this letter');
19396
19397
19398                     returnable += letter;
19399                     return;
19400                   } else if (_typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19401                     // match
19402                     returnable += localVersion[0]; // console.log('added the first letter from the same array');
19403
19404                     return;
19405                   }
19406                 }
19407               } // try ligatures
19408
19409
19410               for (var v2 = 0; v2 < reference.ligatureList.length; v2++) {
19411                 var normalForm = reference.ligatureList[v2];
19412
19413                 if (normalForm !== 'words') {
19414                   var ligForms = Object.keys(unicodeLigatures["default"][normalForm]);
19415
19416                   for (var f = 0; f < ligForms.length; f++) {
19417                     if (unicodeLigatures["default"][normalForm][ligForms[f]] === letter) {
19418                       returnable += normalForm;
19419                       return;
19420                     }
19421                   }
19422                 }
19423               } // try words ligatures
19424
19425
19426               for (var v3 = 0; v3 < reference.ligatureWordList.length; v3++) {
19427                 var _normalForm = reference.ligatureWordList[v3];
19428
19429                 if (unicodeLigatures["default"].words[_normalForm] === letter) {
19430                   returnable += _normalForm;
19431                   return;
19432                 }
19433               }
19434
19435               returnable += letter; // console.log('kept the letter')
19436             });
19437             return returnable;
19438           }
19439
19440           exports.Normal = Normal;
19441         });
19442
19443         var CharShaper_1 = createCommonjsModule(function (module, exports) {
19444
19445           Object.defineProperty(exports, "__esModule", {
19446             value: true
19447           });
19448
19449           function CharShaper(letter, form) {
19450             if (!isArabic_1.isArabic(letter)) {
19451               // fail not Arabic
19452               throw new Error('Not Arabic');
19453             }
19454
19455             if (letter === "\u0621") {
19456               // hamza alone
19457               return "\u0621";
19458             }
19459
19460             for (var w = 0; w < reference.letterList.length; w++) {
19461               // ok so we are checking this potential lettertron
19462               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19463               var versions = Object.keys(letterForms);
19464
19465               for (var v = 0; v < versions.length; v++) {
19466                 var localVersion = letterForms[versions[v]];
19467
19468                 if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19469                   if (versions.indexOf(form) > -1) {
19470                     return letterForms[form];
19471                   }
19472                 } else if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19473                   // check embedded
19474                   var embeddedVersions = Object.keys(localVersion);
19475
19476                   for (var ev = 0; ev < embeddedVersions.length; ev++) {
19477                     if (localVersion[embeddedVersions[ev]] === letter || _typeof(localVersion[embeddedVersions[ev]]) === 'object' && localVersion[embeddedVersions[ev]].indexOf && localVersion[embeddedVersions[ev]].indexOf(letter) > -1) {
19478                       if (embeddedVersions.indexOf(form) > -1) {
19479                         return localVersion[form];
19480                       }
19481                     }
19482                   }
19483                 }
19484               }
19485             }
19486           }
19487
19488           exports.CharShaper = CharShaper;
19489         });
19490
19491         var WordShaper_1 = createCommonjsModule(function (module, exports) {
19492
19493           Object.defineProperty(exports, "__esModule", {
19494             value: true
19495           });
19496
19497           function WordShaper(word) {
19498             var state = 'initial';
19499             var output = '';
19500
19501             for (var w = 0; w < word.length; w++) {
19502               var nextLetter = ' ';
19503
19504               for (var nxw = w + 1; nxw < word.length; nxw++) {
19505                 if (!isArabic_1.isArabic(word[nxw])) {
19506                   break;
19507                 }
19508
19509                 if (reference.tashkeel.indexOf(word[nxw]) === -1) {
19510                   nextLetter = word[nxw];
19511                   break;
19512                 }
19513               }
19514
19515               if (!isArabic_1.isArabic(word[w]) || isArabic_1.isMath(word[w])) {
19516                 // space or other non-Arabic
19517                 output += word[w];
19518                 state = 'initial';
19519               } else if (reference.tashkeel.indexOf(word[w]) > -1) {
19520                 // tashkeel - add without changing state
19521                 output += word[w];
19522               } else if (nextLetter === ' ' || // last Arabic letter in this word
19523               reference.lineBreakers.indexOf(word[w]) > -1) {
19524                 // the current letter is known to break lines
19525                 output += CharShaper_1.CharShaper(word[w], state === 'initial' ? 'isolated' : 'final');
19526                 state = 'initial';
19527               } else if (reference.lams.indexOf(word[w]) > -1 && reference.alefs.indexOf(nextLetter) > -1) {
19528                 // LA letters - advance an additional letter after this
19529                 output += unicodeLigatures["default"][word[w] + nextLetter][state === 'initial' ? 'isolated' : 'final'];
19530
19531                 while (word[w] !== nextLetter) {
19532                   w++;
19533                 }
19534
19535                 state = 'initial';
19536               } else {
19537                 output += CharShaper_1.CharShaper(word[w], state);
19538                 state = 'medial';
19539               }
19540             }
19541
19542             return output;
19543           }
19544
19545           exports.WordShaper = WordShaper;
19546         });
19547
19548         var ParentLetter_1 = createCommonjsModule(function (module, exports) {
19549
19550           Object.defineProperty(exports, "__esModule", {
19551             value: true
19552           });
19553
19554           function ParentLetter(letter) {
19555             if (!isArabic_1.isArabic(letter)) {
19556               throw new Error('Not an Arabic letter');
19557             }
19558
19559             for (var w = 0; w < reference.letterList.length; w++) {
19560               // ok so we are checking this potential lettertron
19561               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19562               var versions = Object.keys(letterForms);
19563
19564               for (var v = 0; v < versions.length; v++) {
19565                 var localVersion = letterForms[versions[v]];
19566
19567                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19568                   // look at this embedded object
19569                   var embeddedForms = Object.keys(localVersion);
19570
19571                   for (var ef = 0; ef < embeddedForms.length; ef++) {
19572                     var form = localVersion[embeddedForms[ef]];
19573
19574                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19575                       // match
19576                       return localVersion;
19577                     }
19578                   }
19579                 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19580                   // match
19581                   return letterForms;
19582                 }
19583               }
19584
19585               return null;
19586             }
19587           }
19588
19589           exports.ParentLetter = ParentLetter;
19590
19591           function GrandparentLetter(letter) {
19592             if (!isArabic_1.isArabic(letter)) {
19593               throw new Error('Not an Arabic letter');
19594             }
19595
19596             for (var w = 0; w < reference.letterList.length; w++) {
19597               // ok so we are checking this potential lettertron
19598               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19599               var versions = Object.keys(letterForms);
19600
19601               for (var v = 0; v < versions.length; v++) {
19602                 var localVersion = letterForms[versions[v]];
19603
19604                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19605                   // look at this embedded object
19606                   var embeddedForms = Object.keys(localVersion);
19607
19608                   for (var ef = 0; ef < embeddedForms.length; ef++) {
19609                     var form = localVersion[embeddedForms[ef]];
19610
19611                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19612                       // match
19613                       return letterForms;
19614                     }
19615                   }
19616                 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19617                   // match
19618                   return letterForms;
19619                 }
19620               }
19621
19622               return null;
19623             }
19624           }
19625
19626           exports.GrandparentLetter = GrandparentLetter;
19627         });
19628
19629         var lib = createCommonjsModule(function (module, exports) {
19630
19631           Object.defineProperty(exports, "__esModule", {
19632             value: true
19633           });
19634           exports.isArabic = isArabic_1.isArabic;
19635           exports.GlyphSplitter = GlyphSplitter_1.GlyphSplitter;
19636           exports.BaselineSplitter = BaselineSplitter_1.BaselineSplitter;
19637           exports.Normal = Normalization.Normal;
19638           exports.CharShaper = CharShaper_1.CharShaper;
19639           exports.WordShaper = WordShaper_1.WordShaper;
19640           exports.ParentLetter = ParentLetter_1.ParentLetter;
19641           exports.GrandparentLetter = ParentLetter_1.GrandparentLetter;
19642         });
19643
19644         var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u07BF\u08A0–\u08BF]/;
19645         function fixRTLTextForSvg(inputText) {
19646           var ret = '',
19647               rtlBuffer = [];
19648           var arabicRegex = /[\u0600-\u06FF]/g;
19649           var arabicDiacritics = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06ED]/g;
19650           var arabicMath = /[\u0660-\u066C\u06F0-\u06F9]+/g;
19651           var thaanaVowel = /[\u07A6-\u07B0]/;
19652           var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/; // Arabic word shaping
19653
19654           if (arabicRegex.test(inputText)) {
19655             inputText = lib.WordShaper(inputText);
19656           }
19657
19658           for (var n = 0; n < inputText.length; n++) {
19659             var c = inputText[n];
19660
19661             if (arabicMath.test(c)) {
19662               // Arabic numbers go LTR
19663               ret += rtlBuffer.reverse().join('');
19664               rtlBuffer = [c];
19665             } else {
19666               if (rtlBuffer.length && arabicMath.test(rtlBuffer[rtlBuffer.length - 1])) {
19667                 ret += rtlBuffer.reverse().join('');
19668                 rtlBuffer = [];
19669               }
19670
19671               if ((thaanaVowel.test(c) || hebrewSign.test(c) || arabicDiacritics.test(c)) && rtlBuffer.length) {
19672                 rtlBuffer[rtlBuffer.length - 1] += c;
19673               } else if (rtlRegex.test(c) // include Arabic presentation forms
19674               || c.charCodeAt(0) >= 64336 && c.charCodeAt(0) <= 65023 || c.charCodeAt(0) >= 65136 && c.charCodeAt(0) <= 65279) {
19675                 rtlBuffer.push(c);
19676               } else if (c === ' ' && rtlBuffer.length) {
19677                 // whitespace within RTL text
19678                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
19679               } else {
19680                 // non-RTL character
19681                 ret += rtlBuffer.reverse().join('') + c;
19682                 rtlBuffer = [];
19683               }
19684             }
19685           }
19686
19687           ret += rtlBuffer.reverse().join('');
19688           return ret;
19689         }
19690
19691         var propertyIsEnumerable = objectPropertyIsEnumerable.f;
19692
19693         // `Object.{ entries, values }` methods implementation
19694         var createMethod$5 = function (TO_ENTRIES) {
19695           return function (it) {
19696             var O = toIndexedObject(it);
19697             var keys = objectKeys(O);
19698             var length = keys.length;
19699             var i = 0;
19700             var result = [];
19701             var key;
19702             while (length > i) {
19703               key = keys[i++];
19704               if (!descriptors || propertyIsEnumerable.call(O, key)) {
19705                 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
19706               }
19707             }
19708             return result;
19709           };
19710         };
19711
19712         var objectToArray = {
19713           // `Object.entries` method
19714           // https://tc39.github.io/ecma262/#sec-object.entries
19715           entries: createMethod$5(true),
19716           // `Object.values` method
19717           // https://tc39.github.io/ecma262/#sec-object.values
19718           values: createMethod$5(false)
19719         };
19720
19721         var $values = objectToArray.values;
19722
19723         // `Object.values` method
19724         // https://tc39.github.io/ecma262/#sec-object.values
19725         _export({ target: 'Object', stat: true }, {
19726           values: function values(O) {
19727             return $values(O);
19728           }
19729         });
19730
19731         // https://github.com/openstreetmap/iD/issues/772
19732         // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
19733         var _storage;
19734
19735         try {
19736           _storage = localStorage;
19737         } catch (e) {} // eslint-disable-line no-empty
19738
19739
19740         _storage = _storage || function () {
19741           var s = {};
19742           return {
19743             getItem: function getItem(k) {
19744               return s[k];
19745             },
19746             setItem: function setItem(k, v) {
19747               return s[k] = v;
19748             },
19749             removeItem: function removeItem(k) {
19750               return delete s[k];
19751             }
19752           };
19753         }(); //
19754         // corePreferences is an interface for persisting basic key-value strings
19755         // within and between iD sessions on the same site.
19756         //
19757
19758
19759         function corePreferences(k, v) {
19760           try {
19761             if (arguments.length === 1) return _storage.getItem(k);else if (v === null) _storage.removeItem(k);else _storage.setItem(k, v);
19762           } catch (e) {
19763             /* eslint-disable no-console */
19764             if (typeof console !== 'undefined') {
19765               console.error('localStorage quota exceeded');
19766             }
19767             /* eslint-enable no-console */
19768
19769           }
19770         }
19771
19772         function responseText(response) {
19773           if (!response.ok) throw new Error(response.status + " " + response.statusText);
19774           return response.text();
19775         }
19776
19777         function d3_text (input, init) {
19778           return fetch(input, init).then(responseText);
19779         }
19780
19781         function responseJson(response) {
19782           if (!response.ok) throw new Error(response.status + " " + response.statusText);
19783           if (response.status === 204 || response.status === 205) return;
19784           return response.json();
19785         }
19786
19787         function d3_json (input, init) {
19788           return fetch(input, init).then(responseJson);
19789         }
19790
19791         function parser(type) {
19792           return function (input, init) {
19793             return d3_text(input, init).then(function (text) {
19794               return new DOMParser().parseFromString(text, type);
19795             });
19796           };
19797         }
19798
19799         var d3_xml = parser("application/xml");
19800         var svg = parser("image/svg+xml");
19801
19802         var _mainFileFetcher = coreFileFetcher(); // singleton
19803         // coreFileFetcher asynchronously fetches data from JSON files
19804         //
19805
19806         function coreFileFetcher() {
19807           var _this = {};
19808           var _inflight = {};
19809           var _fileMap = {
19810             'address_formats': 'data/address_formats.min.json',
19811             'deprecated': 'data/deprecated.min.json',
19812             'discarded': 'data/discarded.min.json',
19813             'imagery': 'data/imagery.min.json',
19814             'intro_graph': 'data/intro_graph.min.json',
19815             'keepRight': 'data/keepRight.min.json',
19816             'languages': 'data/languages.min.json',
19817             'locales': 'data/locales.min.json',
19818             'nsi_brands': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@4/dist/brands.min.json',
19819             'nsi_filters': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@4/dist/filters.min.json',
19820             'oci_features': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/features.min.json',
19821             'oci_resources': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/resources.min.json',
19822             'preset_categories': 'data/preset_categories.min.json',
19823             'preset_defaults': 'data/preset_defaults.min.json',
19824             'preset_fields': 'data/preset_fields.min.json',
19825             'preset_presets': 'data/preset_presets.min.json',
19826             'phone_formats': 'data/phone_formats.min.json',
19827             'qa_data': 'data/qa_data.min.json',
19828             'shortcuts': 'data/shortcuts.min.json',
19829             'territory_languages': 'data/territory_languages.min.json',
19830             'wmf_sitematrix': 'https://cdn.jsdelivr.net/npm/wmf-sitematrix@0.1/wikipedia.min.json'
19831           };
19832           var _cachedData = {}; // expose the cache; useful for tests
19833
19834           _this.cache = function () {
19835             return _cachedData;
19836           }; // Returns a Promise to fetch data
19837           // (resolved with the data if we have it already)
19838
19839
19840           _this.get = function (which) {
19841             if (_cachedData[which]) {
19842               return Promise.resolve(_cachedData[which]);
19843             }
19844
19845             var file = _fileMap[which];
19846
19847             var url = file && _this.asset(file);
19848
19849             if (!url) {
19850               return Promise.reject("Unknown data file for \"".concat(which, "\""));
19851             }
19852
19853             var prom = _inflight[url];
19854
19855             if (!prom) {
19856               _inflight[url] = prom = d3_json(url).then(function (result) {
19857                 delete _inflight[url];
19858
19859                 if (!result) {
19860                   throw new Error("No data loaded for \"".concat(which, "\""));
19861                 }
19862
19863                 _cachedData[which] = result;
19864                 return result;
19865               })["catch"](function (err) {
19866                 delete _inflight[url];
19867                 throw err;
19868               });
19869             }
19870
19871             return prom;
19872           }; // Accessor for the file map
19873
19874
19875           _this.fileMap = function (val) {
19876             if (!arguments.length) return _fileMap;
19877             _fileMap = val;
19878             return _this;
19879           };
19880
19881           var _assetPath = '';
19882
19883           _this.assetPath = function (val) {
19884             if (!arguments.length) return _assetPath;
19885             _assetPath = val;
19886             return _this;
19887           };
19888
19889           var _assetMap = {};
19890
19891           _this.assetMap = function (val) {
19892             if (!arguments.length) return _assetMap;
19893             _assetMap = val;
19894             return _this;
19895           };
19896
19897           _this.asset = function (val) {
19898             if (/^http(s)?:\/\//i.test(val)) return val;
19899             var filename = _assetPath + val;
19900             return _assetMap[filename] || filename;
19901           };
19902
19903           return _this;
19904         }
19905
19906         var $findIndex$1 = arrayIteration.findIndex;
19907
19908
19909
19910         var FIND_INDEX = 'findIndex';
19911         var SKIPS_HOLES$1 = true;
19912
19913         var USES_TO_LENGTH$b = arrayMethodUsesToLength(FIND_INDEX);
19914
19915         // Shouldn't skip holes
19916         if (FIND_INDEX in []) Array(1)[FIND_INDEX](function () { SKIPS_HOLES$1 = false; });
19917
19918         // `Array.prototype.findIndex` method
19919         // https://tc39.github.io/ecma262/#sec-array.prototype.findindex
19920         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES$1 || !USES_TO_LENGTH$b }, {
19921           findIndex: function findIndex(callbackfn /* , that = undefined */) {
19922             return $findIndex$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
19923           }
19924         });
19925
19926         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
19927         addToUnscopables(FIND_INDEX);
19928
19929         var $includes$1 = arrayIncludes.includes;
19930
19931
19932
19933         var USES_TO_LENGTH$c = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });
19934
19935         // `Array.prototype.includes` method
19936         // https://tc39.github.io/ecma262/#sec-array.prototype.includes
19937         _export({ target: 'Array', proto: true, forced: !USES_TO_LENGTH$c }, {
19938           includes: function includes(el /* , fromIndex = 0 */) {
19939             return $includes$1(this, el, arguments.length > 1 ? arguments[1] : undefined);
19940           }
19941         });
19942
19943         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
19944         addToUnscopables('includes');
19945
19946         var notARegexp = function (it) {
19947           if (isRegexp(it)) {
19948             throw TypeError("The method doesn't accept regular expressions");
19949           } return it;
19950         };
19951
19952         var MATCH$2 = wellKnownSymbol('match');
19953
19954         var correctIsRegexpLogic = function (METHOD_NAME) {
19955           var regexp = /./;
19956           try {
19957             '/./'[METHOD_NAME](regexp);
19958           } catch (e) {
19959             try {
19960               regexp[MATCH$2] = false;
19961               return '/./'[METHOD_NAME](regexp);
19962             } catch (f) { /* empty */ }
19963           } return false;
19964         };
19965
19966         // `String.prototype.includes` method
19967         // https://tc39.github.io/ecma262/#sec-string.prototype.includes
19968         _export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, {
19969           includes: function includes(searchString /* , position = 0 */) {
19970             return !!~String(requireObjectCoercible(this))
19971               .indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
19972           }
19973         });
19974
19975         var _detected;
19976
19977         function utilDetect(refresh) {
19978           if (_detected && !refresh) return _detected;
19979           _detected = {};
19980           var ua = navigator.userAgent;
19981           var m = null;
19982           /* Browser */
19983
19984           m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
19985
19986           if (m !== null) {
19987             _detected.browser = m[1];
19988             _detected.version = m[2];
19989           }
19990
19991           if (!_detected.browser) {
19992             m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
19993
19994             if (m !== null) {
19995               _detected.browser = 'msie';
19996               _detected.version = m[1];
19997             }
19998           }
19999
20000           if (!_detected.browser) {
20001             m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
20002
20003             if (m !== null) {
20004               _detected.browser = 'Opera';
20005               _detected.version = m[2];
20006             }
20007           }
20008
20009           if (!_detected.browser) {
20010             m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
20011
20012             if (m !== null) {
20013               _detected.browser = m[1];
20014               _detected.version = m[2];
20015               m = ua.match(/version\/([\.\d]+)/i);
20016               if (m !== null) _detected.version = m[1];
20017             }
20018           }
20019
20020           if (!_detected.browser) {
20021             _detected.browser = navigator.appName;
20022             _detected.version = navigator.appVersion;
20023           } // keep major.minor version only..
20024
20025
20026           _detected.version = _detected.version.split(/\W/).slice(0, 2).join('.'); // detect other browser capabilities
20027           // Legacy Opera has incomplete svg style support. See #715
20028
20029           _detected.opera = _detected.browser.toLowerCase() === 'opera' && parseFloat(_detected.version) < 15;
20030
20031           if (_detected.browser.toLowerCase() === 'msie') {
20032             _detected.ie = true;
20033             _detected.browser = 'Internet Explorer';
20034             _detected.support = parseFloat(_detected.version) >= 11;
20035           } else {
20036             _detected.ie = false;
20037             _detected.support = true;
20038           }
20039
20040           _detected.filedrop = window.FileReader && 'ondrop' in window;
20041           _detected.download = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
20042           _detected.cssfilters = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
20043           /* Platform */
20044
20045           if (/Win/.test(ua)) {
20046             _detected.os = 'win';
20047             _detected.platform = 'Windows';
20048           } else if (/Mac/.test(ua)) {
20049             _detected.os = 'mac';
20050             _detected.platform = 'Macintosh';
20051           } else if (/X11/.test(ua) || /Linux/.test(ua)) {
20052             _detected.os = 'linux';
20053             _detected.platform = 'Linux';
20054           } else {
20055             _detected.os = 'win';
20056             _detected.platform = 'Unknown';
20057           }
20058
20059           _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
20060           // so assume any "mac" with multitouch is actually iOS
20061           navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
20062           /* Locale */
20063           // An array of locales requested by the browser in priority order.
20064
20065           _detected.browserLocales = Array.from(new Set( // remove duplicates
20066           [navigator.language].concat(navigator.languages || []).concat([// old property for backwards compatibility
20067           navigator.userLanguage]) // remove any undefined values
20068           .filter(Boolean)));
20069           /* Host */
20070
20071           var loc = window.top.location;
20072           var origin = loc.origin;
20073
20074           if (!origin) {
20075             // for unpatched IE11
20076             origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port : '');
20077           }
20078
20079           _detected.host = origin + loc.pathname;
20080           return _detected;
20081         }
20082
20083         var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
20084         var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
20085         var defineProperty$a = objectDefineProperty.f;
20086         var trim$2 = stringTrim.trim;
20087
20088         var NUMBER = 'Number';
20089         var NativeNumber = global_1[NUMBER];
20090         var NumberPrototype = NativeNumber.prototype;
20091
20092         // Opera ~12 has broken Object#toString
20093         var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER;
20094
20095         // `ToNumber` abstract operation
20096         // https://tc39.github.io/ecma262/#sec-tonumber
20097         var toNumber = function (argument) {
20098           var it = toPrimitive(argument, false);
20099           var first, third, radix, maxCode, digits, length, index, code;
20100           if (typeof it == 'string' && it.length > 2) {
20101             it = trim$2(it);
20102             first = it.charCodeAt(0);
20103             if (first === 43 || first === 45) {
20104               third = it.charCodeAt(2);
20105               if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
20106             } else if (first === 48) {
20107               switch (it.charCodeAt(1)) {
20108                 case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i
20109                 case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i
20110                 default: return +it;
20111               }
20112               digits = it.slice(2);
20113               length = digits.length;
20114               for (index = 0; index < length; index++) {
20115                 code = digits.charCodeAt(index);
20116                 // parseInt parses a string to a first unavailable symbol
20117                 // but ToNumber should return NaN if a string contains unavailable symbols
20118                 if (code < 48 || code > maxCode) return NaN;
20119               } return parseInt(digits, radix);
20120             }
20121           } return +it;
20122         };
20123
20124         // `Number` constructor
20125         // https://tc39.github.io/ecma262/#sec-number-constructor
20126         if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
20127           var NumberWrapper = function Number(value) {
20128             var it = arguments.length < 1 ? 0 : value;
20129             var dummy = this;
20130             return dummy instanceof NumberWrapper
20131               // check on 1..constructor(foo) case
20132               && (BROKEN_CLASSOF ? fails(function () { NumberPrototype.valueOf.call(dummy); }) : classofRaw(dummy) != NUMBER)
20133                 ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it);
20134           };
20135           for (var keys$3 = descriptors ? getOwnPropertyNames$2(NativeNumber) : (
20136             // ES3:
20137             'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +
20138             // ES2015 (in case, if modules with ES2015 Number statics required before):
20139             'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +
20140             'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger'
20141           ).split(','), j$2 = 0, key$1; keys$3.length > j$2; j$2++) {
20142             if (has(NativeNumber, key$1 = keys$3[j$2]) && !has(NumberWrapper, key$1)) {
20143               defineProperty$a(NumberWrapper, key$1, getOwnPropertyDescriptor$3(NativeNumber, key$1));
20144             }
20145           }
20146           NumberWrapper.prototype = NumberPrototype;
20147           NumberPrototype.constructor = NumberWrapper;
20148           redefine(global_1, NUMBER, NumberWrapper);
20149         }
20150
20151         // `Number.MAX_SAFE_INTEGER` constant
20152         // https://tc39.github.io/ecma262/#sec-number.max_safe_integer
20153         _export({ target: 'Number', stat: true }, {
20154           MAX_SAFE_INTEGER: 0x1FFFFFFFFFFFFF
20155         });
20156
20157         var aesJs = createCommonjsModule(function (module, exports) {
20158           /*! MIT License. Copyright 2015-2018 Richard Moore <me@ricmoo.com>. See LICENSE.txt. */
20159           (function (root) {
20160
20161             function checkInt(value) {
20162               return parseInt(value) === value;
20163             }
20164
20165             function checkInts(arrayish) {
20166               if (!checkInt(arrayish.length)) {
20167                 return false;
20168               }
20169
20170               for (var i = 0; i < arrayish.length; i++) {
20171                 if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
20172                   return false;
20173                 }
20174               }
20175
20176               return true;
20177             }
20178
20179             function coerceArray(arg, copy) {
20180               // ArrayBuffer view
20181               if (arg.buffer && arg.name === 'Uint8Array') {
20182                 if (copy) {
20183                   if (arg.slice) {
20184                     arg = arg.slice();
20185                   } else {
20186                     arg = Array.prototype.slice.call(arg);
20187                   }
20188                 }
20189
20190                 return arg;
20191               } // It's an array; check it is a valid representation of a byte
20192
20193
20194               if (Array.isArray(arg)) {
20195                 if (!checkInts(arg)) {
20196                   throw new Error('Array contains invalid value: ' + arg);
20197                 }
20198
20199                 return new Uint8Array(arg);
20200               } // Something else, but behaves like an array (maybe a Buffer? Arguments?)
20201
20202
20203               if (checkInt(arg.length) && checkInts(arg)) {
20204                 return new Uint8Array(arg);
20205               }
20206
20207               throw new Error('unsupported array-like object');
20208             }
20209
20210             function createArray(length) {
20211               return new Uint8Array(length);
20212             }
20213
20214             function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
20215               if (sourceStart != null || sourceEnd != null) {
20216                 if (sourceArray.slice) {
20217                   sourceArray = sourceArray.slice(sourceStart, sourceEnd);
20218                 } else {
20219                   sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
20220                 }
20221               }
20222
20223               targetArray.set(sourceArray, targetStart);
20224             }
20225
20226             var convertUtf8 = function () {
20227               function toBytes(text) {
20228                 var result = [],
20229                     i = 0;
20230                 text = encodeURI(text);
20231
20232                 while (i < text.length) {
20233                   var c = text.charCodeAt(i++); // if it is a % sign, encode the following 2 bytes as a hex value
20234
20235                   if (c === 37) {
20236                     result.push(parseInt(text.substr(i, 2), 16));
20237                     i += 2; // otherwise, just the actual byte
20238                   } else {
20239                     result.push(c);
20240                   }
20241                 }
20242
20243                 return coerceArray(result);
20244               }
20245
20246               function fromBytes(bytes) {
20247                 var result = [],
20248                     i = 0;
20249
20250                 while (i < bytes.length) {
20251                   var c = bytes[i];
20252
20253                   if (c < 128) {
20254                     result.push(String.fromCharCode(c));
20255                     i++;
20256                   } else if (c > 191 && c < 224) {
20257                     result.push(String.fromCharCode((c & 0x1f) << 6 | bytes[i + 1] & 0x3f));
20258                     i += 2;
20259                   } else {
20260                     result.push(String.fromCharCode((c & 0x0f) << 12 | (bytes[i + 1] & 0x3f) << 6 | bytes[i + 2] & 0x3f));
20261                     i += 3;
20262                   }
20263                 }
20264
20265                 return result.join('');
20266               }
20267
20268               return {
20269                 toBytes: toBytes,
20270                 fromBytes: fromBytes
20271               };
20272             }();
20273
20274             var convertHex = function () {
20275               function toBytes(text) {
20276                 var result = [];
20277
20278                 for (var i = 0; i < text.length; i += 2) {
20279                   result.push(parseInt(text.substr(i, 2), 16));
20280                 }
20281
20282                 return result;
20283               } // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
20284
20285
20286               var Hex = '0123456789abcdef';
20287
20288               function fromBytes(bytes) {
20289                 var result = [];
20290
20291                 for (var i = 0; i < bytes.length; i++) {
20292                   var v = bytes[i];
20293                   result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
20294                 }
20295
20296                 return result.join('');
20297               }
20298
20299               return {
20300                 toBytes: toBytes,
20301                 fromBytes: fromBytes
20302               };
20303             }(); // Number of rounds by keysize
20304
20305
20306             var numberOfRounds = {
20307               16: 10,
20308               24: 12,
20309               32: 14
20310             }; // Round constant words
20311
20312             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)
20313
20314             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];
20315             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
20316
20317             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];
20318             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];
20319             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];
20320             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
20321
20322             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];
20323             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];
20324             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];
20325             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
20326
20327             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];
20328             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];
20329             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];
20330             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];
20331
20332             function convertToInt32(bytes) {
20333               var result = [];
20334
20335               for (var i = 0; i < bytes.length; i += 4) {
20336                 result.push(bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]);
20337               }
20338
20339               return result;
20340             }
20341
20342             var AES = function AES(key) {
20343               if (!(this instanceof AES)) {
20344                 throw Error('AES must be instanitated with `new`');
20345               }
20346
20347               Object.defineProperty(this, 'key', {
20348                 value: coerceArray(key, true)
20349               });
20350
20351               this._prepare();
20352             };
20353
20354             AES.prototype._prepare = function () {
20355               var rounds = numberOfRounds[this.key.length];
20356
20357               if (rounds == null) {
20358                 throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
20359               } // encryption round keys
20360
20361
20362               this._Ke = []; // decryption round keys
20363
20364               this._Kd = [];
20365
20366               for (var i = 0; i <= rounds; i++) {
20367                 this._Ke.push([0, 0, 0, 0]);
20368
20369                 this._Kd.push([0, 0, 0, 0]);
20370               }
20371
20372               var roundKeyCount = (rounds + 1) * 4;
20373               var KC = this.key.length / 4; // convert the key into ints
20374
20375               var tk = convertToInt32(this.key); // copy values into round key arrays
20376
20377               var index;
20378
20379               for (var i = 0; i < KC; i++) {
20380                 index = i >> 2;
20381                 this._Ke[index][i % 4] = tk[i];
20382                 this._Kd[rounds - index][i % 4] = tk[i];
20383               } // key expansion (fips-197 section 5.2)
20384
20385
20386               var rconpointer = 0;
20387               var t = KC,
20388                   tt;
20389
20390               while (t < roundKeyCount) {
20391                 tt = tk[KC - 1];
20392                 tk[0] ^= S[tt >> 16 & 0xFF] << 24 ^ S[tt >> 8 & 0xFF] << 16 ^ S[tt & 0xFF] << 8 ^ S[tt >> 24 & 0xFF] ^ rcon[rconpointer] << 24;
20393                 rconpointer += 1; // key expansion (for non-256 bit)
20394
20395                 if (KC != 8) {
20396                   for (var i = 1; i < KC; i++) {
20397                     tk[i] ^= tk[i - 1];
20398                   } // key expansion for 256-bit keys is "slightly different" (fips-197)
20399
20400                 } else {
20401                   for (var i = 1; i < KC / 2; i++) {
20402                     tk[i] ^= tk[i - 1];
20403                   }
20404
20405                   tt = tk[KC / 2 - 1];
20406                   tk[KC / 2] ^= S[tt & 0xFF] ^ S[tt >> 8 & 0xFF] << 8 ^ S[tt >> 16 & 0xFF] << 16 ^ S[tt >> 24 & 0xFF] << 24;
20407
20408                   for (var i = KC / 2 + 1; i < KC; i++) {
20409                     tk[i] ^= tk[i - 1];
20410                   }
20411                 } // copy values into round key arrays
20412
20413
20414                 var i = 0,
20415                     r,
20416                     c;
20417
20418                 while (i < KC && t < roundKeyCount) {
20419                   r = t >> 2;
20420                   c = t % 4;
20421                   this._Ke[r][c] = tk[i];
20422                   this._Kd[rounds - r][c] = tk[i++];
20423                   t++;
20424                 }
20425               } // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
20426
20427
20428               for (var r = 1; r < rounds; r++) {
20429                 for (var c = 0; c < 4; c++) {
20430                   tt = this._Kd[r][c];
20431                   this._Kd[r][c] = U1[tt >> 24 & 0xFF] ^ U2[tt >> 16 & 0xFF] ^ U3[tt >> 8 & 0xFF] ^ U4[tt & 0xFF];
20432                 }
20433               }
20434             };
20435
20436             AES.prototype.encrypt = function (plaintext) {
20437               if (plaintext.length != 16) {
20438                 throw new Error('invalid plaintext size (must be 16 bytes)');
20439               }
20440
20441               var rounds = this._Ke.length - 1;
20442               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
20443
20444               var t = convertToInt32(plaintext);
20445
20446               for (var i = 0; i < 4; i++) {
20447                 t[i] ^= this._Ke[0][i];
20448               } // apply round transforms
20449
20450
20451               for (var r = 1; r < rounds; r++) {
20452                 for (var i = 0; i < 4; i++) {
20453                   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];
20454                 }
20455
20456                 t = a.slice();
20457               } // the last round is special
20458
20459
20460               var result = createArray(16),
20461                   tt;
20462
20463               for (var i = 0; i < 4; i++) {
20464                 tt = this._Ke[rounds][i];
20465                 result[4 * i] = (S[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
20466                 result[4 * i + 1] = (S[t[(i + 1) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
20467                 result[4 * i + 2] = (S[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
20468                 result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
20469               }
20470
20471               return result;
20472             };
20473
20474             AES.prototype.decrypt = function (ciphertext) {
20475               if (ciphertext.length != 16) {
20476                 throw new Error('invalid ciphertext size (must be 16 bytes)');
20477               }
20478
20479               var rounds = this._Kd.length - 1;
20480               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
20481
20482               var t = convertToInt32(ciphertext);
20483
20484               for (var i = 0; i < 4; i++) {
20485                 t[i] ^= this._Kd[0][i];
20486               } // apply round transforms
20487
20488
20489               for (var r = 1; r < rounds; r++) {
20490                 for (var i = 0; i < 4; i++) {
20491                   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];
20492                 }
20493
20494                 t = a.slice();
20495               } // the last round is special
20496
20497
20498               var result = createArray(16),
20499                   tt;
20500
20501               for (var i = 0; i < 4; i++) {
20502                 tt = this._Kd[rounds][i];
20503                 result[4 * i] = (Si[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
20504                 result[4 * i + 1] = (Si[t[(i + 3) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
20505                 result[4 * i + 2] = (Si[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
20506                 result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
20507               }
20508
20509               return result;
20510             };
20511             /**
20512              *  Mode Of Operation - Electonic Codebook (ECB)
20513              */
20514
20515
20516             var ModeOfOperationECB = function ModeOfOperationECB(key) {
20517               if (!(this instanceof ModeOfOperationECB)) {
20518                 throw Error('AES must be instanitated with `new`');
20519               }
20520
20521               this.description = "Electronic Code Block";
20522               this.name = "ecb";
20523               this._aes = new AES(key);
20524             };
20525
20526             ModeOfOperationECB.prototype.encrypt = function (plaintext) {
20527               plaintext = coerceArray(plaintext);
20528
20529               if (plaintext.length % 16 !== 0) {
20530                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
20531               }
20532
20533               var ciphertext = createArray(plaintext.length);
20534               var block = createArray(16);
20535
20536               for (var i = 0; i < plaintext.length; i += 16) {
20537                 copyArray(plaintext, block, 0, i, i + 16);
20538                 block = this._aes.encrypt(block);
20539                 copyArray(block, ciphertext, i);
20540               }
20541
20542               return ciphertext;
20543             };
20544
20545             ModeOfOperationECB.prototype.decrypt = function (ciphertext) {
20546               ciphertext = coerceArray(ciphertext);
20547
20548               if (ciphertext.length % 16 !== 0) {
20549                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
20550               }
20551
20552               var plaintext = createArray(ciphertext.length);
20553               var block = createArray(16);
20554
20555               for (var i = 0; i < ciphertext.length; i += 16) {
20556                 copyArray(ciphertext, block, 0, i, i + 16);
20557                 block = this._aes.decrypt(block);
20558                 copyArray(block, plaintext, i);
20559               }
20560
20561               return plaintext;
20562             };
20563             /**
20564              *  Mode Of Operation - Cipher Block Chaining (CBC)
20565              */
20566
20567
20568             var ModeOfOperationCBC = function ModeOfOperationCBC(key, iv) {
20569               if (!(this instanceof ModeOfOperationCBC)) {
20570                 throw Error('AES must be instanitated with `new`');
20571               }
20572
20573               this.description = "Cipher Block Chaining";
20574               this.name = "cbc";
20575
20576               if (!iv) {
20577                 iv = createArray(16);
20578               } else if (iv.length != 16) {
20579                 throw new Error('invalid initialation vector size (must be 16 bytes)');
20580               }
20581
20582               this._lastCipherblock = coerceArray(iv, true);
20583               this._aes = new AES(key);
20584             };
20585
20586             ModeOfOperationCBC.prototype.encrypt = function (plaintext) {
20587               plaintext = coerceArray(plaintext);
20588
20589               if (plaintext.length % 16 !== 0) {
20590                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
20591               }
20592
20593               var ciphertext = createArray(plaintext.length);
20594               var block = createArray(16);
20595
20596               for (var i = 0; i < plaintext.length; i += 16) {
20597                 copyArray(plaintext, block, 0, i, i + 16);
20598
20599                 for (var j = 0; j < 16; j++) {
20600                   block[j] ^= this._lastCipherblock[j];
20601                 }
20602
20603                 this._lastCipherblock = this._aes.encrypt(block);
20604                 copyArray(this._lastCipherblock, ciphertext, i);
20605               }
20606
20607               return ciphertext;
20608             };
20609
20610             ModeOfOperationCBC.prototype.decrypt = function (ciphertext) {
20611               ciphertext = coerceArray(ciphertext);
20612
20613               if (ciphertext.length % 16 !== 0) {
20614                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
20615               }
20616
20617               var plaintext = createArray(ciphertext.length);
20618               var block = createArray(16);
20619
20620               for (var i = 0; i < ciphertext.length; i += 16) {
20621                 copyArray(ciphertext, block, 0, i, i + 16);
20622                 block = this._aes.decrypt(block);
20623
20624                 for (var j = 0; j < 16; j++) {
20625                   plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
20626                 }
20627
20628                 copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
20629               }
20630
20631               return plaintext;
20632             };
20633             /**
20634              *  Mode Of Operation - Cipher Feedback (CFB)
20635              */
20636
20637
20638             var ModeOfOperationCFB = function ModeOfOperationCFB(key, iv, segmentSize) {
20639               if (!(this instanceof ModeOfOperationCFB)) {
20640                 throw Error('AES must be instanitated with `new`');
20641               }
20642
20643               this.description = "Cipher Feedback";
20644               this.name = "cfb";
20645
20646               if (!iv) {
20647                 iv = createArray(16);
20648               } else if (iv.length != 16) {
20649                 throw new Error('invalid initialation vector size (must be 16 size)');
20650               }
20651
20652               if (!segmentSize) {
20653                 segmentSize = 1;
20654               }
20655
20656               this.segmentSize = segmentSize;
20657               this._shiftRegister = coerceArray(iv, true);
20658               this._aes = new AES(key);
20659             };
20660
20661             ModeOfOperationCFB.prototype.encrypt = function (plaintext) {
20662               if (plaintext.length % this.segmentSize != 0) {
20663                 throw new Error('invalid plaintext size (must be segmentSize bytes)');
20664               }
20665
20666               var encrypted = coerceArray(plaintext, true);
20667               var xorSegment;
20668
20669               for (var i = 0; i < encrypted.length; i += this.segmentSize) {
20670                 xorSegment = this._aes.encrypt(this._shiftRegister);
20671
20672                 for (var j = 0; j < this.segmentSize; j++) {
20673                   encrypted[i + j] ^= xorSegment[j];
20674                 } // Shift the register
20675
20676
20677                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
20678                 copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
20679               }
20680
20681               return encrypted;
20682             };
20683
20684             ModeOfOperationCFB.prototype.decrypt = function (ciphertext) {
20685               if (ciphertext.length % this.segmentSize != 0) {
20686                 throw new Error('invalid ciphertext size (must be segmentSize bytes)');
20687               }
20688
20689               var plaintext = coerceArray(ciphertext, true);
20690               var xorSegment;
20691
20692               for (var i = 0; i < plaintext.length; i += this.segmentSize) {
20693                 xorSegment = this._aes.encrypt(this._shiftRegister);
20694
20695                 for (var j = 0; j < this.segmentSize; j++) {
20696                   plaintext[i + j] ^= xorSegment[j];
20697                 } // Shift the register
20698
20699
20700                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
20701                 copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
20702               }
20703
20704               return plaintext;
20705             };
20706             /**
20707              *  Mode Of Operation - Output Feedback (OFB)
20708              */
20709
20710
20711             var ModeOfOperationOFB = function ModeOfOperationOFB(key, iv) {
20712               if (!(this instanceof ModeOfOperationOFB)) {
20713                 throw Error('AES must be instanitated with `new`');
20714               }
20715
20716               this.description = "Output Feedback";
20717               this.name = "ofb";
20718
20719               if (!iv) {
20720                 iv = createArray(16);
20721               } else if (iv.length != 16) {
20722                 throw new Error('invalid initialation vector size (must be 16 bytes)');
20723               }
20724
20725               this._lastPrecipher = coerceArray(iv, true);
20726               this._lastPrecipherIndex = 16;
20727               this._aes = new AES(key);
20728             };
20729
20730             ModeOfOperationOFB.prototype.encrypt = function (plaintext) {
20731               var encrypted = coerceArray(plaintext, true);
20732
20733               for (var i = 0; i < encrypted.length; i++) {
20734                 if (this._lastPrecipherIndex === 16) {
20735                   this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
20736                   this._lastPrecipherIndex = 0;
20737                 }
20738
20739                 encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
20740               }
20741
20742               return encrypted;
20743             }; // Decryption is symetric
20744
20745
20746             ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
20747             /**
20748              *  Counter object for CTR common mode of operation
20749              */
20750
20751             var Counter = function Counter(initialValue) {
20752               if (!(this instanceof Counter)) {
20753                 throw Error('Counter must be instanitated with `new`');
20754               } // We allow 0, but anything false-ish uses the default 1
20755
20756
20757               if (initialValue !== 0 && !initialValue) {
20758                 initialValue = 1;
20759               }
20760
20761               if (typeof initialValue === 'number') {
20762                 this._counter = createArray(16);
20763                 this.setValue(initialValue);
20764               } else {
20765                 this.setBytes(initialValue);
20766               }
20767             };
20768
20769             Counter.prototype.setValue = function (value) {
20770               if (typeof value !== 'number' || parseInt(value) != value) {
20771                 throw new Error('invalid counter value (must be an integer)');
20772               } // We cannot safely handle numbers beyond the safe range for integers
20773
20774
20775               if (value > Number.MAX_SAFE_INTEGER) {
20776                 throw new Error('integer value out of safe range');
20777               }
20778
20779               for (var index = 15; index >= 0; --index) {
20780                 this._counter[index] = value % 256;
20781                 value = parseInt(value / 256);
20782               }
20783             };
20784
20785             Counter.prototype.setBytes = function (bytes) {
20786               bytes = coerceArray(bytes, true);
20787
20788               if (bytes.length != 16) {
20789                 throw new Error('invalid counter bytes size (must be 16 bytes)');
20790               }
20791
20792               this._counter = bytes;
20793             };
20794
20795             Counter.prototype.increment = function () {
20796               for (var i = 15; i >= 0; i--) {
20797                 if (this._counter[i] === 255) {
20798                   this._counter[i] = 0;
20799                 } else {
20800                   this._counter[i]++;
20801                   break;
20802                 }
20803               }
20804             };
20805             /**
20806              *  Mode Of Operation - Counter (CTR)
20807              */
20808
20809
20810             var ModeOfOperationCTR = function ModeOfOperationCTR(key, counter) {
20811               if (!(this instanceof ModeOfOperationCTR)) {
20812                 throw Error('AES must be instanitated with `new`');
20813               }
20814
20815               this.description = "Counter";
20816               this.name = "ctr";
20817
20818               if (!(counter instanceof Counter)) {
20819                 counter = new Counter(counter);
20820               }
20821
20822               this._counter = counter;
20823               this._remainingCounter = null;
20824               this._remainingCounterIndex = 16;
20825               this._aes = new AES(key);
20826             };
20827
20828             ModeOfOperationCTR.prototype.encrypt = function (plaintext) {
20829               var encrypted = coerceArray(plaintext, true);
20830
20831               for (var i = 0; i < encrypted.length; i++) {
20832                 if (this._remainingCounterIndex === 16) {
20833                   this._remainingCounter = this._aes.encrypt(this._counter._counter);
20834                   this._remainingCounterIndex = 0;
20835
20836                   this._counter.increment();
20837                 }
20838
20839                 encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
20840               }
20841
20842               return encrypted;
20843             }; // Decryption is symetric
20844
20845
20846             ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt; ///////////////////////
20847             // Padding
20848             // See:https://tools.ietf.org/html/rfc2315
20849
20850             function pkcs7pad(data) {
20851               data = coerceArray(data, true);
20852               var padder = 16 - data.length % 16;
20853               var result = createArray(data.length + padder);
20854               copyArray(data, result);
20855
20856               for (var i = data.length; i < result.length; i++) {
20857                 result[i] = padder;
20858               }
20859
20860               return result;
20861             }
20862
20863             function pkcs7strip(data) {
20864               data = coerceArray(data, true);
20865
20866               if (data.length < 16) {
20867                 throw new Error('PKCS#7 invalid length');
20868               }
20869
20870               var padder = data[data.length - 1];
20871
20872               if (padder > 16) {
20873                 throw new Error('PKCS#7 padding byte out of range');
20874               }
20875
20876               var length = data.length - padder;
20877
20878               for (var i = 0; i < padder; i++) {
20879                 if (data[length + i] !== padder) {
20880                   throw new Error('PKCS#7 invalid padding byte');
20881                 }
20882               }
20883
20884               var result = createArray(length);
20885               copyArray(data, result, 0, 0, length);
20886               return result;
20887             } ///////////////////////
20888             // Exporting
20889             // The block cipher
20890
20891
20892             var aesjs = {
20893               AES: AES,
20894               Counter: Counter,
20895               ModeOfOperation: {
20896                 ecb: ModeOfOperationECB,
20897                 cbc: ModeOfOperationCBC,
20898                 cfb: ModeOfOperationCFB,
20899                 ofb: ModeOfOperationOFB,
20900                 ctr: ModeOfOperationCTR
20901               },
20902               utils: {
20903                 hex: convertHex,
20904                 utf8: convertUtf8
20905               },
20906               padding: {
20907                 pkcs7: {
20908                   pad: pkcs7pad,
20909                   strip: pkcs7strip
20910                 }
20911               },
20912               _arrayTest: {
20913                 coerceArray: coerceArray,
20914                 createArray: createArray,
20915                 copyArray: copyArray
20916               }
20917             }; // node.js
20918
20919             {
20920               module.exports = aesjs; // RequireJS/AMD
20921               // http://www.requirejs.org/docs/api.html
20922               // https://github.com/amdjs/amdjs-api/wiki/AMD
20923             }
20924           })();
20925         });
20926
20927         // We can use keys that are 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes).
20928         // To generate a random key:  window.crypto.getRandomValues(new Uint8Array(16));
20929         // This default signing key is built into iD and can be used to mask/unmask sensitive values.
20930
20931         var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
20932         function utilAesEncrypt(text, key) {
20933           key = key || DEFAULT_128;
20934           var textBytes = aesJs.utils.utf8.toBytes(text);
20935           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
20936           var encryptedBytes = aesCtr.encrypt(textBytes);
20937           var encryptedHex = aesJs.utils.hex.fromBytes(encryptedBytes);
20938           return encryptedHex;
20939         }
20940         function utilAesDecrypt(encryptedHex, key) {
20941           key = key || DEFAULT_128;
20942           var encryptedBytes = aesJs.utils.hex.toBytes(encryptedHex);
20943           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
20944           var decryptedBytes = aesCtr.decrypt(encryptedBytes);
20945           var text = aesJs.utils.utf8.fromBytes(decryptedBytes);
20946           return text;
20947         }
20948
20949         function utilCleanTags(tags) {
20950           var out = {};
20951
20952           for (var k in tags) {
20953             if (!k) continue;
20954             var v = tags[k];
20955
20956             if (v !== undefined) {
20957               out[k] = cleanValue(k, v);
20958             }
20959           }
20960
20961           return out;
20962
20963           function cleanValue(k, v) {
20964             function keepSpaces(k) {
20965               return /_hours|_times|:conditional$/.test(k);
20966             }
20967
20968             function skip(k) {
20969               return /^(description|note|fixme)$/.test(k);
20970             }
20971
20972             if (skip(k)) return v;
20973             var cleaned = v.split(';').map(function (s) {
20974               return s.trim();
20975             }).join(keepSpaces(k) ? '; ' : ';'); // The code below is not intended to validate websites and emails.
20976             // It is only intended to prevent obvious copy-paste errors. (#2323)
20977             // clean website- and email-like tags
20978
20979             if (k.indexOf('website') !== -1 || k.indexOf('email') !== -1 || cleaned.indexOf('http') === 0) {
20980               cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
20981             }
20982
20983             return cleaned;
20984           }
20985         }
20986
20987         // Like selection.property('value', ...), but avoids no-op value sets,
20988         // which can result in layout/repaint thrashing in some situations.
20989         function utilGetSetValue(selection, value) {
20990           function d3_selection_value(value) {
20991             function valueNull() {
20992               delete this.value;
20993             }
20994
20995             function valueConstant() {
20996               if (this.value !== value) {
20997                 this.value = value;
20998               }
20999             }
21000
21001             function valueFunction() {
21002               var x = value.apply(this, arguments);
21003
21004               if (x === null || x === undefined) {
21005                 delete this.value;
21006               } else if (this.value !== x) {
21007                 this.value = x;
21008               }
21009             }
21010
21011             return value === null || value === undefined ? valueNull : typeof value === 'function' ? valueFunction : valueConstant;
21012           }
21013
21014           if (arguments.length === 1) {
21015             return selection.property('value');
21016           }
21017
21018           return selection.each(d3_selection_value(value));
21019         }
21020
21021         function utilKeybinding(namespace) {
21022           var _keybindings = {};
21023
21024           function testBindings(d3_event, isCapturing) {
21025             var didMatch = false;
21026             var bindings = Object.keys(_keybindings).map(function (id) {
21027               return _keybindings[id];
21028             });
21029             var i, binding; // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
21030             // so we don't strictly match on the shift key, but we prioritize
21031             // shifted keybindings first, and fallback to unshifted only if no match.
21032             // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
21033             // priority match shifted keybindings first
21034
21035             for (i = 0; i < bindings.length; i++) {
21036               binding = bindings[i];
21037               if (!binding.event.modifiers.shiftKey) continue; // no shift
21038
21039               if (!!binding.capture !== isCapturing) continue;
21040
21041               if (matches(d3_event, binding, true)) {
21042                 binding.callback(d3_event);
21043                 didMatch = true; // match a max of one binding per event
21044
21045                 break;
21046               }
21047             }
21048
21049             if (didMatch) return; // then unshifted keybindings
21050
21051             for (i = 0; i < bindings.length; i++) {
21052               binding = bindings[i];
21053               if (binding.event.modifiers.shiftKey) continue; // shift
21054
21055               if (!!binding.capture !== isCapturing) continue;
21056
21057               if (matches(d3_event, binding, false)) {
21058                 binding.callback(d3_event);
21059                 break;
21060               }
21061             }
21062
21063             function matches(d3_event, binding, testShift) {
21064               var event = d3_event;
21065               var isMatch = false;
21066               var tryKeyCode = true; // Prefer a match on `KeyboardEvent.key`
21067
21068               if (event.key !== undefined) {
21069                 tryKeyCode = event.key.charCodeAt(0) > 255; // outside ISO-Latin-1
21070
21071                 isMatch = true;
21072
21073                 if (binding.event.key === undefined) {
21074                   isMatch = false;
21075                 } else if (Array.isArray(binding.event.key)) {
21076                   if (binding.event.key.map(function (s) {
21077                     return s.toLowerCase();
21078                   }).indexOf(event.key.toLowerCase()) === -1) isMatch = false;
21079                 } else {
21080                   if (event.key.toLowerCase() !== binding.event.key.toLowerCase()) isMatch = false;
21081                 }
21082               } // Fallback match on `KeyboardEvent.keyCode`, can happen if:
21083               // - browser doesn't support `KeyboardEvent.key`
21084               // - `KeyboardEvent.key` is outside ISO-Latin-1 range (cyrillic?)
21085
21086
21087               if (!isMatch && tryKeyCode) {
21088                 isMatch = event.keyCode === binding.event.keyCode;
21089               }
21090
21091               if (!isMatch) return false; // test modifier keys
21092
21093               if (!(event.ctrlKey && event.altKey)) {
21094                 // if both are set, assume AltGr and skip it - #4096
21095                 if (event.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
21096                 if (event.altKey !== binding.event.modifiers.altKey) return false;
21097               }
21098
21099               if (event.metaKey !== binding.event.modifiers.metaKey) return false;
21100               if (testShift && event.shiftKey !== binding.event.modifiers.shiftKey) return false;
21101               return true;
21102             }
21103           }
21104
21105           function capture(d3_event) {
21106             testBindings(d3_event, true);
21107           }
21108
21109           function bubble(d3_event) {
21110             var tagName = select(d3_event.target).node().tagName;
21111
21112             if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
21113               return;
21114             }
21115
21116             testBindings(d3_event, false);
21117           }
21118
21119           function keybinding(selection) {
21120             selection = selection || select(document);
21121             selection.on('keydown.capture.' + namespace, capture, true);
21122             selection.on('keydown.bubble.' + namespace, bubble, false);
21123             return keybinding;
21124           } // was: keybinding.off()
21125
21126
21127           keybinding.unbind = function (selection) {
21128             _keybindings = [];
21129             selection = selection || select(document);
21130             selection.on('keydown.capture.' + namespace, null);
21131             selection.on('keydown.bubble.' + namespace, null);
21132             return keybinding;
21133           };
21134
21135           keybinding.clear = function () {
21136             _keybindings = {};
21137             return keybinding;
21138           }; // Remove one or more keycode bindings.
21139
21140
21141           keybinding.off = function (codes, capture) {
21142             var arr = utilArrayUniq([].concat(codes));
21143
21144             for (var i = 0; i < arr.length; i++) {
21145               var id = arr[i] + (capture ? '-capture' : '-bubble');
21146               delete _keybindings[id];
21147             }
21148
21149             return keybinding;
21150           }; // Add one or more keycode bindings.
21151
21152
21153           keybinding.on = function (codes, callback, capture) {
21154             if (typeof callback !== 'function') {
21155               return keybinding.off(codes, capture);
21156             }
21157
21158             var arr = utilArrayUniq([].concat(codes));
21159
21160             for (var i = 0; i < arr.length; i++) {
21161               var id = arr[i] + (capture ? '-capture' : '-bubble');
21162               var binding = {
21163                 id: id,
21164                 capture: capture,
21165                 callback: callback,
21166                 event: {
21167                   key: undefined,
21168                   // preferred
21169                   keyCode: 0,
21170                   // fallback
21171                   modifiers: {
21172                     shiftKey: false,
21173                     ctrlKey: false,
21174                     altKey: false,
21175                     metaKey: false
21176                   }
21177                 }
21178               };
21179
21180               if (_keybindings[id]) {
21181                 console.warn('warning: duplicate keybinding for "' + id + '"'); // eslint-disable-line no-console
21182               }
21183
21184               _keybindings[id] = binding;
21185               var matches = arr[i].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
21186
21187               for (var j = 0; j < matches.length; j++) {
21188                 // Normalise matching errors
21189                 if (matches[j] === '++') matches[j] = '+';
21190
21191                 if (matches[j] in utilKeybinding.modifierCodes) {
21192                   var prop = utilKeybinding.modifierProperties[utilKeybinding.modifierCodes[matches[j]]];
21193                   binding.event.modifiers[prop] = true;
21194                 } else {
21195                   binding.event.key = utilKeybinding.keys[matches[j]] || matches[j];
21196
21197                   if (matches[j] in utilKeybinding.keyCodes) {
21198                     binding.event.keyCode = utilKeybinding.keyCodes[matches[j]];
21199                   }
21200                 }
21201               }
21202             }
21203
21204             return keybinding;
21205           };
21206
21207           return keybinding;
21208         }
21209         /*
21210          * See https://github.com/keithamus/jwerty
21211          */
21212
21213         utilKeybinding.modifierCodes = {
21214           // Shift key, ⇧
21215           '⇧': 16,
21216           shift: 16,
21217           // CTRL key, on Mac: ⌃
21218           '⌃': 17,
21219           ctrl: 17,
21220           // ALT key, on Mac: ⌥ (Alt)
21221           '⌥': 18,
21222           alt: 18,
21223           option: 18,
21224           // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
21225           '⌘': 91,
21226           meta: 91,
21227           cmd: 91,
21228           'super': 91,
21229           win: 91
21230         };
21231         utilKeybinding.modifierProperties = {
21232           16: 'shiftKey',
21233           17: 'ctrlKey',
21234           18: 'altKey',
21235           91: 'metaKey'
21236         };
21237         utilKeybinding.plusKeys = ['plus', 'ffplus', '=', 'ffequals', '≠', '±'];
21238         utilKeybinding.minusKeys = ['_', '-', 'ffminus', 'dash', '–', '—'];
21239         utilKeybinding.keys = {
21240           // Backspace key, on Mac: ⌫ (Backspace)
21241           '⌫': 'Backspace',
21242           backspace: 'Backspace',
21243           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
21244           '⇥': 'Tab',
21245           '⇆': 'Tab',
21246           tab: 'Tab',
21247           // Return key, ↩
21248           '↩': 'Enter',
21249           '↵': 'Enter',
21250           '⏎': 'Enter',
21251           'return': 'Enter',
21252           enter: 'Enter',
21253           '⌅': 'Enter',
21254           // Pause/Break key
21255           'pause': 'Pause',
21256           'pause-break': 'Pause',
21257           // Caps Lock key, ⇪
21258           '⇪': 'CapsLock',
21259           caps: 'CapsLock',
21260           'caps-lock': 'CapsLock',
21261           // Escape key, on Mac: ⎋, on Windows: Esc
21262           '⎋': ['Escape', 'Esc'],
21263           escape: ['Escape', 'Esc'],
21264           esc: ['Escape', 'Esc'],
21265           // Space key
21266           space: [' ', 'Spacebar'],
21267           // Page-Up key, or pgup, on Mac: ↖
21268           '↖': 'PageUp',
21269           pgup: 'PageUp',
21270           'page-up': 'PageUp',
21271           // Page-Down key, or pgdown, on Mac: ↘
21272           '↘': 'PageDown',
21273           pgdown: 'PageDown',
21274           'page-down': 'PageDown',
21275           // END key, on Mac: ⇟
21276           '⇟': 'End',
21277           end: 'End',
21278           // HOME key, on Mac: ⇞
21279           '⇞': 'Home',
21280           home: 'Home',
21281           // Insert key, or ins
21282           ins: 'Insert',
21283           insert: 'Insert',
21284           // Delete key, on Mac: ⌦ (Delete)
21285           '⌦': ['Delete', 'Del'],
21286           del: ['Delete', 'Del'],
21287           'delete': ['Delete', 'Del'],
21288           // Left Arrow Key, or ←
21289           '←': ['ArrowLeft', 'Left'],
21290           left: ['ArrowLeft', 'Left'],
21291           'arrow-left': ['ArrowLeft', 'Left'],
21292           // Up Arrow Key, or ↑
21293           '↑': ['ArrowUp', 'Up'],
21294           up: ['ArrowUp', 'Up'],
21295           'arrow-up': ['ArrowUp', 'Up'],
21296           // Right Arrow Key, or →
21297           '→': ['ArrowRight', 'Right'],
21298           right: ['ArrowRight', 'Right'],
21299           'arrow-right': ['ArrowRight', 'Right'],
21300           // Up Arrow Key, or ↓
21301           '↓': ['ArrowDown', 'Down'],
21302           down: ['ArrowDown', 'Down'],
21303           'arrow-down': ['ArrowDown', 'Down'],
21304           // odities, stuff for backward compatibility (browsers and code):
21305           // Num-Multiply, or *
21306           '*': ['*', 'Multiply'],
21307           star: ['*', 'Multiply'],
21308           asterisk: ['*', 'Multiply'],
21309           multiply: ['*', 'Multiply'],
21310           // Num-Plus or +
21311           '+': ['+', 'Add'],
21312           'plus': ['+', 'Add'],
21313           // Num-Subtract, or -
21314           '-': ['-', 'Subtract'],
21315           subtract: ['-', 'Subtract'],
21316           'dash': ['-', 'Subtract'],
21317           // Semicolon
21318           semicolon: ';',
21319           // = or equals
21320           equals: '=',
21321           // Comma, or ,
21322           comma: ',',
21323           // Period, or ., or full-stop
21324           period: '.',
21325           'full-stop': '.',
21326           // Slash, or /, or forward-slash
21327           slash: '/',
21328           'forward-slash': '/',
21329           // Tick, or `, or back-quote
21330           tick: '`',
21331           'back-quote': '`',
21332           // Open bracket, or [
21333           'open-bracket': '[',
21334           // Back slash, or \
21335           'back-slash': '\\',
21336           // Close backet, or ]
21337           'close-bracket': ']',
21338           // Apostrophe, or Quote, or '
21339           quote: '\'',
21340           apostrophe: '\'',
21341           // NUMPAD 0-9
21342           'num-0': '0',
21343           'num-1': '1',
21344           'num-2': '2',
21345           'num-3': '3',
21346           'num-4': '4',
21347           'num-5': '5',
21348           'num-6': '6',
21349           'num-7': '7',
21350           'num-8': '8',
21351           'num-9': '9',
21352           // F1-F25
21353           f1: 'F1',
21354           f2: 'F2',
21355           f3: 'F3',
21356           f4: 'F4',
21357           f5: 'F5',
21358           f6: 'F6',
21359           f7: 'F7',
21360           f8: 'F8',
21361           f9: 'F9',
21362           f10: 'F10',
21363           f11: 'F11',
21364           f12: 'F12',
21365           f13: 'F13',
21366           f14: 'F14',
21367           f15: 'F15',
21368           f16: 'F16',
21369           f17: 'F17',
21370           f18: 'F18',
21371           f19: 'F19',
21372           f20: 'F20',
21373           f21: 'F21',
21374           f22: 'F22',
21375           f23: 'F23',
21376           f24: 'F24',
21377           f25: 'F25'
21378         };
21379         utilKeybinding.keyCodes = {
21380           // Backspace key, on Mac: ⌫ (Backspace)
21381           '⌫': 8,
21382           backspace: 8,
21383           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
21384           '⇥': 9,
21385           '⇆': 9,
21386           tab: 9,
21387           // Return key, ↩
21388           '↩': 13,
21389           '↵': 13,
21390           '⏎': 13,
21391           'return': 13,
21392           enter: 13,
21393           '⌅': 13,
21394           // Pause/Break key
21395           'pause': 19,
21396           'pause-break': 19,
21397           // Caps Lock key, ⇪
21398           '⇪': 20,
21399           caps: 20,
21400           'caps-lock': 20,
21401           // Escape key, on Mac: ⎋, on Windows: Esc
21402           '⎋': 27,
21403           escape: 27,
21404           esc: 27,
21405           // Space key
21406           space: 32,
21407           // Page-Up key, or pgup, on Mac: ↖
21408           '↖': 33,
21409           pgup: 33,
21410           'page-up': 33,
21411           // Page-Down key, or pgdown, on Mac: ↘
21412           '↘': 34,
21413           pgdown: 34,
21414           'page-down': 34,
21415           // END key, on Mac: ⇟
21416           '⇟': 35,
21417           end: 35,
21418           // HOME key, on Mac: ⇞
21419           '⇞': 36,
21420           home: 36,
21421           // Insert key, or ins
21422           ins: 45,
21423           insert: 45,
21424           // Delete key, on Mac: ⌦ (Delete)
21425           '⌦': 46,
21426           del: 46,
21427           'delete': 46,
21428           // Left Arrow Key, or ←
21429           '←': 37,
21430           left: 37,
21431           'arrow-left': 37,
21432           // Up Arrow Key, or ↑
21433           '↑': 38,
21434           up: 38,
21435           'arrow-up': 38,
21436           // Right Arrow Key, or →
21437           '→': 39,
21438           right: 39,
21439           'arrow-right': 39,
21440           // Up Arrow Key, or ↓
21441           '↓': 40,
21442           down: 40,
21443           'arrow-down': 40,
21444           // odities, printing characters that come out wrong:
21445           // Firefox Equals
21446           'ffequals': 61,
21447           // Num-Multiply, or *
21448           '*': 106,
21449           star: 106,
21450           asterisk: 106,
21451           multiply: 106,
21452           // Num-Plus or +
21453           '+': 107,
21454           'plus': 107,
21455           // Num-Subtract, or -
21456           '-': 109,
21457           subtract: 109,
21458           // Firefox Plus
21459           'ffplus': 171,
21460           // Firefox Minus
21461           'ffminus': 173,
21462           // Semicolon
21463           ';': 186,
21464           semicolon: 186,
21465           // = or equals
21466           '=': 187,
21467           'equals': 187,
21468           // Comma, or ,
21469           ',': 188,
21470           comma: 188,
21471           // Dash / Underscore key
21472           'dash': 189,
21473           // Period, or ., or full-stop
21474           '.': 190,
21475           period: 190,
21476           'full-stop': 190,
21477           // Slash, or /, or forward-slash
21478           '/': 191,
21479           slash: 191,
21480           'forward-slash': 191,
21481           // Tick, or `, or back-quote
21482           '`': 192,
21483           tick: 192,
21484           'back-quote': 192,
21485           // Open bracket, or [
21486           '[': 219,
21487           'open-bracket': 219,
21488           // Back slash, or \
21489           '\\': 220,
21490           'back-slash': 220,
21491           // Close backet, or ]
21492           ']': 221,
21493           'close-bracket': 221,
21494           // Apostrophe, or Quote, or '
21495           '\'': 222,
21496           quote: 222,
21497           apostrophe: 222
21498         }; // NUMPAD 0-9
21499
21500         var i$1 = 95,
21501             n = 0;
21502
21503         while (++i$1 < 106) {
21504           utilKeybinding.keyCodes['num-' + n] = i$1;
21505           ++n;
21506         } // 0-9
21507
21508
21509         i$1 = 47;
21510         n = 0;
21511
21512         while (++i$1 < 58) {
21513           utilKeybinding.keyCodes[n] = i$1;
21514           ++n;
21515         } // F1-F25
21516
21517
21518         i$1 = 111;
21519         n = 1;
21520
21521         while (++i$1 < 136) {
21522           utilKeybinding.keyCodes['f' + n] = i$1;
21523           ++n;
21524         } // a-z
21525
21526
21527         i$1 = 64;
21528
21529         while (++i$1 < 91) {
21530           utilKeybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
21531         }
21532
21533         function utilObjectOmit(obj, omitKeys) {
21534           return Object.keys(obj).reduce(function (result, key) {
21535             if (omitKeys.indexOf(key) === -1) {
21536               result[key] = obj[key]; // keep
21537             }
21538
21539             return result;
21540           }, {});
21541         }
21542
21543         // Copies a variable number of methods from source to target.
21544         function utilRebind(target, source) {
21545           var i = 1,
21546               n = arguments.length,
21547               method;
21548
21549           while (++i < n) {
21550             target[method = arguments[i]] = d3_rebind(target, source, source[method]);
21551           }
21552
21553           return target;
21554         } // Method is assumed to be a standard D3 getter-setter:
21555         // If passed with no arguments, gets the value.
21556         // If passed with arguments, sets the value and returns the target.
21557
21558         function d3_rebind(target, source, method) {
21559           return function () {
21560             var value = method.apply(source, arguments);
21561             return value === source ? target : value;
21562           };
21563         }
21564
21565         // A per-domain session mutex backed by a cookie and dead man's
21566         // switch. If the session crashes, the mutex will auto-release
21567         // after 5 seconds.
21568         // This accepts a string and returns an object that complies with utilSessionMutexType
21569         function utilSessionMutex(name) {
21570           var mutex = {};
21571           var intervalID;
21572
21573           function renew() {
21574             var expires = new Date();
21575             expires.setSeconds(expires.getSeconds() + 5);
21576             document.cookie = name + '=1; expires=' + expires.toUTCString() + '; sameSite=strict';
21577           }
21578
21579           mutex.lock = function () {
21580             if (intervalID) return true;
21581             var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
21582             if (cookie) return false;
21583             renew();
21584             intervalID = window.setInterval(renew, 4000);
21585             return true;
21586           };
21587
21588           mutex.unlock = function () {
21589             if (!intervalID) return;
21590             document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict';
21591             clearInterval(intervalID);
21592             intervalID = null;
21593           };
21594
21595           mutex.locked = function () {
21596             return !!intervalID;
21597           };
21598
21599           return mutex;
21600         }
21601
21602         function utilTiler() {
21603           var _size = [256, 256];
21604           var _scale = 256;
21605           var _tileSize = 256;
21606           var _zoomExtent = [0, 20];
21607           var _translate = [_size[0] / 2, _size[1] / 2];
21608           var _margin = 0;
21609           var _skipNullIsland = false;
21610
21611           function clamp(num, min, max) {
21612             return Math.max(min, Math.min(num, max));
21613           }
21614
21615           function nearNullIsland(tile) {
21616             var x = tile[0];
21617             var y = tile[1];
21618             var z = tile[2];
21619
21620             if (z >= 7) {
21621               var center = Math.pow(2, z - 1);
21622               var width = Math.pow(2, z - 6);
21623               var min = center - width / 2;
21624               var max = center + width / 2 - 1;
21625               return x >= min && x <= max && y >= min && y <= max;
21626             }
21627
21628             return false;
21629           }
21630
21631           function tiler() {
21632             var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
21633             var z0 = clamp(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
21634             var tileMin = 0;
21635             var tileMax = Math.pow(2, z0) - 1;
21636             var log2ts = Math.log(_tileSize) * Math.LOG2E;
21637             var k = Math.pow(2, z - z0 + log2ts);
21638             var origin = [(_translate[0] - _scale / 2) / k, (_translate[1] - _scale / 2) / k];
21639             var cols = range(clamp(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[0] / k - origin[0]) + _margin, tileMin, tileMax + 1));
21640             var rows = range(clamp(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[1] / k - origin[1]) + _margin, tileMin, tileMax + 1));
21641             var tiles = [];
21642
21643             for (var i = 0; i < rows.length; i++) {
21644               var y = rows[i];
21645
21646               for (var j = 0; j < cols.length; j++) {
21647                 var x = cols[j];
21648
21649                 if (i >= _margin && i <= rows.length - _margin && j >= _margin && j <= cols.length - _margin) {
21650                   tiles.unshift([x, y, z0]); // tiles in view at beginning
21651                 } else {
21652                   tiles.push([x, y, z0]); // tiles in margin at the end
21653                 }
21654               }
21655             }
21656
21657             tiles.translate = origin;
21658             tiles.scale = k;
21659             return tiles;
21660           }
21661           /**
21662            * getTiles() returns an array of tiles that cover the map view
21663            */
21664
21665
21666           tiler.getTiles = function (projection) {
21667             var origin = [projection.scale() * Math.PI - projection.translate()[0], projection.scale() * Math.PI - projection.translate()[1]];
21668             this.size(projection.clipExtent()[1]).scale(projection.scale() * 2 * Math.PI).translate(projection.translate());
21669             var tiles = tiler();
21670             var ts = tiles.scale;
21671             return tiles.map(function (tile) {
21672               if (_skipNullIsland && nearNullIsland(tile)) {
21673                 return false;
21674               }
21675
21676               var x = tile[0] * ts - origin[0];
21677               var y = tile[1] * ts - origin[1];
21678               return {
21679                 id: tile.toString(),
21680                 xyz: tile,
21681                 extent: geoExtent(projection.invert([x, y + ts]), projection.invert([x + ts, y]))
21682               };
21683             }).filter(Boolean);
21684           };
21685           /**
21686            * getGeoJSON() returns a FeatureCollection for debugging tiles
21687            */
21688
21689
21690           tiler.getGeoJSON = function (projection) {
21691             var features = tiler.getTiles(projection).map(function (tile) {
21692               return {
21693                 type: 'Feature',
21694                 properties: {
21695                   id: tile.id,
21696                   name: tile.id
21697                 },
21698                 geometry: {
21699                   type: 'Polygon',
21700                   coordinates: [tile.extent.polygon()]
21701                 }
21702               };
21703             });
21704             return {
21705               type: 'FeatureCollection',
21706               features: features
21707             };
21708           };
21709
21710           tiler.tileSize = function (val) {
21711             if (!arguments.length) return _tileSize;
21712             _tileSize = val;
21713             return tiler;
21714           };
21715
21716           tiler.zoomExtent = function (val) {
21717             if (!arguments.length) return _zoomExtent;
21718             _zoomExtent = val;
21719             return tiler;
21720           };
21721
21722           tiler.size = function (val) {
21723             if (!arguments.length) return _size;
21724             _size = val;
21725             return tiler;
21726           };
21727
21728           tiler.scale = function (val) {
21729             if (!arguments.length) return _scale;
21730             _scale = val;
21731             return tiler;
21732           };
21733
21734           tiler.translate = function (val) {
21735             if (!arguments.length) return _translate;
21736             _translate = val;
21737             return tiler;
21738           }; // number to extend the rows/columns beyond those covering the viewport
21739
21740
21741           tiler.margin = function (val) {
21742             if (!arguments.length) return _margin;
21743             _margin = +val;
21744             return tiler;
21745           };
21746
21747           tiler.skipNullIsland = function (val) {
21748             if (!arguments.length) return _skipNullIsland;
21749             _skipNullIsland = val;
21750             return tiler;
21751           };
21752
21753           return tiler;
21754         }
21755
21756         function utilTriggerEvent(target, type) {
21757           target.each(function () {
21758             var evt = document.createEvent('HTMLEvents');
21759             evt.initEvent(type, true, true);
21760             this.dispatchEvent(evt);
21761           });
21762         }
21763
21764         var _mainLocalizer = coreLocalizer(); // singleton
21765
21766
21767         var _t = _mainLocalizer.t;
21768         // coreLocalizer manages language and locale parameters including translated strings
21769         //
21770
21771         function coreLocalizer() {
21772           var localizer = {};
21773           var _dataLanguages = {}; // `_dataLocales` is an object containing all _supported_ locale codes -> language info.
21774           // * `rtl` - right-to-left or left-to-right text direction
21775           // * `pct` - the percent of strings translated; 1 = 100%, full coverage
21776           //
21777           // {
21778           // en: { rtl: false, pct: {…} },
21779           // de: { rtl: false, pct: {…} },
21780           // …
21781           // }
21782
21783           var _dataLocales = {}; // `localeStrings` is an object containing all _loaded_ locale codes -> string data.
21784           // {
21785           // en: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
21786           // de: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
21787           // …
21788           // }
21789
21790           var _localeStrings = {}; // the current locale
21791
21792           var _localeCode = 'en-US'; // `_localeCodes` must contain `_localeCode` first, optionally followed by fallbacks
21793
21794           var _localeCodes = ['en-US', 'en'];
21795           var _languageCode = 'en';
21796           var _textDirection = 'ltr';
21797           var _usesMetric = false;
21798           var _languageNames = {};
21799           var _scriptNames = {}; // getters for the current locale parameters
21800
21801           localizer.localeCode = function () {
21802             return _localeCode;
21803           };
21804
21805           localizer.localeCodes = function () {
21806             return _localeCodes;
21807           };
21808
21809           localizer.languageCode = function () {
21810             return _languageCode;
21811           };
21812
21813           localizer.textDirection = function () {
21814             return _textDirection;
21815           };
21816
21817           localizer.usesMetric = function () {
21818             return _usesMetric;
21819           };
21820
21821           localizer.languageNames = function () {
21822             return _languageNames;
21823           };
21824
21825           localizer.scriptNames = function () {
21826             return _scriptNames;
21827           }; // The client app may want to manually set the locale, regardless of the
21828           // settings provided by the browser
21829
21830
21831           var _preferredLocaleCodes = [];
21832
21833           localizer.preferredLocaleCodes = function (codes) {
21834             if (!arguments.length) return _preferredLocaleCodes;
21835
21836             if (typeof codes === 'string') {
21837               // be generous and accept delimited strings as input
21838               _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
21839             } else {
21840               _preferredLocaleCodes = codes;
21841             }
21842
21843             return localizer;
21844           };
21845
21846           var _loadPromise;
21847
21848           localizer.ensureLoaded = function () {
21849             if (_loadPromise) return _loadPromise;
21850             return _loadPromise = Promise.all([// load the list of languages
21851             _mainFileFetcher.get('languages'), // load the list of supported locales
21852             _mainFileFetcher.get('locales')]).then(function (results) {
21853               _dataLanguages = results[0];
21854               _dataLocales = results[1];
21855             }).then(function () {
21856               var requestedLocales = (_preferredLocaleCodes || []). // List of locales preferred by the browser in priority order.
21857               concat(utilDetect().browserLocales) // fallback to English since it's the only guaranteed complete language
21858               .concat(['en']);
21859
21860               _localeCodes = localesToUseFrom(requestedLocales); // Run iD in the highest-priority locale; the rest are fallbacks
21861
21862               _localeCode = _localeCodes[0]; // Will always return the index for `en` if nothing else
21863
21864               var fullCoverageIndex = _localeCodes.findIndex(function (locale) {
21865                 return _dataLocales[locale].pct === 1;
21866               }); // We only need to load locales up until we find one with full coverage
21867
21868
21869               var loadStringsPromises = _localeCodes.slice(0, fullCoverageIndex + 1).map(function (code) {
21870                 return localizer.loadLocale(code);
21871               });
21872
21873               return Promise.all(loadStringsPromises);
21874             }).then(function () {
21875               updateForCurrentLocale();
21876             })["catch"](function (err) {
21877               return console.error(err);
21878             }); // eslint-disable-line
21879           }; // Returns the locales from `requestedLocales` supported by iD that we should use
21880
21881
21882           function localesToUseFrom(requestedLocales) {
21883             var supportedLocales = _dataLocales;
21884             var toUse = [];
21885
21886             for (var i in requestedLocales) {
21887               var locale = requestedLocales[i];
21888               if (supportedLocales[locale]) toUse.push(locale);
21889
21890               if (locale.includes('-')) {
21891                 // Full locale ('es-ES'), add fallback to the base ('es')
21892                 var langPart = locale.split('-')[0];
21893                 if (supportedLocales[langPart]) toUse.push(langPart);
21894               }
21895             } // remove duplicates
21896
21897
21898             return utilArrayUniq(toUse);
21899           }
21900
21901           function updateForCurrentLocale() {
21902             if (!_localeCode) return;
21903             _languageCode = _localeCode.split('-')[0];
21904             var currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
21905             var hash = utilStringQs(window.location.hash);
21906
21907             if (hash.rtl === 'true') {
21908               _textDirection = 'rtl';
21909             } else if (hash.rtl === 'false') {
21910               _textDirection = 'ltr';
21911             } else {
21912               _textDirection = currentData && currentData.rtl ? 'rtl' : 'ltr';
21913             }
21914
21915             var locale = _localeCode;
21916             if (locale.toLowerCase() === 'en-us') locale = 'en';
21917             _languageNames = _localeStrings[locale].languageNames;
21918             _scriptNames = _localeStrings[locale].scriptNames;
21919             _usesMetric = _localeCode.slice(-3).toLowerCase() !== '-us';
21920           }
21921           /* Locales */
21922           // Returns a Promise to load the strings for the requested locale
21923
21924
21925           localizer.loadLocale = function (requested) {
21926             if (!_dataLocales) {
21927               return Promise.reject('loadLocale called before init');
21928             }
21929
21930             var locale = requested; // US English is the default
21931
21932             if (locale.toLowerCase() === 'en-us') locale = 'en';
21933
21934             if (!_dataLocales[locale]) {
21935               return Promise.reject("Unsupported locale: ".concat(requested));
21936             }
21937
21938             if (_localeStrings[locale]) {
21939               // already loaded
21940               return Promise.resolve(locale);
21941             }
21942
21943             var fileMap = _mainFileFetcher.fileMap();
21944             var key = "locale_".concat(locale);
21945             fileMap[key] = "locales/".concat(locale, ".json");
21946             return _mainFileFetcher.get(key).then(function (d) {
21947               _localeStrings[locale] = d[locale];
21948               return locale;
21949             });
21950           };
21951
21952           localizer.pluralRule = function (number) {
21953             return pluralRule(number, _localeCode);
21954           }; // Returns the plural rule for the given `number` with the given `localeCode`.
21955           // One of: `zero`, `one`, `two`, `few`, `many`, `other`
21956
21957
21958           function pluralRule(number, localeCode) {
21959             // modern browsers have this functionality built-in
21960             var rules = 'Intl' in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
21961
21962             if (rules) {
21963               return rules.select(number);
21964             } // fallback to basic one/other, as in English
21965
21966
21967             if (number === 1) return 'one';
21968             return 'other';
21969           }
21970           /**
21971           * Try to find that string in `locale` or the current `_localeCode` matching
21972           * the given `stringId`. If no string can be found in the requested locale,
21973           * we'll recurse down all the `_localeCodes` until one is found.
21974           *
21975           * @param  {string}   stringId      string identifier
21976           * @param  {object?}  replacements  token replacements and default string
21977           * @param  {string?}  locale        locale to use (defaults to currentLocale)
21978           * @return {string?}  localized string
21979           */
21980
21981
21982           localizer.tInfo = function (stringId, replacements, locale) {
21983             locale = locale || _localeCode;
21984             var path = stringId.split('.').map(function (s) {
21985               return s.replace(/<TX_DOT>/g, '.');
21986             }).reverse();
21987             var stringsKey = locale; // US English is the default
21988
21989             if (stringsKey.toLowerCase() === 'en-us') stringsKey = 'en';
21990             var result = _localeStrings[stringsKey];
21991
21992             while (result !== undefined && path.length) {
21993               result = result[path.pop()];
21994             }
21995
21996             if (result !== undefined) {
21997               if (replacements) {
21998                 if (_typeof(result) === 'object' && Object.keys(result).length) {
21999                   // If plural forms are provided, dig one level deeper based on the
22000                   // first numeric token replacement provided.
22001                   var number = Object.values(replacements).find(function (value) {
22002                     return typeof value === 'number';
22003                   });
22004
22005                   if (number !== undefined) {
22006                     var rule = pluralRule(number, locale);
22007
22008                     if (result[rule]) {
22009                       result = result[rule];
22010                     } else {
22011                       // We're pretty sure this should be a plural but no string
22012                       // could be found for the given rule. Just pick the first
22013                       // string and hope it makes sense.
22014                       result = Object.values(result)[0];
22015                     }
22016                   }
22017                 }
22018
22019                 if (typeof result === 'string') {
22020                   for (var key in replacements) {
22021                     var value = replacements[key];
22022
22023                     if (typeof value === 'number' && value.toLocaleString) {
22024                       // format numbers for the locale
22025                       value = value.toLocaleString(locale, {
22026                         style: 'decimal',
22027                         useGrouping: true,
22028                         minimumFractionDigits: 0
22029                       });
22030                     }
22031
22032                     var token = "{".concat(key, "}");
22033                     var regex = new RegExp(token, 'g');
22034                     result = result.replace(regex, value);
22035                   }
22036                 }
22037               }
22038
22039               if (typeof result === 'string') {
22040                 // found a localized string!
22041                 return {
22042                   text: result,
22043                   locale: locale
22044                 };
22045               }
22046             } // no localized string found...
22047             // attempt to fallback to a lower-priority language
22048
22049
22050             var index = _localeCodes.indexOf(locale);
22051
22052             if (index >= 0 && index < _localeCodes.length - 1) {
22053               // eventually this will be 'en' or another locale with 100% coverage
22054               var fallback = _localeCodes[index + 1];
22055               return localizer.tInfo(stringId, replacements, fallback);
22056             }
22057
22058             if (replacements && 'default' in replacements) {
22059               // Fallback to a default value if one is specified in `replacements`
22060               return {
22061                 text: replacements["default"],
22062                 locale: null
22063               };
22064             }
22065
22066             var missing = "Missing ".concat(locale, " translation: ").concat(stringId);
22067             if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
22068
22069             return {
22070               text: missing,
22071               locale: 'en'
22072             };
22073           }; // Returns only the localized text, discarding the locale info
22074
22075
22076           localizer.t = function (stringId, replacements, locale) {
22077             return localizer.tInfo(stringId, replacements, locale).text;
22078           }; // Returns the localized text wrapped in an HTML element encoding the locale info
22079
22080
22081           localizer.t.html = function (stringId, replacements, locale) {
22082             var info = localizer.tInfo(stringId, replacements, locale); // text may be empty or undefined if `replacements.default` is
22083
22084             return info.text ? localizer.htmlForLocalizedText(info.text, info.locale) : '';
22085           };
22086
22087           localizer.htmlForLocalizedText = function (text, localeCode) {
22088             return "<span class=\"localized-text\" lang=\"".concat(localeCode || 'unknown', "\">").concat(text, "</span>");
22089           };
22090
22091           localizer.languageName = function (code, options) {
22092             if (_languageNames[code]) {
22093               // name in locale language
22094               // e.g. "German"
22095               return _languageNames[code];
22096             } // sometimes we only want the local name
22097
22098
22099             if (options && options.localOnly) return null;
22100             var langInfo = _dataLanguages[code];
22101
22102             if (langInfo) {
22103               if (langInfo.nativeName) {
22104                 // name in native language
22105                 // e.g. "Deutsch (de)"
22106                 return localizer.t('translate.language_and_code', {
22107                   language: langInfo.nativeName,
22108                   code: code
22109                 });
22110               } else if (langInfo.base && langInfo.script) {
22111                 var base = langInfo.base; // the code of the language this is based on
22112
22113                 if (_languageNames[base]) {
22114                   // base language name in locale language
22115                   var scriptCode = langInfo.script;
22116                   var script = _scriptNames[scriptCode] || scriptCode; // e.g. "Serbian (Cyrillic)"
22117
22118                   return localizer.t('translate.language_and_code', {
22119                     language: _languageNames[base],
22120                     code: script
22121                   });
22122                 } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
22123                   // e.g. "српски (sr-Cyrl)"
22124                   return localizer.t('translate.language_and_code', {
22125                     language: _dataLanguages[base].nativeName,
22126                     code: code
22127                   });
22128                 }
22129               }
22130             }
22131
22132             return code; // if not found, use the code
22133           };
22134
22135           return localizer;
22136         }
22137
22138         // `presetCollection` is a wrapper around an `Array` of presets `collection`,
22139         // and decorated with some extra methods for searching and matching geometry
22140         //
22141
22142         function presetCollection(collection) {
22143           var MAXRESULTS = 50;
22144           var _this = {};
22145           var _memo = {};
22146           _this.collection = collection;
22147
22148           _this.item = function (id) {
22149             if (_memo[id]) return _memo[id];
22150
22151             var found = _this.collection.find(function (d) {
22152               return d.id === id;
22153             });
22154
22155             if (found) _memo[id] = found;
22156             return found;
22157           };
22158
22159           _this.index = function (id) {
22160             return _this.collection.findIndex(function (d) {
22161               return d.id === id;
22162             });
22163           };
22164
22165           _this.matchGeometry = function (geometry) {
22166             return presetCollection(_this.collection.filter(function (d) {
22167               return d.matchGeometry(geometry);
22168             }));
22169           };
22170
22171           _this.matchAllGeometry = function (geometries) {
22172             return presetCollection(_this.collection.filter(function (d) {
22173               return d && d.matchAllGeometry(geometries);
22174             }));
22175           };
22176
22177           _this.matchAnyGeometry = function (geometries) {
22178             return presetCollection(_this.collection.filter(function (d) {
22179               return geometries.some(function (geom) {
22180                 return d.matchGeometry(geom);
22181               });
22182             }));
22183           };
22184
22185           _this.fallback = function (geometry) {
22186             var id = geometry;
22187             if (id === 'vertex') id = 'point';
22188             return _this.item(id);
22189           };
22190
22191           _this.search = function (value, geometry, countryCode) {
22192             if (!value) return _this;
22193             value = value.toLowerCase().trim(); // match at name beginning or just after a space (e.g. "office" -> match "Law Office")
22194
22195             function leading(a) {
22196               var index = a.indexOf(value);
22197               return index === 0 || a[index - 1] === ' ';
22198             } // match at name beginning only
22199
22200
22201             function leadingStrict(a) {
22202               var index = a.indexOf(value);
22203               return index === 0;
22204             }
22205
22206             function sortNames(a, b) {
22207               var aCompare = (a.suggestion ? a.originalName : a.name()).toLowerCase();
22208               var bCompare = (b.suggestion ? b.originalName : b.name()).toLowerCase(); // priority if search string matches preset name exactly - #4325
22209
22210               if (value === aCompare) return -1;
22211               if (value === bCompare) return 1; // priority for higher matchScore
22212
22213               var i = b.originalScore - a.originalScore;
22214               if (i !== 0) return i; // priority if search string appears earlier in preset name
22215
22216               i = aCompare.indexOf(value) - bCompare.indexOf(value);
22217               if (i !== 0) return i; // priority for shorter preset names
22218
22219               return aCompare.length - bCompare.length;
22220             }
22221
22222             var pool = _this.collection;
22223
22224             if (countryCode) {
22225               pool = pool.filter(function (a) {
22226                 if (a.countryCodes && a.countryCodes.indexOf(countryCode) === -1) return false;
22227                 if (a.notCountryCodes && a.notCountryCodes.indexOf(countryCode) !== -1) return false;
22228                 return true;
22229               });
22230             }
22231
22232             var searchable = pool.filter(function (a) {
22233               return a.searchable !== false && a.suggestion !== true;
22234             });
22235             var suggestions = pool.filter(function (a) {
22236               return a.suggestion === true;
22237             }); // matches value to preset.name
22238
22239             var leading_name = searchable.filter(function (a) {
22240               return leading(a.name().toLowerCase());
22241             }).sort(sortNames); // matches value to preset suggestion name (original name is unhyphenated)
22242
22243             var leading_suggestions = suggestions.filter(function (a) {
22244               return leadingStrict(a.originalName.toLowerCase());
22245             }).sort(sortNames); // matches value to preset.terms values
22246
22247             var leading_terms = searchable.filter(function (a) {
22248               return (a.terms() || []).some(leading);
22249             }); // matches value to preset.tags values
22250
22251             var leading_tag_values = searchable.filter(function (a) {
22252               return Object.values(a.tags || {}).filter(function (val) {
22253                 return val !== '*';
22254               }).some(leading);
22255             }); // finds close matches to value in preset.name
22256
22257             var similar_name = searchable.map(function (a) {
22258               return {
22259                 preset: a,
22260                 dist: utilEditDistance(value, a.name())
22261               };
22262             }).filter(function (a) {
22263               return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
22264             }).sort(function (a, b) {
22265               return a.dist - b.dist;
22266             }).map(function (a) {
22267               return a.preset;
22268             }); // finds close matches to value to preset suggestion name (original name is unhyphenated)
22269
22270             var similar_suggestions = suggestions.map(function (a) {
22271               return {
22272                 preset: a,
22273                 dist: utilEditDistance(value, a.originalName.toLowerCase())
22274               };
22275             }).filter(function (a) {
22276               return a.dist + Math.min(value.length - a.preset.originalName.length, 0) < 1;
22277             }).sort(function (a, b) {
22278               return a.dist - b.dist;
22279             }).map(function (a) {
22280               return a.preset;
22281             }); // finds close matches to value in preset.terms
22282
22283             var similar_terms = searchable.filter(function (a) {
22284               return (a.terms() || []).some(function (b) {
22285                 return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
22286               });
22287             });
22288             var results = leading_name.concat(leading_suggestions, leading_terms, leading_tag_values, similar_name, similar_suggestions, similar_terms).slice(0, MAXRESULTS - 1);
22289
22290             if (geometry) {
22291               if (typeof geometry === 'string') {
22292                 results.push(_this.fallback(geometry));
22293               } else {
22294                 geometry.forEach(function (geom) {
22295                   return results.push(_this.fallback(geom));
22296                 });
22297               }
22298             }
22299
22300             return presetCollection(utilArrayUniq(results));
22301           };
22302
22303           return _this;
22304         }
22305
22306         // `presetCategory` builds a `presetCollection` of member presets,
22307         // decorated with some extra methods for searching and matching geometry
22308         //
22309
22310         function presetCategory(categoryID, category, all) {
22311           var _this = Object.assign({}, category); // shallow copy
22312
22313
22314           _this.id = categoryID;
22315           _this.members = presetCollection(category.members.map(function (presetID) {
22316             return all.item(presetID);
22317           }).filter(Boolean));
22318           _this.geometry = _this.members.collection.reduce(function (acc, preset) {
22319             for (var i in preset.geometry) {
22320               var geometry = preset.geometry[i];
22321
22322               if (acc.indexOf(geometry) === -1) {
22323                 acc.push(geometry);
22324               }
22325             }
22326
22327             return acc;
22328           }, []);
22329
22330           _this.matchGeometry = function (geom) {
22331             return _this.geometry.indexOf(geom) >= 0;
22332           };
22333
22334           _this.matchAllGeometry = function (geometries) {
22335             return _this.members.collection.some(function (preset) {
22336               return preset.matchAllGeometry(geometries);
22337             });
22338           };
22339
22340           _this.matchScore = function () {
22341             return -1;
22342           };
22343
22344           _this.name = function () {
22345             return _t("presets.categories.".concat(categoryID, ".name"), {
22346               'default': categoryID
22347             });
22348           };
22349
22350           _this.nameLabel = function () {
22351             return _t.html("presets.categories.".concat(categoryID, ".name"), {
22352               'default': categoryID
22353             });
22354           };
22355
22356           _this.terms = function () {
22357             return [];
22358           };
22359
22360           return _this;
22361         }
22362
22363         // `presetField` decorates a given `field` Object
22364         // with some extra methods for searching and matching geometry
22365         //
22366
22367         function presetField(fieldID, field) {
22368           var _this = Object.assign({}, field); // shallow copy
22369
22370
22371           _this.id = fieldID; // for use in classes, element ids, css selectors
22372
22373           _this.safeid = utilSafeClassName(fieldID);
22374
22375           _this.matchGeometry = function (geom) {
22376             return !_this.geometry || _this.geometry.indexOf(geom) !== -1;
22377           };
22378
22379           _this.matchAllGeometry = function (geometries) {
22380             return !_this.geometry || geometries.every(function (geom) {
22381               return _this.geometry.indexOf(geom) !== -1;
22382             });
22383           };
22384
22385           _this.t = function (scope, options) {
22386             return _t("presets.fields.".concat(fieldID, ".").concat(scope), options);
22387           };
22388
22389           _this.t.html = function (scope, options) {
22390             return _t.html("presets.fields.".concat(fieldID, ".").concat(scope), options);
22391           };
22392
22393           _this.title = function () {
22394             return _this.overrideLabel || _this.t('label', {
22395               'default': fieldID
22396             });
22397           };
22398
22399           _this.label = function () {
22400             return _this.overrideLabel || _this.t.html('label', {
22401               'default': fieldID
22402             });
22403           };
22404
22405           var _placeholder = _this.placeholder;
22406
22407           _this.placeholder = function () {
22408             return _this.t('placeholder', {
22409               'default': _placeholder
22410             });
22411           };
22412
22413           _this.originalTerms = (_this.terms || []).join();
22414
22415           _this.terms = function () {
22416             return _this.t('terms', {
22417               'default': _this.originalTerms
22418             }).toLowerCase().trim().split(/\s*,+\s*/);
22419           };
22420
22421           _this.increment = _this.type === 'number' ? _this.increment || 1 : undefined;
22422           return _this;
22423         }
22424
22425         // `Array.prototype.lastIndexOf` method
22426         // https://tc39.github.io/ecma262/#sec-array.prototype.lastindexof
22427         _export({ target: 'Array', proto: true, forced: arrayLastIndexOf !== [].lastIndexOf }, {
22428           lastIndexOf: arrayLastIndexOf
22429         });
22430
22431         // `presetPreset` decorates a given `preset` Object
22432         // with some extra methods for searching and matching geometry
22433         //
22434
22435         function presetPreset(presetID, preset, addable, allFields, allPresets) {
22436           allFields = allFields || {};
22437           allPresets = allPresets || {};
22438
22439           var _this = Object.assign({}, preset); // shallow copy
22440
22441
22442           var _addable = addable || false;
22443
22444           var _resolvedFields; // cache
22445
22446
22447           var _resolvedMoreFields; // cache
22448
22449
22450           _this.id = presetID;
22451           _this.safeid = utilSafeClassName(presetID); // for use in css classes, selectors, element ids
22452
22453           _this.originalTerms = (_this.terms || []).join();
22454           _this.originalName = _this.name || '';
22455           _this.originalScore = _this.matchScore || 1;
22456           _this.originalReference = _this.reference || {};
22457           _this.originalFields = _this.fields || [];
22458           _this.originalMoreFields = _this.moreFields || [];
22459
22460           _this.fields = function () {
22461             return _resolvedFields || (_resolvedFields = resolve('fields'));
22462           };
22463
22464           _this.moreFields = function () {
22465             return _resolvedMoreFields || (_resolvedMoreFields = resolve('moreFields'));
22466           };
22467
22468           _this.resetFields = function () {
22469             return _resolvedFields = _resolvedMoreFields = null;
22470           };
22471
22472           _this.tags = _this.tags || {};
22473           _this.addTags = _this.addTags || _this.tags;
22474           _this.removeTags = _this.removeTags || _this.addTags;
22475           _this.geometry = _this.geometry || [];
22476
22477           _this.matchGeometry = function (geom) {
22478             return _this.geometry.indexOf(geom) >= 0;
22479           };
22480
22481           _this.matchAllGeometry = function (geoms) {
22482             return geoms.every(_this.matchGeometry);
22483           };
22484
22485           _this.matchScore = function (entityTags) {
22486             var tags = _this.tags;
22487             var seen = {};
22488             var score = 0; // match on tags
22489
22490             for (var k in tags) {
22491               seen[k] = true;
22492
22493               if (entityTags[k] === tags[k]) {
22494                 score += _this.originalScore;
22495               } else if (tags[k] === '*' && k in entityTags) {
22496                 score += _this.originalScore / 2;
22497               } else {
22498                 return -1;
22499               }
22500             } // boost score for additional matches in addTags - #6802
22501
22502
22503             var addTags = _this.addTags;
22504
22505             for (var _k in addTags) {
22506               if (!seen[_k] && entityTags[_k] === addTags[_k]) {
22507                 score += _this.originalScore;
22508               }
22509             }
22510
22511             return score;
22512           };
22513
22514           _this.t = function (scope, options) {
22515             var textID = "presets.presets.".concat(presetID, ".").concat(scope);
22516             return _t(textID, options);
22517           };
22518
22519           _this.t.html = function (scope, options) {
22520             var textID = "presets.presets.".concat(presetID, ".").concat(scope);
22521             return _t.html(textID, options);
22522           };
22523
22524           _this.name = function () {
22525             return _this.t('name', {
22526               'default': _this.originalName
22527             });
22528           };
22529
22530           _this.nameLabel = function () {
22531             return _this.t.html('name', {
22532               'default': _this.originalName
22533             });
22534           };
22535
22536           _this.subtitle = function () {
22537             if (_this.suggestion) {
22538               var path = presetID.split('/');
22539               path.pop(); // remove brand name
22540
22541               return _t('presets.presets.' + path.join('/') + '.name');
22542             }
22543
22544             return null;
22545           };
22546
22547           _this.subtitleLabel = function () {
22548             if (_this.suggestion) {
22549               var path = presetID.split('/');
22550               path.pop(); // remove brand name
22551
22552               return _t.html('presets.presets.' + path.join('/') + '.name');
22553             }
22554
22555             return null;
22556           };
22557
22558           _this.terms = function () {
22559             return _this.t('terms', {
22560               'default': _this.originalTerms
22561             }).toLowerCase().trim().split(/\s*,+\s*/);
22562           };
22563
22564           _this.isFallback = function () {
22565             var tagCount = Object.keys(_this.tags).length;
22566             return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty('area');
22567           };
22568
22569           _this.addable = function (val) {
22570             if (!arguments.length) return _addable;
22571             _addable = val;
22572             return _this;
22573           };
22574
22575           _this.reference = function () {
22576             // Lookup documentation on Wikidata...
22577             var qid = _this.tags.wikidata || _this.tags['brand:wikidata'] || _this.tags['operator:wikidata'];
22578
22579             if (qid) {
22580               return {
22581                 qid: qid
22582               };
22583             } // Lookup documentation on OSM Wikibase...
22584
22585
22586             var key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
22587             var value = _this.originalReference.value || _this.tags[key];
22588
22589             if (value === '*') {
22590               return {
22591                 key: key
22592               };
22593             } else {
22594               return {
22595                 key: key,
22596                 value: value
22597               };
22598             }
22599           };
22600
22601           _this.unsetTags = function (tags, geometry, skipFieldDefaults) {
22602             tags = utilObjectOmit(tags, Object.keys(_this.removeTags));
22603
22604             if (geometry && !skipFieldDefaults) {
22605               _this.fields().forEach(function (field) {
22606                 if (field.matchGeometry(geometry) && field.key && field["default"] === tags[field.key]) {
22607                   delete tags[field.key];
22608                 }
22609               });
22610             }
22611
22612             delete tags.area;
22613             return tags;
22614           };
22615
22616           _this.setTags = function (tags, geometry, skipFieldDefaults) {
22617             var addTags = _this.addTags;
22618             tags = Object.assign({}, tags); // shallow copy
22619
22620             for (var k in addTags) {
22621               if (addTags[k] === '*') {
22622                 tags[k] = 'yes';
22623               } else {
22624                 tags[k] = addTags[k];
22625               }
22626             } // Add area=yes if necessary.
22627             // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
22628             // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
22629             // 2. chosen preset doesn't have a key in osmAreaKeys (`railway=station`)
22630
22631
22632             if (!addTags.hasOwnProperty('area')) {
22633               delete tags.area;
22634
22635               if (geometry === 'area') {
22636                 var needsAreaTag = true;
22637
22638                 if (_this.geometry.indexOf('line') === -1) {
22639                   for (var _k2 in addTags) {
22640                     if (_k2 in osmAreaKeys) {
22641                       needsAreaTag = false;
22642                       break;
22643                     }
22644                   }
22645                 }
22646
22647                 if (needsAreaTag) {
22648                   tags.area = 'yes';
22649                 }
22650               }
22651             }
22652
22653             if (geometry && !skipFieldDefaults) {
22654               _this.fields().forEach(function (field) {
22655                 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field["default"]) {
22656                   tags[field.key] = field["default"];
22657                 }
22658               });
22659             }
22660
22661             return tags;
22662           }; // For a preset without fields, use the fields of the parent preset.
22663           // Replace {preset} placeholders with the fields of the specified presets.
22664
22665
22666           function resolve(which) {
22667             var fieldIDs = which === 'fields' ? _this.originalFields : _this.originalMoreFields;
22668             var resolved = [];
22669             fieldIDs.forEach(function (fieldID) {
22670               var match = fieldID.match(/\{(.*)\}/);
22671
22672               if (match !== null) {
22673                 // a presetID wrapped in braces {}
22674                 resolved = resolved.concat(inheritFields(match[1], which));
22675               } else if (allFields[fieldID]) {
22676                 // a normal fieldID
22677                 resolved.push(allFields[fieldID]);
22678               } else {
22679                 console.log("Cannot resolve \"".concat(fieldID, "\" found in ").concat(_this.id, ".").concat(which)); // eslint-disable-line no-console
22680               }
22681             }); // no fields resolved, so use the parent's if possible
22682
22683             if (!resolved.length) {
22684               var endIndex = _this.id.lastIndexOf('/');
22685
22686               var parentID = endIndex && _this.id.substring(0, endIndex);
22687
22688               if (parentID) {
22689                 resolved = inheritFields(parentID, which);
22690               }
22691             }
22692
22693             return utilArrayUniq(resolved); // returns an array of fields to inherit from the given presetID, if found
22694
22695             function inheritFields(presetID, which) {
22696               var parent = allPresets[presetID];
22697               if (!parent) return [];
22698
22699               if (which === 'fields') {
22700                 return parent.fields().filter(shouldInherit);
22701               } else if (which === 'moreFields') {
22702                 return parent.moreFields();
22703               } else {
22704                 return [];
22705               }
22706             } // Skip `fields` for the keys which define the preset.
22707             // These are usually `typeCombo` fields like `shop=*`
22708
22709
22710             function shouldInherit(f) {
22711               if (f.key && _this.tags[f.key] !== undefined && // inherit anyway if multiple values are allowed or just a checkbox
22712               f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'manyCombo' && f.type !== 'check') return false;
22713               return true;
22714             }
22715           }
22716
22717           return _this;
22718         }
22719
22720         var _mainPresetIndex = presetIndex(); // singleton
22721         // `presetIndex` wraps a `presetCollection`
22722         // with methods for loading new data and returning defaults
22723         //
22724
22725         function presetIndex() {
22726           var dispatch$1 = dispatch('favoritePreset', 'recentsChange');
22727           var MAXRECENTS = 30; // seed the preset lists with geometry fallbacks
22728
22729           var POINT = presetPreset('point', {
22730             name: 'Point',
22731             tags: {},
22732             geometry: ['point', 'vertex'],
22733             matchScore: 0.1
22734           });
22735           var LINE = presetPreset('line', {
22736             name: 'Line',
22737             tags: {},
22738             geometry: ['line'],
22739             matchScore: 0.1
22740           });
22741           var AREA = presetPreset('area', {
22742             name: 'Area',
22743             tags: {
22744               area: 'yes'
22745             },
22746             geometry: ['area'],
22747             matchScore: 0.1
22748           });
22749           var RELATION = presetPreset('relation', {
22750             name: 'Relation',
22751             tags: {},
22752             geometry: ['relation'],
22753             matchScore: 0.1
22754           });
22755
22756           var _this = presetCollection([POINT, LINE, AREA, RELATION]);
22757
22758           var _presets = {
22759             point: POINT,
22760             line: LINE,
22761             area: AREA,
22762             relation: RELATION
22763           };
22764           var _defaults = {
22765             point: presetCollection([POINT]),
22766             vertex: presetCollection([POINT]),
22767             line: presetCollection([LINE]),
22768             area: presetCollection([AREA]),
22769             relation: presetCollection([RELATION])
22770           };
22771           var _fields = {};
22772           var _categories = {};
22773           var _universal = [];
22774           var _addablePresetIDs = null; // Set of preset IDs that the user can add
22775
22776           var _recents;
22777
22778           var _favorites; // Index of presets by (geometry, tag key).
22779
22780
22781           var _geometryIndex = {
22782             point: {},
22783             vertex: {},
22784             line: {},
22785             area: {},
22786             relation: {}
22787           };
22788
22789           var _loadPromise;
22790
22791           _this.ensureLoaded = function () {
22792             if (_loadPromise) return _loadPromise;
22793             return _loadPromise = Promise.all([_mainFileFetcher.get('preset_categories'), _mainFileFetcher.get('preset_defaults'), _mainFileFetcher.get('preset_presets'), _mainFileFetcher.get('preset_fields')]).then(function (vals) {
22794               _this.merge({
22795                 categories: vals[0],
22796                 defaults: vals[1],
22797                 presets: vals[2],
22798                 fields: vals[3]
22799               });
22800
22801               osmSetAreaKeys(_this.areaKeys());
22802               osmSetPointTags(_this.pointTags());
22803               osmSetVertexTags(_this.vertexTags());
22804             });
22805           };
22806
22807           _this.merge = function (d) {
22808             // Merge Fields
22809             if (d.fields) {
22810               Object.keys(d.fields).forEach(function (fieldID) {
22811                 var f = d.fields[fieldID];
22812
22813                 if (f) {
22814                   // add or replace
22815                   _fields[fieldID] = presetField(fieldID, f);
22816                 } else {
22817                   // remove
22818                   delete _fields[fieldID];
22819                 }
22820               });
22821             } // Merge Presets
22822
22823
22824             if (d.presets) {
22825               Object.keys(d.presets).forEach(function (presetID) {
22826                 var p = d.presets[presetID];
22827
22828                 if (p) {
22829                   // add or replace
22830                   var isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
22831
22832                   _presets[presetID] = presetPreset(presetID, p, isAddable, _fields, _presets);
22833                 } else {
22834                   // remove (but not if it's a fallback)
22835                   var existing = _presets[presetID];
22836
22837                   if (existing && !existing.isFallback()) {
22838                     delete _presets[presetID];
22839                   }
22840                 }
22841               });
22842             } // Need to rebuild _this.collection before loading categories
22843
22844
22845             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Categories
22846
22847             if (d.categories) {
22848               Object.keys(d.categories).forEach(function (categoryID) {
22849                 var c = d.categories[categoryID];
22850
22851                 if (c) {
22852                   // add or replace
22853                   _categories[categoryID] = presetCategory(categoryID, c, _this);
22854                 } else {
22855                   // remove
22856                   delete _categories[categoryID];
22857                 }
22858               });
22859             } // Rebuild _this.collection after loading categories
22860
22861
22862             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Defaults
22863
22864             if (d.defaults) {
22865               Object.keys(d.defaults).forEach(function (geometry) {
22866                 var def = d.defaults[geometry];
22867
22868                 if (Array.isArray(def)) {
22869                   // add or replace
22870                   _defaults[geometry] = presetCollection(def.map(function (id) {
22871                     return _presets[id] || _categories[id];
22872                   }).filter(Boolean));
22873                 } else {
22874                   // remove
22875                   delete _defaults[geometry];
22876                 }
22877               });
22878             } // Rebuild universal fields array
22879
22880
22881             _universal = Object.values(_fields).filter(function (field) {
22882               return field.universal;
22883             }); // Reset all the preset fields - they'll need to be resolved again
22884
22885             Object.values(_presets).forEach(function (preset) {
22886               return preset.resetFields();
22887             }); // Rebuild geometry index
22888
22889             _geometryIndex = {
22890               point: {},
22891               vertex: {},
22892               line: {},
22893               area: {},
22894               relation: {}
22895             };
22896
22897             _this.collection.forEach(function (preset) {
22898               (preset.geometry || []).forEach(function (geometry) {
22899                 var g = _geometryIndex[geometry];
22900
22901                 for (var key in preset.tags) {
22902                   (g[key] = g[key] || []).push(preset);
22903                 }
22904               });
22905             });
22906
22907             return _this;
22908           };
22909
22910           _this.match = function (entity, resolver) {
22911             return resolver["transient"](entity, 'presetMatch', function () {
22912               var geometry = entity.geometry(resolver); // Treat entities on addr:interpolation lines as points, not vertices - #3241
22913
22914               if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
22915                 geometry = 'point';
22916               }
22917
22918               return _this.matchTags(entity.tags, geometry);
22919             });
22920           };
22921
22922           _this.matchTags = function (tags, geometry) {
22923             var geometryMatches = _geometryIndex[geometry];
22924             var address;
22925             var best = -1;
22926             var match;
22927
22928             for (var k in tags) {
22929               // If any part of an address is present, allow fallback to "Address" preset - #4353
22930               if (/^addr:/.test(k) && geometryMatches['addr:*']) {
22931                 address = geometryMatches['addr:*'][0];
22932               }
22933
22934               var keyMatches = geometryMatches[k];
22935               if (!keyMatches) continue;
22936
22937               for (var i = 0; i < keyMatches.length; i++) {
22938                 var score = keyMatches[i].matchScore(tags);
22939
22940                 if (score > best) {
22941                   best = score;
22942                   match = keyMatches[i];
22943                 }
22944               }
22945             }
22946
22947             if (address && (!match || match.isFallback())) {
22948               match = address;
22949             }
22950
22951             return match || _this.fallback(geometry);
22952           };
22953
22954           _this.allowsVertex = function (entity, resolver) {
22955             if (entity.type !== 'node') return false;
22956             if (Object.keys(entity.tags).length === 0) return true;
22957             return resolver["transient"](entity, 'vertexMatch', function () {
22958               // address lines allow vertices to act as standalone points
22959               if (entity.isOnAddressLine(resolver)) return true;
22960               var geometries = osmNodeGeometriesForTags(entity.tags);
22961               if (geometries.vertex) return true;
22962               if (geometries.point) return false; // allow vertices for unspecified points
22963
22964               return true;
22965             });
22966           }; // Because of the open nature of tagging, iD will never have a complete
22967           // list of tags used in OSM, so we want it to have logic like "assume
22968           // that a closed way with an amenity tag is an area, unless the amenity
22969           // is one of these specific types". This function computes a structure
22970           // that allows testing of such conditions, based on the presets designated
22971           // as as supporting (or not supporting) the area geometry.
22972           //
22973           // The returned object L is a keeplist/discardlist of tags. A closed way
22974           // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
22975           // (see `Way#isArea()`). In other words, the keys of L form the keeplist,
22976           // and the subkeys form the discardlist.
22977
22978
22979           _this.areaKeys = function () {
22980             // The ignore list is for keys that imply lines. (We always add `area=yes` for exceptions)
22981             var ignore = ['barrier', 'highway', 'footway', 'railway', 'junction', 'type'];
22982             var areaKeys = {}; // ignore name-suggestion-index and deprecated presets
22983
22984             var presets = _this.collection.filter(function (p) {
22985               return !p.suggestion && !p.replacement;
22986             }); // keeplist
22987
22988
22989             presets.forEach(function (p) {
22990               var keys = p.tags && Object.keys(p.tags);
22991               var key = keys && keys.length && keys[0]; // pick the first tag
22992
22993               if (!key) return;
22994               if (ignore.indexOf(key) !== -1) return;
22995
22996               if (p.geometry.indexOf('area') !== -1) {
22997                 // probably an area..
22998                 areaKeys[key] = areaKeys[key] || {};
22999               }
23000             }); // discardlist
23001
23002             presets.forEach(function (p) {
23003               var key;
23004
23005               for (key in p.addTags) {
23006                 // examine all addTags to get a better sense of what can be tagged on lines - #6800
23007                 var value = p.addTags[key];
23008
23009                 if (key in areaKeys && // probably an area...
23010                 p.geometry.indexOf('line') !== -1 && // but sometimes a line
23011                 value !== '*') {
23012                   areaKeys[key][value] = true;
23013                 }
23014               }
23015             });
23016             return areaKeys;
23017           };
23018
23019           _this.pointTags = function () {
23020             return _this.collection.reduce(function (pointTags, d) {
23021               // ignore name-suggestion-index, deprecated, and generic presets
23022               if (d.suggestion || d.replacement || d.searchable === false) return pointTags; // only care about the primary tag
23023
23024               var keys = d.tags && Object.keys(d.tags);
23025               var key = keys && keys.length && keys[0]; // pick the first tag
23026
23027               if (!key) return pointTags; // if this can be a point
23028
23029               if (d.geometry.indexOf('point') !== -1) {
23030                 pointTags[key] = pointTags[key] || {};
23031                 pointTags[key][d.tags[key]] = true;
23032               }
23033
23034               return pointTags;
23035             }, {});
23036           };
23037
23038           _this.vertexTags = function () {
23039             return _this.collection.reduce(function (vertexTags, d) {
23040               // ignore name-suggestion-index, deprecated, and generic presets
23041               if (d.suggestion || d.replacement || d.searchable === false) return vertexTags; // only care about the primary tag
23042
23043               var keys = d.tags && Object.keys(d.tags);
23044               var key = keys && keys.length && keys[0]; // pick the first tag
23045
23046               if (!key) return vertexTags; // if this can be a vertex
23047
23048               if (d.geometry.indexOf('vertex') !== -1) {
23049                 vertexTags[key] = vertexTags[key] || {};
23050                 vertexTags[key][d.tags[key]] = true;
23051               }
23052
23053               return vertexTags;
23054             }, {});
23055           };
23056
23057           _this.field = function (id) {
23058             return _fields[id];
23059           };
23060
23061           _this.universal = function () {
23062             return _universal;
23063           };
23064
23065           _this.defaults = function (geometry, n, startWithRecents) {
23066             var recents = [];
23067
23068             if (startWithRecents) {
23069               recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
23070             }
23071
23072             var defaults;
23073
23074             if (_addablePresetIDs) {
23075               defaults = Array.from(_addablePresetIDs).map(function (id) {
23076                 var preset = _this.item(id);
23077
23078                 if (preset && preset.matchGeometry(geometry)) return preset;
23079                 return null;
23080               }).filter(Boolean);
23081             } else {
23082               defaults = _defaults[geometry].collection.concat(_this.fallback(geometry));
23083             }
23084
23085             return presetCollection(utilArrayUniq(recents.concat(defaults)).slice(0, n - 1));
23086           }; // pass a Set of addable preset ids
23087
23088
23089           _this.addablePresetIDs = function (val) {
23090             if (!arguments.length) return _addablePresetIDs; // accept and convert arrays
23091
23092             if (Array.isArray(val)) val = new Set(val);
23093             _addablePresetIDs = val;
23094
23095             if (_addablePresetIDs) {
23096               // reset all presets
23097               _this.collection.forEach(function (p) {
23098                 // categories aren't addable
23099                 if (p.addable) p.addable(_addablePresetIDs.has(p.id));
23100               });
23101             } else {
23102               _this.collection.forEach(function (p) {
23103                 if (p.addable) p.addable(true);
23104               });
23105             }
23106
23107             return _this;
23108           };
23109
23110           _this.recent = function () {
23111             return presetCollection(utilArrayUniq(_this.getRecents().map(function (d) {
23112               return d.preset;
23113             })));
23114           };
23115
23116           function RibbonItem(preset, source) {
23117             var item = {};
23118             item.preset = preset;
23119             item.source = source;
23120
23121             item.isFavorite = function () {
23122               return item.source === 'favorite';
23123             };
23124
23125             item.isRecent = function () {
23126               return item.source === 'recent';
23127             };
23128
23129             item.matches = function (preset) {
23130               return item.preset.id === preset.id;
23131             };
23132
23133             item.minified = function () {
23134               return {
23135                 pID: item.preset.id
23136               };
23137             };
23138
23139             return item;
23140           }
23141
23142           function ribbonItemForMinified(d, source) {
23143             if (d && d.pID) {
23144               var preset = _this.item(d.pID);
23145
23146               if (!preset) return null;
23147               return RibbonItem(preset, source);
23148             }
23149
23150             return null;
23151           }
23152
23153           _this.getGenericRibbonItems = function () {
23154             return ['point', 'line', 'area'].map(function (id) {
23155               return RibbonItem(_this.item(id), 'generic');
23156             });
23157           };
23158
23159           _this.getAddable = function () {
23160             if (!_addablePresetIDs) return [];
23161             return _addablePresetIDs.map(function (id) {
23162               var preset = _this.item(id);
23163
23164               if (preset) return RibbonItem(preset, 'addable');
23165               return null;
23166             }).filter(Boolean);
23167           };
23168
23169           function setRecents(items) {
23170             _recents = items;
23171             var minifiedItems = items.map(function (d) {
23172               return d.minified();
23173             });
23174             corePreferences('preset_recents', JSON.stringify(minifiedItems));
23175             dispatch$1.call('recentsChange');
23176           }
23177
23178           _this.getRecents = function () {
23179             if (!_recents) {
23180               // fetch from local storage
23181               _recents = (JSON.parse(corePreferences('preset_recents')) || []).reduce(function (acc, d) {
23182                 var item = ribbonItemForMinified(d, 'recent');
23183                 if (item && item.preset.addable()) acc.push(item);
23184                 return acc;
23185               }, []);
23186             }
23187
23188             return _recents;
23189           };
23190
23191           _this.addRecent = function (preset, besidePreset, after) {
23192             var recents = _this.getRecents();
23193
23194             var beforeItem = _this.recentMatching(besidePreset);
23195
23196             var toIndex = recents.indexOf(beforeItem);
23197             if (after) toIndex += 1;
23198             var newItem = RibbonItem(preset, 'recent');
23199             recents.splice(toIndex, 0, newItem);
23200             setRecents(recents);
23201           };
23202
23203           _this.removeRecent = function (preset) {
23204             var item = _this.recentMatching(preset);
23205
23206             if (item) {
23207               var items = _this.getRecents();
23208
23209               items.splice(items.indexOf(item), 1);
23210               setRecents(items);
23211             }
23212           };
23213
23214           _this.recentMatching = function (preset) {
23215             var items = _this.getRecents();
23216
23217             for (var i in items) {
23218               if (items[i].matches(preset)) {
23219                 return items[i];
23220               }
23221             }
23222
23223             return null;
23224           };
23225
23226           _this.moveItem = function (items, fromIndex, toIndex) {
23227             if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) return null;
23228             items.splice(toIndex, 0, items.splice(fromIndex, 1)[0]);
23229             return items;
23230           };
23231
23232           _this.moveRecent = function (item, beforeItem) {
23233             var recents = _this.getRecents();
23234
23235             var fromIndex = recents.indexOf(item);
23236             var toIndex = recents.indexOf(beforeItem);
23237
23238             var items = _this.moveItem(recents, fromIndex, toIndex);
23239
23240             if (items) setRecents(items);
23241           };
23242
23243           _this.setMostRecent = function (preset) {
23244             if (preset.searchable === false) return;
23245
23246             var items = _this.getRecents();
23247
23248             var item = _this.recentMatching(preset);
23249
23250             if (item) {
23251               items.splice(items.indexOf(item), 1);
23252             } else {
23253               item = RibbonItem(preset, 'recent');
23254             } // remove the last recent (first in, first out)
23255
23256
23257             while (items.length >= MAXRECENTS) {
23258               items.pop();
23259             } // prepend array
23260
23261
23262             items.unshift(item);
23263             setRecents(items);
23264           };
23265
23266           function setFavorites(items) {
23267             _favorites = items;
23268             var minifiedItems = items.map(function (d) {
23269               return d.minified();
23270             });
23271             corePreferences('preset_favorites', JSON.stringify(minifiedItems)); // call update
23272
23273             dispatch$1.call('favoritePreset');
23274           }
23275
23276           _this.addFavorite = function (preset, besidePreset, after) {
23277             var favorites = _this.getFavorites();
23278
23279             var beforeItem = _this.favoriteMatching(besidePreset);
23280
23281             var toIndex = favorites.indexOf(beforeItem);
23282             if (after) toIndex += 1;
23283             var newItem = RibbonItem(preset, 'favorite');
23284             favorites.splice(toIndex, 0, newItem);
23285             setFavorites(favorites);
23286           };
23287
23288           _this.toggleFavorite = function (preset) {
23289             var favs = _this.getFavorites();
23290
23291             var favorite = _this.favoriteMatching(preset);
23292
23293             if (favorite) {
23294               favs.splice(favs.indexOf(favorite), 1);
23295             } else {
23296               // only allow 10 favorites
23297               if (favs.length === 10) {
23298                 // remove the last favorite (last in, first out)
23299                 favs.pop();
23300               } // append array
23301
23302
23303               favs.push(RibbonItem(preset, 'favorite'));
23304             }
23305
23306             setFavorites(favs);
23307           };
23308
23309           _this.removeFavorite = function (preset) {
23310             var item = _this.favoriteMatching(preset);
23311
23312             if (item) {
23313               var items = _this.getFavorites();
23314
23315               items.splice(items.indexOf(item), 1);
23316               setFavorites(items);
23317             }
23318           };
23319
23320           _this.getFavorites = function () {
23321             if (!_favorites) {
23322               // fetch from local storage
23323               var rawFavorites = JSON.parse(corePreferences('preset_favorites'));
23324
23325               if (!rawFavorites) {
23326                 rawFavorites = [];
23327                 corePreferences('preset_favorites', JSON.stringify(rawFavorites));
23328               }
23329
23330               _favorites = rawFavorites.reduce(function (output, d) {
23331                 var item = ribbonItemForMinified(d, 'favorite');
23332                 if (item && item.preset.addable()) output.push(item);
23333                 return output;
23334               }, []);
23335             }
23336
23337             return _favorites;
23338           };
23339
23340           _this.favoriteMatching = function (preset) {
23341             var favs = _this.getFavorites();
23342
23343             for (var index in favs) {
23344               if (favs[index].matches(preset)) {
23345                 return favs[index];
23346               }
23347             }
23348
23349             return null;
23350           };
23351
23352           return utilRebind(_this, dispatch$1, 'on');
23353         }
23354
23355         function utilTagText(entity) {
23356           var obj = entity && entity.tags || {};
23357           return Object.keys(obj).map(function (k) {
23358             return k + '=' + obj[k];
23359           }).join(', ');
23360         }
23361         function utilTotalExtent(array, graph) {
23362           var extent = geoExtent();
23363           var val, entity;
23364
23365           for (var i = 0; i < array.length; i++) {
23366             val = array[i];
23367             entity = typeof val === 'string' ? graph.hasEntity(val) : val;
23368
23369             if (entity) {
23370               extent._extend(entity.extent(graph));
23371             }
23372           }
23373
23374           return extent;
23375         }
23376         function utilTagDiff(oldTags, newTags) {
23377           var tagDiff = [];
23378           var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
23379           keys.forEach(function (k) {
23380             var oldVal = oldTags[k];
23381             var newVal = newTags[k];
23382
23383             if ((oldVal || oldVal === '') && (newVal === undefined || newVal !== oldVal)) {
23384               tagDiff.push({
23385                 type: '-',
23386                 key: k,
23387                 oldVal: oldVal,
23388                 newVal: newVal,
23389                 display: '- ' + k + '=' + oldVal
23390               });
23391             }
23392
23393             if ((newVal || newVal === '') && (oldVal === undefined || newVal !== oldVal)) {
23394               tagDiff.push({
23395                 type: '+',
23396                 key: k,
23397                 oldVal: oldVal,
23398                 newVal: newVal,
23399                 display: '+ ' + k + '=' + newVal
23400               });
23401             }
23402           });
23403           return tagDiff;
23404         }
23405         function utilEntitySelector(ids) {
23406           return ids.length ? '.' + ids.join(',.') : 'nothing';
23407         } // returns an selector to select entity ids for:
23408         //  - entityIDs passed in
23409         //  - shallow descendant entityIDs for any of those entities that are relations
23410
23411         function utilEntityOrMemberSelector(ids, graph) {
23412           var seen = new Set(ids);
23413           ids.forEach(collectShallowDescendants);
23414           return utilEntitySelector(Array.from(seen));
23415
23416           function collectShallowDescendants(id) {
23417             var entity = graph.hasEntity(id);
23418             if (!entity || entity.type !== 'relation') return;
23419             entity.members.map(function (member) {
23420               return member.id;
23421             }).forEach(function (id) {
23422               seen.add(id);
23423             });
23424           }
23425         } // returns an selector to select entity ids for:
23426         //  - entityIDs passed in
23427         //  - deep descendant entityIDs for any of those entities that are relations
23428
23429         function utilEntityOrDeepMemberSelector(ids, graph) {
23430           return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
23431         } // returns an selector to select entity ids for:
23432         //  - entityIDs passed in
23433         //  - deep descendant entityIDs for any of those entities that are relations
23434
23435         function utilEntityAndDeepMemberIDs(ids, graph) {
23436           var seen = new Set();
23437           ids.forEach(collectDeepDescendants);
23438           return Array.from(seen);
23439
23440           function collectDeepDescendants(id) {
23441             if (seen.has(id)) return;
23442             seen.add(id);
23443             var entity = graph.hasEntity(id);
23444             if (!entity || entity.type !== 'relation') return;
23445             entity.members.map(function (member) {
23446               return member.id;
23447             }).forEach(collectDeepDescendants); // recurse
23448           }
23449         } // returns an selector to select entity ids for:
23450         //  - deep descendant entityIDs for any of those entities that are relations
23451
23452         function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
23453           var idsSet = new Set(ids);
23454           var seen = new Set();
23455           var returners = new Set();
23456           ids.forEach(collectDeepDescendants);
23457           return utilEntitySelector(Array.from(returners));
23458
23459           function collectDeepDescendants(id) {
23460             if (seen.has(id)) return;
23461             seen.add(id);
23462
23463             if (!idsSet.has(id)) {
23464               returners.add(id);
23465             }
23466
23467             var entity = graph.hasEntity(id);
23468             if (!entity || entity.type !== 'relation') return;
23469             if (skipMultipolgonMembers && entity.isMultipolygon()) return;
23470             entity.members.map(function (member) {
23471               return member.id;
23472             }).forEach(collectDeepDescendants); // recurse
23473           }
23474         } // Adds or removes highlight styling for the specified entities
23475
23476         function utilHighlightEntities(ids, highlighted, context) {
23477           context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed('highlighted', highlighted);
23478         } // returns an Array that is the union of:
23479         //  - nodes for any nodeIDs passed in
23480         //  - child nodes of any wayIDs passed in
23481         //  - descendant member and child nodes of relationIDs passed in
23482
23483         function utilGetAllNodes(ids, graph) {
23484           var seen = new Set();
23485           var nodes = new Set();
23486           ids.forEach(collectNodes);
23487           return Array.from(nodes);
23488
23489           function collectNodes(id) {
23490             if (seen.has(id)) return;
23491             seen.add(id);
23492             var entity = graph.hasEntity(id);
23493             if (!entity) return;
23494
23495             if (entity.type === 'node') {
23496               nodes.add(entity);
23497             } else if (entity.type === 'way') {
23498               entity.nodes.forEach(collectNodes);
23499             } else {
23500               entity.members.map(function (member) {
23501                 return member.id;
23502               }).forEach(collectNodes); // recurse
23503             }
23504           }
23505         }
23506         function utilDisplayName(entity) {
23507           var localizedNameKey = 'name:' + _mainLocalizer.languageCode().toLowerCase();
23508           var name = entity.tags[localizedNameKey] || entity.tags.name || '';
23509           var network = entity.tags.cycle_network || entity.tags.network;
23510
23511           if (!name && entity.tags.ref) {
23512             name = entity.tags.ref;
23513
23514             if (network) {
23515               name = network + ' ' + name;
23516             }
23517           }
23518
23519           return name;
23520         }
23521         function utilDisplayNameForPath(entity) {
23522           var name = utilDisplayName(entity);
23523           var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
23524
23525           if (!isFirefox && name && rtlRegex.test(name)) {
23526             name = fixRTLTextForSvg(name);
23527           }
23528
23529           return name;
23530         }
23531         function utilDisplayType(id) {
23532           return {
23533             n: _t('inspector.node'),
23534             w: _t('inspector.way'),
23535             r: _t('inspector.relation')
23536           }[id.charAt(0)];
23537         }
23538         function utilDisplayLabel(entity, graphOrGeometry) {
23539           var displayName = utilDisplayName(entity);
23540
23541           if (displayName) {
23542             // use the display name if there is one
23543             return displayName;
23544           }
23545
23546           var preset = typeof graphOrGeometry === 'string' ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
23547
23548           if (preset && preset.name()) {
23549             // use the preset name if there is a match
23550             return preset.name();
23551           } // fallback to the display type (node/way/relation)
23552
23553
23554           return utilDisplayType(entity.id);
23555         }
23556         function utilEntityRoot(entityType) {
23557           return {
23558             node: 'n',
23559             way: 'w',
23560             relation: 'r'
23561           }[entityType];
23562         } // Returns a single object containing the tags of all the given entities.
23563         // Example:
23564         // {
23565         //   highway: 'service',
23566         //   service: 'parking_aisle'
23567         // }
23568         //           +
23569         // {
23570         //   highway: 'service',
23571         //   service: 'driveway',
23572         //   width: '3'
23573         // }
23574         //           =
23575         // {
23576         //   highway: 'service',
23577         //   service: [ 'driveway', 'parking_aisle' ],
23578         //   width: [ '3', undefined ]
23579         // }
23580
23581         function utilCombinedTags(entityIDs, graph) {
23582           var tags = {};
23583           var tagCounts = {};
23584           var allKeys = new Set();
23585           var entities = entityIDs.map(function (entityID) {
23586             return graph.hasEntity(entityID);
23587           }).filter(Boolean); // gather the aggregate keys
23588
23589           entities.forEach(function (entity) {
23590             var keys = Object.keys(entity.tags).filter(Boolean);
23591             keys.forEach(function (key) {
23592               allKeys.add(key);
23593             });
23594           });
23595           entities.forEach(function (entity) {
23596             allKeys.forEach(function (key) {
23597               var value = entity.tags[key]; // purposely allow `undefined`
23598
23599               if (!tags.hasOwnProperty(key)) {
23600                 // first value, set as raw
23601                 tags[key] = value;
23602               } else {
23603                 if (!Array.isArray(tags[key])) {
23604                   if (tags[key] !== value) {
23605                     // first alternate value, replace single value with array
23606                     tags[key] = [tags[key], value];
23607                   }
23608                 } else {
23609                   // type is array
23610                   if (tags[key].indexOf(value) === -1) {
23611                     // subsequent alternate value, add to array
23612                     tags[key].push(value);
23613                   }
23614                 }
23615               }
23616
23617               var tagHash = key + '=' + value;
23618               if (!tagCounts[tagHash]) tagCounts[tagHash] = 0;
23619               tagCounts[tagHash] += 1;
23620             });
23621           });
23622
23623           for (var key in tags) {
23624             if (!Array.isArray(tags[key])) continue; // sort values by frequency then alphabetically
23625
23626             tags[key] = tags[key].sort(function (val1, val2) {
23627               var key = key; // capture
23628
23629               var count2 = tagCounts[key + '=' + val2];
23630               var count1 = tagCounts[key + '=' + val1];
23631
23632               if (count2 !== count1) {
23633                 return count2 - count1;
23634               }
23635
23636               if (val2 && val1) {
23637                 return val1.localeCompare(val2);
23638               }
23639
23640               return val1 ? 1 : -1;
23641             });
23642           }
23643
23644           return tags;
23645         }
23646         function utilStringQs(str) {
23647           var i = 0; // advance past any leading '?' or '#' characters
23648
23649           while (i < str.length && (str[i] === '?' || str[i] === '#')) {
23650             i++;
23651           }
23652
23653           str = str.slice(i);
23654           return str.split('&').reduce(function (obj, pair) {
23655             var parts = pair.split('=');
23656
23657             if (parts.length === 2) {
23658               obj[parts[0]] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
23659             }
23660
23661             return obj;
23662           }, {});
23663         }
23664         function utilQsString(obj, noencode) {
23665           // encode everything except special characters used in certain hash parameters:
23666           // "/" in map states, ":", ",", {" and "}" in background
23667           function softEncode(s) {
23668             return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
23669           }
23670
23671           return Object.keys(obj).sort().map(function (key) {
23672             return encodeURIComponent(key) + '=' + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
23673           }).join('&');
23674         }
23675         function utilPrefixDOMProperty(property) {
23676           var prefixes = ['webkit', 'ms', 'moz', 'o'];
23677           var i = -1;
23678           var n = prefixes.length;
23679           var s = document.body;
23680           if (property in s) return property;
23681           property = property.substr(0, 1).toUpperCase() + property.substr(1);
23682
23683           while (++i < n) {
23684             if (prefixes[i] + property in s) {
23685               return prefixes[i] + property;
23686             }
23687           }
23688
23689           return false;
23690         }
23691         function utilPrefixCSSProperty(property) {
23692           var prefixes = ['webkit', 'ms', 'Moz', 'O'];
23693           var i = -1;
23694           var n = prefixes.length;
23695           var s = document.body.style;
23696
23697           if (property.toLowerCase() in s) {
23698             return property.toLowerCase();
23699           }
23700
23701           while (++i < n) {
23702             if (prefixes[i] + property in s) {
23703               return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
23704             }
23705           }
23706
23707           return false;
23708         }
23709         var transformProperty;
23710         function utilSetTransform(el, x, y, scale) {
23711           var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform');
23712           var translate = utilDetect().opera ? 'translate(' + x + 'px,' + y + 'px)' : 'translate3d(' + x + 'px,' + y + 'px,0)';
23713           return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
23714         } // Calculates Levenshtein distance between two strings
23715         // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
23716         // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
23717
23718         function utilEditDistance(a, b) {
23719           a = remove$1(a.toLowerCase());
23720           b = remove$1(b.toLowerCase());
23721           if (a.length === 0) return b.length;
23722           if (b.length === 0) return a.length;
23723           var matrix = [];
23724           var i, j;
23725
23726           for (i = 0; i <= b.length; i++) {
23727             matrix[i] = [i];
23728           }
23729
23730           for (j = 0; j <= a.length; j++) {
23731             matrix[0][j] = j;
23732           }
23733
23734           for (i = 1; i <= b.length; i++) {
23735             for (j = 1; j <= a.length; j++) {
23736               if (b.charAt(i - 1) === a.charAt(j - 1)) {
23737                 matrix[i][j] = matrix[i - 1][j - 1];
23738               } else {
23739                 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
23740                 Math.min(matrix[i][j - 1] + 1, // insertion
23741                 matrix[i - 1][j] + 1)); // deletion
23742               }
23743             }
23744           }
23745
23746           return matrix[b.length][a.length];
23747         } // a d3.mouse-alike which
23748         // 1. Only works on HTML elements, not SVG
23749         // 2. Does not cause style recalculation
23750
23751         function utilFastMouse(container) {
23752           var rect = container.getBoundingClientRect();
23753           var rectLeft = rect.left;
23754           var rectTop = rect.top;
23755           var clientLeft = +container.clientLeft;
23756           var clientTop = +container.clientTop;
23757           return function (e) {
23758             return [e.clientX - rectLeft - clientLeft, e.clientY - rectTop - clientTop];
23759           };
23760         }
23761         function utilAsyncMap(inputs, func, callback) {
23762           var remaining = inputs.length;
23763           var results = [];
23764           var errors = [];
23765           inputs.forEach(function (d, i) {
23766             func(d, function done(err, data) {
23767               errors[i] = err;
23768               results[i] = data;
23769               remaining--;
23770               if (!remaining) callback(errors, results);
23771             });
23772           });
23773         } // wraps an index to an interval [0..length-1]
23774
23775         function utilWrap(index, length) {
23776           if (index < 0) {
23777             index += Math.ceil(-index / length) * length;
23778           }
23779
23780           return index % length;
23781         }
23782         /**
23783          * a replacement for functor
23784          *
23785          * @param {*} value any value
23786          * @returns {Function} a function that returns that value or the value if it's a function
23787          */
23788
23789         function utilFunctor(value) {
23790           if (typeof value === 'function') return value;
23791           return function () {
23792             return value;
23793           };
23794         }
23795         function utilNoAuto(selection) {
23796           var isText = selection.size() && selection.node().tagName.toLowerCase() === 'textarea';
23797           return selection // assign 'new-password' even for non-password fields to prevent browsers (Chrome) ignoring 'off'
23798           .attr('autocomplete', 'new-password').attr('autocorrect', 'off').attr('autocapitalize', 'off').attr('spellcheck', isText ? 'true' : 'false');
23799         } // https://stackoverflow.com/questions/194846/is-there-any-kind-of-hash-code-function-in-javascript
23800         // https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
23801
23802         function utilHashcode(str) {
23803           var hash = 0;
23804
23805           if (str.length === 0) {
23806             return hash;
23807           }
23808
23809           for (var i = 0; i < str.length; i++) {
23810             var _char = str.charCodeAt(i);
23811
23812             hash = (hash << 5) - hash + _char;
23813             hash = hash & hash; // Convert to 32bit integer
23814           }
23815
23816           return hash;
23817         } // Returns version of `str` with all runs of special characters replaced by `_`;
23818         // suitable for HTML ids, classes, selectors, etc.
23819
23820         function utilSafeClassName(str) {
23821           return str.toLowerCase().replace(/[^a-z0-9]+/g, '_');
23822         } // Returns string based on `val` that is highly unlikely to collide with an id
23823         // used previously or that's present elsewhere in the document. Useful for preventing
23824         // browser-provided autofills or when embedding iD on pages with unknown elements.
23825
23826         function utilUniqueDomId(val) {
23827           return 'ideditor-' + utilSafeClassName(val.toString()) + '-' + new Date().getTime().toString();
23828         } // Returns the length of `str` in unicode characters. This can be less than
23829         // `String.length()` since a single unicode character can be composed of multiple
23830         // JavaScript UTF-16 code units.
23831
23832         function utilUnicodeCharsCount(str) {
23833           // Native ES2015 implementations of `Array.from` split strings into unicode characters
23834           return Array.from(str).length;
23835         } // Returns a new string representing `str` cut from its start to `limit` length
23836         // in unicode characters. Note that this runs the risk of splitting graphemes.
23837
23838         function utilUnicodeCharsTruncated(str, limit) {
23839           return Array.from(str).slice(0, limit).join('');
23840         }
23841
23842         function osmEntity(attrs) {
23843           // For prototypal inheritance.
23844           if (this instanceof osmEntity) return; // Create the appropriate subtype.
23845
23846           if (attrs && attrs.type) {
23847             return osmEntity[attrs.type].apply(this, arguments);
23848           } else if (attrs && attrs.id) {
23849             return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
23850           } // Initialize a generic Entity (used only in tests).
23851
23852
23853           return new osmEntity().initialize(arguments);
23854         }
23855
23856         osmEntity.id = function (type) {
23857           return osmEntity.id.fromOSM(type, osmEntity.id.next[type]--);
23858         };
23859
23860         osmEntity.id.next = {
23861           changeset: -1,
23862           node: -1,
23863           way: -1,
23864           relation: -1
23865         };
23866
23867         osmEntity.id.fromOSM = function (type, id) {
23868           return type[0] + id;
23869         };
23870
23871         osmEntity.id.toOSM = function (id) {
23872           return id.slice(1);
23873         };
23874
23875         osmEntity.id.type = function (id) {
23876           return {
23877             'c': 'changeset',
23878             'n': 'node',
23879             'w': 'way',
23880             'r': 'relation'
23881           }[id[0]];
23882         }; // A function suitable for use as the second argument to d3.selection#data().
23883
23884
23885         osmEntity.key = function (entity) {
23886           return entity.id + 'v' + (entity.v || 0);
23887         };
23888
23889         var _deprecatedTagValuesByKey;
23890
23891         osmEntity.deprecatedTagValuesByKey = function (dataDeprecated) {
23892           if (!_deprecatedTagValuesByKey) {
23893             _deprecatedTagValuesByKey = {};
23894             dataDeprecated.forEach(function (d) {
23895               var oldKeys = Object.keys(d.old);
23896
23897               if (oldKeys.length === 1) {
23898                 var oldKey = oldKeys[0];
23899                 var oldValue = d.old[oldKey];
23900
23901                 if (oldValue !== '*') {
23902                   if (!_deprecatedTagValuesByKey[oldKey]) {
23903                     _deprecatedTagValuesByKey[oldKey] = [oldValue];
23904                   } else {
23905                     _deprecatedTagValuesByKey[oldKey].push(oldValue);
23906                   }
23907                 }
23908               }
23909             });
23910           }
23911
23912           return _deprecatedTagValuesByKey;
23913         };
23914
23915         osmEntity.prototype = {
23916           tags: {},
23917           initialize: function initialize(sources) {
23918             for (var i = 0; i < sources.length; ++i) {
23919               var source = sources[i];
23920
23921               for (var prop in source) {
23922                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
23923                   if (source[prop] === undefined) {
23924                     delete this[prop];
23925                   } else {
23926                     this[prop] = source[prop];
23927                   }
23928                 }
23929               }
23930             }
23931
23932             if (!this.id && this.type) {
23933               this.id = osmEntity.id(this.type);
23934             }
23935
23936             if (!this.hasOwnProperty('visible')) {
23937               this.visible = true;
23938             }
23939
23940             return this;
23941           },
23942           copy: function copy(resolver, copies) {
23943             if (copies[this.id]) return copies[this.id];
23944             var copy = osmEntity(this, {
23945               id: undefined,
23946               user: undefined,
23947               version: undefined
23948             });
23949             copies[this.id] = copy;
23950             return copy;
23951           },
23952           osmId: function osmId() {
23953             return osmEntity.id.toOSM(this.id);
23954           },
23955           isNew: function isNew() {
23956             return this.osmId() < 0;
23957           },
23958           update: function update(attrs) {
23959             return osmEntity(this, attrs, {
23960               v: 1 + (this.v || 0)
23961             });
23962           },
23963           mergeTags: function mergeTags(tags) {
23964             var merged = Object.assign({}, this.tags); // shallow copy
23965
23966             var changed = false;
23967
23968             for (var k in tags) {
23969               var t1 = merged[k];
23970               var t2 = tags[k];
23971
23972               if (!t1) {
23973                 changed = true;
23974                 merged[k] = t2;
23975               } else if (t1 !== t2) {
23976                 changed = true;
23977                 merged[k] = utilUnicodeCharsTruncated(utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(';'), 255 // avoid exceeding character limit; see also services/osm.js -> maxCharsForTagValue()
23978                 );
23979               }
23980             }
23981
23982             return changed ? this.update({
23983               tags: merged
23984             }) : this;
23985           },
23986           intersects: function intersects(extent, resolver) {
23987             return this.extent(resolver).intersects(extent);
23988           },
23989           hasNonGeometryTags: function hasNonGeometryTags() {
23990             return Object.keys(this.tags).some(function (k) {
23991               return k !== 'area';
23992             });
23993           },
23994           hasParentRelations: function hasParentRelations(resolver) {
23995             return resolver.parentRelations(this).length > 0;
23996           },
23997           hasInterestingTags: function hasInterestingTags() {
23998             return Object.keys(this.tags).some(osmIsInterestingTag);
23999           },
24000           hasWikidata: function hasWikidata() {
24001             return !!this.tags.wikidata || !!this.tags['brand:wikidata'];
24002           },
24003           isHighwayIntersection: function isHighwayIntersection() {
24004             return false;
24005           },
24006           isDegenerate: function isDegenerate() {
24007             return true;
24008           },
24009           deprecatedTags: function deprecatedTags(dataDeprecated) {
24010             var tags = this.tags; // if there are no tags, none can be deprecated
24011
24012             if (Object.keys(tags).length === 0) return [];
24013             var deprecated = [];
24014             dataDeprecated.forEach(function (d) {
24015               var oldKeys = Object.keys(d.old);
24016
24017               if (d.replace) {
24018                 var hasExistingValues = Object.keys(d.replace).some(function (replaceKey) {
24019                   if (!tags[replaceKey] || d.old[replaceKey]) return false;
24020                   var replaceValue = d.replace[replaceKey];
24021                   if (replaceValue === '*') return false;
24022                   if (replaceValue === tags[replaceKey]) return false;
24023                   return true;
24024                 }); // don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
24025
24026                 if (hasExistingValues) return;
24027               }
24028
24029               var matchesDeprecatedTags = oldKeys.every(function (oldKey) {
24030                 if (!tags[oldKey]) return false;
24031                 if (d.old[oldKey] === '*') return true;
24032                 if (d.old[oldKey] === tags[oldKey]) return true;
24033                 var vals = tags[oldKey].split(';').filter(Boolean);
24034
24035                 if (vals.length === 0) {
24036                   return false;
24037                 } else if (vals.length > 1) {
24038                   return vals.indexOf(d.old[oldKey]) !== -1;
24039                 } else {
24040                   if (tags[oldKey] === d.old[oldKey]) {
24041                     if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
24042                       var replaceKeys = Object.keys(d.replace);
24043                       return !replaceKeys.every(function (replaceKey) {
24044                         return tags[replaceKey] === d.replace[replaceKey];
24045                       });
24046                     } else {
24047                       return true;
24048                     }
24049                   }
24050                 }
24051
24052                 return false;
24053               });
24054
24055               if (matchesDeprecatedTags) {
24056                 deprecated.push(d);
24057               }
24058             });
24059             return deprecated;
24060           }
24061         };
24062
24063         function osmLanes(entity) {
24064           if (entity.type !== 'way') return null;
24065           if (!entity.tags.highway) return null;
24066           var tags = entity.tags;
24067           var isOneWay = entity.isOneWay();
24068           var laneCount = getLaneCount(tags, isOneWay);
24069           var maxspeed = parseMaxspeed(tags);
24070           var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
24071           var forward = laneDirections.forward;
24072           var backward = laneDirections.backward;
24073           var bothways = laneDirections.bothways; // parse the piped string 'x|y|z' format
24074
24075           var turnLanes = {};
24076           turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
24077           turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
24078           turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
24079           var maxspeedLanes = {};
24080           maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
24081           maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
24082           maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
24083           var psvLanes = {};
24084           psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
24085           psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
24086           psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
24087           var busLanes = {};
24088           busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
24089           busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
24090           busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
24091           var taxiLanes = {};
24092           taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
24093           taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
24094           taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
24095           var hovLanes = {};
24096           hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
24097           hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
24098           hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
24099           var hgvLanes = {};
24100           hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
24101           hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
24102           hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
24103           var bicyclewayLanes = {};
24104           bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
24105           bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
24106           bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
24107           var lanesObj = {
24108             forward: [],
24109             backward: [],
24110             unspecified: []
24111           }; // map forward/backward/unspecified of each lane type to lanesObj
24112
24113           mapToLanesObj(lanesObj, turnLanes, 'turnLane');
24114           mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
24115           mapToLanesObj(lanesObj, psvLanes, 'psv');
24116           mapToLanesObj(lanesObj, busLanes, 'bus');
24117           mapToLanesObj(lanesObj, taxiLanes, 'taxi');
24118           mapToLanesObj(lanesObj, hovLanes, 'hov');
24119           mapToLanesObj(lanesObj, hgvLanes, 'hgv');
24120           mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
24121           return {
24122             metadata: {
24123               count: laneCount,
24124               oneway: isOneWay,
24125               forward: forward,
24126               backward: backward,
24127               bothways: bothways,
24128               turnLanes: turnLanes,
24129               maxspeed: maxspeed,
24130               maxspeedLanes: maxspeedLanes,
24131               psvLanes: psvLanes,
24132               busLanes: busLanes,
24133               taxiLanes: taxiLanes,
24134               hovLanes: hovLanes,
24135               hgvLanes: hgvLanes,
24136               bicyclewayLanes: bicyclewayLanes
24137             },
24138             lanes: lanesObj
24139           };
24140         }
24141
24142         function getLaneCount(tags, isOneWay) {
24143           var count;
24144
24145           if (tags.lanes) {
24146             count = parseInt(tags.lanes, 10);
24147
24148             if (count > 0) {
24149               return count;
24150             }
24151           }
24152
24153           switch (tags.highway) {
24154             case 'trunk':
24155             case 'motorway':
24156               count = isOneWay ? 2 : 4;
24157               break;
24158
24159             default:
24160               count = isOneWay ? 1 : 2;
24161               break;
24162           }
24163
24164           return count;
24165         }
24166
24167         function parseMaxspeed(tags) {
24168           var maxspeed = tags.maxspeed;
24169           if (!maxspeed) return;
24170           var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
24171           if (!maxspeedRegex.test(maxspeed)) return;
24172           return parseInt(maxspeed, 10);
24173         }
24174
24175         function parseLaneDirections(tags, isOneWay, laneCount) {
24176           var forward = parseInt(tags['lanes:forward'], 10);
24177           var backward = parseInt(tags['lanes:backward'], 10);
24178           var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
24179
24180           if (parseInt(tags.oneway, 10) === -1) {
24181             forward = 0;
24182             bothways = 0;
24183             backward = laneCount;
24184           } else if (isOneWay) {
24185             forward = laneCount;
24186             bothways = 0;
24187             backward = 0;
24188           } else if (isNaN(forward) && isNaN(backward)) {
24189             backward = Math.floor((laneCount - bothways) / 2);
24190             forward = laneCount - bothways - backward;
24191           } else if (isNaN(forward)) {
24192             if (backward > laneCount - bothways) {
24193               backward = laneCount - bothways;
24194             }
24195
24196             forward = laneCount - bothways - backward;
24197           } else if (isNaN(backward)) {
24198             if (forward > laneCount - bothways) {
24199               forward = laneCount - bothways;
24200             }
24201
24202             backward = laneCount - bothways - forward;
24203           }
24204
24205           return {
24206             forward: forward,
24207             backward: backward,
24208             bothways: bothways
24209           };
24210         }
24211
24212         function parseTurnLanes(tag) {
24213           if (!tag) return;
24214           var validValues = ['left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right', 'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'];
24215           return tag.split('|').map(function (s) {
24216             if (s === '') s = 'none';
24217             return s.split(';').map(function (d) {
24218               return validValues.indexOf(d) === -1 ? 'unknown' : d;
24219             });
24220           });
24221         }
24222
24223         function parseMaxspeedLanes(tag, maxspeed) {
24224           if (!tag) return;
24225           return tag.split('|').map(function (s) {
24226             if (s === 'none') return s;
24227             var m = parseInt(s, 10);
24228             if (s === '' || m === maxspeed) return null;
24229             return isNaN(m) ? 'unknown' : m;
24230           });
24231         }
24232
24233         function parseMiscLanes(tag) {
24234           if (!tag) return;
24235           var validValues = ['yes', 'no', 'designated'];
24236           return tag.split('|').map(function (s) {
24237             if (s === '') s = 'no';
24238             return validValues.indexOf(s) === -1 ? 'unknown' : s;
24239           });
24240         }
24241
24242         function parseBicycleWay(tag) {
24243           if (!tag) return;
24244           var validValues = ['yes', 'no', 'designated', 'lane'];
24245           return tag.split('|').map(function (s) {
24246             if (s === '') s = 'no';
24247             return validValues.indexOf(s) === -1 ? 'unknown' : s;
24248           });
24249         }
24250
24251         function mapToLanesObj(lanesObj, data, key) {
24252           if (data.forward) data.forward.forEach(function (l, i) {
24253             if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
24254             lanesObj.forward[i][key] = l;
24255           });
24256           if (data.backward) data.backward.forEach(function (l, i) {
24257             if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
24258             lanesObj.backward[i][key] = l;
24259           });
24260           if (data.unspecified) data.unspecified.forEach(function (l, i) {
24261             if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
24262             lanesObj.unspecified[i][key] = l;
24263           });
24264         }
24265
24266         function osmWay() {
24267           if (!(this instanceof osmWay)) {
24268             return new osmWay().initialize(arguments);
24269           } else if (arguments.length) {
24270             this.initialize(arguments);
24271           }
24272         }
24273         osmEntity.way = osmWay;
24274         osmWay.prototype = Object.create(osmEntity.prototype);
24275         Object.assign(osmWay.prototype, {
24276           type: 'way',
24277           nodes: [],
24278           copy: function copy(resolver, copies) {
24279             if (copies[this.id]) return copies[this.id];
24280             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
24281             var nodes = this.nodes.map(function (id) {
24282               return resolver.entity(id).copy(resolver, copies).id;
24283             });
24284             copy = copy.update({
24285               nodes: nodes
24286             });
24287             copies[this.id] = copy;
24288             return copy;
24289           },
24290           extent: function extent(resolver) {
24291             return resolver["transient"](this, 'extent', function () {
24292               var extent = geoExtent();
24293
24294               for (var i = 0; i < this.nodes.length; i++) {
24295                 var node = resolver.hasEntity(this.nodes[i]);
24296
24297                 if (node) {
24298                   extent._extend(node.extent());
24299                 }
24300               }
24301
24302               return extent;
24303             });
24304           },
24305           first: function first() {
24306             return this.nodes[0];
24307           },
24308           last: function last() {
24309             return this.nodes[this.nodes.length - 1];
24310           },
24311           contains: function contains(node) {
24312             return this.nodes.indexOf(node) >= 0;
24313           },
24314           affix: function affix(node) {
24315             if (this.nodes[0] === node) return 'prefix';
24316             if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
24317           },
24318           layer: function layer() {
24319             // explicit layer tag, clamp between -10, 10..
24320             if (isFinite(this.tags.layer)) {
24321               return Math.max(-10, Math.min(+this.tags.layer, 10));
24322             } // implied layer tag..
24323
24324
24325             if (this.tags.covered === 'yes') return -1;
24326             if (this.tags.location === 'overground') return 1;
24327             if (this.tags.location === 'underground') return -1;
24328             if (this.tags.location === 'underwater') return -10;
24329             if (this.tags.power === 'line') return 10;
24330             if (this.tags.power === 'minor_line') return 10;
24331             if (this.tags.aerialway) return 10;
24332             if (this.tags.bridge) return 1;
24333             if (this.tags.cutting) return -1;
24334             if (this.tags.tunnel) return -1;
24335             if (this.tags.waterway) return -1;
24336             if (this.tags.man_made === 'pipeline') return -10;
24337             if (this.tags.boundary) return -10;
24338             return 0;
24339           },
24340           // the approximate width of the line based on its tags except its `width` tag
24341           impliedLineWidthMeters: function impliedLineWidthMeters() {
24342             var averageWidths = {
24343               highway: {
24344                 // width is for single lane
24345                 motorway: 5,
24346                 motorway_link: 5,
24347                 trunk: 4.5,
24348                 trunk_link: 4.5,
24349                 primary: 4,
24350                 secondary: 4,
24351                 tertiary: 4,
24352                 primary_link: 4,
24353                 secondary_link: 4,
24354                 tertiary_link: 4,
24355                 unclassified: 4,
24356                 road: 4,
24357                 living_street: 4,
24358                 bus_guideway: 4,
24359                 pedestrian: 4,
24360                 residential: 3.5,
24361                 service: 3.5,
24362                 track: 3,
24363                 cycleway: 2.5,
24364                 bridleway: 2,
24365                 corridor: 2,
24366                 steps: 2,
24367                 path: 1.5,
24368                 footway: 1.5
24369               },
24370               railway: {
24371                 // width includes ties and rail bed, not just track gauge
24372                 rail: 2.5,
24373                 light_rail: 2.5,
24374                 tram: 2.5,
24375                 subway: 2.5,
24376                 monorail: 2.5,
24377                 funicular: 2.5,
24378                 disused: 2.5,
24379                 preserved: 2.5,
24380                 miniature: 1.5,
24381                 narrow_gauge: 1.5
24382               },
24383               waterway: {
24384                 river: 50,
24385                 canal: 25,
24386                 stream: 5,
24387                 tidal_channel: 5,
24388                 fish_pass: 2.5,
24389                 drain: 2.5,
24390                 ditch: 1.5
24391               }
24392             };
24393
24394             for (var key in averageWidths) {
24395               if (this.tags[key] && averageWidths[key][this.tags[key]]) {
24396                 var width = averageWidths[key][this.tags[key]];
24397
24398                 if (key === 'highway') {
24399                   var laneCount = this.tags.lanes && parseInt(this.tags.lanes, 10);
24400                   if (!laneCount) laneCount = this.isOneWay() ? 1 : 2;
24401                   return width * laneCount;
24402                 }
24403
24404                 return width;
24405               }
24406             }
24407
24408             return null;
24409           },
24410           isOneWay: function isOneWay() {
24411             // explicit oneway tag..
24412             var values = {
24413               'yes': true,
24414               '1': true,
24415               '-1': true,
24416               'reversible': true,
24417               'alternating': true,
24418               'no': false,
24419               '0': false
24420             };
24421
24422             if (values[this.tags.oneway] !== undefined) {
24423               return values[this.tags.oneway];
24424             } // implied oneway tag..
24425
24426
24427             for (var key in this.tags) {
24428               if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) return true;
24429             }
24430
24431             return false;
24432           },
24433           // Some identifier for tag that implies that this way is "sided",
24434           // i.e. the right side is the 'inside' (e.g. the right side of a
24435           // natural=cliff is lower).
24436           sidednessIdentifier: function sidednessIdentifier() {
24437             for (var key in this.tags) {
24438               var value = this.tags[key];
24439
24440               if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
24441                 if (osmRightSideIsInsideTags[key][value] === true) {
24442                   return key;
24443                 } else {
24444                   // if the map's value is something other than a
24445                   // literal true, we should use it so we can
24446                   // special case some keys (e.g. natural=coastline
24447                   // is handled differently to other naturals).
24448                   return osmRightSideIsInsideTags[key][value];
24449                 }
24450               }
24451             }
24452
24453             return null;
24454           },
24455           isSided: function isSided() {
24456             if (this.tags.two_sided === 'yes') {
24457               return false;
24458             }
24459
24460             return this.sidednessIdentifier() !== null;
24461           },
24462           lanes: function lanes() {
24463             return osmLanes(this);
24464           },
24465           isClosed: function isClosed() {
24466             return this.nodes.length > 1 && this.first() === this.last();
24467           },
24468           isConvex: function isConvex(resolver) {
24469             if (!this.isClosed() || this.isDegenerate()) return null;
24470             var nodes = utilArrayUniq(resolver.childNodes(this));
24471             var coords = nodes.map(function (n) {
24472               return n.loc;
24473             });
24474             var curr = 0;
24475             var prev = 0;
24476
24477             for (var i = 0; i < coords.length; i++) {
24478               var o = coords[(i + 1) % coords.length];
24479               var a = coords[i];
24480               var b = coords[(i + 2) % coords.length];
24481               var res = geoVecCross(a, b, o);
24482               curr = res > 0 ? 1 : res < 0 ? -1 : 0;
24483
24484               if (curr === 0) {
24485                 continue;
24486               } else if (prev && curr !== prev) {
24487                 return false;
24488               }
24489
24490               prev = curr;
24491             }
24492
24493             return true;
24494           },
24495           // returns an object with the tag that implies this is an area, if any
24496           tagSuggestingArea: function tagSuggestingArea() {
24497             return osmTagSuggestingArea(this.tags);
24498           },
24499           isArea: function isArea() {
24500             if (this.tags.area === 'yes') return true;
24501             if (!this.isClosed() || this.tags.area === 'no') return false;
24502             return this.tagSuggestingArea() !== null;
24503           },
24504           isDegenerate: function isDegenerate() {
24505             return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
24506           },
24507           areAdjacent: function areAdjacent(n1, n2) {
24508             for (var i = 0; i < this.nodes.length; i++) {
24509               if (this.nodes[i] === n1) {
24510                 if (this.nodes[i - 1] === n2) return true;
24511                 if (this.nodes[i + 1] === n2) return true;
24512               }
24513             }
24514
24515             return false;
24516           },
24517           geometry: function geometry(graph) {
24518             return graph["transient"](this, 'geometry', function () {
24519               return this.isArea() ? 'area' : 'line';
24520             });
24521           },
24522           // returns an array of objects representing the segments between the nodes in this way
24523           segments: function segments(graph) {
24524             function segmentExtent(graph) {
24525               var n1 = graph.hasEntity(this.nodes[0]);
24526               var n2 = graph.hasEntity(this.nodes[1]);
24527               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])]]);
24528             }
24529
24530             return graph["transient"](this, 'segments', function () {
24531               var segments = [];
24532
24533               for (var i = 0; i < this.nodes.length - 1; i++) {
24534                 segments.push({
24535                   id: this.id + '-' + i,
24536                   wayId: this.id,
24537                   index: i,
24538                   nodes: [this.nodes[i], this.nodes[i + 1]],
24539                   extent: segmentExtent
24540                 });
24541               }
24542
24543               return segments;
24544             });
24545           },
24546           // If this way is not closed, append the beginning node to the end of the nodelist to close it.
24547           close: function close() {
24548             if (this.isClosed() || !this.nodes.length) return this;
24549             var nodes = this.nodes.slice();
24550             nodes = nodes.filter(noRepeatNodes);
24551             nodes.push(nodes[0]);
24552             return this.update({
24553               nodes: nodes
24554             });
24555           },
24556           // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
24557           unclose: function unclose() {
24558             if (!this.isClosed()) return this;
24559             var nodes = this.nodes.slice();
24560             var connector = this.first();
24561             var i = nodes.length - 1; // remove trailing connectors..
24562
24563             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24564               nodes.splice(i, 1);
24565               i = nodes.length - 1;
24566             }
24567
24568             nodes = nodes.filter(noRepeatNodes);
24569             return this.update({
24570               nodes: nodes
24571             });
24572           },
24573           // Adds a node (id) in front of the node which is currently at position index.
24574           // If index is undefined, the node will be added to the end of the way for linear ways,
24575           //   or just before the final connecting node for circular ways.
24576           // Consecutive duplicates are eliminated including existing ones.
24577           // Circularity is always preserved when adding a node.
24578           addNode: function addNode(id, index) {
24579             var nodes = this.nodes.slice();
24580             var isClosed = this.isClosed();
24581             var max = isClosed ? nodes.length - 1 : nodes.length;
24582
24583             if (index === undefined) {
24584               index = max;
24585             }
24586
24587             if (index < 0 || index > max) {
24588               throw new RangeError('index ' + index + ' out of range 0..' + max);
24589             } // If this is a closed way, remove all connector nodes except the first one
24590             // (there may be duplicates) and adjust index if necessary..
24591
24592
24593             if (isClosed) {
24594               var connector = this.first(); // leading connectors..
24595
24596               var i = 1;
24597
24598               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
24599                 nodes.splice(i, 1);
24600                 if (index > i) index--;
24601               } // trailing connectors..
24602
24603
24604               i = nodes.length - 1;
24605
24606               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24607                 nodes.splice(i, 1);
24608                 if (index > i) index--;
24609                 i = nodes.length - 1;
24610               }
24611             }
24612
24613             nodes.splice(index, 0, id);
24614             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24615
24616             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24617               nodes.push(nodes[0]);
24618             }
24619
24620             return this.update({
24621               nodes: nodes
24622             });
24623           },
24624           // Replaces the node which is currently at position index with the given node (id).
24625           // Consecutive duplicates are eliminated including existing ones.
24626           // Circularity is preserved when updating a node.
24627           updateNode: function updateNode(id, index) {
24628             var nodes = this.nodes.slice();
24629             var isClosed = this.isClosed();
24630             var max = nodes.length - 1;
24631
24632             if (index === undefined || index < 0 || index > max) {
24633               throw new RangeError('index ' + index + ' out of range 0..' + max);
24634             } // If this is a closed way, remove all connector nodes except the first one
24635             // (there may be duplicates) and adjust index if necessary..
24636
24637
24638             if (isClosed) {
24639               var connector = this.first(); // leading connectors..
24640
24641               var i = 1;
24642
24643               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
24644                 nodes.splice(i, 1);
24645                 if (index > i) index--;
24646               } // trailing connectors..
24647
24648
24649               i = nodes.length - 1;
24650
24651               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24652                 nodes.splice(i, 1);
24653                 if (index === i) index = 0; // update leading connector instead
24654
24655                 i = nodes.length - 1;
24656               }
24657             }
24658
24659             nodes.splice(index, 1, id);
24660             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24661
24662             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24663               nodes.push(nodes[0]);
24664             }
24665
24666             return this.update({
24667               nodes: nodes
24668             });
24669           },
24670           // Replaces each occurrence of node id needle with replacement.
24671           // Consecutive duplicates are eliminated including existing ones.
24672           // Circularity is preserved.
24673           replaceNode: function replaceNode(needleID, replacementID) {
24674             var nodes = this.nodes.slice();
24675             var isClosed = this.isClosed();
24676
24677             for (var i = 0; i < nodes.length; i++) {
24678               if (nodes[i] === needleID) {
24679                 nodes[i] = replacementID;
24680               }
24681             }
24682
24683             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24684
24685             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24686               nodes.push(nodes[0]);
24687             }
24688
24689             return this.update({
24690               nodes: nodes
24691             });
24692           },
24693           // Removes each occurrence of node id.
24694           // Consecutive duplicates are eliminated including existing ones.
24695           // Circularity is preserved.
24696           removeNode: function removeNode(id) {
24697             var nodes = this.nodes.slice();
24698             var isClosed = this.isClosed();
24699             nodes = nodes.filter(function (node) {
24700               return node !== id;
24701             }).filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24702
24703             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24704               nodes.push(nodes[0]);
24705             }
24706
24707             return this.update({
24708               nodes: nodes
24709             });
24710           },
24711           asJXON: function asJXON(changeset_id) {
24712             var r = {
24713               way: {
24714                 '@id': this.osmId(),
24715                 '@version': this.version || 0,
24716                 nd: this.nodes.map(function (id) {
24717                   return {
24718                     keyAttributes: {
24719                       ref: osmEntity.id.toOSM(id)
24720                     }
24721                   };
24722                 }, this),
24723                 tag: Object.keys(this.tags).map(function (k) {
24724                   return {
24725                     keyAttributes: {
24726                       k: k,
24727                       v: this.tags[k]
24728                     }
24729                   };
24730                 }, this)
24731               }
24732             };
24733
24734             if (changeset_id) {
24735               r.way['@changeset'] = changeset_id;
24736             }
24737
24738             return r;
24739           },
24740           asGeoJSON: function asGeoJSON(resolver) {
24741             return resolver["transient"](this, 'GeoJSON', function () {
24742               var coordinates = resolver.childNodes(this).map(function (n) {
24743                 return n.loc;
24744               });
24745
24746               if (this.isArea() && this.isClosed()) {
24747                 return {
24748                   type: 'Polygon',
24749                   coordinates: [coordinates]
24750                 };
24751               } else {
24752                 return {
24753                   type: 'LineString',
24754                   coordinates: coordinates
24755                 };
24756               }
24757             });
24758           },
24759           area: function area(resolver) {
24760             return resolver["transient"](this, 'area', function () {
24761               var nodes = resolver.childNodes(this);
24762               var json = {
24763                 type: 'Polygon',
24764                 coordinates: [nodes.map(function (n) {
24765                   return n.loc;
24766                 })]
24767               };
24768
24769               if (!this.isClosed() && nodes.length) {
24770                 json.coordinates[0].push(nodes[0].loc);
24771               }
24772
24773               var area = d3_geoArea(json); // Heuristic for detecting counterclockwise winding order. Assumes
24774               // that OpenStreetMap polygons are not hemisphere-spanning.
24775
24776               if (area > 2 * Math.PI) {
24777                 json.coordinates[0] = json.coordinates[0].reverse();
24778                 area = d3_geoArea(json);
24779               }
24780
24781               return isNaN(area) ? 0 : area;
24782             });
24783           }
24784         }); // Filter function to eliminate consecutive duplicates.
24785
24786         function noRepeatNodes(node, i, arr) {
24787           return i === 0 || node !== arr[i - 1];
24788         }
24789
24790         //
24791         // 1. Relation tagged with `type=multipolygon` and no interesting tags.
24792         // 2. One and only one member with the `outer` role. Must be a way with interesting tags.
24793         // 3. No members without a role.
24794         //
24795         // Old multipolygons are no longer recommended but are still rendered as areas by iD.
24796
24797         function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
24798           if (entity.type !== 'relation' || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
24799             return false;
24800           }
24801
24802           var outerMember;
24803
24804           for (var memberIndex in entity.members) {
24805             var member = entity.members[memberIndex];
24806
24807             if (!member.role || member.role === 'outer') {
24808               if (outerMember) return false;
24809               if (member.type !== 'way') return false;
24810               if (!graph.hasEntity(member.id)) return false;
24811               outerMember = graph.entity(member.id);
24812
24813               if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
24814                 return false;
24815               }
24816             }
24817           }
24818
24819           return outerMember;
24820         } // For fixing up rendering of multipolygons with tags on the outer member.
24821         // https://github.com/openstreetmap/iD/issues/613
24822
24823         function osmIsOldMultipolygonOuterMember(entity, graph) {
24824           if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) return false;
24825           var parents = graph.parentRelations(entity);
24826           if (parents.length !== 1) return false;
24827           var parent = parents[0];
24828           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) return false;
24829           var members = parent.members,
24830               member;
24831
24832           for (var i = 0; i < members.length; i++) {
24833             member = members[i];
24834             if (member.id === entity.id && member.role && member.role !== 'outer') return false; // Not outer member
24835
24836             if (member.id !== entity.id && (!member.role || member.role === 'outer')) return false; // Not a simple multipolygon
24837           }
24838
24839           return parent;
24840         }
24841         function osmOldMultipolygonOuterMember(entity, graph) {
24842           if (entity.type !== 'way') return false;
24843           var parents = graph.parentRelations(entity);
24844           if (parents.length !== 1) return false;
24845           var parent = parents[0];
24846           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) return false;
24847           var members = parent.members,
24848               member,
24849               outerMember;
24850
24851           for (var i = 0; i < members.length; i++) {
24852             member = members[i];
24853
24854             if (!member.role || member.role === 'outer') {
24855               if (outerMember) return false; // Not a simple multipolygon
24856
24857               outerMember = member;
24858             }
24859           }
24860
24861           if (!outerMember) return false;
24862           var outerEntity = graph.hasEntity(outerMember.id);
24863           if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) return false;
24864           return outerEntity;
24865         } // Join `toJoin` array into sequences of connecting ways.
24866         // Segments which share identical start/end nodes will, as much as possible,
24867         // be connected with each other.
24868         //
24869         // The return value is a nested array. Each constituent array contains elements
24870         // of `toJoin` which have been determined to connect.
24871         //
24872         // Each consitituent array also has a `nodes` property whose value is an
24873         // ordered array of member nodes, with appropriate order reversal and
24874         // start/end coordinate de-duplication.
24875         //
24876         // Members of `toJoin` must have, at minimum, `type` and `id` properties.
24877         // Thus either an array of `osmWay`s or a relation member array may be used.
24878         //
24879         // If an member is an `osmWay`, its tags and childnodes may be reversed via
24880         // `actionReverse` in the output.
24881         //
24882         // The returned sequences array also has an `actions` array property, containing
24883         // any reversal actions that should be applied to the graph, should the calling
24884         // code attempt to actually join the given ways.
24885         //
24886         // Incomplete members (those for which `graph.hasEntity(element.id)` returns
24887         // false) and non-way members are ignored.
24888         //
24889
24890         function osmJoinWays(toJoin, graph) {
24891           function resolve(member) {
24892             return graph.childNodes(graph.entity(member.id));
24893           }
24894
24895           function reverse(item) {
24896             var action = actionReverse(item.id, {
24897               reverseOneway: true
24898             });
24899             sequences.actions.push(action);
24900             return item instanceof osmWay ? action(graph).entity(item.id) : item;
24901           } // make a copy containing only the items to join
24902
24903
24904           toJoin = toJoin.filter(function (member) {
24905             return member.type === 'way' && graph.hasEntity(member.id);
24906           }); // Are the things we are joining relation members or `osmWays`?
24907           // If `osmWays`, skip the "prefer a forward path" code below (see #4872)
24908
24909           var i;
24910           var joinAsMembers = true;
24911
24912           for (i = 0; i < toJoin.length; i++) {
24913             if (toJoin[i] instanceof osmWay) {
24914               joinAsMembers = false;
24915               break;
24916             }
24917           }
24918
24919           var sequences = [];
24920           sequences.actions = [];
24921
24922           while (toJoin.length) {
24923             // start a new sequence
24924             var item = toJoin.shift();
24925             var currWays = [item];
24926             var currNodes = resolve(item).slice(); // add to it
24927
24928             while (toJoin.length) {
24929               var start = currNodes[0];
24930               var end = currNodes[currNodes.length - 1];
24931               var fn = null;
24932               var nodes = null; // Find the next way/member to join.
24933
24934               for (i = 0; i < toJoin.length; i++) {
24935                 item = toJoin[i];
24936                 nodes = resolve(item); // (for member ordering only, not way ordering - see #4872)
24937                 // Strongly prefer to generate a forward path that preserves the order
24938                 // of the members array. For multipolygons and most relations, member
24939                 // order does not matter - but for routes, it does. (see #4589)
24940                 // If we started this sequence backwards (i.e. next member way attaches to
24941                 // the start node and not the end node), reverse the initial way before continuing.
24942
24943                 if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start || nodes[0] === start)) {
24944                   currWays[0] = reverse(currWays[0]);
24945                   currNodes.reverse();
24946                   start = currNodes[0];
24947                   end = currNodes[currNodes.length - 1];
24948                 }
24949
24950                 if (nodes[0] === end) {
24951                   fn = currNodes.push; // join to end
24952
24953                   nodes = nodes.slice(1);
24954                   break;
24955                 } else if (nodes[nodes.length - 1] === end) {
24956                   fn = currNodes.push; // join to end
24957
24958                   nodes = nodes.slice(0, -1).reverse();
24959                   item = reverse(item);
24960                   break;
24961                 } else if (nodes[nodes.length - 1] === start) {
24962                   fn = currNodes.unshift; // join to beginning
24963
24964                   nodes = nodes.slice(0, -1);
24965                   break;
24966                 } else if (nodes[0] === start) {
24967                   fn = currNodes.unshift; // join to beginning
24968
24969                   nodes = nodes.slice(1).reverse();
24970                   item = reverse(item);
24971                   break;
24972                 } else {
24973                   fn = nodes = null;
24974                 }
24975               }
24976
24977               if (!nodes) {
24978                 // couldn't find a joinable way/member
24979                 break;
24980               }
24981
24982               fn.apply(currWays, [item]);
24983               fn.apply(currNodes, nodes);
24984               toJoin.splice(i, 1);
24985             }
24986
24987             currWays.nodes = currNodes;
24988             sequences.push(currWays);
24989           }
24990
24991           return sequences;
24992         }
24993
24994         function actionAddMember(relationId, member, memberIndex, insertPair) {
24995           return function action(graph) {
24996             var relation = graph.entity(relationId); // There are some special rules for Public Transport v2 routes.
24997
24998             var isPTv2 = /stop|platform/.test(member.role);
24999
25000             if ((isNaN(memberIndex) || insertPair) && member.type === 'way' && !isPTv2) {
25001               // Try to perform sensible inserts based on how the ways join together
25002               graph = addWayMember(relation, graph);
25003             } else {
25004               // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
25005               // Stops and Platforms for PTv2 should be ordered first.
25006               // hack: We do not currently have the ability to place them in the exactly correct order.
25007               if (isPTv2 && isNaN(memberIndex)) {
25008                 memberIndex = 0;
25009               }
25010
25011               graph = graph.replace(relation.addMember(member, memberIndex));
25012             }
25013
25014             return graph;
25015           }; // Add a way member into the relation "wherever it makes sense".
25016           // In this situation we were not supplied a memberIndex.
25017
25018           function addWayMember(relation, graph) {
25019             var groups, tempWay, item, i, j, k; // remove PTv2 stops and platforms before doing anything.
25020
25021             var PTv2members = [];
25022             var members = [];
25023
25024             for (i = 0; i < relation.members.length; i++) {
25025               var m = relation.members[i];
25026
25027               if (/stop|platform/.test(m.role)) {
25028                 PTv2members.push(m);
25029               } else {
25030                 members.push(m);
25031               }
25032             }
25033
25034             relation = relation.update({
25035               members: members
25036             });
25037
25038             if (insertPair) {
25039               // We're adding a member that must stay paired with an existing member.
25040               // (This feature is used by `actionSplit`)
25041               //
25042               // This is tricky because the members may exist multiple times in the
25043               // member list, and with different A-B/B-A ordering and different roles.
25044               // (e.g. a bus route that loops out and back - #4589).
25045               //
25046               // Replace the existing member with a temporary way,
25047               // so that `osmJoinWays` can treat the pair like a single way.
25048               tempWay = osmWay({
25049                 id: 'wTemp',
25050                 nodes: insertPair.nodes
25051               });
25052               graph = graph.replace(tempWay);
25053               var tempMember = {
25054                 id: tempWay.id,
25055                 type: 'way',
25056                 role: member.role
25057               };
25058               var tempRelation = relation.replaceMember({
25059                 id: insertPair.originalID
25060               }, tempMember, true);
25061               groups = utilArrayGroupBy(tempRelation.members, 'type');
25062               groups.way = groups.way || [];
25063             } else {
25064               // Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
25065               groups = utilArrayGroupBy(relation.members, 'type');
25066               groups.way = groups.way || [];
25067               groups.way.push(member);
25068             }
25069
25070             members = withIndex(groups.way);
25071             var joined = osmJoinWays(members, graph); // `joined` might not contain all of the way members,
25072             // But will contain only the completed (downloaded) members
25073
25074             for (i = 0; i < joined.length; i++) {
25075               var segment = joined[i];
25076               var nodes = segment.nodes.slice();
25077               var startIndex = segment[0].index; // j = array index in `members` where this segment starts
25078
25079               for (j = 0; j < members.length; j++) {
25080                 if (members[j].index === startIndex) {
25081                   break;
25082                 }
25083               } // k = each member in segment
25084
25085
25086               for (k = 0; k < segment.length; k++) {
25087                 item = segment[k];
25088                 var way = graph.entity(item.id); // If this is a paired item, generate members in correct order and role
25089
25090                 if (tempWay && item.id === tempWay.id) {
25091                   if (nodes[0].id === insertPair.nodes[0]) {
25092                     item.pair = [{
25093                       id: insertPair.originalID,
25094                       type: 'way',
25095                       role: item.role
25096                     }, {
25097                       id: insertPair.insertedID,
25098                       type: 'way',
25099                       role: item.role
25100                     }];
25101                   } else {
25102                     item.pair = [{
25103                       id: insertPair.insertedID,
25104                       type: 'way',
25105                       role: item.role
25106                     }, {
25107                       id: insertPair.originalID,
25108                       type: 'way',
25109                       role: item.role
25110                     }];
25111                   }
25112                 } // reorder `members` if necessary
25113
25114
25115                 if (k > 0) {
25116                   if (j + k >= members.length || item.index !== members[j + k].index) {
25117                     moveMember(members, item.index, j + k);
25118                   }
25119                 }
25120
25121                 nodes.splice(0, way.nodes.length - 1);
25122               }
25123             }
25124
25125             if (tempWay) {
25126               graph = graph.remove(tempWay);
25127             } // Final pass: skip dead items, split pairs, remove index properties
25128
25129
25130             var wayMembers = [];
25131
25132             for (i = 0; i < members.length; i++) {
25133               item = members[i];
25134               if (item.index === -1) continue;
25135
25136               if (item.pair) {
25137                 wayMembers.push(item.pair[0]);
25138                 wayMembers.push(item.pair[1]);
25139               } else {
25140                 wayMembers.push(utilObjectOmit(item, ['index']));
25141               }
25142             } // Put stops and platforms first, then nodes, ways, relations
25143             // This is recommended for Public Transport v2 routes:
25144             // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
25145
25146
25147             var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
25148             return graph.replace(relation.update({
25149               members: newMembers
25150             })); // `moveMember()` changes the `members` array in place by splicing
25151             // the item with `.index = findIndex` to where it belongs,
25152             // and marking the old position as "dead" with `.index = -1`
25153             //
25154             // j=5, k=0                jk
25155             // segment                 5 4 7 6
25156             // members       0 1 2 3 4 5 6 7 8 9        keep 5 in j+k
25157             //
25158             // j=5, k=1                j k
25159             // segment                 5 4 7 6
25160             // members       0 1 2 3 4 5 6 7 8 9        move 4 to j+k
25161             // members       0 1 2 3 x 5 4 6 7 8 9      moved
25162             //
25163             // j=5, k=2                j   k
25164             // segment                 5 4 7 6
25165             // members       0 1 2 3 x 5 4 6 7 8 9      move 7 to j+k
25166             // members       0 1 2 3 x 5 4 7 6 x 8 9    moved
25167             //
25168             // j=5, k=3                j     k
25169             // segment                 5 4 7 6
25170             // members       0 1 2 3 x 5 4 7 6 x 8 9    keep 6 in j+k
25171             //
25172
25173             function moveMember(arr, findIndex, toIndex) {
25174               var i;
25175
25176               for (i = 0; i < arr.length; i++) {
25177                 if (arr[i].index === findIndex) {
25178                   break;
25179                 }
25180               }
25181
25182               var item = Object.assign({}, arr[i]); // shallow copy
25183
25184               arr[i].index = -1; // mark as dead
25185
25186               item.index = toIndex;
25187               arr.splice(toIndex, 0, item);
25188             } // This is the same as `Relation.indexedMembers`,
25189             // Except we don't want to index all the members, only the ways
25190
25191
25192             function withIndex(arr) {
25193               var result = new Array(arr.length);
25194
25195               for (var i = 0; i < arr.length; i++) {
25196                 result[i] = Object.assign({}, arr[i]); // shallow copy
25197
25198                 result[i].index = i;
25199               }
25200
25201               return result;
25202             }
25203           }
25204         }
25205
25206         function actionAddMidpoint(midpoint, node) {
25207           return function (graph) {
25208             graph = graph.replace(node.move(midpoint.loc));
25209             var parents = utilArrayIntersection(graph.parentWays(graph.entity(midpoint.edge[0])), graph.parentWays(graph.entity(midpoint.edge[1])));
25210             parents.forEach(function (way) {
25211               for (var i = 0; i < way.nodes.length - 1; i++) {
25212                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
25213                   graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1)); // Add only one midpoint on doubled-back segments,
25214                   // turning them into self-intersections.
25215
25216                   return;
25217                 }
25218               }
25219             });
25220             return graph;
25221           };
25222         }
25223
25224         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
25225         function actionAddVertex(wayId, nodeId, index) {
25226           return function (graph) {
25227             return graph.replace(graph.entity(wayId).addNode(nodeId, index));
25228           };
25229         }
25230
25231         function actionChangeMember(relationId, member, memberIndex) {
25232           return function (graph) {
25233             return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
25234           };
25235         }
25236
25237         function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
25238           return function action(graph) {
25239             var entity = graph.entity(entityID);
25240             var geometry = entity.geometry(graph);
25241             var tags = entity.tags;
25242             if (oldPreset) tags = oldPreset.unsetTags(tags, geometry);
25243             if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
25244             return graph.replace(entity.update({
25245               tags: tags
25246             }));
25247           };
25248         }
25249
25250         function actionChangeTags(entityId, tags) {
25251           return function (graph) {
25252             var entity = graph.entity(entityId);
25253             return graph.replace(entity.update({
25254               tags: tags
25255             }));
25256           };
25257         }
25258
25259         function osmNode() {
25260           if (!(this instanceof osmNode)) {
25261             return new osmNode().initialize(arguments);
25262           } else if (arguments.length) {
25263             this.initialize(arguments);
25264           }
25265         }
25266         osmEntity.node = osmNode;
25267         osmNode.prototype = Object.create(osmEntity.prototype);
25268         Object.assign(osmNode.prototype, {
25269           type: 'node',
25270           loc: [9999, 9999],
25271           extent: function extent() {
25272             return new geoExtent(this.loc);
25273           },
25274           geometry: function geometry(graph) {
25275             return graph["transient"](this, 'geometry', function () {
25276               return graph.isPoi(this) ? 'point' : 'vertex';
25277             });
25278           },
25279           move: function move(loc) {
25280             return this.update({
25281               loc: loc
25282             });
25283           },
25284           isDegenerate: function isDegenerate() {
25285             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);
25286           },
25287           // Inspect tags and geometry to determine which direction(s) this node/vertex points
25288           directions: function directions(resolver, projection) {
25289             var val;
25290             var i; // which tag to use?
25291
25292             if (this.isHighwayIntersection(resolver) && (this.tags.stop || '').toLowerCase() === 'all') {
25293               // all-way stop tag on a highway intersection
25294               val = 'all';
25295             } else {
25296               // generic direction tag
25297               val = (this.tags.direction || '').toLowerCase(); // better suffix-style direction tag
25298
25299               var re = /:direction$/i;
25300               var keys = Object.keys(this.tags);
25301
25302               for (i = 0; i < keys.length; i++) {
25303                 if (re.test(keys[i])) {
25304                   val = this.tags[keys[i]].toLowerCase();
25305                   break;
25306                 }
25307               }
25308             }
25309
25310             if (val === '') return [];
25311             var cardinal = {
25312               north: 0,
25313               n: 0,
25314               northnortheast: 22,
25315               nne: 22,
25316               northeast: 45,
25317               ne: 45,
25318               eastnortheast: 67,
25319               ene: 67,
25320               east: 90,
25321               e: 90,
25322               eastsoutheast: 112,
25323               ese: 112,
25324               southeast: 135,
25325               se: 135,
25326               southsoutheast: 157,
25327               sse: 157,
25328               south: 180,
25329               s: 180,
25330               southsouthwest: 202,
25331               ssw: 202,
25332               southwest: 225,
25333               sw: 225,
25334               westsouthwest: 247,
25335               wsw: 247,
25336               west: 270,
25337               w: 270,
25338               westnorthwest: 292,
25339               wnw: 292,
25340               northwest: 315,
25341               nw: 315,
25342               northnorthwest: 337,
25343               nnw: 337
25344             };
25345             var values = val.split(';');
25346             var results = [];
25347             values.forEach(function (v) {
25348               // swap cardinal for numeric directions
25349               if (cardinal[v] !== undefined) {
25350                 v = cardinal[v];
25351               } // numeric direction - just add to results
25352
25353
25354               if (v !== '' && !isNaN(+v)) {
25355                 results.push(+v);
25356                 return;
25357               } // string direction - inspect parent ways
25358
25359
25360               var lookBackward = this.tags['traffic_sign:backward'] || v === 'backward' || v === 'both' || v === 'all';
25361               var lookForward = this.tags['traffic_sign:forward'] || v === 'forward' || v === 'both' || v === 'all';
25362               if (!lookForward && !lookBackward) return;
25363               var nodeIds = {};
25364               resolver.parentWays(this).forEach(function (parent) {
25365                 var nodes = parent.nodes;
25366
25367                 for (i = 0; i < nodes.length; i++) {
25368                   if (nodes[i] === this.id) {
25369                     // match current entity
25370                     if (lookForward && i > 0) {
25371                       nodeIds[nodes[i - 1]] = true; // look back to prev node
25372                     }
25373
25374                     if (lookBackward && i < nodes.length - 1) {
25375                       nodeIds[nodes[i + 1]] = true; // look ahead to next node
25376                     }
25377                   }
25378                 }
25379               }, this);
25380               Object.keys(nodeIds).forEach(function (nodeId) {
25381                 // +90 because geoAngle returns angle from X axis, not Y (north)
25382                 results.push(geoAngle(this, resolver.entity(nodeId), projection) * (180 / Math.PI) + 90);
25383               }, this);
25384             }, this);
25385             return utilArrayUniq(results);
25386           },
25387           isEndpoint: function isEndpoint(resolver) {
25388             return resolver["transient"](this, 'isEndpoint', function () {
25389               var id = this.id;
25390               return resolver.parentWays(this).filter(function (parent) {
25391                 return !parent.isClosed() && !!parent.affix(id);
25392               }).length > 0;
25393             });
25394           },
25395           isConnected: function isConnected(resolver) {
25396             return resolver["transient"](this, 'isConnected', function () {
25397               var parents = resolver.parentWays(this);
25398
25399               if (parents.length > 1) {
25400                 // vertex is connected to multiple parent ways
25401                 for (var i in parents) {
25402                   if (parents[i].geometry(resolver) === 'line' && parents[i].hasInterestingTags()) return true;
25403                 }
25404               } else if (parents.length === 1) {
25405                 var way = parents[0];
25406                 var nodes = way.nodes.slice();
25407
25408                 if (way.isClosed()) {
25409                   nodes.pop();
25410                 } // ignore connecting node if closed
25411                 // return true if vertex appears multiple times (way is self intersecting)
25412
25413
25414                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
25415               }
25416
25417               return false;
25418             });
25419           },
25420           parentIntersectionWays: function parentIntersectionWays(resolver) {
25421             return resolver["transient"](this, 'parentIntersectionWays', function () {
25422               return resolver.parentWays(this).filter(function (parent) {
25423                 return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === 'line';
25424               });
25425             });
25426           },
25427           isIntersection: function isIntersection(resolver) {
25428             return this.parentIntersectionWays(resolver).length > 1;
25429           },
25430           isHighwayIntersection: function isHighwayIntersection(resolver) {
25431             return resolver["transient"](this, 'isHighwayIntersection', function () {
25432               return resolver.parentWays(this).filter(function (parent) {
25433                 return parent.tags.highway && parent.geometry(resolver) === 'line';
25434               }).length > 1;
25435             });
25436           },
25437           isOnAddressLine: function isOnAddressLine(resolver) {
25438             return resolver["transient"](this, 'isOnAddressLine', function () {
25439               return resolver.parentWays(this).filter(function (parent) {
25440                 return parent.tags.hasOwnProperty('addr:interpolation') && parent.geometry(resolver) === 'line';
25441               }).length > 0;
25442             });
25443           },
25444           asJXON: function asJXON(changeset_id) {
25445             var r = {
25446               node: {
25447                 '@id': this.osmId(),
25448                 '@lon': this.loc[0],
25449                 '@lat': this.loc[1],
25450                 '@version': this.version || 0,
25451                 tag: Object.keys(this.tags).map(function (k) {
25452                   return {
25453                     keyAttributes: {
25454                       k: k,
25455                       v: this.tags[k]
25456                     }
25457                   };
25458                 }, this)
25459               }
25460             };
25461             if (changeset_id) r.node['@changeset'] = changeset_id;
25462             return r;
25463           },
25464           asGeoJSON: function asGeoJSON() {
25465             return {
25466               type: 'Point',
25467               coordinates: this.loc
25468             };
25469           }
25470         });
25471
25472         function actionCircularize(wayId, projection, maxAngle) {
25473           maxAngle = (maxAngle || 20) * Math.PI / 180;
25474
25475           var action = function action(graph, t) {
25476             if (t === null || !isFinite(t)) t = 1;
25477             t = Math.min(Math.max(+t, 0), 1);
25478             var way = graph.entity(wayId);
25479             var origNodes = {};
25480             graph.childNodes(way).forEach(function (node) {
25481               if (!origNodes[node.id]) origNodes[node.id] = node;
25482             });
25483
25484             if (!way.isConvex(graph)) {
25485               graph = action.makeConvex(graph);
25486             }
25487
25488             var nodes = utilArrayUniq(graph.childNodes(way));
25489             var keyNodes = nodes.filter(function (n) {
25490               return graph.parentWays(n).length !== 1;
25491             });
25492             var points = nodes.map(function (n) {
25493               return projection(n.loc);
25494             });
25495             var keyPoints = keyNodes.map(function (n) {
25496               return projection(n.loc);
25497             });
25498             var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points);
25499             var radius = d3_median(points, function (p) {
25500               return geoVecLength(centroid, p);
25501             });
25502             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
25503             var ids, i, j, k; // we need at least two key nodes for the algorithm to work
25504
25505             if (!keyNodes.length) {
25506               keyNodes = [nodes[0]];
25507               keyPoints = [points[0]];
25508             }
25509
25510             if (keyNodes.length === 1) {
25511               var index = nodes.indexOf(keyNodes[0]);
25512               var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
25513               keyNodes.push(nodes[oppositeIndex]);
25514               keyPoints.push(points[oppositeIndex]);
25515             } // key points and nodes are those connected to the ways,
25516             // they are projected onto the circle, in between nodes are moved
25517             // to constant intervals between key nodes, extra in between nodes are
25518             // added if necessary.
25519
25520
25521             for (i = 0; i < keyPoints.length; i++) {
25522               var nextKeyNodeIndex = (i + 1) % keyNodes.length;
25523               var startNode = keyNodes[i];
25524               var endNode = keyNodes[nextKeyNodeIndex];
25525               var startNodeIndex = nodes.indexOf(startNode);
25526               var endNodeIndex = nodes.indexOf(endNode);
25527               var numberNewPoints = -1;
25528               var indexRange = endNodeIndex - startNodeIndex;
25529               var nearNodes = {};
25530               var inBetweenNodes = [];
25531               var startAngle, endAngle, totalAngle, eachAngle;
25532               var angle, loc, node, origNode;
25533
25534               if (indexRange < 0) {
25535                 indexRange += nodes.length;
25536               } // position this key node
25537
25538
25539               var distance = geoVecLength(centroid, keyPoints[i]) || 1e-4;
25540               keyPoints[i] = [centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
25541               loc = projection.invert(keyPoints[i]);
25542               node = keyNodes[i];
25543               origNode = origNodes[node.id];
25544               node = node.move(geoVecInterp(origNode.loc, loc, t));
25545               graph = graph.replace(node); // figure out the between delta angle we want to match to
25546
25547               startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
25548               endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
25549               totalAngle = endAngle - startAngle; // detects looping around -pi/pi
25550
25551               if (totalAngle * sign > 0) {
25552                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
25553               }
25554
25555               do {
25556                 numberNewPoints++;
25557                 eachAngle = totalAngle / (indexRange + numberNewPoints);
25558               } while (Math.abs(eachAngle) > maxAngle); // move existing nodes
25559
25560
25561               for (j = 1; j < indexRange; j++) {
25562                 angle = startAngle + j * eachAngle;
25563                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]);
25564                 node = nodes[(j + startNodeIndex) % nodes.length];
25565                 origNode = origNodes[node.id];
25566                 nearNodes[node.id] = angle;
25567                 node = node.move(geoVecInterp(origNode.loc, loc, t));
25568                 graph = graph.replace(node);
25569               } // add new in between nodes if necessary
25570
25571
25572               for (j = 0; j < numberNewPoints; j++) {
25573                 angle = startAngle + (indexRange + j) * eachAngle;
25574                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]); // choose a nearnode to use as the original
25575
25576                 var min = Infinity;
25577
25578                 for (var nodeId in nearNodes) {
25579                   var nearAngle = nearNodes[nodeId];
25580                   var dist = Math.abs(nearAngle - angle);
25581
25582                   if (dist < min) {
25583                     min = dist;
25584                     origNode = origNodes[nodeId];
25585                   }
25586                 }
25587
25588                 node = osmNode({
25589                   loc: geoVecInterp(origNode.loc, loc, t)
25590                 });
25591                 graph = graph.replace(node);
25592                 nodes.splice(endNodeIndex + j, 0, node);
25593                 inBetweenNodes.push(node.id);
25594               } // Check for other ways that share these keyNodes..
25595               // If keyNodes are adjacent in both ways,
25596               // we can add inBetweenNodes to that shared way too..
25597
25598
25599               if (indexRange === 1 && inBetweenNodes.length) {
25600                 var startIndex1 = way.nodes.lastIndexOf(startNode.id);
25601                 var endIndex1 = way.nodes.lastIndexOf(endNode.id);
25602                 var wayDirection1 = endIndex1 - startIndex1;
25603
25604                 if (wayDirection1 < -1) {
25605                   wayDirection1 = 1;
25606                 }
25607
25608                 var parentWays = graph.parentWays(keyNodes[i]);
25609
25610                 for (j = 0; j < parentWays.length; j++) {
25611                   var sharedWay = parentWays[j];
25612                   if (sharedWay === way) continue;
25613
25614                   if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
25615                     var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id);
25616                     var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id);
25617                     var wayDirection2 = endIndex2 - startIndex2;
25618                     var insertAt = endIndex2;
25619
25620                     if (wayDirection2 < -1) {
25621                       wayDirection2 = 1;
25622                     }
25623
25624                     if (wayDirection1 !== wayDirection2) {
25625                       inBetweenNodes.reverse();
25626                       insertAt = startIndex2;
25627                     }
25628
25629                     for (k = 0; k < inBetweenNodes.length; k++) {
25630                       sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
25631                     }
25632
25633                     graph = graph.replace(sharedWay);
25634                   }
25635                 }
25636               }
25637             } // update the way to have all the new nodes
25638
25639
25640             ids = nodes.map(function (n) {
25641               return n.id;
25642             });
25643             ids.push(ids[0]);
25644             way = way.update({
25645               nodes: ids
25646             });
25647             graph = graph.replace(way);
25648             return graph;
25649           };
25650
25651           action.makeConvex = function (graph) {
25652             var way = graph.entity(wayId);
25653             var nodes = utilArrayUniq(graph.childNodes(way));
25654             var points = nodes.map(function (n) {
25655               return projection(n.loc);
25656             });
25657             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
25658             var hull = d3_polygonHull(points);
25659             var i, j; // D3 convex hulls go counterclockwise..
25660
25661             if (sign === -1) {
25662               nodes.reverse();
25663               points.reverse();
25664             }
25665
25666             for (i = 0; i < hull.length - 1; i++) {
25667               var startIndex = points.indexOf(hull[i]);
25668               var endIndex = points.indexOf(hull[i + 1]);
25669               var indexRange = endIndex - startIndex;
25670
25671               if (indexRange < 0) {
25672                 indexRange += nodes.length;
25673               } // move interior nodes to the surface of the convex hull..
25674
25675
25676               for (j = 1; j < indexRange; j++) {
25677                 var point = geoVecInterp(hull[i], hull[i + 1], j / indexRange);
25678                 var node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
25679                 graph = graph.replace(node);
25680               }
25681             }
25682
25683             return graph;
25684           };
25685
25686           action.disabled = function (graph) {
25687             if (!graph.entity(wayId).isClosed()) {
25688               return 'not_closed';
25689             } //disable when already circular
25690
25691
25692             var way = graph.entity(wayId);
25693             var nodes = utilArrayUniq(graph.childNodes(way));
25694             var points = nodes.map(function (n) {
25695               return projection(n.loc);
25696             });
25697             var hull = d3_polygonHull(points);
25698             var epsilonAngle = Math.PI / 180;
25699
25700             if (hull.length !== points.length || hull.length < 3) {
25701               return false;
25702             }
25703
25704             var centroid = d3_polygonCentroid(points);
25705             var radius = geoVecLengthSquare(centroid, points[0]);
25706             var i, actualPoint; // compare distances between centroid and points
25707
25708             for (i = 0; i < hull.length; i++) {
25709               actualPoint = hull[i];
25710               var actualDist = geoVecLengthSquare(actualPoint, centroid);
25711               var diff = Math.abs(actualDist - radius); //compare distances with epsilon-error (5%)
25712
25713               if (diff > 0.05 * radius) {
25714                 return false;
25715               }
25716             } //check if central angles are smaller than maxAngle
25717
25718
25719             for (i = 0; i < hull.length; i++) {
25720               actualPoint = hull[i];
25721               var nextPoint = hull[(i + 1) % hull.length];
25722               var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
25723               var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
25724               var angle = endAngle - startAngle;
25725
25726               if (angle < 0) {
25727                 angle = -angle;
25728               }
25729
25730               if (angle > Math.PI) {
25731                 angle = 2 * Math.PI - angle;
25732               }
25733
25734               if (angle > maxAngle + epsilonAngle) {
25735                 return false;
25736               }
25737             }
25738
25739             return 'already_circular';
25740           };
25741
25742           action.transitionable = true;
25743           return action;
25744         }
25745
25746         function actionDeleteWay(wayID) {
25747           function canDeleteNode(node, graph) {
25748             // don't delete nodes still attached to ways or relations
25749             if (graph.parentWays(node).length || graph.parentRelations(node).length) return false;
25750             var geometries = osmNodeGeometriesForTags(node.tags); // don't delete if this node can be a standalone point
25751
25752             if (geometries.point) return false; // delete if this node only be a vertex
25753
25754             if (geometries.vertex) return true; // iD doesn't know if this should be a point or vertex,
25755             // so only delete if there are no interesting tags
25756
25757             return !node.hasInterestingTags();
25758           }
25759
25760           var action = function action(graph) {
25761             var way = graph.entity(wayID);
25762             graph.parentRelations(way).forEach(function (parent) {
25763               parent = parent.removeMembersWithID(wayID);
25764               graph = graph.replace(parent);
25765
25766               if (parent.isDegenerate()) {
25767                 graph = actionDeleteRelation(parent.id)(graph);
25768               }
25769             });
25770             new Set(way.nodes).forEach(function (nodeID) {
25771               graph = graph.replace(way.removeNode(nodeID));
25772               var node = graph.entity(nodeID);
25773
25774               if (canDeleteNode(node, graph)) {
25775                 graph = graph.remove(node);
25776               }
25777             });
25778             return graph.remove(way);
25779           };
25780
25781           return action;
25782         }
25783
25784         function actionDeleteMultiple(ids) {
25785           var actions = {
25786             way: actionDeleteWay,
25787             node: actionDeleteNode,
25788             relation: actionDeleteRelation
25789           };
25790
25791           var action = function action(graph) {
25792             ids.forEach(function (id) {
25793               if (graph.hasEntity(id)) {
25794                 // It may have been deleted already.
25795                 graph = actions[graph.entity(id).type](id)(graph);
25796               }
25797             });
25798             return graph;
25799           };
25800
25801           return action;
25802         }
25803
25804         function actionDeleteRelation(relationID, allowUntaggedMembers) {
25805           function canDeleteEntity(entity, graph) {
25806             return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && !entity.hasInterestingTags() && !allowUntaggedMembers;
25807           }
25808
25809           var action = function action(graph) {
25810             var relation = graph.entity(relationID);
25811             graph.parentRelations(relation).forEach(function (parent) {
25812               parent = parent.removeMembersWithID(relationID);
25813               graph = graph.replace(parent);
25814
25815               if (parent.isDegenerate()) {
25816                 graph = actionDeleteRelation(parent.id)(graph);
25817               }
25818             });
25819             var memberIDs = utilArrayUniq(relation.members.map(function (m) {
25820               return m.id;
25821             }));
25822             memberIDs.forEach(function (memberID) {
25823               graph = graph.replace(relation.removeMembersWithID(memberID));
25824               var entity = graph.entity(memberID);
25825
25826               if (canDeleteEntity(entity, graph)) {
25827                 graph = actionDeleteMultiple([memberID])(graph);
25828               }
25829             });
25830             return graph.remove(relation);
25831           };
25832
25833           return action;
25834         }
25835
25836         function actionDeleteNode(nodeId) {
25837           var action = function action(graph) {
25838             var node = graph.entity(nodeId);
25839             graph.parentWays(node).forEach(function (parent) {
25840               parent = parent.removeNode(nodeId);
25841               graph = graph.replace(parent);
25842
25843               if (parent.isDegenerate()) {
25844                 graph = actionDeleteWay(parent.id)(graph);
25845               }
25846             });
25847             graph.parentRelations(node).forEach(function (parent) {
25848               parent = parent.removeMembersWithID(nodeId);
25849               graph = graph.replace(parent);
25850
25851               if (parent.isDegenerate()) {
25852                 graph = actionDeleteRelation(parent.id)(graph);
25853               }
25854             });
25855             return graph.remove(node);
25856           };
25857
25858           return action;
25859         }
25860
25861         //
25862         // First choose a node to be the survivor, with preference given
25863         // to an existing (not new) node.
25864         //
25865         // Tags and relation memberships of of non-surviving nodes are merged
25866         // to the survivor.
25867         //
25868         // This is the inverse of `iD.actionDisconnect`.
25869         //
25870         // Reference:
25871         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
25872         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
25873         //
25874
25875         function actionConnect(nodeIDs) {
25876           var action = function action(graph) {
25877             var survivor;
25878             var node;
25879             var parents;
25880             var i, j; // Choose a survivor node, prefer an existing (not new) node - #4974
25881
25882             for (i = 0; i < nodeIDs.length; i++) {
25883               survivor = graph.entity(nodeIDs[i]);
25884               if (survivor.version) break; // found one
25885             } // Replace all non-surviving nodes with the survivor and merge tags.
25886
25887
25888             for (i = 0; i < nodeIDs.length; i++) {
25889               node = graph.entity(nodeIDs[i]);
25890               if (node.id === survivor.id) continue;
25891               parents = graph.parentWays(node);
25892
25893               for (j = 0; j < parents.length; j++) {
25894                 graph = graph.replace(parents[j].replaceNode(node.id, survivor.id));
25895               }
25896
25897               parents = graph.parentRelations(node);
25898
25899               for (j = 0; j < parents.length; j++) {
25900                 graph = graph.replace(parents[j].replaceMember(node, survivor));
25901               }
25902
25903               survivor = survivor.mergeTags(node.tags);
25904               graph = actionDeleteNode(node.id)(graph);
25905             }
25906
25907             graph = graph.replace(survivor); // find and delete any degenerate ways created by connecting adjacent vertices
25908
25909             parents = graph.parentWays(survivor);
25910
25911             for (i = 0; i < parents.length; i++) {
25912               if (parents[i].isDegenerate()) {
25913                 graph = actionDeleteWay(parents[i].id)(graph);
25914               }
25915             }
25916
25917             return graph;
25918           };
25919
25920           action.disabled = function (graph) {
25921             var seen = {};
25922             var restrictionIDs = [];
25923             var survivor;
25924             var node, way;
25925             var relations, relation, role;
25926             var i, j, k; // Choose a survivor node, prefer an existing (not new) node - #4974
25927
25928             for (i = 0; i < nodeIDs.length; i++) {
25929               survivor = graph.entity(nodeIDs[i]);
25930               if (survivor.version) break; // found one
25931             } // 1. disable if the nodes being connected have conflicting relation roles
25932
25933
25934             for (i = 0; i < nodeIDs.length; i++) {
25935               node = graph.entity(nodeIDs[i]);
25936               relations = graph.parentRelations(node);
25937
25938               for (j = 0; j < relations.length; j++) {
25939                 relation = relations[j];
25940                 role = relation.memberById(node.id).role || ''; // if this node is a via node in a restriction, remember for later
25941
25942                 if (relation.hasFromViaTo()) {
25943                   restrictionIDs.push(relation.id);
25944                 }
25945
25946                 if (seen[relation.id] !== undefined && seen[relation.id] !== role) {
25947                   return 'relation';
25948                 } else {
25949                   seen[relation.id] = role;
25950                 }
25951               }
25952             } // gather restrictions for parent ways
25953
25954
25955             for (i = 0; i < nodeIDs.length; i++) {
25956               node = graph.entity(nodeIDs[i]);
25957               var parents = graph.parentWays(node);
25958
25959               for (j = 0; j < parents.length; j++) {
25960                 var parent = parents[j];
25961                 relations = graph.parentRelations(parent);
25962
25963                 for (k = 0; k < relations.length; k++) {
25964                   relation = relations[k];
25965
25966                   if (relation.hasFromViaTo()) {
25967                     restrictionIDs.push(relation.id);
25968                   }
25969                 }
25970               }
25971             } // test restrictions
25972
25973
25974             restrictionIDs = utilArrayUniq(restrictionIDs);
25975
25976             for (i = 0; i < restrictionIDs.length; i++) {
25977               relation = graph.entity(restrictionIDs[i]);
25978               if (!relation.isComplete(graph)) continue;
25979               var memberWays = relation.members.filter(function (m) {
25980                 return m.type === 'way';
25981               }).map(function (m) {
25982                 return graph.entity(m.id);
25983               });
25984               memberWays = utilArrayUniq(memberWays);
25985               var f = relation.memberByRole('from');
25986               var t = relation.memberByRole('to');
25987               var isUturn = f.id === t.id; // 2a. disable if connection would damage a restriction
25988               // (a key node is a node at the junction of ways)
25989
25990               var nodes = {
25991                 from: [],
25992                 via: [],
25993                 to: [],
25994                 keyfrom: [],
25995                 keyto: []
25996               };
25997
25998               for (j = 0; j < relation.members.length; j++) {
25999                 collectNodes(relation.members[j], nodes);
26000               }
26001
26002               nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
26003               nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
26004               var filter = keyNodeFilter(nodes.keyfrom, nodes.keyto);
26005               nodes.from = nodes.from.filter(filter);
26006               nodes.via = nodes.via.filter(filter);
26007               nodes.to = nodes.to.filter(filter);
26008               var connectFrom = false;
26009               var connectVia = false;
26010               var connectTo = false;
26011               var connectKeyFrom = false;
26012               var connectKeyTo = false;
26013
26014               for (j = 0; j < nodeIDs.length; j++) {
26015                 var n = nodeIDs[j];
26016
26017                 if (nodes.from.indexOf(n) !== -1) {
26018                   connectFrom = true;
26019                 }
26020
26021                 if (nodes.via.indexOf(n) !== -1) {
26022                   connectVia = true;
26023                 }
26024
26025                 if (nodes.to.indexOf(n) !== -1) {
26026                   connectTo = true;
26027                 }
26028
26029                 if (nodes.keyfrom.indexOf(n) !== -1) {
26030                   connectKeyFrom = true;
26031                 }
26032
26033                 if (nodes.keyto.indexOf(n) !== -1) {
26034                   connectKeyTo = true;
26035                 }
26036               }
26037
26038               if (connectFrom && connectTo && !isUturn) {
26039                 return 'restriction';
26040               }
26041
26042               if (connectFrom && connectVia) {
26043                 return 'restriction';
26044               }
26045
26046               if (connectTo && connectVia) {
26047                 return 'restriction';
26048               } // connecting to a key node -
26049               // if both nodes are on a member way (i.e. part of the turn restriction),
26050               // the connecting node must be adjacent to the key node.
26051
26052
26053               if (connectKeyFrom || connectKeyTo) {
26054                 if (nodeIDs.length !== 2) {
26055                   return 'restriction';
26056                 }
26057
26058                 var n0 = null;
26059                 var n1 = null;
26060
26061                 for (j = 0; j < memberWays.length; j++) {
26062                   way = memberWays[j];
26063
26064                   if (way.contains(nodeIDs[0])) {
26065                     n0 = nodeIDs[0];
26066                   }
26067
26068                   if (way.contains(nodeIDs[1])) {
26069                     n1 = nodeIDs[1];
26070                   }
26071                 }
26072
26073                 if (n0 && n1) {
26074                   // both nodes are part of the restriction
26075                   var ok = false;
26076
26077                   for (j = 0; j < memberWays.length; j++) {
26078                     way = memberWays[j];
26079
26080                     if (way.areAdjacent(n0, n1)) {
26081                       ok = true;
26082                       break;
26083                     }
26084                   }
26085
26086                   if (!ok) {
26087                     return 'restriction';
26088                   }
26089                 }
26090               } // 2b. disable if nodes being connected will destroy a member way in a restriction
26091               // (to test, make a copy and try actually connecting the nodes)
26092
26093
26094               for (j = 0; j < memberWays.length; j++) {
26095                 way = memberWays[j].update({}); // make copy
26096
26097                 for (k = 0; k < nodeIDs.length; k++) {
26098                   if (nodeIDs[k] === survivor.id) continue;
26099
26100                   if (way.areAdjacent(nodeIDs[k], survivor.id)) {
26101                     way = way.removeNode(nodeIDs[k]);
26102                   } else {
26103                     way = way.replaceNode(nodeIDs[k], survivor.id);
26104                   }
26105                 }
26106
26107                 if (way.isDegenerate()) {
26108                   return 'restriction';
26109                 }
26110               }
26111             }
26112
26113             return false; // if a key node appears multiple times (indexOf !== lastIndexOf) it's a FROM-VIA or TO-VIA junction
26114
26115             function hasDuplicates(n, i, arr) {
26116               return arr.indexOf(n) !== arr.lastIndexOf(n);
26117             }
26118
26119             function keyNodeFilter(froms, tos) {
26120               return function (n) {
26121                 return froms.indexOf(n) === -1 && tos.indexOf(n) === -1;
26122               };
26123             }
26124
26125             function collectNodes(member, collection) {
26126               var entity = graph.hasEntity(member.id);
26127               if (!entity) return;
26128               var role = member.role || '';
26129
26130               if (!collection[role]) {
26131                 collection[role] = [];
26132               }
26133
26134               if (member.type === 'node') {
26135                 collection[role].push(member.id);
26136
26137                 if (role === 'via') {
26138                   collection.keyfrom.push(member.id);
26139                   collection.keyto.push(member.id);
26140                 }
26141               } else if (member.type === 'way') {
26142                 collection[role].push.apply(collection[role], entity.nodes);
26143
26144                 if (role === 'from' || role === 'via') {
26145                   collection.keyfrom.push(entity.first());
26146                   collection.keyfrom.push(entity.last());
26147                 }
26148
26149                 if (role === 'to' || role === 'via') {
26150                   collection.keyto.push(entity.first());
26151                   collection.keyto.push(entity.last());
26152                 }
26153               }
26154             }
26155           };
26156
26157           return action;
26158         }
26159
26160         function actionCopyEntities(ids, fromGraph) {
26161           var _copies = {};
26162
26163           var action = function action(graph) {
26164             ids.forEach(function (id) {
26165               fromGraph.entity(id).copy(fromGraph, _copies);
26166             });
26167
26168             for (var id in _copies) {
26169               graph = graph.replace(_copies[id]);
26170             }
26171
26172             return graph;
26173           };
26174
26175           action.copies = function () {
26176             return _copies;
26177           };
26178
26179           return action;
26180         }
26181
26182         function actionDeleteMember(relationId, memberIndex) {
26183           return function (graph) {
26184             var relation = graph.entity(relationId).removeMember(memberIndex);
26185             graph = graph.replace(relation);
26186             if (relation.isDegenerate()) graph = actionDeleteRelation(relation.id)(graph);
26187             return graph;
26188           };
26189         }
26190
26191         function actionDiscardTags(difference, discardTags) {
26192           discardTags = discardTags || {};
26193           return function (graph) {
26194             difference.modified().forEach(checkTags);
26195             difference.created().forEach(checkTags);
26196             return graph;
26197
26198             function checkTags(entity) {
26199               var keys = Object.keys(entity.tags);
26200               var didDiscard = false;
26201               var tags = {};
26202
26203               for (var i = 0; i < keys.length; i++) {
26204                 var k = keys[i];
26205
26206                 if (discardTags[k] || !entity.tags[k]) {
26207                   didDiscard = true;
26208                 } else {
26209                   tags[k] = entity.tags[k];
26210                 }
26211               }
26212
26213               if (didDiscard) {
26214                 graph = graph.replace(entity.update({
26215                   tags: tags
26216                 }));
26217               }
26218             }
26219           };
26220         }
26221
26222         //
26223         // Optionally, disconnect only the given ways.
26224         //
26225         // For testing convenience, accepts an ID to assign to the (first) new node.
26226         // Normally, this will be undefined and the way will automatically
26227         // be assigned a new ID.
26228         //
26229         // This is the inverse of `iD.actionConnect`.
26230         //
26231         // Reference:
26232         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
26233         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
26234         //
26235
26236         function actionDisconnect(nodeId, newNodeId) {
26237           var wayIds;
26238
26239           var action = function action(graph) {
26240             var node = graph.entity(nodeId);
26241             var connections = action.connections(graph);
26242             connections.forEach(function (connection) {
26243               var way = graph.entity(connection.wayID);
26244               var newNode = osmNode({
26245                 id: newNodeId,
26246                 loc: node.loc,
26247                 tags: node.tags
26248               });
26249               graph = graph.replace(newNode);
26250
26251               if (connection.index === 0 && way.isArea()) {
26252                 // replace shared node with shared node..
26253                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
26254               } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
26255                 // replace closing node with new new node..
26256                 graph = graph.replace(way.unclose().addNode(newNode.id));
26257               } else {
26258                 // replace shared node with multiple new nodes..
26259                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
26260               }
26261             });
26262             return graph;
26263           };
26264
26265           action.connections = function (graph) {
26266             var candidates = [];
26267             var keeping = false;
26268             var parentWays = graph.parentWays(graph.entity(nodeId));
26269             var way, waynode;
26270
26271             for (var i = 0; i < parentWays.length; i++) {
26272               way = parentWays[i];
26273
26274               if (wayIds && wayIds.indexOf(way.id) === -1) {
26275                 keeping = true;
26276                 continue;
26277               }
26278
26279               if (way.isArea() && way.nodes[0] === nodeId) {
26280                 candidates.push({
26281                   wayID: way.id,
26282                   index: 0
26283                 });
26284               } else {
26285                 for (var j = 0; j < way.nodes.length; j++) {
26286                   waynode = way.nodes[j];
26287
26288                   if (waynode === nodeId) {
26289                     if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j === way.nodes.length - 1) {
26290                       continue;
26291                     }
26292
26293                     candidates.push({
26294                       wayID: way.id,
26295                       index: j
26296                     });
26297                   }
26298                 }
26299               }
26300             }
26301
26302             return keeping ? candidates : candidates.slice(1);
26303           };
26304
26305           action.disabled = function (graph) {
26306             var connections = action.connections(graph);
26307             if (connections.length === 0) return 'not_connected';
26308             var parentWays = graph.parentWays(graph.entity(nodeId));
26309             var seenRelationIds = {};
26310             var sharedRelation;
26311             parentWays.forEach(function (way) {
26312               var relations = graph.parentRelations(way);
26313               relations.forEach(function (relation) {
26314                 if (relation.id in seenRelationIds) {
26315                   if (wayIds) {
26316                     if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
26317                       sharedRelation = relation;
26318                     }
26319                   } else {
26320                     sharedRelation = relation;
26321                   }
26322                 } else {
26323                   seenRelationIds[relation.id] = way.id;
26324                 }
26325               });
26326             });
26327             if (sharedRelation) return 'relation';
26328           };
26329
26330           action.limitWays = function (val) {
26331             if (!arguments.length) return wayIds;
26332             wayIds = val;
26333             return action;
26334           };
26335
26336           return action;
26337         }
26338
26339         function actionExtract(entityID) {
26340           var extractedNodeID;
26341
26342           var action = function action(graph) {
26343             var entity = graph.entity(entityID);
26344
26345             if (entity.type === 'node') {
26346               return extractFromNode(entity, graph);
26347             }
26348
26349             return extractFromWayOrRelation(entity, graph);
26350           };
26351
26352           function extractFromNode(node, graph) {
26353             extractedNodeID = node.id; // Create a new node to replace the one we will detach
26354
26355             var replacement = osmNode({
26356               loc: node.loc
26357             });
26358             graph = graph.replace(replacement); // Process each way in turn, updating the graph as we go
26359
26360             graph = graph.parentWays(node).reduce(function (accGraph, parentWay) {
26361               return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
26362             }, graph); // Process any relations too
26363
26364             return graph.parentRelations(node).reduce(function (accGraph, parentRel) {
26365               return accGraph.replace(parentRel.replaceMember(node, replacement));
26366             }, graph);
26367           }
26368
26369           function extractFromWayOrRelation(entity, graph) {
26370             var fromGeometry = entity.geometry(graph);
26371             var keysToCopyAndRetain = ['source', 'wheelchair'];
26372             var keysToRetain = ['area'];
26373             var buildingKeysToRetain = ['architect', 'building', 'height', 'layer'];
26374             var extractedLoc = d3_geoCentroid(entity.asGeoJSON(graph));
26375
26376             if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
26377               extractedLoc = entity.extent(graph).center();
26378             }
26379
26380             var indoorAreaValues = {
26381               area: true,
26382               corridor: true,
26383               elevator: true,
26384               level: true,
26385               room: true
26386             };
26387             var isBuilding = entity.tags.building && entity.tags.building !== 'no' || entity.tags['building:part'] && entity.tags['building:part'] !== 'no';
26388             var isIndoorArea = fromGeometry === 'area' && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
26389             var entityTags = Object.assign({}, entity.tags); // shallow copy
26390
26391             var pointTags = {};
26392
26393             for (var key in entityTags) {
26394               if (entity.type === 'relation' && key === 'type') {
26395                 continue;
26396               }
26397
26398               if (keysToRetain.indexOf(key) !== -1) {
26399                 continue;
26400               }
26401
26402               if (isBuilding) {
26403                 // don't transfer building-related tags
26404                 if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
26405               } // leave `indoor` tag on the area
26406
26407
26408               if (isIndoorArea && key === 'indoor') {
26409                 continue;
26410               } // copy the tag from the entity to the point
26411
26412
26413               pointTags[key] = entityTags[key]; // leave addresses and some other tags so they're on both features
26414
26415               if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
26416                 continue;
26417               } else if (isIndoorArea && key === 'level') {
26418                 // leave `level` on both features
26419                 continue;
26420               } // remove the tag from the entity
26421
26422
26423               delete entityTags[key];
26424             }
26425
26426             if (!isBuilding && !isIndoorArea && fromGeometry === 'area') {
26427               // ensure that areas keep area geometry
26428               entityTags.area = 'yes';
26429             }
26430
26431             var replacement = osmNode({
26432               loc: extractedLoc,
26433               tags: pointTags
26434             });
26435             graph = graph.replace(replacement);
26436             extractedNodeID = replacement.id;
26437             return graph.replace(entity.update({
26438               tags: entityTags
26439             }));
26440           }
26441
26442           action.getExtractedNodeID = function () {
26443             return extractedNodeID;
26444           };
26445
26446           return action;
26447         }
26448
26449         //
26450         // This is the inverse of `iD.actionSplit`.
26451         //
26452         // Reference:
26453         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
26454         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
26455         //
26456
26457         function actionJoin(ids) {
26458           function groupEntitiesByGeometry(graph) {
26459             var entities = ids.map(function (id) {
26460               return graph.entity(id);
26461             });
26462             return Object.assign({
26463               line: []
26464             }, utilArrayGroupBy(entities, function (entity) {
26465               return entity.geometry(graph);
26466             }));
26467           }
26468
26469           var action = function action(graph) {
26470             var ways = ids.map(graph.entity, graph);
26471             var survivorID = ways[0].id; // if any of the ways are sided (e.g. coastline, cliff, kerb)
26472             // sort them first so they establish the overall order - #6033
26473
26474             ways.sort(function (a, b) {
26475               var aSided = a.isSided();
26476               var bSided = b.isSided();
26477               return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
26478             }); // Prefer to keep an existing way.
26479
26480             for (var i = 0; i < ways.length; i++) {
26481               if (!ways[i].isNew()) {
26482                 survivorID = ways[i].id;
26483                 break;
26484               }
26485             }
26486
26487             var sequences = osmJoinWays(ways, graph);
26488             var joined = sequences[0]; // We might need to reverse some of these ways before joining them.  #4688
26489             // `joined.actions` property will contain any actions we need to apply.
26490
26491             graph = sequences.actions.reduce(function (g, action) {
26492               return action(g);
26493             }, graph);
26494             var survivor = graph.entity(survivorID);
26495             survivor = survivor.update({
26496               nodes: joined.nodes.map(function (n) {
26497                 return n.id;
26498               })
26499             });
26500             graph = graph.replace(survivor);
26501             joined.forEach(function (way) {
26502               if (way.id === survivorID) return;
26503               graph.parentRelations(way).forEach(function (parent) {
26504                 graph = graph.replace(parent.replaceMember(way, survivor));
26505               });
26506               survivor = survivor.mergeTags(way.tags);
26507               graph = graph.replace(survivor);
26508               graph = actionDeleteWay(way.id)(graph);
26509             }); // Finds if the join created a single-member multipolygon,
26510             // and if so turns it into a basic area instead
26511
26512             function checkForSimpleMultipolygon() {
26513               if (!survivor.isClosed()) return;
26514               var multipolygons = graph.parentMultipolygons(survivor).filter(function (multipolygon) {
26515                 // find multipolygons where the survivor is the only member
26516                 return multipolygon.members.length === 1;
26517               }); // skip if this is the single member of multiple multipolygons
26518
26519               if (multipolygons.length !== 1) return;
26520               var multipolygon = multipolygons[0];
26521
26522               for (var key in survivor.tags) {
26523                 if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
26524                 multipolygon.tags[key] !== survivor.tags[key]) return;
26525               }
26526
26527               survivor = survivor.mergeTags(multipolygon.tags);
26528               graph = graph.replace(survivor);
26529               graph = actionDeleteRelation(multipolygon.id, true
26530               /* allow untagged members */
26531               )(graph);
26532               var tags = Object.assign({}, survivor.tags);
26533
26534               if (survivor.geometry(graph) !== 'area') {
26535                 // ensure the feature persists as an area
26536                 tags.area = 'yes';
26537               }
26538
26539               delete tags.type; // remove type=multipolygon
26540
26541               survivor = survivor.update({
26542                 tags: tags
26543               });
26544               graph = graph.replace(survivor);
26545             }
26546
26547             checkForSimpleMultipolygon();
26548             return graph;
26549           }; // Returns the number of nodes the resultant way is expected to have
26550
26551
26552           action.resultingWayNodesLength = function (graph) {
26553             return ids.reduce(function (count, id) {
26554               return count + graph.entity(id).nodes.length;
26555             }, 0) - ids.length - 1;
26556           };
26557
26558           action.disabled = function (graph) {
26559             var geometries = groupEntitiesByGeometry(graph);
26560
26561             if (ids.length < 2 || ids.length !== geometries.line.length) {
26562               return 'not_eligible';
26563             }
26564
26565             var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
26566
26567             if (joined.length > 1) {
26568               return 'not_adjacent';
26569             } // Loop through all combinations of path-pairs
26570             // to check potential intersections between all pairs
26571
26572
26573             for (var i = 0; i < ids.length - 1; i++) {
26574               for (var j = i + 1; j < ids.length; j++) {
26575                 var path1 = graph.childNodes(graph.entity(ids[i])).map(function (e) {
26576                   return e.loc;
26577                 });
26578                 var path2 = graph.childNodes(graph.entity(ids[j])).map(function (e) {
26579                   return e.loc;
26580                 });
26581                 var intersections = geoPathIntersections(path1, path2); // Check if intersections are just nodes lying on top of
26582                 // each other/the line, as opposed to crossing it
26583
26584                 var common = utilArrayIntersection(joined[0].nodes.map(function (n) {
26585                   return n.loc.toString();
26586                 }), intersections.map(function (n) {
26587                   return n.toString();
26588                 }));
26589
26590                 if (common.length !== intersections.length) {
26591                   return 'paths_intersect';
26592                 }
26593               }
26594             }
26595
26596             var nodeIds = joined[0].nodes.map(function (n) {
26597               return n.id;
26598             }).slice(1, -1);
26599             var relation;
26600             var tags = {};
26601             var conflicting = false;
26602             joined[0].forEach(function (way) {
26603               var parents = graph.parentRelations(way);
26604               parents.forEach(function (parent) {
26605                 if (parent.isRestriction() && parent.members.some(function (m) {
26606                   return nodeIds.indexOf(m.id) >= 0;
26607                 })) {
26608                   relation = parent;
26609                 }
26610               });
26611
26612               for (var k in way.tags) {
26613                 if (!(k in tags)) {
26614                   tags[k] = way.tags[k];
26615                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
26616                   conflicting = true;
26617                 }
26618               }
26619             });
26620
26621             if (relation) {
26622               return 'restriction';
26623             }
26624
26625             if (conflicting) {
26626               return 'conflicting_tags';
26627             }
26628           };
26629
26630           return action;
26631         }
26632
26633         function actionMerge(ids) {
26634           function groupEntitiesByGeometry(graph) {
26635             var entities = ids.map(function (id) {
26636               return graph.entity(id);
26637             });
26638             return Object.assign({
26639               point: [],
26640               area: [],
26641               line: [],
26642               relation: []
26643             }, utilArrayGroupBy(entities, function (entity) {
26644               return entity.geometry(graph);
26645             }));
26646           }
26647
26648           var action = function action(graph) {
26649             var geometries = groupEntitiesByGeometry(graph);
26650             var target = geometries.area[0] || geometries.line[0];
26651             var points = geometries.point;
26652             points.forEach(function (point) {
26653               target = target.mergeTags(point.tags);
26654               graph = graph.replace(target);
26655               graph.parentRelations(point).forEach(function (parent) {
26656                 graph = graph.replace(parent.replaceMember(point, target));
26657               });
26658               var nodes = utilArrayUniq(graph.childNodes(target));
26659               var removeNode = point;
26660
26661               for (var i = 0; i < nodes.length; i++) {
26662                 var node = nodes[i];
26663
26664                 if (graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags()) {
26665                   continue;
26666                 } // Found an uninteresting child node on the target way.
26667                 // Move orig point into its place to preserve point's history. #3683
26668
26669
26670                 graph = graph.replace(point.update({
26671                   tags: {},
26672                   loc: node.loc
26673                 }));
26674                 target = target.replaceNode(node.id, point.id);
26675                 graph = graph.replace(target);
26676                 removeNode = node;
26677                 break;
26678               }
26679
26680               graph = graph.remove(removeNode);
26681             });
26682
26683             if (target.tags.area === 'yes') {
26684               var tags = Object.assign({}, target.tags); // shallow copy
26685
26686               delete tags.area;
26687
26688               if (osmTagSuggestingArea(tags)) {
26689                 // remove the `area` tag if area geometry is now implied - #3851
26690                 target = target.update({
26691                   tags: tags
26692                 });
26693                 graph = graph.replace(target);
26694               }
26695             }
26696
26697             return graph;
26698           };
26699
26700           action.disabled = function (graph) {
26701             var geometries = groupEntitiesByGeometry(graph);
26702
26703             if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
26704               return 'not_eligible';
26705             }
26706           };
26707
26708           return action;
26709         }
26710
26711         //
26712         // 1. move all the nodes to a common location
26713         // 2. `actionConnect` them
26714
26715         function actionMergeNodes(nodeIDs, loc) {
26716           // If there is a single "interesting" node, use that as the location.
26717           // Otherwise return the average location of all the nodes.
26718           function chooseLoc(graph) {
26719             if (!nodeIDs.length) return null;
26720             var sum = [0, 0];
26721             var interestingCount = 0;
26722             var interestingLoc;
26723
26724             for (var i = 0; i < nodeIDs.length; i++) {
26725               var node = graph.entity(nodeIDs[i]);
26726
26727               if (node.hasInterestingTags()) {
26728                 interestingLoc = ++interestingCount === 1 ? node.loc : null;
26729               }
26730
26731               sum = geoVecAdd(sum, node.loc);
26732             }
26733
26734             return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
26735           }
26736
26737           var action = function action(graph) {
26738             if (nodeIDs.length < 2) return graph;
26739             var toLoc = loc;
26740
26741             if (!toLoc) {
26742               toLoc = chooseLoc(graph);
26743             }
26744
26745             for (var i = 0; i < nodeIDs.length; i++) {
26746               var node = graph.entity(nodeIDs[i]);
26747
26748               if (node.loc !== toLoc) {
26749                 graph = graph.replace(node.move(toLoc));
26750               }
26751             }
26752
26753             return actionConnect(nodeIDs)(graph);
26754           };
26755
26756           action.disabled = function (graph) {
26757             if (nodeIDs.length < 2) return 'not_eligible';
26758
26759             for (var i = 0; i < nodeIDs.length; i++) {
26760               var entity = graph.entity(nodeIDs[i]);
26761               if (entity.type !== 'node') return 'not_eligible';
26762             }
26763
26764             return actionConnect(nodeIDs).disabled(graph);
26765           };
26766
26767           return action;
26768         }
26769
26770         function osmChangeset() {
26771           if (!(this instanceof osmChangeset)) {
26772             return new osmChangeset().initialize(arguments);
26773           } else if (arguments.length) {
26774             this.initialize(arguments);
26775           }
26776         }
26777         osmEntity.changeset = osmChangeset;
26778         osmChangeset.prototype = Object.create(osmEntity.prototype);
26779         Object.assign(osmChangeset.prototype, {
26780           type: 'changeset',
26781           extent: function extent() {
26782             return new geoExtent();
26783           },
26784           geometry: function geometry() {
26785             return 'changeset';
26786           },
26787           asJXON: function asJXON() {
26788             return {
26789               osm: {
26790                 changeset: {
26791                   tag: Object.keys(this.tags).map(function (k) {
26792                     return {
26793                       '@k': k,
26794                       '@v': this.tags[k]
26795                     };
26796                   }, this),
26797                   '@version': 0.6,
26798                   '@generator': 'iD'
26799                 }
26800               }
26801             };
26802           },
26803           // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26804           // XML. Returns a string.
26805           osmChangeJXON: function osmChangeJXON(changes) {
26806             var changeset_id = this.id;
26807
26808             function nest(x, order) {
26809               var groups = {};
26810
26811               for (var i = 0; i < x.length; i++) {
26812                 var tagName = Object.keys(x[i])[0];
26813                 if (!groups[tagName]) groups[tagName] = [];
26814                 groups[tagName].push(x[i][tagName]);
26815               }
26816
26817               var ordered = {};
26818               order.forEach(function (o) {
26819                 if (groups[o]) ordered[o] = groups[o];
26820               });
26821               return ordered;
26822             } // sort relations in a changeset by dependencies
26823
26824
26825             function sort(changes) {
26826               // find a referenced relation in the current changeset
26827               function resolve(item) {
26828                 return relations.find(function (relation) {
26829                   return item.keyAttributes.type === 'relation' && item.keyAttributes.ref === relation['@id'];
26830                 });
26831               } // a new item is an item that has not been already processed
26832
26833
26834               function isNew(item) {
26835                 return !sorted[item['@id']] && !processing.find(function (proc) {
26836                   return proc['@id'] === item['@id'];
26837                 });
26838               }
26839
26840               var processing = [];
26841               var sorted = {};
26842               var relations = changes.relation;
26843               if (!relations) return changes;
26844
26845               for (var i = 0; i < relations.length; i++) {
26846                 var relation = relations[i]; // skip relation if already sorted
26847
26848                 if (!sorted[relation['@id']]) {
26849                   processing.push(relation);
26850                 }
26851
26852                 while (processing.length > 0) {
26853                   var next = processing[0],
26854                       deps = next.member.map(resolve).filter(Boolean).filter(isNew);
26855
26856                   if (deps.length === 0) {
26857                     sorted[next['@id']] = next;
26858                     processing.shift();
26859                   } else {
26860                     processing = deps.concat(processing);
26861                   }
26862                 }
26863               }
26864
26865               changes.relation = Object.values(sorted);
26866               return changes;
26867             }
26868
26869             function rep(entity) {
26870               return entity.asJXON(changeset_id);
26871             }
26872
26873             return {
26874               osmChange: {
26875                 '@version': 0.6,
26876                 '@generator': 'iD',
26877                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
26878                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26879                 'delete': Object.assign(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {
26880                   '@if-unused': true
26881                 })
26882               }
26883             };
26884           },
26885           asGeoJSON: function asGeoJSON() {
26886             return {};
26887           }
26888         });
26889
26890         function osmNote() {
26891           if (!(this instanceof osmNote)) {
26892             return new osmNote().initialize(arguments);
26893           } else if (arguments.length) {
26894             this.initialize(arguments);
26895           }
26896         }
26897
26898         osmNote.id = function () {
26899           return osmNote.id.next--;
26900         };
26901
26902         osmNote.id.next = -1;
26903         Object.assign(osmNote.prototype, {
26904           type: 'note',
26905           initialize: function initialize(sources) {
26906             for (var i = 0; i < sources.length; ++i) {
26907               var source = sources[i];
26908
26909               for (var prop in source) {
26910                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
26911                   if (source[prop] === undefined) {
26912                     delete this[prop];
26913                   } else {
26914                     this[prop] = source[prop];
26915                   }
26916                 }
26917               }
26918             }
26919
26920             if (!this.id) {
26921               this.id = osmNote.id().toString();
26922             }
26923
26924             return this;
26925           },
26926           extent: function extent() {
26927             return new geoExtent(this.loc);
26928           },
26929           update: function update(attrs) {
26930             return osmNote(this, attrs); // {v: 1 + (this.v || 0)}
26931           },
26932           isNew: function isNew() {
26933             return this.id < 0;
26934           },
26935           move: function move(loc) {
26936             return this.update({
26937               loc: loc
26938             });
26939           }
26940         });
26941
26942         function osmRelation() {
26943           if (!(this instanceof osmRelation)) {
26944             return new osmRelation().initialize(arguments);
26945           } else if (arguments.length) {
26946             this.initialize(arguments);
26947           }
26948         }
26949         osmEntity.relation = osmRelation;
26950         osmRelation.prototype = Object.create(osmEntity.prototype);
26951
26952         osmRelation.creationOrder = function (a, b) {
26953           var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
26954           var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
26955           if (aId < 0 || bId < 0) return aId - bId;
26956           return bId - aId;
26957         };
26958
26959         Object.assign(osmRelation.prototype, {
26960           type: 'relation',
26961           members: [],
26962           copy: function copy(resolver, copies) {
26963             if (copies[this.id]) return copies[this.id];
26964             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
26965             var members = this.members.map(function (member) {
26966               return Object.assign({}, member, {
26967                 id: resolver.entity(member.id).copy(resolver, copies).id
26968               });
26969             });
26970             copy = copy.update({
26971               members: members
26972             });
26973             copies[this.id] = copy;
26974             return copy;
26975           },
26976           extent: function extent(resolver, memo) {
26977             return resolver["transient"](this, 'extent', function () {
26978               if (memo && memo[this.id]) return geoExtent();
26979               memo = memo || {};
26980               memo[this.id] = true;
26981               var extent = geoExtent();
26982
26983               for (var i = 0; i < this.members.length; i++) {
26984                 var member = resolver.hasEntity(this.members[i].id);
26985
26986                 if (member) {
26987                   extent._extend(member.extent(resolver, memo));
26988                 }
26989               }
26990
26991               return extent;
26992             });
26993           },
26994           geometry: function geometry(graph) {
26995             return graph["transient"](this, 'geometry', function () {
26996               return this.isMultipolygon() ? 'area' : 'relation';
26997             });
26998           },
26999           isDegenerate: function isDegenerate() {
27000             return this.members.length === 0;
27001           },
27002           // Return an array of members, each extended with an 'index' property whose value
27003           // is the member index.
27004           indexedMembers: function indexedMembers() {
27005             var result = new Array(this.members.length);
27006
27007             for (var i = 0; i < this.members.length; i++) {
27008               result[i] = Object.assign({}, this.members[i], {
27009                 index: i
27010               });
27011             }
27012
27013             return result;
27014           },
27015           // Return the first member with the given role. A copy of the member object
27016           // is returned, extended with an 'index' property whose value is the member index.
27017           memberByRole: function memberByRole(role) {
27018             for (var i = 0; i < this.members.length; i++) {
27019               if (this.members[i].role === role) {
27020                 return Object.assign({}, this.members[i], {
27021                   index: i
27022                 });
27023               }
27024             }
27025           },
27026           // Same as memberByRole, but returns all members with the given role
27027           membersByRole: function membersByRole(role) {
27028             var result = [];
27029
27030             for (var i = 0; i < this.members.length; i++) {
27031               if (this.members[i].role === role) {
27032                 result.push(Object.assign({}, this.members[i], {
27033                   index: i
27034                 }));
27035               }
27036             }
27037
27038             return result;
27039           },
27040           // Return the first member with the given id. A copy of the member object
27041           // is returned, extended with an 'index' property whose value is the member index.
27042           memberById: function memberById(id) {
27043             for (var i = 0; i < this.members.length; i++) {
27044               if (this.members[i].id === id) {
27045                 return Object.assign({}, this.members[i], {
27046                   index: i
27047                 });
27048               }
27049             }
27050           },
27051           // Return the first member with the given id and role. A copy of the member object
27052           // is returned, extended with an 'index' property whose value is the member index.
27053           memberByIdAndRole: function memberByIdAndRole(id, role) {
27054             for (var i = 0; i < this.members.length; i++) {
27055               if (this.members[i].id === id && this.members[i].role === role) {
27056                 return Object.assign({}, this.members[i], {
27057                   index: i
27058                 });
27059               }
27060             }
27061           },
27062           addMember: function addMember(member, index) {
27063             var members = this.members.slice();
27064             members.splice(index === undefined ? members.length : index, 0, member);
27065             return this.update({
27066               members: members
27067             });
27068           },
27069           updateMember: function updateMember(member, index) {
27070             var members = this.members.slice();
27071             members.splice(index, 1, Object.assign({}, members[index], member));
27072             return this.update({
27073               members: members
27074             });
27075           },
27076           removeMember: function removeMember(index) {
27077             var members = this.members.slice();
27078             members.splice(index, 1);
27079             return this.update({
27080               members: members
27081             });
27082           },
27083           removeMembersWithID: function removeMembersWithID(id) {
27084             var members = this.members.filter(function (m) {
27085               return m.id !== id;
27086             });
27087             return this.update({
27088               members: members
27089             });
27090           },
27091           moveMember: function moveMember(fromIndex, toIndex) {
27092             var members = this.members.slice();
27093             members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
27094             return this.update({
27095               members: members
27096             });
27097           },
27098           // Wherever a member appears with id `needle.id`, replace it with a member
27099           // with id `replacement.id`, type `replacement.type`, and the original role,
27100           // By default, adding a duplicate member (by id and role) is prevented.
27101           // Return an updated relation.
27102           replaceMember: function replaceMember(needle, replacement, keepDuplicates) {
27103             if (!this.memberById(needle.id)) return this;
27104             var members = [];
27105
27106             for (var i = 0; i < this.members.length; i++) {
27107               var member = this.members[i];
27108
27109               if (member.id !== needle.id) {
27110                 members.push(member);
27111               } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
27112                 members.push({
27113                   id: replacement.id,
27114                   type: replacement.type,
27115                   role: member.role
27116                 });
27117               }
27118             }
27119
27120             return this.update({
27121               members: members
27122             });
27123           },
27124           asJXON: function asJXON(changeset_id) {
27125             var r = {
27126               relation: {
27127                 '@id': this.osmId(),
27128                 '@version': this.version || 0,
27129                 member: this.members.map(function (member) {
27130                   return {
27131                     keyAttributes: {
27132                       type: member.type,
27133                       role: member.role,
27134                       ref: osmEntity.id.toOSM(member.id)
27135                     }
27136                   };
27137                 }, this),
27138                 tag: Object.keys(this.tags).map(function (k) {
27139                   return {
27140                     keyAttributes: {
27141                       k: k,
27142                       v: this.tags[k]
27143                     }
27144                   };
27145                 }, this)
27146               }
27147             };
27148
27149             if (changeset_id) {
27150               r.relation['@changeset'] = changeset_id;
27151             }
27152
27153             return r;
27154           },
27155           asGeoJSON: function asGeoJSON(resolver) {
27156             return resolver["transient"](this, 'GeoJSON', function () {
27157               if (this.isMultipolygon()) {
27158                 return {
27159                   type: 'MultiPolygon',
27160                   coordinates: this.multipolygon(resolver)
27161                 };
27162               } else {
27163                 return {
27164                   type: 'FeatureCollection',
27165                   properties: this.tags,
27166                   features: this.members.map(function (member) {
27167                     return Object.assign({
27168                       role: member.role
27169                     }, resolver.entity(member.id).asGeoJSON(resolver));
27170                   })
27171                 };
27172               }
27173             });
27174           },
27175           area: function area(resolver) {
27176             return resolver["transient"](this, 'area', function () {
27177               return d3_geoArea(this.asGeoJSON(resolver));
27178             });
27179           },
27180           isMultipolygon: function isMultipolygon() {
27181             return this.tags.type === 'multipolygon';
27182           },
27183           isComplete: function isComplete(resolver) {
27184             for (var i = 0; i < this.members.length; i++) {
27185               if (!resolver.hasEntity(this.members[i].id)) {
27186                 return false;
27187               }
27188             }
27189
27190             return true;
27191           },
27192           hasFromViaTo: function hasFromViaTo() {
27193             return this.members.some(function (m) {
27194               return m.role === 'from';
27195             }) && this.members.some(function (m) {
27196               return m.role === 'via';
27197             }) && this.members.some(function (m) {
27198               return m.role === 'to';
27199             });
27200           },
27201           isRestriction: function isRestriction() {
27202             return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27203           },
27204           isValidRestriction: function isValidRestriction() {
27205             if (!this.isRestriction()) return false;
27206             var froms = this.members.filter(function (m) {
27207               return m.role === 'from';
27208             });
27209             var vias = this.members.filter(function (m) {
27210               return m.role === 'via';
27211             });
27212             var tos = this.members.filter(function (m) {
27213               return m.role === 'to';
27214             });
27215             if (froms.length !== 1 && this.tags.restriction !== 'no_entry') return false;
27216             if (froms.some(function (m) {
27217               return m.type !== 'way';
27218             })) return false;
27219             if (tos.length !== 1 && this.tags.restriction !== 'no_exit') return false;
27220             if (tos.some(function (m) {
27221               return m.type !== 'way';
27222             })) return false;
27223             if (vias.length === 0) return false;
27224             if (vias.length > 1 && vias.some(function (m) {
27225               return m.type !== 'way';
27226             })) return false;
27227             return true;
27228           },
27229           // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27230           // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27231           //
27232           // This corresponds to the structure needed for rendering a multipolygon path using a
27233           // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27234           //
27235           // In the case of invalid geometries, this function will still return a result which
27236           // includes the nodes of all way members, but some Nds may be unclosed and some inner
27237           // rings not matched with the intended outer ring.
27238           //
27239           multipolygon: function multipolygon(resolver) {
27240             var outers = this.members.filter(function (m) {
27241               return 'outer' === (m.role || 'outer');
27242             });
27243             var inners = this.members.filter(function (m) {
27244               return 'inner' === m.role;
27245             });
27246             outers = osmJoinWays(outers, resolver);
27247             inners = osmJoinWays(inners, resolver);
27248
27249             var sequenceToLineString = function sequenceToLineString(sequence) {
27250               if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
27251                 // close unclosed parts to ensure correct area rendering - #2945
27252                 sequence.nodes.push(sequence.nodes[0]);
27253               }
27254
27255               return sequence.nodes.map(function (node) {
27256                 return node.loc;
27257               });
27258             };
27259
27260             outers = outers.map(sequenceToLineString);
27261             inners = inners.map(sequenceToLineString);
27262             var result = outers.map(function (o) {
27263               // Heuristic for detecting counterclockwise winding order. Assumes
27264               // that OpenStreetMap polygons are not hemisphere-spanning.
27265               return [d3_geoArea({
27266                 type: 'Polygon',
27267                 coordinates: [o]
27268               }) > 2 * Math.PI ? o.reverse() : o];
27269             });
27270
27271             function findOuter(inner) {
27272               var o, outer;
27273
27274               for (o = 0; o < outers.length; o++) {
27275                 outer = outers[o];
27276                 if (geoPolygonContainsPolygon(outer, inner)) return o;
27277               }
27278
27279               for (o = 0; o < outers.length; o++) {
27280                 outer = outers[o];
27281                 if (geoPolygonIntersectsPolygon(outer, inner, false)) return o;
27282               }
27283             }
27284
27285             for (var i = 0; i < inners.length; i++) {
27286               var inner = inners[i];
27287
27288               if (d3_geoArea({
27289                 type: 'Polygon',
27290                 coordinates: [inner]
27291               }) < 2 * Math.PI) {
27292                 inner = inner.reverse();
27293               }
27294
27295               var o = findOuter(inners[i]);
27296
27297               if (o !== undefined) {
27298                 result[o].push(inners[i]);
27299               } else {
27300                 result.push([inners[i]]); // Invalid geometry
27301               }
27302             }
27303
27304             return result;
27305           }
27306         });
27307
27308         var QAItem = /*#__PURE__*/function () {
27309           function QAItem(loc, service, itemType, id, props) {
27310             _classCallCheck(this, QAItem);
27311
27312             // Store required properties
27313             this.loc = loc;
27314             this.service = service.title;
27315             this.itemType = itemType; // All issues must have an ID for selection, use generic if none specified
27316
27317             this.id = id ? id : "".concat(QAItem.id());
27318             this.update(props); // Some QA services have marker icons to differentiate issues
27319
27320             if (service && typeof service.getIcon === 'function') {
27321               this.icon = service.getIcon(itemType);
27322             }
27323           }
27324
27325           _createClass(QAItem, [{
27326             key: "update",
27327             value: function update(props) {
27328               var _this = this;
27329
27330               // You can't override this initial information
27331               var loc = this.loc,
27332                   service = this.service,
27333                   itemType = this.itemType,
27334                   id = this.id;
27335               Object.keys(props).forEach(function (prop) {
27336                 return _this[prop] = props[prop];
27337               });
27338               this.loc = loc;
27339               this.service = service;
27340               this.itemType = itemType;
27341               this.id = id;
27342               return this;
27343             } // Generic handling for newly created QAItems
27344
27345           }], [{
27346             key: "id",
27347             value: function id() {
27348               return this.nextId--;
27349             }
27350           }]);
27351
27352           return QAItem;
27353         }();
27354         QAItem.nextId = -1;
27355
27356         //
27357         // Optionally, split only the given ways, if multiple ways share
27358         // the given node.
27359         //
27360         // This is the inverse of `iD.actionJoin`.
27361         //
27362         // For testing convenience, accepts an ID to assign to the new way.
27363         // Normally, this will be undefined and the way will automatically
27364         // be assigned a new ID.
27365         //
27366         // Reference:
27367         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
27368         //
27369
27370         function actionSplit(nodeIds, newWayIds) {
27371           // accept single ID for backwards-compatiblity
27372           if (typeof nodeIds === 'string') nodeIds = [nodeIds];
27373
27374           var _wayIDs; // the strategy for picking which way will have a new version and which way is newly created
27375
27376
27377           var _keepHistoryOn = 'longest'; // 'longest', 'first'
27378           // The IDs of the ways actually created by running this action
27379
27380           var _createdWayIDs = [];
27381
27382           function dist(graph, nA, nB) {
27383             var locA = graph.entity(nA).loc;
27384             var locB = graph.entity(nB).loc;
27385             var epsilon = 1e-6;
27386             return locA && locB ? geoSphericalDistance(locA, locB) : epsilon;
27387           } // If the way is closed, we need to search for a partner node
27388           // to split the way at.
27389           //
27390           // The following looks for a node that is both far away from
27391           // the initial node in terms of way segment length and nearby
27392           // in terms of beeline-distance. This assures that areas get
27393           // split on the most "natural" points (independent of the number
27394           // of nodes).
27395           // For example: bone-shaped areas get split across their waist
27396           // line, circles across the diameter.
27397
27398
27399           function splitArea(nodes, idxA, graph) {
27400             var lengths = new Array(nodes.length);
27401             var length;
27402             var i;
27403             var best = 0;
27404             var idxB;
27405
27406             function wrap(index) {
27407               return utilWrap(index, nodes.length);
27408             } // calculate lengths
27409
27410
27411             length = 0;
27412
27413             for (i = wrap(idxA + 1); i !== idxA; i = wrap(i + 1)) {
27414               length += dist(graph, nodes[i], nodes[wrap(i - 1)]);
27415               lengths[i] = length;
27416             }
27417
27418             length = 0;
27419
27420             for (i = wrap(idxA - 1); i !== idxA; i = wrap(i - 1)) {
27421               length += dist(graph, nodes[i], nodes[wrap(i + 1)]);
27422
27423               if (length < lengths[i]) {
27424                 lengths[i] = length;
27425               }
27426             } // determine best opposite node to split
27427
27428
27429             for (i = 0; i < nodes.length; i++) {
27430               var cost = lengths[i] / dist(graph, nodes[idxA], nodes[i]);
27431
27432               if (cost > best) {
27433                 idxB = i;
27434                 best = cost;
27435               }
27436             }
27437
27438             return idxB;
27439           }
27440
27441           function totalLengthBetweenNodes(graph, nodes) {
27442             var totalLength = 0;
27443
27444             for (var i = 0; i < nodes.length - 1; i++) {
27445               totalLength += dist(graph, nodes[i], nodes[i + 1]);
27446             }
27447
27448             return totalLength;
27449           }
27450
27451           function split(graph, nodeId, wayA, newWayId) {
27452             var wayB = osmWay({
27453               id: newWayId,
27454               tags: wayA.tags
27455             }); // `wayB` is the NEW way
27456
27457             var origNodes = wayA.nodes.slice();
27458             var nodesA;
27459             var nodesB;
27460             var isArea = wayA.isArea();
27461             var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
27462
27463             if (wayA.isClosed()) {
27464               var nodes = wayA.nodes.slice(0, -1);
27465               var idxA = nodes.indexOf(nodeId);
27466               var idxB = splitArea(nodes, idxA, graph);
27467
27468               if (idxB < idxA) {
27469                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
27470                 nodesB = nodes.slice(idxB, idxA + 1);
27471               } else {
27472                 nodesA = nodes.slice(idxA, idxB + 1);
27473                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
27474               }
27475             } else {
27476               var idx = wayA.nodes.indexOf(nodeId, 1);
27477               nodesA = wayA.nodes.slice(0, idx + 1);
27478               nodesB = wayA.nodes.slice(idx);
27479             }
27480
27481             var lengthA = totalLengthBetweenNodes(graph, nodesA);
27482             var lengthB = totalLengthBetweenNodes(graph, nodesB);
27483
27484             if (_keepHistoryOn === 'longest' && lengthB > lengthA) {
27485               // keep the history on the longer way, regardless of the node count
27486               wayA = wayA.update({
27487                 nodes: nodesB
27488               });
27489               wayB = wayB.update({
27490                 nodes: nodesA
27491               });
27492               var temp = lengthA;
27493               lengthA = lengthB;
27494               lengthB = temp;
27495             } else {
27496               wayA = wayA.update({
27497                 nodes: nodesA
27498               });
27499               wayB = wayB.update({
27500                 nodes: nodesB
27501               });
27502             }
27503
27504             if (wayA.tags.step_count) {
27505               // divide up the the step count proportionally between the two ways
27506               var stepCount = parseFloat(wayA.tags.step_count);
27507
27508               if (stepCount && // ensure a number
27509               isFinite(stepCount) && // ensure positive
27510               stepCount > 0 && // ensure integer
27511               Math.round(stepCount) === stepCount) {
27512                 var tagsA = Object.assign({}, wayA.tags);
27513                 var tagsB = Object.assign({}, wayB.tags);
27514                 var ratioA = lengthA / (lengthA + lengthB);
27515                 var countA = Math.round(stepCount * ratioA);
27516                 tagsA.step_count = countA.toString();
27517                 tagsB.step_count = (stepCount - countA).toString();
27518                 wayA = wayA.update({
27519                   tags: tagsA
27520                 });
27521                 wayB = wayB.update({
27522                   tags: tagsB
27523                 });
27524               }
27525             }
27526
27527             graph = graph.replace(wayA);
27528             graph = graph.replace(wayB);
27529             graph.parentRelations(wayA).forEach(function (relation) {
27530               var member; // Turn restrictions - make sure:
27531               // 1. Splitting a FROM/TO way - only `wayA` OR `wayB` remains in relation
27532               //    (whichever one is connected to the VIA node/ways)
27533               // 2. Splitting a VIA way - `wayB` remains in relation as a VIA way
27534
27535               if (relation.hasFromViaTo()) {
27536                 var f = relation.memberByRole('from');
27537                 var v = relation.membersByRole('via');
27538                 var t = relation.memberByRole('to');
27539                 var i; // 1. split a FROM/TO
27540
27541                 if (f.id === wayA.id || t.id === wayA.id) {
27542                   var keepB = false;
27543
27544                   if (v.length === 1 && v[0].type === 'node') {
27545                     // check via node
27546                     keepB = wayB.contains(v[0].id);
27547                   } else {
27548                     // check via way(s)
27549                     for (i = 0; i < v.length; i++) {
27550                       if (v[i].type === 'way') {
27551                         var wayVia = graph.hasEntity(v[i].id);
27552
27553                         if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
27554                           keepB = true;
27555                           break;
27556                         }
27557                       }
27558                     }
27559                   }
27560
27561                   if (keepB) {
27562                     relation = relation.replaceMember(wayA, wayB);
27563                     graph = graph.replace(relation);
27564                   } // 2. split a VIA
27565
27566                 } else {
27567                   for (i = 0; i < v.length; i++) {
27568                     if (v[i].type === 'way' && v[i].id === wayA.id) {
27569                       member = {
27570                         id: wayB.id,
27571                         type: 'way',
27572                         role: 'via'
27573                       };
27574                       graph = actionAddMember(relation.id, member, v[i].index + 1)(graph);
27575                       break;
27576                     }
27577                   }
27578                 } // All other relations (Routes, Multipolygons, etc):
27579                 // 1. Both `wayA` and `wayB` remain in the relation
27580                 // 2. But must be inserted as a pair (see `actionAddMember` for details)
27581
27582               } else {
27583                 if (relation === isOuter) {
27584                   graph = graph.replace(relation.mergeTags(wayA.tags));
27585                   graph = graph.replace(wayA.update({
27586                     tags: {}
27587                   }));
27588                   graph = graph.replace(wayB.update({
27589                     tags: {}
27590                   }));
27591                 }
27592
27593                 member = {
27594                   id: wayB.id,
27595                   type: 'way',
27596                   role: relation.memberById(wayA.id).role
27597                 };
27598                 var insertPair = {
27599                   originalID: wayA.id,
27600                   insertedID: wayB.id,
27601                   nodes: origNodes
27602                 };
27603                 graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
27604               }
27605             });
27606
27607             if (!isOuter && isArea) {
27608               var multipolygon = osmRelation({
27609                 tags: Object.assign({}, wayA.tags, {
27610                   type: 'multipolygon'
27611                 }),
27612                 members: [{
27613                   id: wayA.id,
27614                   role: 'outer',
27615                   type: 'way'
27616                 }, {
27617                   id: wayB.id,
27618                   role: 'outer',
27619                   type: 'way'
27620                 }]
27621               });
27622               graph = graph.replace(multipolygon);
27623               graph = graph.replace(wayA.update({
27624                 tags: {}
27625               }));
27626               graph = graph.replace(wayB.update({
27627                 tags: {}
27628               }));
27629             }
27630
27631             _createdWayIDs.push(wayB.id);
27632
27633             return graph;
27634           }
27635
27636           var action = function action(graph) {
27637             _createdWayIDs = [];
27638             var newWayIndex = 0;
27639
27640             for (var i = 0; i < nodeIds.length; i++) {
27641               var nodeId = nodeIds[i];
27642               var candidates = action.waysForNode(nodeId, graph);
27643
27644               for (var j = 0; j < candidates.length; j++) {
27645                 graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
27646                 newWayIndex += 1;
27647               }
27648             }
27649
27650             return graph;
27651           };
27652
27653           action.getCreatedWayIDs = function () {
27654             return _createdWayIDs;
27655           };
27656
27657           action.waysForNode = function (nodeId, graph) {
27658             var node = graph.entity(nodeId);
27659             var splittableParents = graph.parentWays(node).filter(isSplittable);
27660
27661             if (!_wayIDs) {
27662               // If the ways to split aren't specified, only split the lines.
27663               // If there are no lines to split, split the areas.
27664               var hasLine = splittableParents.some(function (parent) {
27665                 return parent.geometry(graph) === 'line';
27666               });
27667
27668               if (hasLine) {
27669                 return splittableParents.filter(function (parent) {
27670                   return parent.geometry(graph) === 'line';
27671                 });
27672               }
27673             }
27674
27675             return splittableParents;
27676
27677             function isSplittable(parent) {
27678               // If the ways to split are specified, ignore everything else.
27679               if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false; // We can fake splitting closed ways at their endpoints...
27680
27681               if (parent.isClosed()) return true; // otherwise, we can't split nodes at their endpoints.
27682
27683               for (var i = 1; i < parent.nodes.length - 1; i++) {
27684                 if (parent.nodes[i] === nodeId) return true;
27685               }
27686
27687               return false;
27688             }
27689           };
27690
27691           action.ways = function (graph) {
27692             return utilArrayUniq([].concat.apply([], nodeIds.map(function (nodeId) {
27693               return action.waysForNode(nodeId, graph);
27694             })));
27695           };
27696
27697           action.disabled = function (graph) {
27698             for (var i = 0; i < nodeIds.length; i++) {
27699               var nodeId = nodeIds[i];
27700               var candidates = action.waysForNode(nodeId, graph);
27701
27702               if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
27703                 return 'not_eligible';
27704               }
27705             }
27706           };
27707
27708           action.limitWays = function (val) {
27709             if (!arguments.length) return _wayIDs;
27710             _wayIDs = val;
27711             return action;
27712           };
27713
27714           action.keepHistoryOn = function (val) {
27715             if (!arguments.length) return _keepHistoryOn;
27716             _keepHistoryOn = val;
27717             return action;
27718           };
27719
27720           return action;
27721         }
27722
27723         function coreGraph(other, mutable) {
27724           if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
27725
27726           if (other instanceof coreGraph) {
27727             var base = other.base();
27728             this.entities = Object.assign(Object.create(base.entities), other.entities);
27729             this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
27730             this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
27731           } else {
27732             this.entities = Object.create({});
27733             this._parentWays = Object.create({});
27734             this._parentRels = Object.create({});
27735             this.rebase(other || [], [this]);
27736           }
27737
27738           this.transients = {};
27739           this._childNodes = {};
27740           this.frozen = !mutable;
27741         }
27742         coreGraph.prototype = {
27743           hasEntity: function hasEntity(id) {
27744             return this.entities[id];
27745           },
27746           entity: function entity(id) {
27747             var entity = this.entities[id]; //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
27748
27749             if (!entity) {
27750               entity = this.entities.__proto__[id]; // eslint-disable-line no-proto
27751             }
27752
27753             if (!entity) {
27754               throw new Error('entity ' + id + ' not found');
27755             }
27756
27757             return entity;
27758           },
27759           geometry: function geometry(id) {
27760             return this.entity(id).geometry(this);
27761           },
27762           "transient": function transient(entity, key, fn) {
27763             var id = entity.id;
27764             var transients = this.transients[id] || (this.transients[id] = {});
27765
27766             if (transients[key] !== undefined) {
27767               return transients[key];
27768             }
27769
27770             transients[key] = fn.call(entity);
27771             return transients[key];
27772           },
27773           parentWays: function parentWays(entity) {
27774             var parents = this._parentWays[entity.id];
27775             var result = [];
27776
27777             if (parents) {
27778               parents.forEach(function (id) {
27779                 result.push(this.entity(id));
27780               }, this);
27781             }
27782
27783             return result;
27784           },
27785           isPoi: function isPoi(entity) {
27786             var parents = this._parentWays[entity.id];
27787             return !parents || parents.size === 0;
27788           },
27789           isShared: function isShared(entity) {
27790             var parents = this._parentWays[entity.id];
27791             return parents && parents.size > 1;
27792           },
27793           parentRelations: function parentRelations(entity) {
27794             var parents = this._parentRels[entity.id];
27795             var result = [];
27796
27797             if (parents) {
27798               parents.forEach(function (id) {
27799                 result.push(this.entity(id));
27800               }, this);
27801             }
27802
27803             return result;
27804           },
27805           parentMultipolygons: function parentMultipolygons(entity) {
27806             return this.parentRelations(entity).filter(function (relation) {
27807               return relation.isMultipolygon();
27808             });
27809           },
27810           childNodes: function childNodes(entity) {
27811             if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27812             if (!entity.nodes) return [];
27813             var nodes = [];
27814
27815             for (var i = 0; i < entity.nodes.length; i++) {
27816               nodes[i] = this.entity(entity.nodes[i]);
27817             }
27818             this._childNodes[entity.id] = nodes;
27819             return this._childNodes[entity.id];
27820           },
27821           base: function base() {
27822             return {
27823               'entities': Object.getPrototypeOf(this.entities),
27824               'parentWays': Object.getPrototypeOf(this._parentWays),
27825               'parentRels': Object.getPrototypeOf(this._parentRels)
27826             };
27827           },
27828           // Unlike other graph methods, rebase mutates in place. This is because it
27829           // is used only during the history operation that merges newly downloaded
27830           // data into each state. To external consumers, it should appear as if the
27831           // graph always contained the newly downloaded data.
27832           rebase: function rebase(entities, stack, force) {
27833             var base = this.base();
27834             var i, j, k, id;
27835
27836             for (i = 0; i < entities.length; i++) {
27837               var entity = entities[i];
27838               if (!entity.visible || !force && base.entities[entity.id]) continue; // Merging data into the base graph
27839
27840               base.entities[entity.id] = entity;
27841
27842               this._updateCalculated(undefined, entity, base.parentWays, base.parentRels); // Restore provisionally-deleted nodes that are discovered to have an extant parent
27843
27844
27845               if (entity.type === 'way') {
27846                 for (j = 0; j < entity.nodes.length; j++) {
27847                   id = entity.nodes[j];
27848
27849                   for (k = 1; k < stack.length; k++) {
27850                     var ents = stack[k].entities;
27851
27852                     if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27853                       delete ents[id];
27854                     }
27855                   }
27856                 }
27857               }
27858             }
27859
27860             for (i = 0; i < stack.length; i++) {
27861               stack[i]._updateRebased();
27862             }
27863           },
27864           _updateRebased: function _updateRebased() {
27865             var base = this.base();
27866             Object.keys(this._parentWays).forEach(function (child) {
27867               if (base.parentWays[child]) {
27868                 base.parentWays[child].forEach(function (id) {
27869                   if (!this.entities.hasOwnProperty(id)) {
27870                     this._parentWays[child].add(id);
27871                   }
27872                 }, this);
27873               }
27874             }, this);
27875             Object.keys(this._parentRels).forEach(function (child) {
27876               if (base.parentRels[child]) {
27877                 base.parentRels[child].forEach(function (id) {
27878                   if (!this.entities.hasOwnProperty(id)) {
27879                     this._parentRels[child].add(id);
27880                   }
27881                 }, this);
27882               }
27883             }, this);
27884             this.transients = {}; // this._childNodes is not updated, under the assumption that
27885             // ways are always downloaded with their child nodes.
27886           },
27887           // Updates calculated properties (parentWays, parentRels) for the specified change
27888           _updateCalculated: function _updateCalculated(oldentity, entity, parentWays, parentRels) {
27889             parentWays = parentWays || this._parentWays;
27890             parentRels = parentRels || this._parentRels;
27891             var type = entity && entity.type || oldentity && oldentity.type;
27892             var removed, added, i;
27893
27894             if (type === 'way') {
27895               // Update parentWays
27896               if (oldentity && entity) {
27897                 removed = utilArrayDifference(oldentity.nodes, entity.nodes);
27898                 added = utilArrayDifference(entity.nodes, oldentity.nodes);
27899               } else if (oldentity) {
27900                 removed = oldentity.nodes;
27901                 added = [];
27902               } else if (entity) {
27903                 removed = [];
27904                 added = entity.nodes;
27905               }
27906
27907               for (i = 0; i < removed.length; i++) {
27908                 // make a copy of prototype property, store as own property, and update..
27909                 parentWays[removed[i]] = new Set(parentWays[removed[i]]);
27910                 parentWays[removed[i]]["delete"](oldentity.id);
27911               }
27912
27913               for (i = 0; i < added.length; i++) {
27914                 // make a copy of prototype property, store as own property, and update..
27915                 parentWays[added[i]] = new Set(parentWays[added[i]]);
27916                 parentWays[added[i]].add(entity.id);
27917               }
27918             } else if (type === 'relation') {
27919               // Update parentRels
27920               // diff only on the IDs since the same entity can be a member multiple times with different roles
27921               var oldentityMemberIDs = oldentity ? oldentity.members.map(function (m) {
27922                 return m.id;
27923               }) : [];
27924               var entityMemberIDs = entity ? entity.members.map(function (m) {
27925                 return m.id;
27926               }) : [];
27927
27928               if (oldentity && entity) {
27929                 removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
27930                 added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
27931               } else if (oldentity) {
27932                 removed = oldentityMemberIDs;
27933                 added = [];
27934               } else if (entity) {
27935                 removed = [];
27936                 added = entityMemberIDs;
27937               }
27938
27939               for (i = 0; i < removed.length; i++) {
27940                 // make a copy of prototype property, store as own property, and update..
27941                 parentRels[removed[i]] = new Set(parentRels[removed[i]]);
27942                 parentRels[removed[i]]["delete"](oldentity.id);
27943               }
27944
27945               for (i = 0; i < added.length; i++) {
27946                 // make a copy of prototype property, store as own property, and update..
27947                 parentRels[added[i]] = new Set(parentRels[added[i]]);
27948                 parentRels[added[i]].add(entity.id);
27949               }
27950             }
27951           },
27952           replace: function replace(entity) {
27953             if (this.entities[entity.id] === entity) return this;
27954             return this.update(function () {
27955               this._updateCalculated(this.entities[entity.id], entity);
27956
27957               this.entities[entity.id] = entity;
27958             });
27959           },
27960           remove: function remove(entity) {
27961             return this.update(function () {
27962               this._updateCalculated(entity, undefined);
27963
27964               this.entities[entity.id] = undefined;
27965             });
27966           },
27967           revert: function revert(id) {
27968             var baseEntity = this.base().entities[id];
27969             var headEntity = this.entities[id];
27970             if (headEntity === baseEntity) return this;
27971             return this.update(function () {
27972               this._updateCalculated(headEntity, baseEntity);
27973
27974               delete this.entities[id];
27975             });
27976           },
27977           update: function update() {
27978             var graph = this.frozen ? coreGraph(this, true) : this;
27979
27980             for (var i = 0; i < arguments.length; i++) {
27981               arguments[i].call(graph, graph);
27982             }
27983
27984             if (this.frozen) graph.frozen = true;
27985             return graph;
27986           },
27987           // Obliterates any existing entities
27988           load: function load(entities) {
27989             var base = this.base();
27990             this.entities = Object.create(base.entities);
27991
27992             for (var i in entities) {
27993               this.entities[i] = entities[i];
27994
27995               this._updateCalculated(base.entities[i], this.entities[i]);
27996             }
27997
27998             return this;
27999           }
28000         };
28001
28002         function osmTurn(turn) {
28003           if (!(this instanceof osmTurn)) {
28004             return new osmTurn(turn);
28005           }
28006
28007           Object.assign(this, turn);
28008         }
28009         function osmIntersection(graph, startVertexId, maxDistance) {
28010           maxDistance = maxDistance || 30; // in meters
28011
28012           var vgraph = coreGraph(); // virtual graph
28013
28014           var i, j, k;
28015
28016           function memberOfRestriction(entity) {
28017             return graph.parentRelations(entity).some(function (r) {
28018               return r.isRestriction();
28019             });
28020           }
28021
28022           function isRoad(way) {
28023             if (way.isArea() || way.isDegenerate()) return false;
28024             var roads = {
28025               'motorway': true,
28026               'motorway_link': true,
28027               'trunk': true,
28028               'trunk_link': true,
28029               'primary': true,
28030               'primary_link': true,
28031               'secondary': true,
28032               'secondary_link': true,
28033               'tertiary': true,
28034               'tertiary_link': true,
28035               'residential': true,
28036               'unclassified': true,
28037               'living_street': true,
28038               'service': true,
28039               'road': true,
28040               'track': true
28041             };
28042             return roads[way.tags.highway];
28043           }
28044
28045           var startNode = graph.entity(startVertexId);
28046           var checkVertices = [startNode];
28047           var checkWays;
28048           var vertices = [];
28049           var vertexIds = [];
28050           var vertex;
28051           var ways = [];
28052           var wayIds = [];
28053           var way;
28054           var nodes = [];
28055           var node;
28056           var parents = [];
28057           var parent; // `actions` will store whatever actions must be performed to satisfy
28058           // preconditions for adding a turn restriction to this intersection.
28059           //  - Remove any existing degenerate turn restrictions (missing from/to, etc)
28060           //  - Reverse oneways so that they are drawn in the forward direction
28061           //  - Split ways on key vertices
28062
28063           var actions = []; // STEP 1:  walk the graph outwards from starting vertex to search
28064           //  for more key vertices and ways to include in the intersection..
28065
28066           while (checkVertices.length) {
28067             vertex = checkVertices.pop(); // check this vertex for parent ways that are roads
28068
28069             checkWays = graph.parentWays(vertex);
28070             var hasWays = false;
28071
28072             for (i = 0; i < checkWays.length; i++) {
28073               way = checkWays[i];
28074               if (!isRoad(way) && !memberOfRestriction(way)) continue;
28075               ways.push(way); // it's a road, or it's already in a turn restriction
28076
28077               hasWays = true; // check the way's children for more key vertices
28078
28079               nodes = utilArrayUniq(graph.childNodes(way));
28080
28081               for (j = 0; j < nodes.length; j++) {
28082                 node = nodes[j];
28083                 if (node === vertex) continue; // same thing
28084
28085                 if (vertices.indexOf(node) !== -1) continue; // seen it already
28086
28087                 if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start
28088                 // a key vertex will have parents that are also roads
28089
28090                 var hasParents = false;
28091                 parents = graph.parentWays(node);
28092
28093                 for (k = 0; k < parents.length; k++) {
28094                   parent = parents[k];
28095                   if (parent === way) continue; // same thing
28096
28097                   if (ways.indexOf(parent) !== -1) continue; // seen it already
28098
28099                   if (!isRoad(parent)) continue; // not a road
28100
28101                   hasParents = true;
28102                   break;
28103                 }
28104
28105                 if (hasParents) {
28106                   checkVertices.push(node);
28107                 }
28108               }
28109             }
28110
28111             if (hasWays) {
28112               vertices.push(vertex);
28113             }
28114           }
28115
28116           vertices = utilArrayUniq(vertices);
28117           ways = utilArrayUniq(ways); // STEP 2:  Build a virtual graph containing only the entities in the intersection..
28118           // Everything done after this step should act on the virtual graph
28119           // Any actions that must be performed later to the main graph go in `actions` array
28120
28121           ways.forEach(function (way) {
28122             graph.childNodes(way).forEach(function (node) {
28123               vgraph = vgraph.replace(node);
28124             });
28125             vgraph = vgraph.replace(way);
28126             graph.parentRelations(way).forEach(function (relation) {
28127               if (relation.isRestriction()) {
28128                 if (relation.isValidRestriction(graph)) {
28129                   vgraph = vgraph.replace(relation);
28130                 } else if (relation.isComplete(graph)) {
28131                   actions.push(actionDeleteRelation(relation.id));
28132                 }
28133               }
28134             });
28135           }); // STEP 3:  Force all oneways to be drawn in the forward direction
28136
28137           ways.forEach(function (w) {
28138             var way = vgraph.entity(w.id);
28139
28140             if (way.tags.oneway === '-1') {
28141               var action = actionReverse(way.id, {
28142                 reverseOneway: true
28143               });
28144               actions.push(action);
28145               vgraph = action(vgraph);
28146             }
28147           }); // STEP 4:  Split ways on key vertices
28148
28149           var origCount = osmEntity.id.next.way;
28150           vertices.forEach(function (v) {
28151             // This is an odd way to do it, but we need to find all the ways that
28152             // will be split here, then split them one at a time to ensure that these
28153             // actions can be replayed on the main graph exactly in the same order.
28154             // (It is unintuitive, but the order of ways returned from graph.parentWays()
28155             // is arbitrary, depending on how the main graph and vgraph were built)
28156             var splitAll = actionSplit([v.id]).keepHistoryOn('first');
28157
28158             if (!splitAll.disabled(vgraph)) {
28159               splitAll.ways(vgraph).forEach(function (way) {
28160                 var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
28161                 actions.push(splitOne);
28162                 vgraph = splitOne(vgraph);
28163               });
28164             }
28165           }); // In here is where we should also split the intersection at nearby junction.
28166           //   for https://github.com/mapbox/iD-internal/issues/31
28167           // nearbyVertices.forEach(function(v) {
28168           // });
28169           // Reasons why we reset the way id count here:
28170           //  1. Continuity with way ids created by the splits so that we can replay
28171           //     these actions later if the user decides to create a turn restriction
28172           //  2. Avoids churning way ids just by hovering over a vertex
28173           //     and displaying the turn restriction editor
28174
28175           osmEntity.id.next.way = origCount; // STEP 5:  Update arrays to point to vgraph entities
28176
28177           vertexIds = vertices.map(function (v) {
28178             return v.id;
28179           });
28180           vertices = [];
28181           ways = [];
28182           vertexIds.forEach(function (id) {
28183             var vertex = vgraph.entity(id);
28184             var parents = vgraph.parentWays(vertex);
28185             vertices.push(vertex);
28186             ways = ways.concat(parents);
28187           });
28188           vertices = utilArrayUniq(vertices);
28189           ways = utilArrayUniq(ways);
28190           vertexIds = vertices.map(function (v) {
28191             return v.id;
28192           });
28193           wayIds = ways.map(function (w) {
28194             return w.id;
28195           }); // STEP 6:  Update the ways with some metadata that will be useful for
28196           // walking the intersection graph later and rendering turn arrows.
28197
28198           function withMetadata(way, vertexIds) {
28199             var __oneWay = way.isOneWay(); // which affixes are key vertices?
28200
28201
28202             var __first = vertexIds.indexOf(way.first()) !== -1;
28203
28204             var __last = vertexIds.indexOf(way.last()) !== -1; // what roles is this way eligible for?
28205
28206
28207             var __via = __first && __last;
28208
28209             var __from = __first && !__oneWay || __last;
28210
28211             var __to = __first || __last && !__oneWay;
28212
28213             return way.update({
28214               __first: __first,
28215               __last: __last,
28216               __from: __from,
28217               __via: __via,
28218               __to: __to,
28219               __oneWay: __oneWay
28220             });
28221           }
28222
28223           ways = [];
28224           wayIds.forEach(function (id) {
28225             var way = withMetadata(vgraph.entity(id), vertexIds);
28226             vgraph = vgraph.replace(way);
28227             ways.push(way);
28228           }); // STEP 7:  Simplify - This is an iterative process where we:
28229           //  1. Find trivial vertices with only 2 parents
28230           //  2. trim off the leaf way from those vertices and remove from vgraph
28231
28232           var keepGoing;
28233           var removeWayIds = [];
28234           var removeVertexIds = [];
28235
28236           do {
28237             keepGoing = false;
28238             checkVertices = vertexIds.slice();
28239
28240             for (i = 0; i < checkVertices.length; i++) {
28241               var vertexId = checkVertices[i];
28242               vertex = vgraph.hasEntity(vertexId);
28243
28244               if (!vertex) {
28245                 if (vertexIds.indexOf(vertexId) !== -1) {
28246                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28247                 }
28248
28249                 removeVertexIds.push(vertexId);
28250                 continue;
28251               }
28252
28253               parents = vgraph.parentWays(vertex);
28254
28255               if (parents.length < 3) {
28256                 if (vertexIds.indexOf(vertexId) !== -1) {
28257                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28258                 }
28259               }
28260
28261               if (parents.length === 2) {
28262                 // vertex with 2 parents is trivial
28263                 var a = parents[0];
28264                 var b = parents[1];
28265                 var aIsLeaf = a && !a.__via;
28266                 var bIsLeaf = b && !b.__via;
28267                 var leaf, survivor;
28268
28269                 if (aIsLeaf && !bIsLeaf) {
28270                   leaf = a;
28271                   survivor = b;
28272                 } else if (!aIsLeaf && bIsLeaf) {
28273                   leaf = b;
28274                   survivor = a;
28275                 }
28276
28277                 if (leaf && survivor) {
28278                   survivor = withMetadata(survivor, vertexIds); // update survivor way
28279
28280                   vgraph = vgraph.replace(survivor).remove(leaf); // update graph
28281
28282                   removeWayIds.push(leaf.id);
28283                   keepGoing = true;
28284                 }
28285               }
28286
28287               parents = vgraph.parentWays(vertex);
28288
28289               if (parents.length < 2) {
28290                 // vertex is no longer a key vertex
28291                 if (vertexIds.indexOf(vertexId) !== -1) {
28292                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28293                 }
28294
28295                 removeVertexIds.push(vertexId);
28296                 keepGoing = true;
28297               }
28298
28299               if (parents.length < 1) {
28300                 // vertex is no longer attached to anything
28301                 vgraph = vgraph.remove(vertex);
28302               }
28303             }
28304           } while (keepGoing);
28305
28306           vertices = vertices.filter(function (vertex) {
28307             return removeVertexIds.indexOf(vertex.id) === -1;
28308           }).map(function (vertex) {
28309             return vgraph.entity(vertex.id);
28310           });
28311           ways = ways.filter(function (way) {
28312             return removeWayIds.indexOf(way.id) === -1;
28313           }).map(function (way) {
28314             return vgraph.entity(way.id);
28315           }); // OK!  Here is our intersection..
28316
28317           var intersection = {
28318             graph: vgraph,
28319             actions: actions,
28320             vertices: vertices,
28321             ways: ways
28322           }; // Get all the valid turns through this intersection given a starting way id.
28323           // This operates on the virtual graph for everything.
28324           //
28325           // Basically, walk through all possible paths from starting way,
28326           //   honoring the existing turn restrictions as we go (watch out for loops!)
28327           //
28328           // For each path found, generate and return a `osmTurn` datastructure.
28329           //
28330
28331           intersection.turns = function (fromWayId, maxViaWay) {
28332             if (!fromWayId) return [];
28333             if (!maxViaWay) maxViaWay = 0;
28334             var vgraph = intersection.graph;
28335             var keyVertexIds = intersection.vertices.map(function (v) {
28336               return v.id;
28337             });
28338             var start = vgraph.entity(fromWayId);
28339             if (!start || !(start.__from || start.__via)) return []; // maxViaWay=0   from-*-to              (0 vias)
28340             // maxViaWay=1   from-*-via-*-to        (1 via max)
28341             // maxViaWay=2   from-*-via-*-via-*-to  (2 vias max)
28342
28343             var maxPathLength = maxViaWay * 2 + 3;
28344             var turns = [];
28345             step(start);
28346             return turns; // traverse the intersection graph and find all the valid paths
28347
28348             function step(entity, currPath, currRestrictions, matchedRestriction) {
28349               currPath = (currPath || []).slice(); // shallow copy
28350
28351               if (currPath.length >= maxPathLength) return;
28352               currPath.push(entity.id);
28353               currRestrictions = (currRestrictions || []).slice(); // shallow copy
28354
28355               var i, j;
28356
28357               if (entity.type === 'node') {
28358                 var parents = vgraph.parentWays(entity);
28359                 var nextWays = []; // which ways can we step into?
28360
28361                 for (i = 0; i < parents.length; i++) {
28362                   var way = parents[i]; // if next way is a oneway incoming to this vertex, skip
28363
28364                   if (way.__oneWay && way.nodes[0] !== entity.id) continue; // if we have seen it before (allowing for an initial u-turn), skip
28365
28366                   if (currPath.indexOf(way.id) !== -1 && currPath.length >= 3) continue; // Check all "current" restrictions (where we've already walked the `FROM`)
28367
28368                   var restrict = null;
28369
28370                   for (j = 0; j < currRestrictions.length; j++) {
28371                     var restriction = currRestrictions[j];
28372                     var f = restriction.memberByRole('from');
28373                     var v = restriction.membersByRole('via');
28374                     var t = restriction.memberByRole('to');
28375                     var isOnly = /^only_/.test(restriction.tags.restriction); // Does the current path match this turn restriction?
28376
28377                     var matchesFrom = f.id === fromWayId;
28378                     var matchesViaTo = false;
28379                     var isAlongOnlyPath = false;
28380
28381                     if (t.id === way.id) {
28382                       // match TO
28383                       if (v.length === 1 && v[0].type === 'node') {
28384                         // match VIA node
28385                         matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
28386                       } else {
28387                         // match all VIA ways
28388                         var pathVias = [];
28389
28390                         for (k = 2; k < currPath.length; k += 2) {
28391                           // k = 2 skips FROM
28392                           pathVias.push(currPath[k]); // (path goes way-node-way...)
28393                         }
28394
28395                         var restrictionVias = [];
28396
28397                         for (k = 0; k < v.length; k++) {
28398                           if (v[k].type === 'way') {
28399                             restrictionVias.push(v[k].id);
28400                           }
28401                         }
28402
28403                         var diff = utilArrayDifference(pathVias, restrictionVias);
28404                         matchesViaTo = !diff.length;
28405                       }
28406                     } else if (isOnly) {
28407                       for (k = 0; k < v.length; k++) {
28408                         // way doesn't match TO, but is one of the via ways along the path of an "only"
28409                         if (v[k].type === 'way' && v[k].id === way.id) {
28410                           isAlongOnlyPath = true;
28411                           break;
28412                         }
28413                       }
28414                     }
28415
28416                     if (matchesViaTo) {
28417                       if (isOnly) {
28418                         restrict = {
28419                           id: restriction.id,
28420                           direct: matchesFrom,
28421                           from: f.id,
28422                           only: true,
28423                           end: true
28424                         };
28425                       } else {
28426                         restrict = {
28427                           id: restriction.id,
28428                           direct: matchesFrom,
28429                           from: f.id,
28430                           no: true,
28431                           end: true
28432                         };
28433                       }
28434                     } else {
28435                       // indirect - caused by a different nearby restriction
28436                       if (isAlongOnlyPath) {
28437                         restrict = {
28438                           id: restriction.id,
28439                           direct: false,
28440                           from: f.id,
28441                           only: true,
28442                           end: false
28443                         };
28444                       } else if (isOnly) {
28445                         restrict = {
28446                           id: restriction.id,
28447                           direct: false,
28448                           from: f.id,
28449                           no: true,
28450                           end: true
28451                         };
28452                       }
28453                     } // stop looking if we find a "direct" restriction (matching FROM, VIA, TO)
28454
28455
28456                     if (restrict && restrict.direct) break;
28457                   }
28458
28459                   nextWays.push({
28460                     way: way,
28461                     restrict: restrict
28462                   });
28463                 }
28464
28465                 nextWays.forEach(function (nextWay) {
28466                   step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
28467                 });
28468               } else {
28469                 // entity.type === 'way'
28470                 if (currPath.length >= 3) {
28471                   // this is a "complete" path..
28472                   var turnPath = currPath.slice(); // shallow copy
28473                   // an indirect restriction - only include the partial path (starting at FROM)
28474
28475                   if (matchedRestriction && matchedRestriction.direct === false) {
28476                     for (i = 0; i < turnPath.length; i++) {
28477                       if (turnPath[i] === matchedRestriction.from) {
28478                         turnPath = turnPath.slice(i);
28479                         break;
28480                       }
28481                     }
28482                   }
28483
28484                   var turn = pathToTurn(turnPath);
28485
28486                   if (turn) {
28487                     if (matchedRestriction) {
28488                       turn.restrictionID = matchedRestriction.id;
28489                       turn.no = matchedRestriction.no;
28490                       turn.only = matchedRestriction.only;
28491                       turn.direct = matchedRestriction.direct;
28492                     }
28493
28494                     turns.push(osmTurn(turn));
28495                   }
28496
28497                   if (currPath[0] === currPath[2]) return; // if we made a u-turn - stop here
28498                 }
28499
28500                 if (matchedRestriction && matchedRestriction.end) return; // don't advance any further
28501                 // which nodes can we step into?
28502
28503                 var n1 = vgraph.entity(entity.first());
28504                 var n2 = vgraph.entity(entity.last());
28505                 var dist = geoSphericalDistance(n1.loc, n2.loc);
28506                 var nextNodes = [];
28507
28508                 if (currPath.length > 1) {
28509                   if (dist > maxDistance) return; // the next node is too far
28510
28511                   if (!entity.__via) return; // this way is a leaf / can't be a via
28512                 }
28513
28514                 if (!entity.__oneWay && // bidirectional..
28515                 keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
28516                 currPath.indexOf(n1.id) === -1) {
28517                   // haven't seen it yet..
28518                   nextNodes.push(n1); // can advance to first node
28519                 }
28520
28521                 if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
28522                 currPath.indexOf(n2.id) === -1) {
28523                   // haven't seen it yet..
28524                   nextNodes.push(n2); // can advance to last node
28525                 }
28526
28527                 nextNodes.forEach(function (nextNode) {
28528                   // gather restrictions FROM this way
28529                   var fromRestrictions = vgraph.parentRelations(entity).filter(function (r) {
28530                     if (!r.isRestriction()) return false;
28531                     var f = r.memberByRole('from');
28532                     if (!f || f.id !== entity.id) return false;
28533                     var isOnly = /^only_/.test(r.tags.restriction);
28534                     if (!isOnly) return true; // `only_` restrictions only matter along the direction of the VIA - #4849
28535
28536                     var isOnlyVia = false;
28537                     var v = r.membersByRole('via');
28538
28539                     if (v.length === 1 && v[0].type === 'node') {
28540                       // via node
28541                       isOnlyVia = v[0].id === nextNode.id;
28542                     } else {
28543                       // via way(s)
28544                       for (var i = 0; i < v.length; i++) {
28545                         if (v[i].type !== 'way') continue;
28546                         var viaWay = vgraph.entity(v[i].id);
28547
28548                         if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
28549                           isOnlyVia = true;
28550                           break;
28551                         }
28552                       }
28553                     }
28554
28555                     return isOnlyVia;
28556                   });
28557                   step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
28558                 });
28559               }
28560             } // assumes path is alternating way-node-way of odd length
28561
28562
28563             function pathToTurn(path) {
28564               if (path.length < 3) return;
28565               var fromWayId, fromNodeId, fromVertexId;
28566               var toWayId, toNodeId, toVertexId;
28567               var viaWayIds, viaNodeId, isUturn;
28568               fromWayId = path[0];
28569               toWayId = path[path.length - 1];
28570
28571               if (path.length === 3 && fromWayId === toWayId) {
28572                 // u turn
28573                 var way = vgraph.entity(fromWayId);
28574                 if (way.__oneWay) return null;
28575                 isUturn = true;
28576                 viaNodeId = fromVertexId = toVertexId = path[1];
28577                 fromNodeId = toNodeId = adjacentNode(fromWayId, viaNodeId);
28578               } else {
28579                 isUturn = false;
28580                 fromVertexId = path[1];
28581                 fromNodeId = adjacentNode(fromWayId, fromVertexId);
28582                 toVertexId = path[path.length - 2];
28583                 toNodeId = adjacentNode(toWayId, toVertexId);
28584
28585                 if (path.length === 3) {
28586                   viaNodeId = path[1];
28587                 } else {
28588                   viaWayIds = path.filter(function (entityId) {
28589                     return entityId[0] === 'w';
28590                   });
28591                   viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1); // remove first, last
28592                 }
28593               }
28594
28595               return {
28596                 key: path.join('_'),
28597                 path: path,
28598                 from: {
28599                   node: fromNodeId,
28600                   way: fromWayId,
28601                   vertex: fromVertexId
28602                 },
28603                 via: {
28604                   node: viaNodeId,
28605                   ways: viaWayIds
28606                 },
28607                 to: {
28608                   node: toNodeId,
28609                   way: toWayId,
28610                   vertex: toVertexId
28611                 },
28612                 u: isUturn
28613               };
28614
28615               function adjacentNode(wayId, affixId) {
28616                 var nodes = vgraph.entity(wayId).nodes;
28617                 return affixId === nodes[0] ? nodes[1] : nodes[nodes.length - 2];
28618               }
28619             }
28620           };
28621
28622           return intersection;
28623         }
28624         function osmInferRestriction(graph, turn, projection) {
28625           var fromWay = graph.entity(turn.from.way);
28626           var fromNode = graph.entity(turn.from.node);
28627           var fromVertex = graph.entity(turn.from.vertex);
28628           var toWay = graph.entity(turn.to.way);
28629           var toNode = graph.entity(turn.to.node);
28630           var toVertex = graph.entity(turn.to.vertex);
28631           var fromOneWay = fromWay.tags.oneway === 'yes';
28632           var toOneWay = toWay.tags.oneway === 'yes';
28633           var angle = (geoAngle(fromVertex, fromNode, projection) - geoAngle(toVertex, toNode, projection)) * 180 / Math.PI;
28634
28635           while (angle < 0) {
28636             angle += 360;
28637           }
28638
28639           if (fromNode === toNode) return 'no_u_turn';
28640           if ((angle < 23 || angle > 336) && fromOneWay && toOneWay) return 'no_u_turn'; // wider tolerance for u-turn if both ways are oneway
28641
28642           if ((angle < 40 || angle > 319) && fromOneWay && toOneWay && turn.from.vertex !== turn.to.vertex) return 'no_u_turn'; // even wider tolerance for u-turn if there is a via way (from !== to)
28643
28644           if (angle < 158) return 'no_right_turn';
28645           if (angle > 202) return 'no_left_turn';
28646           return 'no_straight_on';
28647         }
28648
28649         function actionMergePolygon(ids, newRelationId) {
28650           function groupEntities(graph) {
28651             var entities = ids.map(function (id) {
28652               return graph.entity(id);
28653             });
28654             var geometryGroups = utilArrayGroupBy(entities, function (entity) {
28655               if (entity.type === 'way' && entity.isClosed()) {
28656                 return 'closedWay';
28657               } else if (entity.type === 'relation' && entity.isMultipolygon()) {
28658                 return 'multipolygon';
28659               } else {
28660                 return 'other';
28661               }
28662             });
28663             return Object.assign({
28664               closedWay: [],
28665               multipolygon: [],
28666               other: []
28667             }, geometryGroups);
28668           }
28669
28670           var action = function action(graph) {
28671             var entities = groupEntities(graph); // An array representing all the polygons that are part of the multipolygon.
28672             //
28673             // Each element is itself an array of objects with an id property, and has a
28674             // locs property which is an array of the locations forming the polygon.
28675
28676             var polygons = entities.multipolygon.reduce(function (polygons, m) {
28677               return polygons.concat(osmJoinWays(m.members, graph));
28678             }, []).concat(entities.closedWay.map(function (d) {
28679               var member = [{
28680                 id: d.id
28681               }];
28682               member.nodes = graph.childNodes(d);
28683               return member;
28684             })); // contained is an array of arrays of boolean values,
28685             // where contained[j][k] is true iff the jth way is
28686             // contained by the kth way.
28687
28688             var contained = polygons.map(function (w, i) {
28689               return polygons.map(function (d, n) {
28690                 if (i === n) return null;
28691                 return geoPolygonContainsPolygon(d.nodes.map(function (n) {
28692                   return n.loc;
28693                 }), w.nodes.map(function (n) {
28694                   return n.loc;
28695                 }));
28696               });
28697             }); // Sort all polygons as either outer or inner ways
28698
28699             var members = [];
28700             var outer = true;
28701
28702             while (polygons.length) {
28703               extractUncontained(polygons);
28704               polygons = polygons.filter(isContained);
28705               contained = contained.filter(isContained).map(filterContained);
28706             }
28707
28708             function isContained(d, i) {
28709               return contained[i].some(function (val) {
28710                 return val;
28711               });
28712             }
28713
28714             function filterContained(d) {
28715               return d.filter(isContained);
28716             }
28717
28718             function extractUncontained(polygons) {
28719               polygons.forEach(function (d, i) {
28720                 if (!isContained(d, i)) {
28721                   d.forEach(function (member) {
28722                     members.push({
28723                       type: 'way',
28724                       id: member.id,
28725                       role: outer ? 'outer' : 'inner'
28726                     });
28727                   });
28728                 }
28729               });
28730               outer = !outer;
28731             } // Move all tags to one relation
28732
28733
28734             var relation = entities.multipolygon[0] || osmRelation({
28735               id: newRelationId,
28736               tags: {
28737                 type: 'multipolygon'
28738               }
28739             });
28740             entities.multipolygon.slice(1).forEach(function (m) {
28741               relation = relation.mergeTags(m.tags);
28742               graph = graph.remove(m);
28743             });
28744             entities.closedWay.forEach(function (way) {
28745               function isThisOuter(m) {
28746                 return m.id === way.id && m.role !== 'inner';
28747               }
28748
28749               if (members.some(isThisOuter)) {
28750                 relation = relation.mergeTags(way.tags);
28751                 graph = graph.replace(way.update({
28752                   tags: {}
28753                 }));
28754               }
28755             });
28756             return graph.replace(relation.update({
28757               members: members,
28758               tags: utilObjectOmit(relation.tags, ['area'])
28759             }));
28760           };
28761
28762           action.disabled = function (graph) {
28763             var entities = groupEntities(graph);
28764
28765             if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
28766               return 'not_eligible';
28767             }
28768
28769             if (!entities.multipolygon.every(function (r) {
28770               return r.isComplete(graph);
28771             })) {
28772               return 'incomplete_relation';
28773             }
28774
28775             if (!entities.multipolygon.length) {
28776               var sharedMultipolygons = [];
28777               entities.closedWay.forEach(function (way, i) {
28778                 if (i === 0) {
28779                   sharedMultipolygons = graph.parentMultipolygons(way);
28780                 } else {
28781                   sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
28782                 }
28783               });
28784               sharedMultipolygons = sharedMultipolygons.filter(function (relation) {
28785                 return relation.members.length === entities.closedWay.length;
28786               });
28787
28788               if (sharedMultipolygons.length) {
28789                 // don't create a new multipolygon if it'd be redundant
28790                 return 'not_eligible';
28791               }
28792             } else if (entities.closedWay.some(function (way) {
28793               return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
28794             })) {
28795               // don't add a way to a multipolygon again if it's already a member
28796               return 'not_eligible';
28797             }
28798           };
28799
28800           return action;
28801         }
28802
28803         var UNSUPPORTED_Y$3 = regexpStickyHelpers.UNSUPPORTED_Y;
28804
28805         // `RegExp.prototype.flags` getter
28806         // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags
28807         if (descriptors && (/./g.flags != 'g' || UNSUPPORTED_Y$3)) {
28808           objectDefineProperty.f(RegExp.prototype, 'flags', {
28809             configurable: true,
28810             get: regexpFlags
28811           });
28812         }
28813
28814         var fastDeepEqual = function equal(a, b) {
28815           if (a === b) return true;
28816
28817           if (a && b && _typeof(a) == 'object' && _typeof(b) == 'object') {
28818             if (a.constructor !== b.constructor) return false;
28819             var length, i, keys;
28820
28821             if (Array.isArray(a)) {
28822               length = a.length;
28823               if (length != b.length) return false;
28824
28825               for (i = length; i-- !== 0;) {
28826                 if (!equal(a[i], b[i])) return false;
28827               }
28828
28829               return true;
28830             }
28831
28832             if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
28833             if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
28834             if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
28835             keys = Object.keys(a);
28836             length = keys.length;
28837             if (length !== Object.keys(b).length) return false;
28838
28839             for (i = length; i-- !== 0;) {
28840               if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
28841             }
28842
28843             for (i = length; i-- !== 0;) {
28844               var key = keys[i];
28845               if (!equal(a[key], b[key])) return false;
28846             }
28847
28848             return true;
28849           } // true if both NaN, false otherwise
28850
28851
28852           return a !== a && b !== b;
28853         };
28854
28855         // J. W. Hunt and M. D. McIlroy, An algorithm for differential buffer
28856         // comparison, Bell Telephone Laboratories CSTR #41 (1976)
28857         // http://www.cs.dartmouth.edu/~doug/
28858         // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
28859         //
28860         // Expects two arrays, finds longest common sequence
28861
28862         function LCS(buffer1, buffer2) {
28863           var equivalenceClasses = {};
28864
28865           for (var j = 0; j < buffer2.length; j++) {
28866             var item = buffer2[j];
28867
28868             if (equivalenceClasses[item]) {
28869               equivalenceClasses[item].push(j);
28870             } else {
28871               equivalenceClasses[item] = [j];
28872             }
28873           }
28874
28875           var NULLRESULT = {
28876             buffer1index: -1,
28877             buffer2index: -1,
28878             chain: null
28879           };
28880           var candidates = [NULLRESULT];
28881
28882           for (var i = 0; i < buffer1.length; i++) {
28883             var _item = buffer1[i];
28884             var buffer2indices = equivalenceClasses[_item] || [];
28885             var r = 0;
28886             var c = candidates[0];
28887
28888             for (var jx = 0; jx < buffer2indices.length; jx++) {
28889               var _j = buffer2indices[jx];
28890               var s = void 0;
28891
28892               for (s = r; s < candidates.length; s++) {
28893                 if (candidates[s].buffer2index < _j && (s === candidates.length - 1 || candidates[s + 1].buffer2index > _j)) {
28894                   break;
28895                 }
28896               }
28897
28898               if (s < candidates.length) {
28899                 var newCandidate = {
28900                   buffer1index: i,
28901                   buffer2index: _j,
28902                   chain: candidates[s]
28903                 };
28904
28905                 if (r === candidates.length) {
28906                   candidates.push(c);
28907                 } else {
28908                   candidates[r] = c;
28909                 }
28910
28911                 r = s + 1;
28912                 c = newCandidate;
28913
28914                 if (r === candidates.length) {
28915                   break; // no point in examining further (j)s
28916                 }
28917               }
28918             }
28919
28920             candidates[r] = c;
28921           } // At this point, we know the LCS: it's in the reverse of the
28922           // linked-list through .chain of candidates[candidates.length - 1].
28923
28924
28925           return candidates[candidates.length - 1];
28926         } // We apply the LCS to build a 'comm'-style picture of the
28927         // offsets and lengths of mismatched chunks in the input
28928         // buffers. This is used by diff3MergeRegions.
28929
28930
28931         function diffIndices(buffer1, buffer2) {
28932           var lcs = LCS(buffer1, buffer2);
28933           var result = [];
28934           var tail1 = buffer1.length;
28935           var tail2 = buffer2.length;
28936
28937           for (var candidate = lcs; candidate !== null; candidate = candidate.chain) {
28938             var mismatchLength1 = tail1 - candidate.buffer1index - 1;
28939             var mismatchLength2 = tail2 - candidate.buffer2index - 1;
28940             tail1 = candidate.buffer1index;
28941             tail2 = candidate.buffer2index;
28942
28943             if (mismatchLength1 || mismatchLength2) {
28944               result.push({
28945                 buffer1: [tail1 + 1, mismatchLength1],
28946                 buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
28947                 buffer2: [tail2 + 1, mismatchLength2],
28948                 buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
28949               });
28950             }
28951           }
28952
28953           result.reverse();
28954           return result;
28955         } // We apply the LCS to build a JSON representation of a
28956         // independently derived from O, returns a fairly complicated
28957         // internal representation of merge decisions it's taken. The
28958         // interested reader may wish to consult
28959         //
28960         // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce.
28961         // 'A Formal Investigation of ' In Arvind and Prasad,
28962         // editors, Foundations of Software Technology and Theoretical
28963         // Computer Science (FSTTCS), December 2007.
28964         //
28965         // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
28966         //
28967
28968
28969         function diff3MergeRegions(a, o, b) {
28970           // "hunks" are array subsets where `a` or `b` are different from `o`
28971           // https://www.gnu.org/software/diffutils/manual/html_node/diff3-Hunks.html
28972           var hunks = [];
28973
28974           function addHunk(h, ab) {
28975             hunks.push({
28976               ab: ab,
28977               oStart: h.buffer1[0],
28978               oLength: h.buffer1[1],
28979               // length of o to remove
28980               abStart: h.buffer2[0],
28981               abLength: h.buffer2[1] // length of a/b to insert
28982               // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
28983
28984             });
28985           }
28986
28987           diffIndices(o, a).forEach(function (item) {
28988             return addHunk(item, 'a');
28989           });
28990           diffIndices(o, b).forEach(function (item) {
28991             return addHunk(item, 'b');
28992           });
28993           hunks.sort(function (x, y) {
28994             return x.oStart - y.oStart;
28995           });
28996           var results = [];
28997           var currOffset = 0;
28998
28999           function advanceTo(endOffset) {
29000             if (endOffset > currOffset) {
29001               results.push({
29002                 stable: true,
29003                 buffer: 'o',
29004                 bufferStart: currOffset,
29005                 bufferLength: endOffset - currOffset,
29006                 bufferContent: o.slice(currOffset, endOffset)
29007               });
29008               currOffset = endOffset;
29009             }
29010           }
29011
29012           while (hunks.length) {
29013             var hunk = hunks.shift();
29014             var regionStart = hunk.oStart;
29015             var regionEnd = hunk.oStart + hunk.oLength;
29016             var regionHunks = [hunk];
29017             advanceTo(regionStart); // Try to pull next overlapping hunk into this region
29018
29019             while (hunks.length) {
29020               var nextHunk = hunks[0];
29021               var nextHunkStart = nextHunk.oStart;
29022               if (nextHunkStart > regionEnd) break; // no overlap
29023
29024               regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
29025               regionHunks.push(hunks.shift());
29026             }
29027
29028             if (regionHunks.length === 1) {
29029               // Only one hunk touches this region, meaning that there is no conflict here.
29030               // Either `a` or `b` is inserting into a region of `o` unchanged by the other.
29031               if (hunk.abLength > 0) {
29032                 var buffer = hunk.ab === 'a' ? a : b;
29033                 results.push({
29034                   stable: true,
29035                   buffer: hunk.ab,
29036                   bufferStart: hunk.abStart,
29037                   bufferLength: hunk.abLength,
29038                   bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
29039                 });
29040               }
29041             } else {
29042               // A true a/b conflict. Determine the bounds involved from `a`, `o`, and `b`.
29043               // Effectively merge all the `a` hunks into one giant hunk, then do the
29044               // same for the `b` hunks; then, correct for skew in the regions of `o`
29045               // that each side changed, and report appropriate spans for the three sides.
29046               var bounds = {
29047                 a: [a.length, -1, o.length, -1],
29048                 b: [b.length, -1, o.length, -1]
29049               };
29050
29051               while (regionHunks.length) {
29052                 hunk = regionHunks.shift();
29053                 var oStart = hunk.oStart;
29054                 var oEnd = oStart + hunk.oLength;
29055                 var abStart = hunk.abStart;
29056                 var abEnd = abStart + hunk.abLength;
29057                 var _b = bounds[hunk.ab];
29058                 _b[0] = Math.min(abStart, _b[0]);
29059                 _b[1] = Math.max(abEnd, _b[1]);
29060                 _b[2] = Math.min(oStart, _b[2]);
29061                 _b[3] = Math.max(oEnd, _b[3]);
29062               }
29063
29064               var aStart = bounds.a[0] + (regionStart - bounds.a[2]);
29065               var aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
29066               var bStart = bounds.b[0] + (regionStart - bounds.b[2]);
29067               var bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
29068               var result = {
29069                 stable: false,
29070                 aStart: aStart,
29071                 aLength: aEnd - aStart,
29072                 aContent: a.slice(aStart, aEnd),
29073                 oStart: regionStart,
29074                 oLength: regionEnd - regionStart,
29075                 oContent: o.slice(regionStart, regionEnd),
29076                 bStart: bStart,
29077                 bLength: bEnd - bStart,
29078                 bContent: b.slice(bStart, bEnd)
29079               };
29080               results.push(result);
29081             }
29082
29083             currOffset = regionEnd;
29084           }
29085
29086           advanceTo(o.length);
29087           return results;
29088         } // Applies the output of diff3MergeRegions to actually
29089         // construct the merged buffer; the returned result alternates
29090         // between 'ok' and 'conflict' blocks.
29091         // A "false conflict" is where `a` and `b` both change the same from `o`
29092
29093
29094         function diff3Merge(a, o, b, options) {
29095           var defaults = {
29096             excludeFalseConflicts: true,
29097             stringSeparator: /\s+/
29098           };
29099           options = Object.assign(defaults, options);
29100           var aString = typeof a === 'string';
29101           var oString = typeof o === 'string';
29102           var bString = typeof b === 'string';
29103           if (aString) a = a.split(options.stringSeparator);
29104           if (oString) o = o.split(options.stringSeparator);
29105           if (bString) b = b.split(options.stringSeparator);
29106           var results = [];
29107           var regions = diff3MergeRegions(a, o, b);
29108           var okBuffer = [];
29109
29110           function flushOk() {
29111             if (okBuffer.length) {
29112               results.push({
29113                 ok: okBuffer
29114               });
29115             }
29116
29117             okBuffer = [];
29118           }
29119
29120           function isFalseConflict(a, b) {
29121             if (a.length !== b.length) return false;
29122
29123             for (var i = 0; i < a.length; i++) {
29124               if (a[i] !== b[i]) return false;
29125             }
29126
29127             return true;
29128           }
29129
29130           regions.forEach(function (region) {
29131             if (region.stable) {
29132               var _okBuffer;
29133
29134               (_okBuffer = okBuffer).push.apply(_okBuffer, _toConsumableArray(region.bufferContent));
29135             } else {
29136               if (options.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
29137                 var _okBuffer2;
29138
29139                 (_okBuffer2 = okBuffer).push.apply(_okBuffer2, _toConsumableArray(region.aContent));
29140               } else {
29141                 flushOk();
29142                 results.push({
29143                   conflict: {
29144                     a: region.aContent,
29145                     aIndex: region.aStart,
29146                     o: region.oContent,
29147                     oIndex: region.oStart,
29148                     b: region.bContent,
29149                     bIndex: region.bStart
29150                   }
29151                 });
29152               }
29153             }
29154           });
29155           flushOk();
29156           return results;
29157         }
29158
29159         function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTags, formatUser) {
29160           discardTags = discardTags || {};
29161           var _option = 'safe'; // 'safe', 'force_local', 'force_remote'
29162
29163           var _conflicts = [];
29164
29165           function user(d) {
29166             return typeof formatUser === 'function' ? formatUser(d) : d;
29167           }
29168
29169           function mergeLocation(remote, target) {
29170             function pointEqual(a, b) {
29171               var epsilon = 1e-6;
29172               return Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon;
29173             }
29174
29175             if (_option === 'force_local' || pointEqual(target.loc, remote.loc)) {
29176               return target;
29177             }
29178
29179             if (_option === 'force_remote') {
29180               return target.update({
29181                 loc: remote.loc
29182               });
29183             }
29184
29185             _conflicts.push(_t('merge_remote_changes.conflict.location', {
29186               user: user(remote.user)
29187             }));
29188
29189             return target;
29190           }
29191
29192           function mergeNodes(base, remote, target) {
29193             if (_option === 'force_local' || fastDeepEqual(target.nodes, remote.nodes)) {
29194               return target;
29195             }
29196
29197             if (_option === 'force_remote') {
29198               return target.update({
29199                 nodes: remote.nodes
29200               });
29201             }
29202
29203             var ccount = _conflicts.length;
29204             var o = base.nodes || [];
29205             var a = target.nodes || [];
29206             var b = remote.nodes || [];
29207             var nodes = [];
29208             var hunks = diff3Merge(a, o, b, {
29209               excludeFalseConflicts: true
29210             });
29211
29212             for (var i = 0; i < hunks.length; i++) {
29213               var hunk = hunks[i];
29214
29215               if (hunk.ok) {
29216                 nodes.push.apply(nodes, hunk.ok);
29217               } else {
29218                 // for all conflicts, we can assume c.a !== c.b
29219                 // because `diff3Merge` called with `true` option to exclude false conflicts..
29220                 var c = hunk.conflict;
29221
29222                 if (fastDeepEqual(c.o, c.a)) {
29223                   // only changed remotely
29224                   nodes.push.apply(nodes, c.b);
29225                 } else if (fastDeepEqual(c.o, c.b)) {
29226                   // only changed locally
29227                   nodes.push.apply(nodes, c.a);
29228                 } else {
29229                   // changed both locally and remotely
29230                   _conflicts.push(_t('merge_remote_changes.conflict.nodelist', {
29231                     user: user(remote.user)
29232                   }));
29233
29234                   break;
29235                 }
29236               }
29237             }
29238
29239             return _conflicts.length === ccount ? target.update({
29240               nodes: nodes
29241             }) : target;
29242           }
29243
29244           function mergeChildren(targetWay, children, updates, graph) {
29245             function isUsed(node, targetWay) {
29246               var hasInterestingParent = graph.parentWays(node).some(function (way) {
29247                 return way.id !== targetWay.id;
29248               });
29249               return node.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node).length > 0;
29250             }
29251
29252             var ccount = _conflicts.length;
29253
29254             for (var i = 0; i < children.length; i++) {
29255               var id = children[i];
29256               var node = graph.hasEntity(id); // remove unused childNodes..
29257
29258               if (targetWay.nodes.indexOf(id) === -1) {
29259                 if (node && !isUsed(node, targetWay)) {
29260                   updates.removeIds.push(id);
29261                 }
29262
29263                 continue;
29264               } // restore used childNodes..
29265
29266
29267               var local = localGraph.hasEntity(id);
29268               var remote = remoteGraph.hasEntity(id);
29269               var target;
29270
29271               if (_option === 'force_remote' && remote && remote.visible) {
29272                 updates.replacements.push(remote);
29273               } else if (_option === 'force_local' && local) {
29274                 target = osmEntity(local);
29275
29276                 if (remote) {
29277                   target = target.update({
29278                     version: remote.version
29279                   });
29280                 }
29281
29282                 updates.replacements.push(target);
29283               } else if (_option === 'safe' && local && remote && local.version !== remote.version) {
29284                 target = osmEntity(local, {
29285                   version: remote.version
29286                 });
29287
29288                 if (remote.visible) {
29289                   target = mergeLocation(remote, target);
29290                 } else {
29291                   _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29292                     user: user(remote.user)
29293                   }));
29294                 }
29295
29296                 if (_conflicts.length !== ccount) break;
29297                 updates.replacements.push(target);
29298               }
29299             }
29300
29301             return targetWay;
29302           }
29303
29304           function updateChildren(updates, graph) {
29305             for (var i = 0; i < updates.replacements.length; i++) {
29306               graph = graph.replace(updates.replacements[i]);
29307             }
29308
29309             if (updates.removeIds.length) {
29310               graph = actionDeleteMultiple(updates.removeIds)(graph);
29311             }
29312
29313             return graph;
29314           }
29315
29316           function mergeMembers(remote, target) {
29317             if (_option === 'force_local' || fastDeepEqual(target.members, remote.members)) {
29318               return target;
29319             }
29320
29321             if (_option === 'force_remote') {
29322               return target.update({
29323                 members: remote.members
29324               });
29325             }
29326
29327             _conflicts.push(_t('merge_remote_changes.conflict.memberlist', {
29328               user: user(remote.user)
29329             }));
29330
29331             return target;
29332           }
29333
29334           function mergeTags(base, remote, target) {
29335             if (_option === 'force_local' || fastDeepEqual(target.tags, remote.tags)) {
29336               return target;
29337             }
29338
29339             if (_option === 'force_remote') {
29340               return target.update({
29341                 tags: remote.tags
29342               });
29343             }
29344
29345             var ccount = _conflicts.length;
29346             var o = base.tags || {};
29347             var a = target.tags || {};
29348             var b = remote.tags || {};
29349             var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function (k) {
29350               return !discardTags[k];
29351             });
29352             var tags = Object.assign({}, a); // shallow copy
29353
29354             var changed = false;
29355
29356             for (var i = 0; i < keys.length; i++) {
29357               var k = keys[i];
29358
29359               if (o[k] !== b[k] && a[k] !== b[k]) {
29360                 // changed remotely..
29361                 if (o[k] !== a[k]) {
29362                   // changed locally..
29363                   _conflicts.push(_t('merge_remote_changes.conflict.tags', {
29364                     tag: k,
29365                     local: a[k],
29366                     remote: b[k],
29367                     user: user(remote.user)
29368                   }));
29369                 } else {
29370                   // unchanged locally, accept remote change..
29371                   if (b.hasOwnProperty(k)) {
29372                     tags[k] = b[k];
29373                   } else {
29374                     delete tags[k];
29375                   }
29376
29377                   changed = true;
29378                 }
29379               }
29380             }
29381
29382             return changed && _conflicts.length === ccount ? target.update({
29383               tags: tags
29384             }) : target;
29385           } //  `graph.base()` is the common ancestor of the two graphs.
29386           //  `localGraph` contains user's edits up to saving
29387           //  `remoteGraph` contains remote edits to modified nodes
29388           //  `graph` must be a descendent of `localGraph` and may include
29389           //      some conflict resolution actions performed on it.
29390           //
29391           //                  --- ... --- `localGraph` -- ... -- `graph`
29392           //                 /
29393           //  `graph.base()` --- ... --- `remoteGraph`
29394           //
29395
29396
29397           var action = function action(graph) {
29398             var updates = {
29399               replacements: [],
29400               removeIds: []
29401             };
29402             var base = graph.base().entities[id];
29403             var local = localGraph.entity(id);
29404             var remote = remoteGraph.entity(id);
29405             var target = osmEntity(local, {
29406               version: remote.version
29407             }); // delete/undelete
29408
29409             if (!remote.visible) {
29410               if (_option === 'force_remote') {
29411                 return actionDeleteMultiple([id])(graph);
29412               } else if (_option === 'force_local') {
29413                 if (target.type === 'way') {
29414                   target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
29415                   graph = updateChildren(updates, graph);
29416                 }
29417
29418                 return graph.replace(target);
29419               } else {
29420                 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29421                   user: user(remote.user)
29422                 }));
29423
29424                 return graph; // do nothing
29425               }
29426             } // merge
29427
29428
29429             if (target.type === 'node') {
29430               target = mergeLocation(remote, target);
29431             } else if (target.type === 'way') {
29432               // pull in any child nodes that may not be present locally..
29433               graph.rebase(remoteGraph.childNodes(remote), [graph], false);
29434               target = mergeNodes(base, remote, target);
29435               target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
29436             } else if (target.type === 'relation') {
29437               target = mergeMembers(remote, target);
29438             }
29439
29440             target = mergeTags(base, remote, target);
29441
29442             if (!_conflicts.length) {
29443               graph = updateChildren(updates, graph).replace(target);
29444             }
29445
29446             return graph;
29447           };
29448
29449           action.withOption = function (opt) {
29450             _option = opt;
29451             return action;
29452           };
29453
29454           action.conflicts = function () {
29455             return _conflicts;
29456           };
29457
29458           return action;
29459         }
29460
29461         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
29462
29463         function actionMove(moveIDs, tryDelta, projection, cache) {
29464           var _delta = tryDelta;
29465
29466           function setupCache(graph) {
29467             function canMove(nodeID) {
29468               // Allow movement of any node that is in the selectedIDs list..
29469               if (moveIDs.indexOf(nodeID) !== -1) return true; // Allow movement of a vertex where 2 ways meet..
29470
29471               var parents = graph.parentWays(graph.entity(nodeID));
29472               if (parents.length < 3) return true; // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
29473
29474               var parentsMoving = parents.every(function (way) {
29475                 return cache.moving[way.id];
29476               });
29477               if (!parentsMoving) delete cache.moving[nodeID];
29478               return parentsMoving;
29479             }
29480
29481             function cacheEntities(ids) {
29482               for (var i = 0; i < ids.length; i++) {
29483                 var id = ids[i];
29484                 if (cache.moving[id]) continue;
29485                 cache.moving[id] = true;
29486                 var entity = graph.hasEntity(id);
29487                 if (!entity) continue;
29488
29489                 if (entity.type === 'node') {
29490                   cache.nodes.push(id);
29491                   cache.startLoc[id] = entity.loc;
29492                 } else if (entity.type === 'way') {
29493                   cache.ways.push(id);
29494                   cacheEntities(entity.nodes);
29495                 } else {
29496                   cacheEntities(entity.members.map(function (member) {
29497                     return member.id;
29498                   }));
29499                 }
29500               }
29501             }
29502
29503             function cacheIntersections(ids) {
29504               function isEndpoint(way, id) {
29505                 return !way.isClosed() && !!way.affix(id);
29506               }
29507
29508               for (var i = 0; i < ids.length; i++) {
29509                 var id = ids[i]; // consider only intersections with 1 moved and 1 unmoved way.
29510
29511                 var childNodes = graph.childNodes(graph.entity(id));
29512
29513                 for (var j = 0; j < childNodes.length; j++) {
29514                   var node = childNodes[j];
29515                   var parents = graph.parentWays(node);
29516                   if (parents.length !== 2) continue;
29517                   var moved = graph.entity(id);
29518                   var unmoved = null;
29519
29520                   for (var k = 0; k < parents.length; k++) {
29521                     var way = parents[k];
29522
29523                     if (!cache.moving[way.id]) {
29524                       unmoved = way;
29525                       break;
29526                     }
29527                   }
29528
29529                   if (!unmoved) continue; // exclude ways that are overly connected..
29530
29531                   if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
29532                   if (moved.isArea() || unmoved.isArea()) continue;
29533                   cache.intersections.push({
29534                     nodeId: node.id,
29535                     movedId: moved.id,
29536                     unmovedId: unmoved.id,
29537                     movedIsEP: isEndpoint(moved, node.id),
29538                     unmovedIsEP: isEndpoint(unmoved, node.id)
29539                   });
29540                 }
29541               }
29542             }
29543
29544             if (!cache) {
29545               cache = {};
29546             }
29547
29548             if (!cache.ok) {
29549               cache.moving = {};
29550               cache.intersections = [];
29551               cache.replacedVertex = {};
29552               cache.startLoc = {};
29553               cache.nodes = [];
29554               cache.ways = [];
29555               cacheEntities(moveIDs);
29556               cacheIntersections(cache.ways);
29557               cache.nodes = cache.nodes.filter(canMove);
29558               cache.ok = true;
29559             }
29560           } // Place a vertex where the moved vertex used to be, to preserve way shape..
29561           //
29562           //  Start:
29563           //      b ---- e
29564           //     / \
29565           //    /   \
29566           //   /     \
29567           //  a       c
29568           //
29569           //      *               node '*' added to preserve shape
29570           //     / \
29571           //    /   b ---- e      way `b,e` moved here:
29572           //   /     \
29573           //  a       c
29574           //
29575           //
29576
29577
29578           function replaceMovedVertex(nodeId, wayId, graph, delta) {
29579             var way = graph.entity(wayId);
29580             var moved = graph.entity(nodeId);
29581             var movedIndex = way.nodes.indexOf(nodeId);
29582             var len, prevIndex, nextIndex;
29583
29584             if (way.isClosed()) {
29585               len = way.nodes.length - 1;
29586               prevIndex = (movedIndex + len - 1) % len;
29587               nextIndex = (movedIndex + len + 1) % len;
29588             } else {
29589               len = way.nodes.length;
29590               prevIndex = movedIndex - 1;
29591               nextIndex = movedIndex + 1;
29592             }
29593
29594             var prev = graph.hasEntity(way.nodes[prevIndex]);
29595             var next = graph.hasEntity(way.nodes[nextIndex]); // Don't add orig vertex at endpoint..
29596
29597             if (!prev || !next) return graph;
29598             var key = wayId + '_' + nodeId;
29599             var orig = cache.replacedVertex[key];
29600
29601             if (!orig) {
29602               orig = osmNode();
29603               cache.replacedVertex[key] = orig;
29604               cache.startLoc[orig.id] = cache.startLoc[nodeId];
29605             }
29606
29607             var start, end;
29608
29609             if (delta) {
29610               start = projection(cache.startLoc[nodeId]);
29611               end = projection.invert(geoVecAdd(start, delta));
29612             } else {
29613               end = cache.startLoc[nodeId];
29614             }
29615
29616             orig = orig.move(end);
29617             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..
29618
29619             if (angle > 175 && angle < 185) return graph; // moving forward or backward along way?
29620
29621             var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection);
29622             var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection);
29623             var d1 = geoPathLength(p1);
29624             var d2 = geoPathLength(p2);
29625             var insertAt = d1 <= d2 ? movedIndex : nextIndex; // moving around closed loop?
29626
29627             if (way.isClosed() && insertAt === 0) insertAt = len;
29628             way = way.addNode(orig.id, insertAt);
29629             return graph.replace(orig).replace(way);
29630           } // Remove duplicate vertex that might have been added by
29631           // replaceMovedVertex.  This is done after the unzorro checks.
29632
29633
29634           function removeDuplicateVertices(wayId, graph) {
29635             var way = graph.entity(wayId);
29636             var epsilon = 1e-6;
29637             var prev, curr;
29638
29639             function isInteresting(node, graph) {
29640               return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
29641             }
29642
29643             for (var i = 0; i < way.nodes.length; i++) {
29644               curr = graph.entity(way.nodes[i]);
29645
29646               if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon)) {
29647                 if (!isInteresting(prev, graph)) {
29648                   way = way.removeNode(prev.id);
29649                   graph = graph.replace(way).remove(prev);
29650                 } else if (!isInteresting(curr, graph)) {
29651                   way = way.removeNode(curr.id);
29652                   graph = graph.replace(way).remove(curr);
29653                 }
29654               }
29655
29656               prev = curr;
29657             }
29658
29659             return graph;
29660           } // Reorder nodes around intersections that have moved..
29661           //
29662           //  Start:                way1.nodes: b,e         (moving)
29663           //  a - b - c ----- d     way2.nodes: a,b,c,d     (static)
29664           //      |                 vertex: b
29665           //      e                 isEP1: true,  isEP2, false
29666           //
29667           //  way1 `b,e` moved here:
29668           //  a ----- c = b - d
29669           //              |
29670           //              e
29671           //
29672           //  reorder nodes         way1.nodes: b,e
29673           //  a ----- c - b - d     way2.nodes: a,c,b,d
29674           //              |
29675           //              e
29676           //
29677
29678
29679           function unZorroIntersection(intersection, graph) {
29680             var vertex = graph.entity(intersection.nodeId);
29681             var way1 = graph.entity(intersection.movedId);
29682             var way2 = graph.entity(intersection.unmovedId);
29683             var isEP1 = intersection.movedIsEP;
29684             var isEP2 = intersection.unmovedIsEP; // don't move the vertex if it is the endpoint of both ways.
29685
29686             if (isEP1 && isEP2) return graph;
29687             var nodes1 = graph.childNodes(way1).filter(function (n) {
29688               return n !== vertex;
29689             });
29690             var nodes2 = graph.childNodes(way2).filter(function (n) {
29691               return n !== vertex;
29692             });
29693             if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
29694             if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
29695             var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection);
29696             var edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection);
29697             var loc; // snap vertex to nearest edge (or some point between them)..
29698
29699             if (!isEP1 && !isEP2) {
29700               var epsilon = 1e-6,
29701                   maxIter = 10;
29702
29703               for (var i = 0; i < maxIter; i++) {
29704                 loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
29705                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
29706                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
29707                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
29708               }
29709             } else if (!isEP1) {
29710               loc = edge1.loc;
29711             } else {
29712               loc = edge2.loc;
29713             }
29714
29715             graph = graph.replace(vertex.move(loc)); // if zorro happened, reorder nodes..
29716
29717             if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
29718               way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
29719               graph = graph.replace(way1);
29720             }
29721
29722             if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
29723               way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
29724               graph = graph.replace(way2);
29725             }
29726
29727             return graph;
29728           }
29729
29730           function cleanupIntersections(graph) {
29731             for (var i = 0; i < cache.intersections.length; i++) {
29732               var obj = cache.intersections[i];
29733               graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
29734               graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
29735               graph = unZorroIntersection(obj, graph);
29736               graph = removeDuplicateVertices(obj.movedId, graph);
29737               graph = removeDuplicateVertices(obj.unmovedId, graph);
29738             }
29739
29740             return graph;
29741           } // check if moving way endpoint can cross an unmoved way, if so limit delta..
29742
29743
29744           function limitDelta(graph) {
29745             function moveNode(loc) {
29746               return geoVecAdd(projection(loc), _delta);
29747             }
29748
29749             for (var i = 0; i < cache.intersections.length; i++) {
29750               var obj = cache.intersections[i]; // Don't limit movement if this is vertex joins 2 endpoints..
29751
29752               if (obj.movedIsEP && obj.unmovedIsEP) continue; // Don't limit movement if this vertex is not an endpoint anyway..
29753
29754               if (!obj.movedIsEP) continue;
29755               var node = graph.entity(obj.nodeId);
29756               var start = projection(node.loc);
29757               var end = geoVecAdd(start, _delta);
29758               var movedNodes = graph.childNodes(graph.entity(obj.movedId));
29759               var movedPath = movedNodes.map(function (n) {
29760                 return moveNode(n.loc);
29761               });
29762               var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
29763               var unmovedPath = unmovedNodes.map(function (n) {
29764                 return projection(n.loc);
29765               });
29766               var hits = geoPathIntersections(movedPath, unmovedPath);
29767
29768               for (var j = 0; i < hits.length; i++) {
29769                 if (geoVecEqual(hits[j], end)) continue;
29770                 var edge = geoChooseEdge(unmovedNodes, end, projection);
29771                 _delta = geoVecSubtract(projection(edge.loc), start);
29772               }
29773             }
29774           }
29775
29776           var action = function action(graph) {
29777             if (_delta[0] === 0 && _delta[1] === 0) return graph;
29778             setupCache(graph);
29779
29780             if (cache.intersections.length) {
29781               limitDelta(graph);
29782             }
29783
29784             for (var i = 0; i < cache.nodes.length; i++) {
29785               var node = graph.entity(cache.nodes[i]);
29786               var start = projection(node.loc);
29787               var end = geoVecAdd(start, _delta);
29788               graph = graph.replace(node.move(projection.invert(end)));
29789             }
29790
29791             if (cache.intersections.length) {
29792               graph = cleanupIntersections(graph);
29793             }
29794
29795             return graph;
29796           };
29797
29798           action.delta = function () {
29799             return _delta;
29800           };
29801
29802           return action;
29803         }
29804
29805         function actionMoveMember(relationId, fromIndex, toIndex) {
29806           return function (graph) {
29807             return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
29808           };
29809         }
29810
29811         function actionMoveNode(nodeID, toLoc) {
29812           var action = function action(graph, t) {
29813             if (t === null || !isFinite(t)) t = 1;
29814             t = Math.min(Math.max(+t, 0), 1);
29815             var node = graph.entity(nodeID);
29816             return graph.replace(node.move(geoVecInterp(node.loc, toLoc, t)));
29817           };
29818
29819           action.transitionable = true;
29820           return action;
29821         }
29822
29823         function actionNoop() {
29824           return function (graph) {
29825             return graph;
29826           };
29827         }
29828
29829         function actionOrthogonalize(wayID, projection, vertexID, degThresh, ep) {
29830           var epsilon = ep || 1e-4;
29831           var threshold = degThresh || 13; // degrees within right or straight to alter
29832           // We test normalized dot products so we can compare as cos(angle)
29833
29834           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
29835           var upperThreshold = Math.cos(threshold * Math.PI / 180);
29836
29837           var action = function action(graph, t) {
29838             if (t === null || !isFinite(t)) t = 1;
29839             t = Math.min(Math.max(+t, 0), 1);
29840             var way = graph.entity(wayID);
29841             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
29842
29843             if (way.tags.nonsquare) {
29844               var tags = Object.assign({}, way.tags); // since we're squaring, remove indication that this is physically unsquare
29845
29846               delete tags.nonsquare;
29847               way = way.update({
29848                 tags: tags
29849               });
29850             }
29851
29852             graph = graph.replace(way);
29853             var isClosed = way.isClosed();
29854             var nodes = graph.childNodes(way).slice(); // shallow copy
29855
29856             if (isClosed) nodes.pop();
29857
29858             if (vertexID !== undefined) {
29859               nodes = nodeSubset(nodes, vertexID, isClosed);
29860               if (nodes.length !== 3) return graph;
29861             } // note: all geometry functions here use the unclosed node/point/coord list
29862
29863
29864             var nodeCount = {};
29865             var points = [];
29866             var corner = {
29867               i: 0,
29868               dotp: 1
29869             };
29870             var node, point, loc, score, motions, i, j;
29871
29872             for (i = 0; i < nodes.length; i++) {
29873               node = nodes[i];
29874               nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
29875               points.push({
29876                 id: node.id,
29877                 coord: projection(node.loc)
29878               });
29879             }
29880
29881             if (points.length === 3) {
29882               // move only one vertex for right triangle
29883               for (i = 0; i < 1000; i++) {
29884                 motions = points.map(calcMotion);
29885                 points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
29886                 score = corner.dotp;
29887
29888                 if (score < epsilon) {
29889                   break;
29890                 }
29891               }
29892
29893               node = graph.entity(nodes[corner.i].id);
29894               loc = projection.invert(points[corner.i].coord);
29895               graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
29896             } else {
29897               var straights = [];
29898               var simplified = []; // Remove points from nearly straight sections..
29899               // This produces a simplified shape to orthogonalize
29900
29901               for (i = 0; i < points.length; i++) {
29902                 point = points[i];
29903                 var dotp = 0;
29904
29905                 if (isClosed || i > 0 && i < points.length - 1) {
29906                   var a = points[(i - 1 + points.length) % points.length];
29907                   var b = points[(i + 1) % points.length];
29908                   dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
29909                 }
29910
29911                 if (dotp > upperThreshold) {
29912                   straights.push(point);
29913                 } else {
29914                   simplified.push(point);
29915                 }
29916               } // Orthogonalize the simplified shape
29917
29918
29919               var bestPoints = clonePoints(simplified);
29920               var originalPoints = clonePoints(simplified);
29921               score = Infinity;
29922
29923               for (i = 0; i < 1000; i++) {
29924                 motions = simplified.map(calcMotion);
29925
29926                 for (j = 0; j < motions.length; j++) {
29927                   simplified[j].coord = geoVecAdd(simplified[j].coord, motions[j]);
29928                 }
29929
29930                 var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon, threshold);
29931
29932                 if (newScore < score) {
29933                   bestPoints = clonePoints(simplified);
29934                   score = newScore;
29935                 }
29936
29937                 if (score < epsilon) {
29938                   break;
29939                 }
29940               }
29941
29942               var bestCoords = bestPoints.map(function (p) {
29943                 return p.coord;
29944               });
29945               if (isClosed) bestCoords.push(bestCoords[0]); // move the nodes that should move
29946
29947               for (i = 0; i < bestPoints.length; i++) {
29948                 point = bestPoints[i];
29949
29950                 if (!geoVecEqual(originalPoints[i].coord, point.coord)) {
29951                   node = graph.entity(point.id);
29952                   loc = projection.invert(point.coord);
29953                   graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
29954                 }
29955               } // move the nodes along straight segments
29956
29957
29958               for (i = 0; i < straights.length; i++) {
29959                 point = straights[i];
29960                 if (nodeCount[point.id] > 1) continue; // skip self-intersections
29961
29962                 node = graph.entity(point.id);
29963
29964                 if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
29965                   // remove uninteresting points..
29966                   graph = actionDeleteNode(node.id)(graph);
29967                 } else {
29968                   // move interesting points to the nearest edge..
29969                   var choice = geoVecProject(point.coord, bestCoords);
29970
29971                   if (choice) {
29972                     loc = projection.invert(choice.target);
29973                     graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
29974                   }
29975                 }
29976               }
29977             }
29978
29979             return graph;
29980
29981             function clonePoints(array) {
29982               return array.map(function (p) {
29983                 return {
29984                   id: p.id,
29985                   coord: [p.coord[0], p.coord[1]]
29986                 };
29987               });
29988             }
29989
29990             function calcMotion(point, i, array) {
29991               // don't try to move the endpoints of a non-closed way.
29992               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)
29993
29994               if (nodeCount[array[i].id] > 1) return [0, 0];
29995               var a = array[(i - 1 + array.length) % array.length].coord;
29996               var origin = point.coord;
29997               var b = array[(i + 1) % array.length].coord;
29998               var p = geoVecSubtract(a, origin);
29999               var q = geoVecSubtract(b, origin);
30000               var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
30001               p = geoVecNormalize(p);
30002               q = geoVecNormalize(q);
30003               var dotp = p[0] * q[0] + p[1] * q[1];
30004               var val = Math.abs(dotp);
30005
30006               if (val < lowerThreshold) {
30007                 // nearly orthogonal
30008                 corner.i = i;
30009                 corner.dotp = val;
30010                 var vec = geoVecNormalize(geoVecAdd(p, q));
30011                 return geoVecScale(vec, 0.1 * dotp * scale);
30012               }
30013
30014               return [0, 0]; // do nothing
30015             }
30016           }; // if we are only orthogonalizing one vertex,
30017           // get that vertex and the previous and next
30018
30019
30020           function nodeSubset(nodes, vertexID, isClosed) {
30021             var first = isClosed ? 0 : 1;
30022             var last = isClosed ? nodes.length : nodes.length - 1;
30023
30024             for (var i = first; i < last; i++) {
30025               if (nodes[i].id === vertexID) {
30026                 return [nodes[(i - 1 + nodes.length) % nodes.length], nodes[i], nodes[(i + 1) % nodes.length]];
30027               }
30028             }
30029
30030             return [];
30031           }
30032
30033           action.disabled = function (graph) {
30034             var way = graph.entity(wayID);
30035             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
30036
30037             graph = graph.replace(way);
30038             var isClosed = way.isClosed();
30039             var nodes = graph.childNodes(way).slice(); // shallow copy
30040
30041             if (isClosed) nodes.pop();
30042             var allowStraightAngles = false;
30043
30044             if (vertexID !== undefined) {
30045               allowStraightAngles = true;
30046               nodes = nodeSubset(nodes, vertexID, isClosed);
30047               if (nodes.length !== 3) return 'end_vertex';
30048             }
30049
30050             var coords = nodes.map(function (n) {
30051               return projection(n.loc);
30052             });
30053             var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles);
30054
30055             if (score === null) {
30056               return 'not_squarish';
30057             } else if (score === 0) {
30058               return 'square_enough';
30059             } else {
30060               return false;
30061             }
30062           };
30063
30064           action.transitionable = true;
30065           return action;
30066         }
30067
30068         //
30069         // `turn` must be an `osmTurn` object
30070         // see osm/intersection.js, pathToTurn()
30071         //
30072         // This specifies a restriction of type `restriction` when traveling from
30073         // `turn.from.way` toward `turn.to.way` via `turn.via.node` OR `turn.via.ways`.
30074         // (The action does not check that these entities form a valid intersection.)
30075         //
30076         // From, to, and via ways should be split before calling this action.
30077         // (old versions of the code would split the ways here, but we no longer do it)
30078         //
30079         // For testing convenience, accepts a restrictionID to assign to the new
30080         // relation. Normally, this will be undefined and the relation will
30081         // automatically be assigned a new ID.
30082         //
30083
30084         function actionRestrictTurn(turn, restrictionType, restrictionID) {
30085           return function (graph) {
30086             var fromWay = graph.entity(turn.from.way);
30087             var toWay = graph.entity(turn.to.way);
30088             var viaNode = turn.via.node && graph.entity(turn.via.node);
30089             var viaWays = turn.via.ways && turn.via.ways.map(function (id) {
30090               return graph.entity(id);
30091             });
30092             var members = [];
30093             members.push({
30094               id: fromWay.id,
30095               type: 'way',
30096               role: 'from'
30097             });
30098
30099             if (viaNode) {
30100               members.push({
30101                 id: viaNode.id,
30102                 type: 'node',
30103                 role: 'via'
30104               });
30105             } else if (viaWays) {
30106               viaWays.forEach(function (viaWay) {
30107                 members.push({
30108                   id: viaWay.id,
30109                   type: 'way',
30110                   role: 'via'
30111                 });
30112               });
30113             }
30114
30115             members.push({
30116               id: toWay.id,
30117               type: 'way',
30118               role: 'to'
30119             });
30120             return graph.replace(osmRelation({
30121               id: restrictionID,
30122               tags: {
30123                 type: 'restriction',
30124                 restriction: restrictionType
30125               },
30126               members: members
30127             }));
30128           };
30129         }
30130
30131         function actionRevert(id) {
30132           var action = function action(graph) {
30133             var entity = graph.hasEntity(id),
30134                 base = graph.base().entities[id];
30135
30136             if (entity && !base) {
30137               // entity will be removed..
30138               if (entity.type === 'node') {
30139                 graph.parentWays(entity).forEach(function (parent) {
30140                   parent = parent.removeNode(id);
30141                   graph = graph.replace(parent);
30142
30143                   if (parent.isDegenerate()) {
30144                     graph = actionDeleteWay(parent.id)(graph);
30145                   }
30146                 });
30147               }
30148
30149               graph.parentRelations(entity).forEach(function (parent) {
30150                 parent = parent.removeMembersWithID(id);
30151                 graph = graph.replace(parent);
30152
30153                 if (parent.isDegenerate()) {
30154                   graph = actionDeleteRelation(parent.id)(graph);
30155                 }
30156               });
30157             }
30158
30159             return graph.revert(id);
30160           };
30161
30162           return action;
30163         }
30164
30165         function actionRotate(rotateIds, pivot, angle, projection) {
30166           var action = function action(graph) {
30167             return graph.update(function (graph) {
30168               utilGetAllNodes(rotateIds, graph).forEach(function (node) {
30169                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
30170                 graph = graph.replace(node.move(projection.invert(point)));
30171               });
30172             });
30173           };
30174
30175           return action;
30176         }
30177
30178         function actionScale(ids, pivotLoc, scaleFactor, projection) {
30179           return function (graph) {
30180             return graph.update(function (graph) {
30181               var point, radial;
30182               utilGetAllNodes(ids, graph).forEach(function (node) {
30183                 point = projection(node.loc);
30184                 radial = [point[0] - pivotLoc[0], point[1] - pivotLoc[1]];
30185                 point = [pivotLoc[0] + scaleFactor * radial[0], pivotLoc[1] + scaleFactor * radial[1]];
30186                 graph = graph.replace(node.move(projection.invert(point)));
30187               });
30188             });
30189           };
30190         }
30191
30192         /* Align nodes along their common axis */
30193
30194         function actionStraightenNodes(nodeIDs, projection) {
30195           function positionAlongWay(a, o, b) {
30196             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30197           } // returns the endpoints of the long axis of symmetry of the `points` bounding rect
30198
30199
30200           function getEndpoints(points) {
30201             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30202             // The shape's surrounding rectangle has 2 axes of symmetry.
30203             // Snap points to the long axis
30204
30205             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30206             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30207             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30208             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30209             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30210
30211             if (isLong) {
30212               return [p1, q1];
30213             }
30214
30215             return [p2, q2];
30216           }
30217
30218           var action = function action(graph, t) {
30219             if (t === null || !isFinite(t)) t = 1;
30220             t = Math.min(Math.max(+t, 0), 1);
30221             var nodes = nodeIDs.map(function (id) {
30222               return graph.entity(id);
30223             });
30224             var points = nodes.map(function (n) {
30225               return projection(n.loc);
30226             });
30227             var endpoints = getEndpoints(points);
30228             var startPoint = endpoints[0];
30229             var endPoint = endpoints[1]; // Move points onto the line connecting the endpoints
30230
30231             for (var i = 0; i < points.length; i++) {
30232               var node = nodes[i];
30233               var point = points[i];
30234               var u = positionAlongWay(point, startPoint, endPoint);
30235               var point2 = geoVecInterp(startPoint, endPoint, u);
30236               var loc2 = projection.invert(point2);
30237               graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30238             }
30239
30240             return graph;
30241           };
30242
30243           action.disabled = function (graph) {
30244             var nodes = nodeIDs.map(function (id) {
30245               return graph.entity(id);
30246             });
30247             var points = nodes.map(function (n) {
30248               return projection(n.loc);
30249             });
30250             var endpoints = getEndpoints(points);
30251             var startPoint = endpoints[0];
30252             var endPoint = endpoints[1];
30253             var maxDistance = 0;
30254
30255             for (var i = 0; i < points.length; i++) {
30256               var point = points[i];
30257               var u = positionAlongWay(point, startPoint, endPoint);
30258               var p = geoVecInterp(startPoint, endPoint, u);
30259               var dist = geoVecLength(p, point);
30260
30261               if (!isNaN(dist) && dist > maxDistance) {
30262                 maxDistance = dist;
30263               }
30264             }
30265
30266             if (maxDistance < 0.0001) {
30267               return 'straight_enough';
30268             }
30269           };
30270
30271           action.transitionable = true;
30272           return action;
30273         }
30274
30275         /*
30276          * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
30277          */
30278
30279         function actionStraightenWay(selectedIDs, projection) {
30280           function positionAlongWay(a, o, b) {
30281             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30282           } // Return all selected ways as a continuous, ordered array of nodes
30283
30284
30285           function allNodes(graph) {
30286             var nodes = [];
30287             var startNodes = [];
30288             var endNodes = [];
30289             var remainingWays = [];
30290             var selectedWays = selectedIDs.filter(function (w) {
30291               return graph.entity(w).type === 'way';
30292             });
30293             var selectedNodes = selectedIDs.filter(function (n) {
30294               return graph.entity(n).type === 'node';
30295             });
30296
30297             for (var i = 0; i < selectedWays.length; i++) {
30298               var way = graph.entity(selectedWays[i]);
30299               nodes = way.nodes.slice(0);
30300               remainingWays.push(nodes);
30301               startNodes.push(nodes[0]);
30302               endNodes.push(nodes[nodes.length - 1]);
30303             } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end,
30304             //   and need to be removed so currNode difference calculation below works)
30305             // i.e. ["n-1", "n-1", "n-2"] => ["n-2"]
30306
30307
30308             startNodes = startNodes.filter(function (n) {
30309               return startNodes.indexOf(n) === startNodes.lastIndexOf(n);
30310             });
30311             endNodes = endNodes.filter(function (n) {
30312               return endNodes.indexOf(n) === endNodes.lastIndexOf(n);
30313             }); // Choose the initial endpoint to start from
30314
30315             var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
30316             var nextWay = [];
30317             nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error
30318
30319             var getNextWay = function getNextWay(currNode, remainingWays) {
30320               return remainingWays.filter(function (way) {
30321                 return way[0] === currNode || way[way.length - 1] === currNode;
30322               })[0];
30323             }; // Add nodes to end of nodes array, until all ways are added
30324
30325
30326             while (remainingWays.length) {
30327               nextWay = getNextWay(currNode, remainingWays);
30328               remainingWays = utilArrayDifference(remainingWays, [nextWay]);
30329
30330               if (nextWay[0] !== currNode) {
30331                 nextWay.reverse();
30332               }
30333
30334               nodes = nodes.concat(nextWay);
30335               currNode = nodes[nodes.length - 1];
30336             } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes
30337
30338
30339             if (selectedNodes.length === 2) {
30340               var startNodeIdx = nodes.indexOf(selectedNodes[0]);
30341               var endNodeIdx = nodes.indexOf(selectedNodes[1]);
30342               var sortedStartEnd = [startNodeIdx, endNodeIdx];
30343               sortedStartEnd.sort(function (a, b) {
30344                 return a - b;
30345               });
30346               nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
30347             }
30348
30349             return nodes.map(function (n) {
30350               return graph.entity(n);
30351             });
30352           }
30353
30354           function shouldKeepNode(node, graph) {
30355             return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
30356           }
30357
30358           var action = function action(graph, t) {
30359             if (t === null || !isFinite(t)) t = 1;
30360             t = Math.min(Math.max(+t, 0), 1);
30361             var nodes = allNodes(graph);
30362             var points = nodes.map(function (n) {
30363               return projection(n.loc);
30364             });
30365             var startPoint = points[0];
30366             var endPoint = points[points.length - 1];
30367             var toDelete = [];
30368             var i;
30369
30370             for (i = 1; i < points.length - 1; i++) {
30371               var node = nodes[i];
30372               var point = points[i];
30373
30374               if (t < 1 || shouldKeepNode(node, graph)) {
30375                 var u = positionAlongWay(point, startPoint, endPoint);
30376                 var p = geoVecInterp(startPoint, endPoint, u);
30377                 var loc2 = projection.invert(p);
30378                 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30379               } else {
30380                 // safe to delete
30381                 if (toDelete.indexOf(node) === -1) {
30382                   toDelete.push(node);
30383                 }
30384               }
30385             }
30386
30387             for (i = 0; i < toDelete.length; i++) {
30388               graph = actionDeleteNode(toDelete[i].id)(graph);
30389             }
30390
30391             return graph;
30392           };
30393
30394           action.disabled = function (graph) {
30395             // check way isn't too bendy
30396             var nodes = allNodes(graph);
30397             var points = nodes.map(function (n) {
30398               return projection(n.loc);
30399             });
30400             var startPoint = points[0];
30401             var endPoint = points[points.length - 1];
30402             var threshold = 0.2 * geoVecLength(startPoint, endPoint);
30403             var i;
30404
30405             if (threshold === 0) {
30406               return 'too_bendy';
30407             }
30408
30409             var maxDistance = 0;
30410
30411             for (i = 1; i < points.length - 1; i++) {
30412               var point = points[i];
30413               var u = positionAlongWay(point, startPoint, endPoint);
30414               var p = geoVecInterp(startPoint, endPoint, u);
30415               var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space
30416
30417               if (isNaN(dist) || dist > threshold) {
30418                 return 'too_bendy';
30419               } else if (dist > maxDistance) {
30420                 maxDistance = dist;
30421               }
30422             }
30423
30424             var keepingAllNodes = nodes.every(function (node, i) {
30425               return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph);
30426             });
30427
30428             if (maxDistance < 0.0001 && // Allow straightening even if already straight in order to remove extraneous nodes
30429             keepingAllNodes) {
30430               return 'straight_enough';
30431             }
30432           };
30433
30434           action.transitionable = true;
30435           return action;
30436         }
30437
30438         //
30439         // `turn` must be an `osmTurn` object with a `restrictionID` property.
30440         // see osm/intersection.js, pathToTurn()
30441         //
30442
30443         function actionUnrestrictTurn(turn) {
30444           return function (graph) {
30445             return actionDeleteRelation(turn.restrictionID)(graph);
30446           };
30447         }
30448
30449         /* Reflect the given area around its axis of symmetry */
30450
30451         function actionReflect(reflectIds, projection) {
30452           var _useLongAxis = true;
30453
30454           var action = function action(graph, t) {
30455             if (t === null || !isFinite(t)) t = 1;
30456             t = Math.min(Math.max(+t, 0), 1);
30457             var nodes = utilGetAllNodes(reflectIds, graph);
30458             var points = nodes.map(function (n) {
30459               return projection(n.loc);
30460             });
30461             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30462             // The shape's surrounding rectangle has 2 axes of symmetry.
30463             // Reflect across the longer axis by default.
30464
30465             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30466             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30467             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30468             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30469             var p, q;
30470             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30471
30472             if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
30473               p = p1;
30474               q = q1;
30475             } else {
30476               p = p2;
30477               q = q2;
30478             } // reflect c across pq
30479             // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
30480
30481
30482             var dx = q[0] - p[0];
30483             var dy = q[1] - p[1];
30484             var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
30485             var b = 2 * dx * dy / (dx * dx + dy * dy);
30486
30487             for (var i = 0; i < nodes.length; i++) {
30488               var node = nodes[i];
30489               var c = projection(node.loc);
30490               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]];
30491               var loc2 = projection.invert(c2);
30492               node = node.move(geoVecInterp(node.loc, loc2, t));
30493               graph = graph.replace(node);
30494             }
30495
30496             return graph;
30497           };
30498
30499           action.useLongAxis = function (val) {
30500             if (!arguments.length) return _useLongAxis;
30501             _useLongAxis = val;
30502             return action;
30503           };
30504
30505           action.transitionable = true;
30506           return action;
30507         }
30508
30509         function actionUpgradeTags(entityId, oldTags, replaceTags) {
30510           return function (graph) {
30511             var entity = graph.entity(entityId);
30512             var tags = Object.assign({}, entity.tags); // shallow copy
30513
30514             var transferValue;
30515             var semiIndex;
30516
30517             for (var oldTagKey in oldTags) {
30518               if (!(oldTagKey in tags)) continue; // wildcard match
30519
30520               if (oldTags[oldTagKey] === '*') {
30521                 // note the value since we might need to transfer it
30522                 transferValue = tags[oldTagKey];
30523                 delete tags[oldTagKey]; // exact match
30524               } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
30525                 delete tags[oldTagKey]; // match is within semicolon-delimited values
30526               } else {
30527                 var vals = tags[oldTagKey].split(';').filter(Boolean);
30528                 var oldIndex = vals.indexOf(oldTags[oldTagKey]);
30529
30530                 if (vals.length === 1 || oldIndex === -1) {
30531                   delete tags[oldTagKey];
30532                 } else {
30533                   if (replaceTags && replaceTags[oldTagKey]) {
30534                     // replacing a value within a semicolon-delimited value, note the index
30535                     semiIndex = oldIndex;
30536                   }
30537
30538                   vals.splice(oldIndex, 1);
30539                   tags[oldTagKey] = vals.join(';');
30540                 }
30541               }
30542             }
30543
30544             if (replaceTags) {
30545               for (var replaceKey in replaceTags) {
30546                 var replaceValue = replaceTags[replaceKey];
30547
30548                 if (replaceValue === '*') {
30549                   if (tags[replaceKey] && tags[replaceKey] !== 'no') {
30550                     // allow any pre-existing value except `no` (troll tag)
30551                     continue;
30552                   } else {
30553                     // otherwise assume `yes` is okay
30554                     tags[replaceKey] = 'yes';
30555                   }
30556                 } else if (replaceValue === '$1') {
30557                   tags[replaceKey] = transferValue;
30558                 } else {
30559                   if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== undefined) {
30560                     // don't override preexisting values
30561                     var existingVals = tags[replaceKey].split(';').filter(Boolean);
30562
30563                     if (existingVals.indexOf(replaceValue) === -1) {
30564                       existingVals.splice(semiIndex, 0, replaceValue);
30565                       tags[replaceKey] = existingVals.join(';');
30566                     }
30567                   } else {
30568                     tags[replaceKey] = replaceValue;
30569                   }
30570                 }
30571               }
30572             }
30573
30574             return graph.replace(entity.update({
30575               tags: tags
30576             }));
30577           };
30578         }
30579
30580         function behaviorEdit(context) {
30581           function behavior() {
30582             context.map().minzoom(context.minEditableZoom());
30583           }
30584
30585           behavior.off = function () {
30586             context.map().minzoom(0);
30587           };
30588
30589           return behavior;
30590         }
30591
30592         /*
30593            The hover behavior adds the `.hover` class on pointerover to all elements to which
30594            the identical datum is bound, and removes it on pointerout.
30595
30596            The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
30597            representation may consist of several elements scattered throughout the DOM hierarchy.
30598            Only one of these elements can have the :hover pseudo-class, but all of them will
30599            have the .hover class.
30600          */
30601
30602         function behaviorHover(context) {
30603           var dispatch$1 = dispatch('hover');
30604
30605           var _selection = select(null);
30606
30607           var _newNodeId = null;
30608           var _initialNodeID = null;
30609
30610           var _altDisables;
30611
30612           var _ignoreVertex;
30613
30614           var _targets = []; // use pointer events on supported platforms; fallback to mouse events
30615
30616           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
30617
30618           function keydown(d3_event) {
30619             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30620               _selection.selectAll('.hover').classed('hover-suppressed', true).classed('hover', false);
30621
30622               _selection.classed('hover-disabled', true);
30623
30624               dispatch$1.call('hover', this, null);
30625             }
30626           }
30627
30628           function keyup(d3_event) {
30629             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30630               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false).classed('hover', true);
30631
30632               _selection.classed('hover-disabled', false);
30633
30634               dispatch$1.call('hover', this, _targets);
30635             }
30636           }
30637
30638           function behavior(selection) {
30639             _selection = selection;
30640             _targets = [];
30641
30642             if (_initialNodeID) {
30643               _newNodeId = _initialNodeID;
30644               _initialNodeID = null;
30645             } else {
30646               _newNodeId = null;
30647             }
30648
30649             _selection.on(_pointerPrefix + 'over.hover', pointerover).on(_pointerPrefix + 'out.hover', pointerout) // treat pointerdown as pointerover for touch devices
30650             .on(_pointerPrefix + 'down.hover', pointerover);
30651
30652             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', pointerout, true).on('keydown.hover', keydown).on('keyup.hover', keyup);
30653
30654             function eventTarget(d3_event) {
30655               var datum = d3_event.target && d3_event.target.__data__;
30656               if (_typeof(datum) !== 'object') return null;
30657
30658               if (!(datum instanceof osmEntity) && datum.properties && datum.properties.entity instanceof osmEntity) {
30659                 return datum.properties.entity;
30660               }
30661
30662               return datum;
30663             }
30664
30665             function pointerover(d3_event) {
30666               // ignore mouse hovers with buttons pressed unless dragging
30667               if (context.mode().id.indexOf('drag') === -1 && (!d3_event.pointerType || d3_event.pointerType === 'mouse') && d3_event.buttons) return;
30668               var target = eventTarget(d3_event);
30669
30670               if (target && _targets.indexOf(target) === -1) {
30671                 _targets.push(target);
30672
30673                 updateHover(d3_event, _targets);
30674               }
30675             }
30676
30677             function pointerout(d3_event) {
30678               var target = eventTarget(d3_event);
30679
30680               var index = _targets.indexOf(target);
30681
30682               if (index !== -1) {
30683                 _targets.splice(index);
30684
30685                 updateHover(d3_event, _targets);
30686               }
30687             }
30688
30689             function allowsVertex(d) {
30690               return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
30691             }
30692
30693             function modeAllowsHover(target) {
30694               var mode = context.mode();
30695
30696               if (mode.id === 'add-point') {
30697                 return mode.preset.matchGeometry('vertex') || target.type !== 'way' && target.geometry(context.graph()) !== 'vertex';
30698               }
30699
30700               return true;
30701             }
30702
30703             function updateHover(d3_event, targets) {
30704               _selection.selectAll('.hover').classed('hover', false);
30705
30706               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30707
30708               var mode = context.mode();
30709
30710               if (!_newNodeId && (mode.id === 'draw-line' || mode.id === 'draw-area')) {
30711                 var node = targets.find(function (target) {
30712                   return target instanceof osmEntity && target.type === 'node';
30713                 });
30714                 _newNodeId = node && node.id;
30715               }
30716
30717               targets = targets.filter(function (datum) {
30718                 if (datum instanceof osmEntity) {
30719                   // If drawing a way, don't hover on a node that was just placed. #3974
30720                   return datum.id !== _newNodeId && (datum.type !== 'node' || !_ignoreVertex || allowsVertex(datum)) && modeAllowsHover(datum);
30721                 }
30722
30723                 return true;
30724               });
30725               var selector = '';
30726
30727               for (var i in targets) {
30728                 var datum = targets[i]; // What are we hovering over?
30729
30730                 if (datum.__featurehash__) {
30731                   // hovering custom data
30732                   selector += ', .data' + datum.__featurehash__;
30733                 } else if (datum instanceof QAItem) {
30734                   selector += ', .' + datum.service + '.itemId-' + datum.id;
30735                 } else if (datum instanceof osmNote) {
30736                   selector += ', .note-' + datum.id;
30737                 } else if (datum instanceof osmEntity) {
30738                   selector += ', .' + datum.id;
30739
30740                   if (datum.type === 'relation') {
30741                     for (var j in datum.members) {
30742                       selector += ', .' + datum.members[j].id;
30743                     }
30744                   }
30745                 }
30746               }
30747
30748               var suppressed = _altDisables && d3_event && d3_event.altKey;
30749
30750               if (selector.trim().length) {
30751                 // remove the first comma
30752                 selector = selector.slice(1);
30753
30754                 _selection.selectAll(selector).classed(suppressed ? 'hover-suppressed' : 'hover', true);
30755               }
30756
30757               dispatch$1.call('hover', this, !suppressed && targets);
30758             }
30759           }
30760
30761           behavior.off = function (selection) {
30762             selection.selectAll('.hover').classed('hover', false);
30763             selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30764             selection.classed('hover-disabled', false);
30765             selection.on(_pointerPrefix + 'over.hover', null).on(_pointerPrefix + 'out.hover', null).on(_pointerPrefix + 'down.hover', null);
30766             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', null, true).on('keydown.hover', null).on('keyup.hover', null);
30767           };
30768
30769           behavior.altDisables = function (val) {
30770             if (!arguments.length) return _altDisables;
30771             _altDisables = val;
30772             return behavior;
30773           };
30774
30775           behavior.ignoreVertex = function (val) {
30776             if (!arguments.length) return _ignoreVertex;
30777             _ignoreVertex = val;
30778             return behavior;
30779           };
30780
30781           behavior.initialNodeID = function (nodeId) {
30782             _initialNodeID = nodeId;
30783             return behavior;
30784           };
30785
30786           return utilRebind(behavior, dispatch$1, 'on');
30787         }
30788
30789         var _disableSpace = false;
30790         var _lastSpace = null;
30791         function behaviorDraw(context) {
30792           var dispatch$1 = dispatch('move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish');
30793           var keybinding = utilKeybinding('draw');
30794
30795           var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on('hover', context.ui().sidebar.hover);
30796
30797           var _edit = behaviorEdit(context);
30798
30799           var _closeTolerance = 4;
30800           var _tolerance = 12;
30801           var _mouseLeave = false;
30802           var _lastMouse = null;
30803
30804           var _lastPointerUpEvent;
30805
30806           var _downPointer; // use pointer events on supported platforms; fallback to mouse events
30807
30808
30809           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // related code
30810           // - `mode/drag_node.js` `datum()`
30811
30812
30813           function datum(d3_event) {
30814             var mode = context.mode();
30815             var isNote = mode && mode.id.indexOf('note') !== -1;
30816             if (d3_event.altKey || isNote) return {};
30817             var element;
30818
30819             if (d3_event.type === 'keydown') {
30820               element = _lastMouse && _lastMouse.target;
30821             } else {
30822               element = d3_event.target;
30823             } // When drawing, snap only to touch targets..
30824             // (this excludes area fills and active drawing elements)
30825
30826
30827             var d = element.__data__;
30828             return d && d.properties && d.properties.target ? d : {};
30829           }
30830
30831           function pointerdown(d3_event) {
30832             if (_downPointer) return;
30833             var pointerLocGetter = utilFastMouse(this);
30834             _downPointer = {
30835               id: d3_event.pointerId || 'mouse',
30836               pointerLocGetter: pointerLocGetter,
30837               downTime: +new Date(),
30838               downLoc: pointerLocGetter(d3_event)
30839             };
30840             dispatch$1.call('down', this, d3_event, datum(d3_event));
30841           }
30842
30843           function pointerup(d3_event) {
30844             if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
30845             var downPointer = _downPointer;
30846             _downPointer = null;
30847             _lastPointerUpEvent = d3_event;
30848             if (downPointer.isCancelled) return;
30849             var t2 = +new Date();
30850             var p2 = downPointer.pointerLocGetter(d3_event);
30851             var dist = geoVecLength(downPointer.downLoc, p2);
30852
30853             if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
30854               // Prevent a quick second click
30855               select(window).on('click.draw-block', function () {
30856                 d3_event.stopPropagation();
30857               }, true);
30858               context.map().dblclickZoomEnable(false);
30859               window.setTimeout(function () {
30860                 context.map().dblclickZoomEnable(true);
30861                 select(window).on('click.draw-block', null);
30862               }, 500);
30863               click(d3_event, p2);
30864             }
30865           }
30866
30867           function pointermove(d3_event) {
30868             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse') && !_downPointer.isCancelled) {
30869               var p2 = _downPointer.pointerLocGetter(d3_event);
30870
30871               var dist = geoVecLength(_downPointer.downLoc, p2);
30872
30873               if (dist >= _closeTolerance) {
30874                 _downPointer.isCancelled = true;
30875                 dispatch$1.call('downcancel', this);
30876               }
30877             }
30878
30879             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
30880             // events immediately after non-mouse pointerup events; detect and ignore them.
30881
30882             if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== 'mouse' && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
30883             _lastMouse = d3_event;
30884             dispatch$1.call('move', this, d3_event, datum(d3_event));
30885           }
30886
30887           function pointercancel(d3_event) {
30888             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse')) {
30889               if (!_downPointer.isCancelled) {
30890                 dispatch$1.call('downcancel', this);
30891               }
30892
30893               _downPointer = null;
30894             }
30895           }
30896
30897           function mouseenter() {
30898             _mouseLeave = false;
30899           }
30900
30901           function mouseleave() {
30902             _mouseLeave = true;
30903           }
30904
30905           function allowsVertex(d) {
30906             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
30907           } // related code
30908           // - `mode/drag_node.js`     `doMove()`
30909           // - `behavior/draw.js`      `click()`
30910           // - `behavior/draw_way.js`  `move()`
30911
30912
30913           function click(d3_event, loc) {
30914             var d = datum(d3_event);
30915             var target = d && d.properties && d.properties.entity;
30916             var mode = context.mode();
30917
30918             if (target && target.type === 'node' && allowsVertex(target)) {
30919               // Snap to a node
30920               dispatch$1.call('clickNode', this, target, d);
30921               return;
30922             } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) {
30923               // Snap to a way
30924               var choice = geoChooseEdge(context.graph().childNodes(target), loc, context.projection, context.activeID());
30925
30926               if (choice) {
30927                 var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
30928                 dispatch$1.call('clickWay', this, choice.loc, edge, d);
30929                 return;
30930               }
30931             } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) {
30932               var locLatLng = context.projection.invert(loc);
30933               dispatch$1.call('click', this, locLatLng, d);
30934             }
30935           } // treat a spacebar press like a click
30936
30937
30938           function space(d3_event) {
30939             d3_event.preventDefault();
30940             d3_event.stopPropagation();
30941             var currSpace = context.map().mouse();
30942
30943             if (_disableSpace && _lastSpace) {
30944               var dist = geoVecLength(_lastSpace, currSpace);
30945
30946               if (dist > _tolerance) {
30947                 _disableSpace = false;
30948               }
30949             }
30950
30951             if (_disableSpace || _mouseLeave || !_lastMouse) return; // user must move mouse or release space bar to allow another click
30952
30953             _lastSpace = currSpace;
30954             _disableSpace = true;
30955             select(window).on('keyup.space-block', function () {
30956               d3_event.preventDefault();
30957               d3_event.stopPropagation();
30958               _disableSpace = false;
30959               select(window).on('keyup.space-block', null);
30960             }); // get the current mouse position
30961
30962             var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
30963             context.projection(context.map().center());
30964             click(d3_event, loc);
30965           }
30966
30967           function backspace(d3_event) {
30968             d3_event.preventDefault();
30969             dispatch$1.call('undo');
30970           }
30971
30972           function del(d3_event) {
30973             d3_event.preventDefault();
30974             dispatch$1.call('cancel');
30975           }
30976
30977           function ret(d3_event) {
30978             d3_event.preventDefault();
30979             dispatch$1.call('finish');
30980           }
30981
30982           function behavior(selection) {
30983             context.install(_hover);
30984             context.install(_edit);
30985             _downPointer = null;
30986             keybinding.on('⌫', backspace).on('⌦', del).on('⎋', ret).on('↩', ret).on('space', space).on('⌥space', space);
30987             selection.on('mouseenter.draw', mouseenter).on('mouseleave.draw', mouseleave).on(_pointerPrefix + 'down.draw', pointerdown).on(_pointerPrefix + 'move.draw', pointermove);
30988             select(window).on(_pointerPrefix + 'up.draw', pointerup, true).on('pointercancel.draw', pointercancel, true);
30989             select(document).call(keybinding);
30990             return behavior;
30991           }
30992
30993           behavior.off = function (selection) {
30994             context.ui().sidebar.hover.cancel();
30995             context.uninstall(_hover);
30996             context.uninstall(_edit);
30997             selection.on('mouseenter.draw', null).on('mouseleave.draw', null).on(_pointerPrefix + 'down.draw', null).on(_pointerPrefix + 'move.draw', null);
30998             select(window).on(_pointerPrefix + 'up.draw', null).on('pointercancel.draw', null); // note: keyup.space-block, click.draw-block should remain
30999
31000             select(document).call(keybinding.unbind);
31001           };
31002
31003           behavior.hover = function () {
31004             return _hover;
31005           };
31006
31007           return utilRebind(behavior, dispatch$1, 'on');
31008         }
31009
31010         function initRange(domain, range) {
31011           switch (arguments.length) {
31012             case 0:
31013               break;
31014
31015             case 1:
31016               this.range(domain);
31017               break;
31018
31019             default:
31020               this.range(range).domain(domain);
31021               break;
31022           }
31023
31024           return this;
31025         }
31026
31027         function constants(x) {
31028           return function () {
31029             return x;
31030           };
31031         }
31032
31033         function number$1(x) {
31034           return +x;
31035         }
31036
31037         var unit = [0, 1];
31038         function identity$3(x) {
31039           return x;
31040         }
31041
31042         function normalize$1(a, b) {
31043           return (b -= a = +a) ? function (x) {
31044             return (x - a) / b;
31045           } : constants(isNaN(b) ? NaN : 0.5);
31046         }
31047
31048         function clamper(a, b) {
31049           var t;
31050           if (a > b) t = a, a = b, b = t;
31051           return function (x) {
31052             return Math.max(a, Math.min(b, x));
31053           };
31054         } // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
31055         // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
31056
31057
31058         function bimap(domain, range, interpolate) {
31059           var d0 = domain[0],
31060               d1 = domain[1],
31061               r0 = range[0],
31062               r1 = range[1];
31063           if (d1 < d0) d0 = normalize$1(d1, d0), r0 = interpolate(r1, r0);else d0 = normalize$1(d0, d1), r0 = interpolate(r0, r1);
31064           return function (x) {
31065             return r0(d0(x));
31066           };
31067         }
31068
31069         function polymap(domain, range, interpolate) {
31070           var j = Math.min(domain.length, range.length) - 1,
31071               d = new Array(j),
31072               r = new Array(j),
31073               i = -1; // Reverse descending domains.
31074
31075           if (domain[j] < domain[0]) {
31076             domain = domain.slice().reverse();
31077             range = range.slice().reverse();
31078           }
31079
31080           while (++i < j) {
31081             d[i] = normalize$1(domain[i], domain[i + 1]);
31082             r[i] = interpolate(range[i], range[i + 1]);
31083           }
31084
31085           return function (x) {
31086             var i = bisectRight(domain, x, 1, j) - 1;
31087             return r[i](d[i](x));
31088           };
31089         }
31090
31091         function copy(source, target) {
31092           return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
31093         }
31094         function transformer$1() {
31095           var domain = unit,
31096               range = unit,
31097               interpolate$1 = interpolate,
31098               transform,
31099               untransform,
31100               unknown,
31101               clamp = identity$3,
31102               piecewise,
31103               output,
31104               input;
31105
31106           function rescale() {
31107             var n = Math.min(domain.length, range.length);
31108             if (clamp !== identity$3) clamp = clamper(domain[0], domain[n - 1]);
31109             piecewise = n > 2 ? polymap : bimap;
31110             output = input = null;
31111             return scale;
31112           }
31113
31114           function scale(x) {
31115             return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate$1)))(transform(clamp(x)));
31116           }
31117
31118           scale.invert = function (y) {
31119             return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3_interpolateNumber)))(y)));
31120           };
31121
31122           scale.domain = function (_) {
31123             return arguments.length ? (domain = Array.from(_, number$1), rescale()) : domain.slice();
31124           };
31125
31126           scale.range = function (_) {
31127             return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
31128           };
31129
31130           scale.rangeRound = function (_) {
31131             return range = Array.from(_), interpolate$1 = interpolateRound, rescale();
31132           };
31133
31134           scale.clamp = function (_) {
31135             return arguments.length ? (clamp = _ ? true : identity$3, rescale()) : clamp !== identity$3;
31136           };
31137
31138           scale.interpolate = function (_) {
31139             return arguments.length ? (interpolate$1 = _, rescale()) : interpolate$1;
31140           };
31141
31142           scale.unknown = function (_) {
31143             return arguments.length ? (unknown = _, scale) : unknown;
31144           };
31145
31146           return function (t, u) {
31147             transform = t, untransform = u;
31148             return rescale();
31149           };
31150         }
31151         function continuous() {
31152           return transformer$1()(identity$3, identity$3);
31153         }
31154
31155         function formatDecimal (x) {
31156           return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
31157         } // Computes the decimal coefficient and exponent of the specified number x with
31158         // significant digits p, where x is positive and p is in [1, 21] or undefined.
31159         // For example, formatDecimalParts(1.23) returns ["123", 0].
31160
31161         function formatDecimalParts(x, p) {
31162           if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
31163
31164           var i,
31165               coefficient = x.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
31166           // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
31167
31168           return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
31169         }
31170
31171         function exponent (x) {
31172           return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
31173         }
31174
31175         function formatGroup (grouping, thousands) {
31176           return function (value, width) {
31177             var i = value.length,
31178                 t = [],
31179                 j = 0,
31180                 g = grouping[0],
31181                 length = 0;
31182
31183             while (i > 0 && g > 0) {
31184               if (length + g + 1 > width) g = Math.max(1, width - length);
31185               t.push(value.substring(i -= g, i + g));
31186               if ((length += g + 1) > width) break;
31187               g = grouping[j = (j + 1) % grouping.length];
31188             }
31189
31190             return t.reverse().join(thousands);
31191           };
31192         }
31193
31194         function formatNumerals (numerals) {
31195           return function (value) {
31196             return value.replace(/[0-9]/g, function (i) {
31197               return numerals[+i];
31198             });
31199           };
31200         }
31201
31202         // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
31203         var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
31204         function formatSpecifier(specifier) {
31205           if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
31206           var match;
31207           return new FormatSpecifier({
31208             fill: match[1],
31209             align: match[2],
31210             sign: match[3],
31211             symbol: match[4],
31212             zero: match[5],
31213             width: match[6],
31214             comma: match[7],
31215             precision: match[8] && match[8].slice(1),
31216             trim: match[9],
31217             type: match[10]
31218           });
31219         }
31220         formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
31221
31222         function FormatSpecifier(specifier) {
31223           this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
31224           this.align = specifier.align === undefined ? ">" : specifier.align + "";
31225           this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
31226           this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
31227           this.zero = !!specifier.zero;
31228           this.width = specifier.width === undefined ? undefined : +specifier.width;
31229           this.comma = !!specifier.comma;
31230           this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
31231           this.trim = !!specifier.trim;
31232           this.type = specifier.type === undefined ? "" : specifier.type + "";
31233         }
31234
31235         FormatSpecifier.prototype.toString = function () {
31236           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;
31237         };
31238
31239         // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
31240         function formatTrim (s) {
31241           out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
31242             switch (s[i]) {
31243               case ".":
31244                 i0 = i1 = i;
31245                 break;
31246
31247               case "0":
31248                 if (i0 === 0) i0 = i;
31249                 i1 = i;
31250                 break;
31251
31252               default:
31253                 if (!+s[i]) break out;
31254                 if (i0 > 0) i0 = 0;
31255                 break;
31256             }
31257           }
31258
31259           return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
31260         }
31261
31262         // `thisNumberValue` abstract operation
31263         // https://tc39.github.io/ecma262/#sec-thisnumbervalue
31264         var thisNumberValue = function (value) {
31265           if (typeof value != 'number' && classofRaw(value) != 'Number') {
31266             throw TypeError('Incorrect invocation');
31267           }
31268           return +value;
31269         };
31270
31271         // `String.prototype.repeat` method implementation
31272         // https://tc39.github.io/ecma262/#sec-string.prototype.repeat
31273         var stringRepeat = ''.repeat || function repeat(count) {
31274           var str = String(requireObjectCoercible(this));
31275           var result = '';
31276           var n = toInteger(count);
31277           if (n < 0 || n == Infinity) throw RangeError('Wrong number of repetitions');
31278           for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;
31279           return result;
31280         };
31281
31282         var nativeToFixed = 1.0.toFixed;
31283         var floor$6 = Math.floor;
31284
31285         var pow$2 = function (x, n, acc) {
31286           return n === 0 ? acc : n % 2 === 1 ? pow$2(x, n - 1, acc * x) : pow$2(x * x, n / 2, acc);
31287         };
31288
31289         var log$2 = function (x) {
31290           var n = 0;
31291           var x2 = x;
31292           while (x2 >= 4096) {
31293             n += 12;
31294             x2 /= 4096;
31295           }
31296           while (x2 >= 2) {
31297             n += 1;
31298             x2 /= 2;
31299           } return n;
31300         };
31301
31302         var FORCED$c = nativeToFixed && (
31303           0.00008.toFixed(3) !== '0.000' ||
31304           0.9.toFixed(0) !== '1' ||
31305           1.255.toFixed(2) !== '1.25' ||
31306           1000000000000000128.0.toFixed(0) !== '1000000000000000128'
31307         ) || !fails(function () {
31308           // V8 ~ Android 4.3-
31309           nativeToFixed.call({});
31310         });
31311
31312         // `Number.prototype.toFixed` method
31313         // https://tc39.github.io/ecma262/#sec-number.prototype.tofixed
31314         _export({ target: 'Number', proto: true, forced: FORCED$c }, {
31315           // eslint-disable-next-line max-statements
31316           toFixed: function toFixed(fractionDigits) {
31317             var number = thisNumberValue(this);
31318             var fractDigits = toInteger(fractionDigits);
31319             var data = [0, 0, 0, 0, 0, 0];
31320             var sign = '';
31321             var result = '0';
31322             var e, z, j, k;
31323
31324             var multiply = function (n, c) {
31325               var index = -1;
31326               var c2 = c;
31327               while (++index < 6) {
31328                 c2 += n * data[index];
31329                 data[index] = c2 % 1e7;
31330                 c2 = floor$6(c2 / 1e7);
31331               }
31332             };
31333
31334             var divide = function (n) {
31335               var index = 6;
31336               var c = 0;
31337               while (--index >= 0) {
31338                 c += data[index];
31339                 data[index] = floor$6(c / n);
31340                 c = (c % n) * 1e7;
31341               }
31342             };
31343
31344             var dataToString = function () {
31345               var index = 6;
31346               var s = '';
31347               while (--index >= 0) {
31348                 if (s !== '' || index === 0 || data[index] !== 0) {
31349                   var t = String(data[index]);
31350                   s = s === '' ? t : s + stringRepeat.call('0', 7 - t.length) + t;
31351                 }
31352               } return s;
31353             };
31354
31355             if (fractDigits < 0 || fractDigits > 20) throw RangeError('Incorrect fraction digits');
31356             // eslint-disable-next-line no-self-compare
31357             if (number != number) return 'NaN';
31358             if (number <= -1e21 || number >= 1e21) return String(number);
31359             if (number < 0) {
31360               sign = '-';
31361               number = -number;
31362             }
31363             if (number > 1e-21) {
31364               e = log$2(number * pow$2(2, 69, 1)) - 69;
31365               z = e < 0 ? number * pow$2(2, -e, 1) : number / pow$2(2, e, 1);
31366               z *= 0x10000000000000;
31367               e = 52 - e;
31368               if (e > 0) {
31369                 multiply(0, z);
31370                 j = fractDigits;
31371                 while (j >= 7) {
31372                   multiply(1e7, 0);
31373                   j -= 7;
31374                 }
31375                 multiply(pow$2(10, j, 1), 0);
31376                 j = e - 1;
31377                 while (j >= 23) {
31378                   divide(1 << 23);
31379                   j -= 23;
31380                 }
31381                 divide(1 << j);
31382                 multiply(1, 1);
31383                 divide(2);
31384                 result = dataToString();
31385               } else {
31386                 multiply(0, z);
31387                 multiply(1 << -e, 0);
31388                 result = dataToString() + stringRepeat.call('0', fractDigits);
31389               }
31390             }
31391             if (fractDigits > 0) {
31392               k = result.length;
31393               result = sign + (k <= fractDigits
31394                 ? '0.' + stringRepeat.call('0', fractDigits - k) + result
31395                 : result.slice(0, k - fractDigits) + '.' + result.slice(k - fractDigits));
31396             } else {
31397               result = sign + result;
31398             } return result;
31399           }
31400         });
31401
31402         var nativeToPrecision = 1.0.toPrecision;
31403
31404         var FORCED$d = fails(function () {
31405           // IE7-
31406           return nativeToPrecision.call(1, undefined) !== '1';
31407         }) || !fails(function () {
31408           // V8 ~ Android 4.3-
31409           nativeToPrecision.call({});
31410         });
31411
31412         // `Number.prototype.toPrecision` method
31413         // https://tc39.github.io/ecma262/#sec-number.prototype.toprecision
31414         _export({ target: 'Number', proto: true, forced: FORCED$d }, {
31415           toPrecision: function toPrecision(precision) {
31416             return precision === undefined
31417               ? nativeToPrecision.call(thisNumberValue(this))
31418               : nativeToPrecision.call(thisNumberValue(this), precision);
31419           }
31420         });
31421
31422         var prefixExponent;
31423         function formatPrefixAuto (x, p) {
31424           var d = formatDecimalParts(x, p);
31425           if (!d) return x + "";
31426           var coefficient = d[0],
31427               exponent = d[1],
31428               i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
31429               n = coefficient.length;
31430           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!
31431         }
31432
31433         function formatRounded (x, p) {
31434           var d = formatDecimalParts(x, p);
31435           if (!d) return x + "";
31436           var coefficient = d[0],
31437               exponent = d[1];
31438           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");
31439         }
31440
31441         var formatTypes = {
31442           "%": function _(x, p) {
31443             return (x * 100).toFixed(p);
31444           },
31445           "b": function b(x) {
31446             return Math.round(x).toString(2);
31447           },
31448           "c": function c(x) {
31449             return x + "";
31450           },
31451           "d": formatDecimal,
31452           "e": function e(x, p) {
31453             return x.toExponential(p);
31454           },
31455           "f": function f(x, p) {
31456             return x.toFixed(p);
31457           },
31458           "g": function g(x, p) {
31459             return x.toPrecision(p);
31460           },
31461           "o": function o(x) {
31462             return Math.round(x).toString(8);
31463           },
31464           "p": function p(x, _p) {
31465             return formatRounded(x * 100, _p);
31466           },
31467           "r": formatRounded,
31468           "s": formatPrefixAuto,
31469           "X": function X(x) {
31470             return Math.round(x).toString(16).toUpperCase();
31471           },
31472           "x": function x(_x) {
31473             return Math.round(_x).toString(16);
31474           }
31475         };
31476
31477         function identity$4 (x) {
31478           return x;
31479         }
31480
31481         var map = Array.prototype.map,
31482             prefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
31483         function formatLocale (locale) {
31484           var group = locale.grouping === undefined || locale.thousands === undefined ? identity$4 : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
31485               currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
31486               currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
31487               decimal = locale.decimal === undefined ? "." : locale.decimal + "",
31488               numerals = locale.numerals === undefined ? identity$4 : formatNumerals(map.call(locale.numerals, String)),
31489               percent = locale.percent === undefined ? "%" : locale.percent + "",
31490               minus = locale.minus === undefined ? "−" : locale.minus + "",
31491               nan = locale.nan === undefined ? "NaN" : locale.nan + "";
31492
31493           function newFormat(specifier) {
31494             specifier = formatSpecifier(specifier);
31495             var fill = specifier.fill,
31496                 align = specifier.align,
31497                 sign = specifier.sign,
31498                 symbol = specifier.symbol,
31499                 zero = specifier.zero,
31500                 width = specifier.width,
31501                 comma = specifier.comma,
31502                 precision = specifier.precision,
31503                 trim = specifier.trim,
31504                 type = specifier.type; // The "n" type is an alias for ",g".
31505
31506             if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g".
31507             else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits.
31508
31509             if (zero || fill === "0" && align === "=") zero = true, fill = "0", align = "="; // Compute the prefix and suffix.
31510             // For SI-prefix, the suffix is lazily computed.
31511
31512             var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
31513                 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use?
31514             // Is this an integer type?
31515             // Can this type generate exponential notation?
31516
31517             var formatType = formatTypes[type],
31518                 maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified,
31519             // or clamp the specified precision to the supported range.
31520             // For significant precision, it must be in [1, 21].
31521             // For fixed precision, it must be in [0, 20].
31522
31523             precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
31524
31525             function format(value) {
31526               var valuePrefix = prefix,
31527                   valueSuffix = suffix,
31528                   i,
31529                   n,
31530                   c;
31531
31532               if (type === "c") {
31533                 valueSuffix = formatType(value) + valueSuffix;
31534                 value = "";
31535               } else {
31536                 value = +value; // Determine the sign. -0 is not less than 0, but 1 / -0 is!
31537
31538                 var valueNegative = value < 0 || 1 / value < 0; // Perform the initial formatting.
31539
31540                 value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros.
31541
31542                 if (trim) value = formatTrim(value); // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
31543
31544                 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix.
31545
31546                 valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
31547                 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be
31548                 // grouped, and fractional or exponential “suffix” part that is not.
31549
31550                 if (maybeSuffix) {
31551                   i = -1, n = value.length;
31552
31553                   while (++i < n) {
31554                     if (c = value.charCodeAt(i), 48 > c || c > 57) {
31555                       valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
31556                       value = value.slice(0, i);
31557                       break;
31558                     }
31559                   }
31560                 }
31561               } // If the fill character is not "0", grouping is applied before padding.
31562
31563
31564               if (comma && !zero) value = group(value, Infinity); // Compute the padding.
31565
31566               var length = valuePrefix.length + value.length + valueSuffix.length,
31567                   padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding.
31568
31569               if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment.
31570
31571               switch (align) {
31572                 case "<":
31573                   value = valuePrefix + value + valueSuffix + padding;
31574                   break;
31575
31576                 case "=":
31577                   value = valuePrefix + padding + value + valueSuffix;
31578                   break;
31579
31580                 case "^":
31581                   value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
31582                   break;
31583
31584                 default:
31585                   value = padding + valuePrefix + value + valueSuffix;
31586                   break;
31587               }
31588
31589               return numerals(value);
31590             }
31591
31592             format.toString = function () {
31593               return specifier + "";
31594             };
31595
31596             return format;
31597           }
31598
31599           function formatPrefix(specifier, value) {
31600             var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
31601                 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
31602                 k = Math.pow(10, -e),
31603                 prefix = prefixes[8 + e / 3];
31604             return function (value) {
31605               return f(k * value) + prefix;
31606             };
31607           }
31608
31609           return {
31610             format: newFormat,
31611             formatPrefix: formatPrefix
31612           };
31613         }
31614
31615         var locale;
31616         var format;
31617         var formatPrefix;
31618         defaultLocale({
31619           thousands: ",",
31620           grouping: [3],
31621           currency: ["$", ""]
31622         });
31623         function defaultLocale(definition) {
31624           locale = formatLocale(definition);
31625           format = locale.format;
31626           formatPrefix = locale.formatPrefix;
31627           return locale;
31628         }
31629
31630         function precisionFixed (step) {
31631           return Math.max(0, -exponent(Math.abs(step)));
31632         }
31633
31634         function precisionPrefix (step, value) {
31635           return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
31636         }
31637
31638         function precisionRound (step, max) {
31639           step = Math.abs(step), max = Math.abs(max) - step;
31640           return Math.max(0, exponent(max) - exponent(step)) + 1;
31641         }
31642
31643         function tickFormat(start, stop, count, specifier) {
31644           var step = tickStep(start, stop, count),
31645               precision;
31646           specifier = formatSpecifier(specifier == null ? ",f" : specifier);
31647
31648           switch (specifier.type) {
31649             case "s":
31650               {
31651                 var value = Math.max(Math.abs(start), Math.abs(stop));
31652                 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
31653                 return formatPrefix(specifier, value);
31654               }
31655
31656             case "":
31657             case "e":
31658             case "g":
31659             case "p":
31660             case "r":
31661               {
31662                 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
31663                 break;
31664               }
31665
31666             case "f":
31667             case "%":
31668               {
31669                 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
31670                 break;
31671               }
31672           }
31673
31674           return format(specifier);
31675         }
31676
31677         function linearish(scale) {
31678           var domain = scale.domain;
31679
31680           scale.ticks = function (count) {
31681             var d = domain();
31682             return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
31683           };
31684
31685           scale.tickFormat = function (count, specifier) {
31686             var d = domain();
31687             return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
31688           };
31689
31690           scale.nice = function (count) {
31691             if (count == null) count = 10;
31692             var d = domain();
31693             var i0 = 0;
31694             var i1 = d.length - 1;
31695             var start = d[i0];
31696             var stop = d[i1];
31697             var prestep;
31698             var step;
31699             var maxIter = 10;
31700
31701             if (stop < start) {
31702               step = start, start = stop, stop = step;
31703               step = i0, i0 = i1, i1 = step;
31704             }
31705
31706             while (maxIter-- > 0) {
31707               step = tickIncrement(start, stop, count);
31708
31709               if (step === prestep) {
31710                 d[i0] = start;
31711                 d[i1] = stop;
31712                 return domain(d);
31713               } else if (step > 0) {
31714                 start = Math.floor(start / step) * step;
31715                 stop = Math.ceil(stop / step) * step;
31716               } else if (step < 0) {
31717                 start = Math.ceil(start * step) / step;
31718                 stop = Math.floor(stop * step) / step;
31719               } else {
31720                 break;
31721               }
31722
31723               prestep = step;
31724             }
31725
31726             return scale;
31727           };
31728
31729           return scale;
31730         }
31731         function linear$2() {
31732           var scale = continuous();
31733
31734           scale.copy = function () {
31735             return copy(scale, linear$2());
31736           };
31737
31738           initRange.apply(scale, arguments);
31739           return linearish(scale);
31740         }
31741
31742         var nativeExpm1 = Math.expm1;
31743         var exp$1 = Math.exp;
31744
31745         // `Math.expm1` method implementation
31746         // https://tc39.github.io/ecma262/#sec-math.expm1
31747         var mathExpm1 = (!nativeExpm1
31748           // Old FF bug
31749           || nativeExpm1(10) > 22025.465794806719 || nativeExpm1(10) < 22025.4657948067165168
31750           // Tor Browser bug
31751           || nativeExpm1(-2e-17) != -2e-17
31752         ) ? function expm1(x) {
31753           return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp$1(x) - 1;
31754         } : nativeExpm1;
31755
31756         function quantize() {
31757           var x0 = 0,
31758               x1 = 1,
31759               n = 1,
31760               domain = [0.5],
31761               range = [0, 1],
31762               unknown;
31763
31764           function scale(x) {
31765             return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
31766           }
31767
31768           function rescale() {
31769             var i = -1;
31770             domain = new Array(n);
31771
31772             while (++i < n) {
31773               domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31774             }
31775
31776             return scale;
31777           }
31778
31779           scale.domain = function (_) {
31780             var _ref, _ref2;
31781
31782             return arguments.length ? ((_ref = _, _ref2 = _slicedToArray(_ref, 2), x0 = _ref2[0], x1 = _ref2[1], _ref), x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
31783           };
31784
31785           scale.range = function (_) {
31786             return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
31787           };
31788
31789           scale.invertExtent = function (y) {
31790             var i = range.indexOf(y);
31791             return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
31792           };
31793
31794           scale.unknown = function (_) {
31795             return arguments.length ? (unknown = _, scale) : scale;
31796           };
31797
31798           scale.thresholds = function () {
31799             return domain.slice();
31800           };
31801
31802           scale.copy = function () {
31803             return quantize().domain([x0, x1]).range(range).unknown(unknown);
31804           };
31805
31806           return initRange.apply(linearish(scale), arguments);
31807         }
31808
31809         // https://github.com/tc39/proposal-string-pad-start-end
31810
31811
31812
31813
31814         var ceil$1 = Math.ceil;
31815
31816         // `String.prototype.{ padStart, padEnd }` methods implementation
31817         var createMethod$6 = function (IS_END) {
31818           return function ($this, maxLength, fillString) {
31819             var S = String(requireObjectCoercible($this));
31820             var stringLength = S.length;
31821             var fillStr = fillString === undefined ? ' ' : String(fillString);
31822             var intMaxLength = toLength(maxLength);
31823             var fillLen, stringFiller;
31824             if (intMaxLength <= stringLength || fillStr == '') return S;
31825             fillLen = intMaxLength - stringLength;
31826             stringFiller = stringRepeat.call(fillStr, ceil$1(fillLen / fillStr.length));
31827             if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen);
31828             return IS_END ? S + stringFiller : stringFiller + S;
31829           };
31830         };
31831
31832         var stringPad = {
31833           // `String.prototype.padStart` method
31834           // https://tc39.github.io/ecma262/#sec-string.prototype.padstart
31835           start: createMethod$6(false),
31836           // `String.prototype.padEnd` method
31837           // https://tc39.github.io/ecma262/#sec-string.prototype.padend
31838           end: createMethod$6(true)
31839         };
31840
31841         var padStart = stringPad.start;
31842
31843         var abs$3 = Math.abs;
31844         var DatePrototype$1 = Date.prototype;
31845         var getTime$1 = DatePrototype$1.getTime;
31846         var nativeDateToISOString = DatePrototype$1.toISOString;
31847
31848         // `Date.prototype.toISOString` method implementation
31849         // https://tc39.github.io/ecma262/#sec-date.prototype.toisostring
31850         // PhantomJS / old WebKit fails here:
31851         var dateToIsoString = (fails(function () {
31852           return nativeDateToISOString.call(new Date(-5e13 - 1)) != '0385-07-25T07:06:39.999Z';
31853         }) || !fails(function () {
31854           nativeDateToISOString.call(new Date(NaN));
31855         })) ? function toISOString() {
31856           if (!isFinite(getTime$1.call(this))) throw RangeError('Invalid time value');
31857           var date = this;
31858           var year = date.getUTCFullYear();
31859           var milliseconds = date.getUTCMilliseconds();
31860           var sign = year < 0 ? '-' : year > 9999 ? '+' : '';
31861           return sign + padStart(abs$3(year), sign ? 6 : 4, 0) +
31862             '-' + padStart(date.getUTCMonth() + 1, 2, 0) +
31863             '-' + padStart(date.getUTCDate(), 2, 0) +
31864             'T' + padStart(date.getUTCHours(), 2, 0) +
31865             ':' + padStart(date.getUTCMinutes(), 2, 0) +
31866             ':' + padStart(date.getUTCSeconds(), 2, 0) +
31867             '.' + padStart(milliseconds, 3, 0) +
31868             'Z';
31869         } : nativeDateToISOString;
31870
31871         // `Date.prototype.toISOString` method
31872         // https://tc39.github.io/ecma262/#sec-date.prototype.toisostring
31873         // PhantomJS / old WebKit has a broken implementations
31874         _export({ target: 'Date', proto: true, forced: Date.prototype.toISOString !== dateToIsoString }, {
31875           toISOString: dateToIsoString
31876         });
31877
31878         function behaviorBreathe() {
31879           var duration = 800;
31880           var steps = 4;
31881           var selector = '.selected.shadow, .selected .shadow';
31882
31883           var _selected = select(null);
31884
31885           var _classed = '';
31886           var _params = {};
31887           var _done = false;
31888
31889           var _timer;
31890
31891           function ratchetyInterpolator(a, b, steps, units) {
31892             a = parseFloat(a);
31893             b = parseFloat(b);
31894             var sample = quantize().domain([0, 1]).range(d3_quantize(d3_interpolateNumber(a, b), steps));
31895             return function (t) {
31896               return String(sample(t)) + (units || '');
31897             };
31898           }
31899
31900           function reset(selection) {
31901             selection.style('stroke-opacity', null).style('stroke-width', null).style('fill-opacity', null).style('r', null);
31902           }
31903
31904           function setAnimationParams(transition, fromTo) {
31905             var toFrom = fromTo === 'from' ? 'to' : 'from';
31906             transition.styleTween('stroke-opacity', function (d) {
31907               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
31908             }).styleTween('stroke-width', function (d) {
31909               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
31910             }).styleTween('fill-opacity', function (d) {
31911               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
31912             }).styleTween('r', function (d) {
31913               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
31914             });
31915           }
31916
31917           function calcAnimationParams(selection) {
31918             selection.call(reset).each(function (d) {
31919               var s = select(this);
31920               var tag = s.node().tagName;
31921               var p = {
31922                 'from': {},
31923                 'to': {}
31924               };
31925               var opacity;
31926               var width; // determine base opacity and width
31927
31928               if (tag === 'circle') {
31929                 opacity = parseFloat(s.style('fill-opacity') || 0.5);
31930                 width = parseFloat(s.style('r') || 15.5);
31931               } else {
31932                 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
31933                 width = parseFloat(s.style('stroke-width') || 10);
31934               } // calculate from/to interpolation params..
31935
31936
31937               p.tag = tag;
31938               p.from.opacity = opacity * 0.6;
31939               p.to.opacity = opacity * 1.25;
31940               p.from.width = width * 0.7;
31941               p.to.width = width * (tag === 'circle' ? 1.5 : 1);
31942               _params[d.id] = p;
31943             });
31944           }
31945
31946           function run(surface, fromTo) {
31947             var toFrom = fromTo === 'from' ? 'to' : 'from';
31948             var currSelected = surface.selectAll(selector);
31949             var currClassed = surface.attr('class');
31950
31951             if (_done || currSelected.empty()) {
31952               _selected.call(reset);
31953
31954               _selected = select(null);
31955               return;
31956             }
31957
31958             if (!fastDeepEqual(currSelected.data(), _selected.data()) || currClassed !== _classed) {
31959               _selected.call(reset);
31960
31961               _classed = currClassed;
31962               _selected = currSelected.call(calcAnimationParams);
31963             }
31964
31965             var didCallNextRun = false;
31966
31967             _selected.transition().duration(duration).call(setAnimationParams, fromTo).on('end', function () {
31968               // `end` event is called for each selected element, but we want
31969               // it to run only once
31970               if (!didCallNextRun) {
31971                 surface.call(run, toFrom);
31972                 didCallNextRun = true;
31973               } // if entity was deselected, remove breathe styling
31974
31975
31976               if (!select(this).classed('selected')) {
31977                 reset(select(this));
31978               }
31979             });
31980           }
31981
31982           function behavior(surface) {
31983             _done = false;
31984             _timer = timer(function () {
31985               // wait for elements to actually become selected
31986               if (surface.selectAll(selector).empty()) {
31987                 return false;
31988               }
31989
31990               surface.call(run, 'from');
31991
31992               _timer.stop();
31993
31994               return true;
31995             }, 20);
31996           }
31997
31998           behavior.restartIfNeeded = function (surface) {
31999             if (_selected.empty()) {
32000               surface.call(run, 'from');
32001
32002               if (_timer) {
32003                 _timer.stop();
32004               }
32005             }
32006           };
32007
32008           behavior.off = function () {
32009             _done = true;
32010
32011             if (_timer) {
32012               _timer.stop();
32013             }
32014
32015             _selected.interrupt().call(reset);
32016           };
32017
32018           return behavior;
32019         }
32020
32021         /* Creates a keybinding behavior for an operation */
32022         function behaviorOperation(context) {
32023           var _operation;
32024
32025           function keypress(d3_event) {
32026             // prevent operations during low zoom selection
32027             if (!context.map().withinEditableZoom()) return;
32028             if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
32029             d3_event.preventDefault();
32030
32031             var disabled = _operation.disabled();
32032
32033             if (disabled) {
32034               context.ui().flash.duration(4000).iconName('#iD-operation-' + _operation.id).iconClass('operation disabled').label(_operation.tooltip)();
32035             } else {
32036               context.ui().flash.duration(2000).iconName('#iD-operation-' + _operation.id).iconClass('operation').label(_operation.annotation() || _operation.title)();
32037               if (_operation.point) _operation.point(null);
32038
32039               _operation();
32040             }
32041           }
32042
32043           function behavior() {
32044             if (_operation && _operation.available()) {
32045               context.keybinding().on(_operation.keys, keypress);
32046             }
32047
32048             return behavior;
32049           }
32050
32051           behavior.off = function () {
32052             context.keybinding().off(_operation.keys);
32053           };
32054
32055           behavior.which = function (_) {
32056             if (!arguments.length) return _operation;
32057             _operation = _;
32058             return behavior;
32059           };
32060
32061           return behavior;
32062         }
32063
32064         function operationCircularize(context, selectedIDs) {
32065           var _extent;
32066
32067           var _actions = selectedIDs.map(getAction).filter(Boolean);
32068
32069           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32070
32071           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32072             return n.loc;
32073           });
32074
32075           function getAction(entityID) {
32076             var entity = context.entity(entityID);
32077             if (entity.type !== 'way' || new Set(entity.nodes).size <= 1) return null;
32078
32079             if (!_extent) {
32080               _extent = entity.extent(context.graph());
32081             } else {
32082               _extent = _extent.extend(entity.extent(context.graph()));
32083             }
32084
32085             return actionCircularize(entityID, context.projection);
32086           }
32087
32088           var operation = function operation() {
32089             if (!_actions.length) return;
32090
32091             var combinedAction = function combinedAction(graph, t) {
32092               _actions.forEach(function (action) {
32093                 if (!action.disabled(graph)) {
32094                   graph = action(graph, t);
32095                 }
32096               });
32097
32098               return graph;
32099             };
32100
32101             combinedAction.transitionable = true;
32102             context.perform(combinedAction, operation.annotation());
32103             window.setTimeout(function () {
32104               context.validator().validate();
32105             }, 300); // after any transition
32106           };
32107
32108           operation.available = function () {
32109             return _actions.length && selectedIDs.length === _actions.length;
32110           }; // don't cache this because the visible extent could change
32111
32112
32113           operation.disabled = function () {
32114             if (!_actions.length) return '';
32115
32116             var actionDisableds = _actions.map(function (action) {
32117               return action.disabled(context.graph());
32118             }).filter(Boolean);
32119
32120             if (actionDisableds.length === _actions.length) {
32121               // none of the features can be circularized
32122               if (new Set(actionDisableds).size > 1) {
32123                 return 'multiple_blockers';
32124               }
32125
32126               return actionDisableds[0];
32127             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
32128               return 'too_large';
32129             } else if (someMissing()) {
32130               return 'not_downloaded';
32131             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32132               return 'connected_to_hidden';
32133             }
32134
32135             return false;
32136
32137             function someMissing() {
32138               if (context.inIntro()) return false;
32139               var osm = context.connection();
32140
32141               if (osm) {
32142                 var missing = _coords.filter(function (loc) {
32143                   return !osm.isDataLoaded(loc);
32144                 });
32145
32146                 if (missing.length) {
32147                   missing.forEach(function (loc) {
32148                     context.loadTileAtLoc(loc);
32149                   });
32150                   return true;
32151                 }
32152               }
32153
32154               return false;
32155             }
32156           };
32157
32158           operation.tooltip = function () {
32159             var disable = operation.disabled();
32160             return disable ? _t('operations.circularize.' + disable + '.' + _amount) : _t('operations.circularize.description.' + _amount);
32161           };
32162
32163           operation.annotation = function () {
32164             return _t('operations.circularize.annotation.feature', {
32165               n: _actions.length
32166             });
32167           };
32168
32169           operation.id = 'circularize';
32170           operation.keys = [_t('operations.circularize.key')];
32171           operation.title = _t('operations.circularize.title');
32172           operation.behavior = behaviorOperation(context).which(operation);
32173           return operation;
32174         }
32175
32176         // For example, ⌘Z -> Ctrl+Z
32177
32178         var uiCmd = function uiCmd(code) {
32179           var detected = utilDetect();
32180
32181           if (detected.os === 'mac') {
32182             return code;
32183           }
32184
32185           if (detected.os === 'win') {
32186             if (code === '⌘⇧Z') return 'Ctrl+Y';
32187           }
32188
32189           var result = '',
32190               replacements = {
32191             '⌘': 'Ctrl',
32192             '⇧': 'Shift',
32193             '⌥': 'Alt',
32194             '⌫': 'Backspace',
32195             '⌦': 'Delete'
32196           };
32197
32198           for (var i = 0; i < code.length; i++) {
32199             if (code[i] in replacements) {
32200               result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
32201             } else {
32202               result += code[i];
32203             }
32204           }
32205
32206           return result;
32207         }; // return a display-focused string for a given keyboard code
32208
32209         uiCmd.display = function (code) {
32210           if (code.length !== 1) return code;
32211           var detected = utilDetect();
32212           var mac = detected.os === 'mac';
32213           var replacements = {
32214             '⌘': mac ? '⌘ ' + _t('shortcuts.key.cmd') : _t('shortcuts.key.ctrl'),
32215             '⇧': mac ? '⇧ ' + _t('shortcuts.key.shift') : _t('shortcuts.key.shift'),
32216             '⌥': mac ? '⌥ ' + _t('shortcuts.key.option') : _t('shortcuts.key.alt'),
32217             '⌃': mac ? '⌃ ' + _t('shortcuts.key.ctrl') : _t('shortcuts.key.ctrl'),
32218             '⌫': mac ? '⌫ ' + _t('shortcuts.key.delete') : _t('shortcuts.key.backspace'),
32219             '⌦': mac ? '⌦ ' + _t('shortcuts.key.del') : _t('shortcuts.key.del'),
32220             '↖': mac ? '↖ ' + _t('shortcuts.key.pgup') : _t('shortcuts.key.pgup'),
32221             '↘': mac ? '↘ ' + _t('shortcuts.key.pgdn') : _t('shortcuts.key.pgdn'),
32222             '⇞': mac ? '⇞ ' + _t('shortcuts.key.home') : _t('shortcuts.key.home'),
32223             '⇟': mac ? '⇟ ' + _t('shortcuts.key.end') : _t('shortcuts.key.end'),
32224             '↵': mac ? '⏎ ' + _t('shortcuts.key.return') : _t('shortcuts.key.enter'),
32225             '⎋': mac ? '⎋ ' + _t('shortcuts.key.esc') : _t('shortcuts.key.esc'),
32226             '☰': mac ? '☰ ' + _t('shortcuts.key.menu') : _t('shortcuts.key.menu')
32227           };
32228           return replacements[code] || code;
32229         };
32230
32231         function operationDelete(context, selectedIDs) {
32232           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32233           var action = actionDeleteMultiple(selectedIDs);
32234           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32235           var coords = nodes.map(function (n) {
32236             return n.loc;
32237           });
32238           var extent = utilTotalExtent(selectedIDs, context.graph());
32239
32240           var operation = function operation() {
32241             var nextSelectedID;
32242             var nextSelectedLoc;
32243
32244             if (selectedIDs.length === 1) {
32245               var id = selectedIDs[0];
32246               var entity = context.entity(id);
32247               var geometry = entity.geometry(context.graph());
32248               var parents = context.graph().parentWays(entity);
32249               var parent = parents[0]; // Select the next closest node in the way.
32250
32251               if (geometry === 'vertex') {
32252                 var nodes = parent.nodes;
32253                 var i = nodes.indexOf(id);
32254
32255                 if (i === 0) {
32256                   i++;
32257                 } else if (i === nodes.length - 1) {
32258                   i--;
32259                 } else {
32260                   var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
32261                   var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
32262                   i = a < b ? i - 1 : i + 1;
32263                 }
32264
32265                 nextSelectedID = nodes[i];
32266                 nextSelectedLoc = context.entity(nextSelectedID).loc;
32267               }
32268             }
32269
32270             context.perform(action, operation.annotation());
32271             context.validator().validate();
32272
32273             if (nextSelectedID && nextSelectedLoc) {
32274               if (context.hasEntity(nextSelectedID)) {
32275                 context.enter(modeSelect(context, [nextSelectedID]).follow(true));
32276               } else {
32277                 context.map().centerEase(nextSelectedLoc);
32278                 context.enter(modeBrowse(context));
32279               }
32280             } else {
32281               context.enter(modeBrowse(context));
32282             }
32283           };
32284
32285           operation.available = function () {
32286             return true;
32287           };
32288
32289           operation.disabled = function () {
32290             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32291               return 'too_large';
32292             } else if (someMissing()) {
32293               return 'not_downloaded';
32294             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32295               return 'connected_to_hidden';
32296             } else if (selectedIDs.some(protectedMember)) {
32297               return 'part_of_relation';
32298             } else if (selectedIDs.some(incompleteRelation)) {
32299               return 'incomplete_relation';
32300             } else if (selectedIDs.some(hasWikidataTag)) {
32301               return 'has_wikidata_tag';
32302             }
32303
32304             return false;
32305
32306             function someMissing() {
32307               if (context.inIntro()) return false;
32308               var osm = context.connection();
32309
32310               if (osm) {
32311                 var missing = coords.filter(function (loc) {
32312                   return !osm.isDataLoaded(loc);
32313                 });
32314
32315                 if (missing.length) {
32316                   missing.forEach(function (loc) {
32317                     context.loadTileAtLoc(loc);
32318                   });
32319                   return true;
32320                 }
32321               }
32322
32323               return false;
32324             }
32325
32326             function hasWikidataTag(id) {
32327               var entity = context.entity(id);
32328               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
32329             }
32330
32331             function incompleteRelation(id) {
32332               var entity = context.entity(id);
32333               return entity.type === 'relation' && !entity.isComplete(context.graph());
32334             }
32335
32336             function protectedMember(id) {
32337               var entity = context.entity(id);
32338               if (entity.type !== 'way') return false;
32339               var parents = context.graph().parentRelations(entity);
32340
32341               for (var i = 0; i < parents.length; i++) {
32342                 var parent = parents[i];
32343                 var type = parent.tags.type;
32344                 var role = parent.memberById(id).role || 'outer';
32345
32346                 if (type === 'route' || type === 'boundary' || type === 'multipolygon' && role === 'outer') {
32347                   return true;
32348                 }
32349               }
32350
32351               return false;
32352             }
32353           };
32354
32355           operation.tooltip = function () {
32356             var disable = operation.disabled();
32357             return disable ? _t('operations.delete.' + disable + '.' + multi) : _t('operations.delete.description.' + multi);
32358           };
32359
32360           operation.annotation = function () {
32361             return selectedIDs.length === 1 ? _t('operations.delete.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.delete.annotation.feature', {
32362               n: selectedIDs.length
32363             });
32364           };
32365
32366           operation.id = 'delete';
32367           operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
32368           operation.title = _t('operations.delete.title');
32369           operation.behavior = behaviorOperation(context).which(operation);
32370           return operation;
32371         }
32372
32373         function operationOrthogonalize(context, selectedIDs) {
32374           var _extent;
32375
32376           var _type;
32377
32378           var _actions = selectedIDs.map(chooseAction).filter(Boolean);
32379
32380           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32381
32382           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32383             return n.loc;
32384           });
32385
32386           function chooseAction(entityID) {
32387             var entity = context.entity(entityID);
32388             var geometry = entity.geometry(context.graph());
32389
32390             if (!_extent) {
32391               _extent = entity.extent(context.graph());
32392             } else {
32393               _extent = _extent.extend(entity.extent(context.graph()));
32394             } // square a line/area
32395
32396
32397             if (entity.type === 'way' && new Set(entity.nodes).size > 2) {
32398               if (_type && _type !== 'feature') return null;
32399               _type = 'feature';
32400               return actionOrthogonalize(entityID, context.projection); // square a single vertex
32401             } else if (geometry === 'vertex') {
32402               if (_type && _type !== 'corner') return null;
32403               _type = 'corner';
32404               var graph = context.graph();
32405               var parents = graph.parentWays(entity);
32406
32407               if (parents.length === 1) {
32408                 var way = parents[0];
32409
32410                 if (way.nodes.indexOf(entityID) !== -1) {
32411                   return actionOrthogonalize(way.id, context.projection, entityID);
32412                 }
32413               }
32414             }
32415
32416             return null;
32417           }
32418
32419           var operation = function operation() {
32420             if (!_actions.length) return;
32421
32422             var combinedAction = function combinedAction(graph, t) {
32423               _actions.forEach(function (action) {
32424                 if (!action.disabled(graph)) {
32425                   graph = action(graph, t);
32426                 }
32427               });
32428
32429               return graph;
32430             };
32431
32432             combinedAction.transitionable = true;
32433             context.perform(combinedAction, operation.annotation());
32434             window.setTimeout(function () {
32435               context.validator().validate();
32436             }, 300); // after any transition
32437           };
32438
32439           operation.available = function () {
32440             return _actions.length && selectedIDs.length === _actions.length;
32441           }; // don't cache this because the visible extent could change
32442
32443
32444           operation.disabled = function () {
32445             if (!_actions.length) return '';
32446
32447             var actionDisableds = _actions.map(function (action) {
32448               return action.disabled(context.graph());
32449             }).filter(Boolean);
32450
32451             if (actionDisableds.length === _actions.length) {
32452               // none of the features can be squared
32453               if (new Set(actionDisableds).size > 1) {
32454                 return 'multiple_blockers';
32455               }
32456
32457               return actionDisableds[0];
32458             } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
32459               return 'too_large';
32460             } else if (someMissing()) {
32461               return 'not_downloaded';
32462             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32463               return 'connected_to_hidden';
32464             }
32465
32466             return false;
32467
32468             function someMissing() {
32469               if (context.inIntro()) return false;
32470               var osm = context.connection();
32471
32472               if (osm) {
32473                 var missing = _coords.filter(function (loc) {
32474                   return !osm.isDataLoaded(loc);
32475                 });
32476
32477                 if (missing.length) {
32478                   missing.forEach(function (loc) {
32479                     context.loadTileAtLoc(loc);
32480                   });
32481                   return true;
32482                 }
32483               }
32484
32485               return false;
32486             }
32487           };
32488
32489           operation.tooltip = function () {
32490             var disable = operation.disabled();
32491             return disable ? _t('operations.orthogonalize.' + disable + '.' + _amount) : _t('operations.orthogonalize.description.' + _type + '.' + _amount);
32492           };
32493
32494           operation.annotation = function () {
32495             return _t('operations.orthogonalize.annotation.' + _type, {
32496               n: _actions.length
32497             });
32498           };
32499
32500           operation.id = 'orthogonalize';
32501           operation.keys = [_t('operations.orthogonalize.key')];
32502           operation.title = _t('operations.orthogonalize.title');
32503           operation.behavior = behaviorOperation(context).which(operation);
32504           return operation;
32505         }
32506
32507         function operationReflectShort(context, selectedIDs) {
32508           return operationReflect(context, selectedIDs, 'short');
32509         }
32510         function operationReflectLong(context, selectedIDs) {
32511           return operationReflect(context, selectedIDs, 'long');
32512         }
32513         function operationReflect(context, selectedIDs, axis) {
32514           axis = axis || 'long';
32515           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32516           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32517           var coords = nodes.map(function (n) {
32518             return n.loc;
32519           });
32520           var extent = utilTotalExtent(selectedIDs, context.graph());
32521
32522           var operation = function operation() {
32523             var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === 'long'));
32524             context.perform(action, operation.annotation());
32525             window.setTimeout(function () {
32526               context.validator().validate();
32527             }, 300); // after any transition
32528           };
32529
32530           operation.available = function () {
32531             return nodes.length >= 3;
32532           }; // don't cache this because the visible extent could change
32533
32534
32535           operation.disabled = function () {
32536             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32537               return 'too_large';
32538             } else if (someMissing()) {
32539               return 'not_downloaded';
32540             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32541               return 'connected_to_hidden';
32542             } else if (selectedIDs.some(incompleteRelation)) {
32543               return 'incomplete_relation';
32544             }
32545
32546             return false;
32547
32548             function someMissing() {
32549               if (context.inIntro()) return false;
32550               var osm = context.connection();
32551
32552               if (osm) {
32553                 var missing = coords.filter(function (loc) {
32554                   return !osm.isDataLoaded(loc);
32555                 });
32556
32557                 if (missing.length) {
32558                   missing.forEach(function (loc) {
32559                     context.loadTileAtLoc(loc);
32560                   });
32561                   return true;
32562                 }
32563               }
32564
32565               return false;
32566             }
32567
32568             function incompleteRelation(id) {
32569               var entity = context.entity(id);
32570               return entity.type === 'relation' && !entity.isComplete(context.graph());
32571             }
32572           };
32573
32574           operation.tooltip = function () {
32575             var disable = operation.disabled();
32576             return disable ? _t('operations.reflect.' + disable + '.' + multi) : _t('operations.reflect.description.' + axis + '.' + multi);
32577           };
32578
32579           operation.annotation = function () {
32580             return _t('operations.reflect.annotation.' + axis + '.feature', {
32581               n: selectedIDs.length
32582             });
32583           };
32584
32585           operation.id = 'reflect-' + axis;
32586           operation.keys = [_t('operations.reflect.key.' + axis)];
32587           operation.title = _t('operations.reflect.title.' + axis);
32588           operation.behavior = behaviorOperation(context).which(operation);
32589           return operation;
32590         }
32591
32592         function operationMove(context, selectedIDs) {
32593           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32594           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32595           var coords = nodes.map(function (n) {
32596             return n.loc;
32597           });
32598           var extent = utilTotalExtent(selectedIDs, context.graph());
32599
32600           var operation = function operation() {
32601             context.enter(modeMove(context, selectedIDs));
32602           };
32603
32604           operation.available = function () {
32605             return selectedIDs.length > 1 || context.entity(selectedIDs[0]).type !== 'node';
32606           };
32607
32608           operation.disabled = function () {
32609             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32610               return 'too_large';
32611             } else if (someMissing()) {
32612               return 'not_downloaded';
32613             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32614               return 'connected_to_hidden';
32615             } else if (selectedIDs.some(incompleteRelation)) {
32616               return 'incomplete_relation';
32617             }
32618
32619             return false;
32620
32621             function someMissing() {
32622               if (context.inIntro()) return false;
32623               var osm = context.connection();
32624
32625               if (osm) {
32626                 var missing = coords.filter(function (loc) {
32627                   return !osm.isDataLoaded(loc);
32628                 });
32629
32630                 if (missing.length) {
32631                   missing.forEach(function (loc) {
32632                     context.loadTileAtLoc(loc);
32633                   });
32634                   return true;
32635                 }
32636               }
32637
32638               return false;
32639             }
32640
32641             function incompleteRelation(id) {
32642               var entity = context.entity(id);
32643               return entity.type === 'relation' && !entity.isComplete(context.graph());
32644             }
32645           };
32646
32647           operation.tooltip = function () {
32648             var disable = operation.disabled();
32649             return disable ? _t('operations.move.' + disable + '.' + multi) : _t('operations.move.description.' + multi);
32650           };
32651
32652           operation.annotation = function () {
32653             return selectedIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.move.annotation.feature', {
32654               n: selectedIDs.length
32655             });
32656           };
32657
32658           operation.id = 'move';
32659           operation.keys = [_t('operations.move.key')];
32660           operation.title = _t('operations.move.title');
32661           operation.behavior = behaviorOperation(context).which(operation);
32662           operation.mouseOnly = true;
32663           return operation;
32664         }
32665
32666         function modeRotate(context, entityIDs) {
32667           var mode = {
32668             id: 'rotate',
32669             button: 'browse'
32670           };
32671           var keybinding = utilKeybinding('rotate');
32672           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];
32673           var annotation = entityIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.rotate.annotation.feature', {
32674             n: entityIDs.length
32675           });
32676
32677           var _prevGraph;
32678
32679           var _prevAngle;
32680
32681           var _prevTransform;
32682
32683           var _pivot;
32684
32685           function doRotate() {
32686             var fn;
32687
32688             if (context.graph() !== _prevGraph) {
32689               fn = context.perform;
32690             } else {
32691               fn = context.replace;
32692             } // projection changed, recalculate _pivot
32693
32694
32695             var projection = context.projection;
32696             var currTransform = projection.transform();
32697
32698             if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
32699               var nodes = utilGetAllNodes(entityIDs, context.graph());
32700               var points = nodes.map(function (n) {
32701                 return projection(n.loc);
32702               });
32703               _pivot = getPivot(points);
32704               _prevAngle = undefined;
32705             }
32706
32707             var currMouse = context.map().mouse();
32708             var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
32709             if (typeof _prevAngle === 'undefined') _prevAngle = currAngle;
32710             var delta = currAngle - _prevAngle;
32711             fn(actionRotate(entityIDs, _pivot, delta, projection));
32712             _prevTransform = currTransform;
32713             _prevAngle = currAngle;
32714             _prevGraph = context.graph();
32715           }
32716
32717           function getPivot(points) {
32718             var _pivot;
32719
32720             if (points.length === 1) {
32721               _pivot = points[0];
32722             } else if (points.length === 2) {
32723               _pivot = geoVecInterp(points[0], points[1], 0.5);
32724             } else {
32725               var polygonHull = d3_polygonHull(points);
32726
32727               if (polygonHull.length === 2) {
32728                 _pivot = geoVecInterp(points[0], points[1], 0.5);
32729               } else {
32730                 _pivot = d3_polygonCentroid(d3_polygonHull(points));
32731               }
32732             }
32733
32734             return _pivot;
32735           }
32736
32737           function finish(d3_event) {
32738             d3_event.stopPropagation();
32739             context.replace(actionNoop(), annotation);
32740             context.enter(modeSelect(context, entityIDs));
32741           }
32742
32743           function cancel() {
32744             context.pop();
32745             context.enter(modeSelect(context, entityIDs));
32746           }
32747
32748           function undone() {
32749             context.enter(modeBrowse(context));
32750           }
32751
32752           mode.enter = function () {
32753             context.features().forceVisible(entityIDs);
32754             behaviors.forEach(context.install);
32755             context.surface().on('mousemove.rotate', doRotate).on('click.rotate', finish);
32756             context.history().on('undone.rotate', undone);
32757             keybinding.on('⎋', cancel).on('↩', finish);
32758             select(document).call(keybinding);
32759           };
32760
32761           mode.exit = function () {
32762             behaviors.forEach(context.uninstall);
32763             context.surface().on('mousemove.rotate', null).on('click.rotate', null);
32764             context.history().on('undone.rotate', null);
32765             select(document).call(keybinding.unbind);
32766             context.features().forceVisible([]);
32767           };
32768
32769           mode.selectedIDs = function () {
32770             if (!arguments.length) return entityIDs; // no assign
32771
32772             return mode;
32773           };
32774
32775           return mode;
32776         }
32777
32778         function operationRotate(context, selectedIDs) {
32779           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32780           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32781           var coords = nodes.map(function (n) {
32782             return n.loc;
32783           });
32784           var extent = utilTotalExtent(selectedIDs, context.graph());
32785
32786           var operation = function operation() {
32787             context.enter(modeRotate(context, selectedIDs));
32788           };
32789
32790           operation.available = function () {
32791             return nodes.length >= 2;
32792           };
32793
32794           operation.disabled = function () {
32795             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32796               return 'too_large';
32797             } else if (someMissing()) {
32798               return 'not_downloaded';
32799             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32800               return 'connected_to_hidden';
32801             } else if (selectedIDs.some(incompleteRelation)) {
32802               return 'incomplete_relation';
32803             }
32804
32805             return false;
32806
32807             function someMissing() {
32808               if (context.inIntro()) return false;
32809               var osm = context.connection();
32810
32811               if (osm) {
32812                 var missing = coords.filter(function (loc) {
32813                   return !osm.isDataLoaded(loc);
32814                 });
32815
32816                 if (missing.length) {
32817                   missing.forEach(function (loc) {
32818                     context.loadTileAtLoc(loc);
32819                   });
32820                   return true;
32821                 }
32822               }
32823
32824               return false;
32825             }
32826
32827             function incompleteRelation(id) {
32828               var entity = context.entity(id);
32829               return entity.type === 'relation' && !entity.isComplete(context.graph());
32830             }
32831           };
32832
32833           operation.tooltip = function () {
32834             var disable = operation.disabled();
32835             return disable ? _t('operations.rotate.' + disable + '.' + multi) : _t('operations.rotate.description.' + multi);
32836           };
32837
32838           operation.annotation = function () {
32839             return selectedIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.rotate.annotation.feature', {
32840               n: selectedIDs.length
32841             });
32842           };
32843
32844           operation.id = 'rotate';
32845           operation.keys = [_t('operations.rotate.key')];
32846           operation.title = _t('operations.rotate.title');
32847           operation.behavior = behaviorOperation(context).which(operation);
32848           operation.mouseOnly = true;
32849           return operation;
32850         }
32851
32852         function modeMove(context, entityIDs, baseGraph) {
32853           var mode = {
32854             id: 'move',
32855             button: 'browse'
32856           };
32857           var keybinding = utilKeybinding('move');
32858           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];
32859           var annotation = entityIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.move.annotation.feature', {
32860             n: entityIDs.length
32861           });
32862
32863           var _prevGraph;
32864
32865           var _cache;
32866
32867           var _origin;
32868
32869           var _nudgeInterval;
32870
32871           function doMove(nudge) {
32872             nudge = nudge || [0, 0];
32873             var fn;
32874
32875             if (_prevGraph !== context.graph()) {
32876               _cache = {};
32877               _origin = context.map().mouseCoordinates();
32878               fn = context.perform;
32879             } else {
32880               fn = context.overwrite;
32881             }
32882
32883             var currMouse = context.map().mouse();
32884             var origMouse = context.projection(_origin);
32885             var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
32886             fn(actionMove(entityIDs, delta, context.projection, _cache));
32887             _prevGraph = context.graph();
32888           }
32889
32890           function startNudge(nudge) {
32891             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
32892             _nudgeInterval = window.setInterval(function () {
32893               context.map().pan(nudge);
32894               doMove(nudge);
32895             }, 50);
32896           }
32897
32898           function stopNudge() {
32899             if (_nudgeInterval) {
32900               window.clearInterval(_nudgeInterval);
32901               _nudgeInterval = null;
32902             }
32903           }
32904
32905           function move() {
32906             doMove();
32907             var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
32908
32909             if (nudge) {
32910               startNudge(nudge);
32911             } else {
32912               stopNudge();
32913             }
32914           }
32915
32916           function finish(d3_event) {
32917             d3_event.stopPropagation();
32918             context.replace(actionNoop(), annotation);
32919             context.enter(modeSelect(context, entityIDs));
32920             stopNudge();
32921           }
32922
32923           function cancel() {
32924             if (baseGraph) {
32925               while (context.graph() !== baseGraph) {
32926                 context.pop();
32927               }
32928
32929               context.enter(modeBrowse(context));
32930             } else {
32931               context.pop();
32932               context.enter(modeSelect(context, entityIDs));
32933             }
32934
32935             stopNudge();
32936           }
32937
32938           function undone() {
32939             context.enter(modeBrowse(context));
32940           }
32941
32942           mode.enter = function () {
32943             _origin = context.map().mouseCoordinates();
32944             _prevGraph = null;
32945             _cache = {};
32946             context.features().forceVisible(entityIDs);
32947             behaviors.forEach(context.install);
32948             context.surface().on('mousemove.move', move).on('click.move', finish);
32949             context.history().on('undone.move', undone);
32950             keybinding.on('⎋', cancel).on('↩', finish);
32951             select(document).call(keybinding);
32952           };
32953
32954           mode.exit = function () {
32955             stopNudge();
32956             behaviors.forEach(function (behavior) {
32957               context.uninstall(behavior);
32958             });
32959             context.surface().on('mousemove.move', null).on('click.move', null);
32960             context.history().on('undone.move', null);
32961             select(document).call(keybinding.unbind);
32962             context.features().forceVisible([]);
32963           };
32964
32965           mode.selectedIDs = function () {
32966             if (!arguments.length) return entityIDs; // no assign
32967
32968             return mode;
32969           };
32970
32971           return mode;
32972         }
32973
32974         function behaviorPaste(context) {
32975           function doPaste(d3_event) {
32976             // prevent paste during low zoom selection
32977             if (!context.map().withinEditableZoom()) return;
32978             d3_event.preventDefault();
32979             var baseGraph = context.graph();
32980             var mouse = context.map().mouse();
32981             var projection = context.projection;
32982             var viewport = geoExtent(projection.clipExtent()).polygon();
32983             if (!geoPointInPolygon(mouse, viewport)) return;
32984             var oldIDs = context.copyIDs();
32985             if (!oldIDs.length) return;
32986             var extent = geoExtent();
32987             var oldGraph = context.copyGraph();
32988             var newIDs = [];
32989             var action = actionCopyEntities(oldIDs, oldGraph);
32990             context.perform(action);
32991             var copies = action.copies();
32992             var originals = new Set();
32993             Object.values(copies).forEach(function (entity) {
32994               originals.add(entity.id);
32995             });
32996
32997             for (var id in copies) {
32998               var oldEntity = oldGraph.entity(id);
32999               var newEntity = copies[id];
33000
33001               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
33002
33003
33004               var parents = context.graph().parentWays(newEntity);
33005               var parentCopied = parents.some(function (parent) {
33006                 return originals.has(parent.id);
33007               });
33008
33009               if (!parentCopied) {
33010                 newIDs.push(newEntity.id);
33011               }
33012             } // Put pasted objects where mouse pointer is..
33013
33014
33015             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
33016             var delta = geoVecSubtract(mouse, copyPoint);
33017             context.perform(actionMove(newIDs, delta, projection));
33018             context.enter(modeMove(context, newIDs, baseGraph));
33019           }
33020
33021           function behavior() {
33022             context.keybinding().on(uiCmd('⌘V'), doPaste);
33023             return behavior;
33024           }
33025
33026           behavior.off = function () {
33027             context.keybinding().off(uiCmd('⌘V'));
33028           };
33029
33030           return behavior;
33031         }
33032
33033         // `String.prototype.repeat` method
33034         // https://tc39.github.io/ecma262/#sec-string.prototype.repeat
33035         _export({ target: 'String', proto: true }, {
33036           repeat: stringRepeat
33037         });
33038
33039         /*
33040             `behaviorDrag` is like `d3_behavior.drag`, with the following differences:
33041
33042             * The `origin` function is expected to return an [x, y] tuple rather than an
33043               {x, y} object.
33044             * The events are `start`, `move`, and `end`.
33045               (https://github.com/mbostock/d3/issues/563)
33046             * The `start` event is not dispatched until the first cursor movement occurs.
33047               (https://github.com/mbostock/d3/pull/368)
33048             * The `move` event has a `point` and `delta` [x, y] tuple properties rather
33049               than `x`, `y`, `dx`, and `dy` properties.
33050             * The `end` event is not dispatched if no movement occurs.
33051             * An `off` function is available that unbinds the drag's internal event handlers.
33052          */
33053
33054         function behaviorDrag() {
33055           var dispatch$1 = dispatch('start', 'move', 'end'); // see also behaviorSelect
33056
33057           var _tolerancePx = 1; // keep this low to facilitate pixel-perfect micromapping
33058
33059           var _penTolerancePx = 4; // styluses can be touchy so require greater movement - #1981
33060
33061           var _origin = null;
33062           var _selector = '';
33063
33064           var _targetNode;
33065
33066           var _targetEntity;
33067
33068           var _surface;
33069
33070           var _pointerId; // use pointer events on supported platforms; fallback to mouse events
33071
33072
33073           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
33074
33075           var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect');
33076
33077           var d3_event_userSelectSuppress = function d3_event_userSelectSuppress() {
33078             var selection$1 = selection();
33079             var select = selection$1.style(d3_event_userSelectProperty);
33080             selection$1.style(d3_event_userSelectProperty, 'none');
33081             return function () {
33082               selection$1.style(d3_event_userSelectProperty, select);
33083             };
33084           };
33085
33086           function pointerdown(d3_event) {
33087             if (_pointerId) return;
33088             _pointerId = d3_event.pointerId || 'mouse';
33089             _targetNode = this; // only force reflow once per drag
33090
33091             var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
33092             var offset;
33093             var startOrigin = pointerLocGetter(d3_event);
33094             var started = false;
33095             var selectEnable = d3_event_userSelectSuppress();
33096             select(window).on(_pointerPrefix + 'move.drag', pointermove).on(_pointerPrefix + 'up.drag pointercancel.drag', pointerup, true);
33097
33098             if (_origin) {
33099               offset = _origin.call(_targetNode, _targetEntity);
33100               offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
33101             } else {
33102               offset = [0, 0];
33103             }
33104
33105             d3_event.stopPropagation();
33106
33107             function pointermove(d3_event) {
33108               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33109               var p = pointerLocGetter(d3_event);
33110
33111               if (!started) {
33112                 var dist = geoVecLength(startOrigin, p);
33113                 var tolerance = d3_event.pointerType === 'pen' ? _penTolerancePx : _tolerancePx; // don't start until the drag has actually moved somewhat
33114
33115                 if (dist < tolerance) return;
33116                 started = true;
33117                 dispatch$1.call('start', this, d3_event, _targetEntity); // Don't send a `move` event in the same cycle as `start` since dragging
33118                 // a midpoint will convert the target to a node.
33119               } else {
33120                 startOrigin = p;
33121                 d3_event.stopPropagation();
33122                 d3_event.preventDefault();
33123                 var dx = p[0] - startOrigin[0];
33124                 var dy = p[1] - startOrigin[1];
33125                 dispatch$1.call('move', this, d3_event, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
33126               }
33127             }
33128
33129             function pointerup(d3_event) {
33130               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33131               _pointerId = null;
33132
33133               if (started) {
33134                 dispatch$1.call('end', this, d3_event, _targetEntity);
33135                 d3_event.preventDefault();
33136               }
33137
33138               select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33139               selectEnable();
33140             }
33141           }
33142
33143           function behavior(selection) {
33144             var matchesSelector = utilPrefixDOMProperty('matchesSelector');
33145             var delegate = pointerdown;
33146
33147             if (_selector) {
33148               delegate = function delegate(d3_event) {
33149                 var root = this;
33150                 var target = d3_event.target;
33151
33152                 for (; target && target !== root; target = target.parentNode) {
33153                   var datum = target.__data__;
33154                   _targetEntity = datum instanceof osmNote ? datum : datum && datum.properties && datum.properties.entity;
33155
33156                   if (_targetEntity && target[matchesSelector](_selector)) {
33157                     return pointerdown.call(target, d3_event);
33158                   }
33159                 }
33160               };
33161             }
33162
33163             selection.on(_pointerPrefix + 'down.drag' + _selector, delegate);
33164           }
33165
33166           behavior.off = function (selection) {
33167             selection.on(_pointerPrefix + 'down.drag' + _selector, null);
33168           };
33169
33170           behavior.selector = function (_) {
33171             if (!arguments.length) return _selector;
33172             _selector = _;
33173             return behavior;
33174           };
33175
33176           behavior.origin = function (_) {
33177             if (!arguments.length) return _origin;
33178             _origin = _;
33179             return behavior;
33180           };
33181
33182           behavior.cancel = function () {
33183             select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33184             return behavior;
33185           };
33186
33187           behavior.targetNode = function (_) {
33188             if (!arguments.length) return _targetNode;
33189             _targetNode = _;
33190             return behavior;
33191           };
33192
33193           behavior.targetEntity = function (_) {
33194             if (!arguments.length) return _targetEntity;
33195             _targetEntity = _;
33196             return behavior;
33197           };
33198
33199           behavior.surface = function (_) {
33200             if (!arguments.length) return _surface;
33201             _surface = _;
33202             return behavior;
33203           };
33204
33205           return utilRebind(behavior, dispatch$1, 'on');
33206         }
33207
33208         function modeDragNode(context) {
33209           var mode = {
33210             id: 'drag-node',
33211             button: 'browse'
33212           };
33213           var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover);
33214           var edit = behaviorEdit(context);
33215
33216           var _nudgeInterval;
33217
33218           var _restoreSelectedIDs = [];
33219           var _wasMidpoint = false;
33220           var _isCancelled = false;
33221
33222           var _activeEntity;
33223
33224           var _startLoc;
33225
33226           var _lastLoc;
33227
33228           function startNudge(d3_event, entity, nudge) {
33229             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
33230             _nudgeInterval = window.setInterval(function () {
33231               context.map().pan(nudge);
33232               doMove(d3_event, entity, nudge);
33233             }, 50);
33234           }
33235
33236           function stopNudge() {
33237             if (_nudgeInterval) {
33238               window.clearInterval(_nudgeInterval);
33239               _nudgeInterval = null;
33240             }
33241           }
33242
33243           function moveAnnotation(entity) {
33244             return _t('operations.move.annotation.' + entity.geometry(context.graph()));
33245           }
33246
33247           function connectAnnotation(nodeEntity, targetEntity) {
33248             var nodeGeometry = nodeEntity.geometry(context.graph());
33249             var targetGeometry = targetEntity.geometry(context.graph());
33250
33251             if (nodeGeometry === 'vertex' && targetGeometry === 'vertex') {
33252               var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
33253               var targetParentWayIDs = context.graph().parentWays(targetEntity);
33254               var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs); // if both vertices are part of the same way
33255
33256               if (sharedParentWays.length !== 0) {
33257                 // if the nodes are next to each other, they are merged
33258                 if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
33259                   return _t('operations.connect.annotation.from_vertex.to_adjacent_vertex');
33260                 }
33261
33262                 return _t('operations.connect.annotation.from_vertex.to_sibling_vertex');
33263               }
33264             }
33265
33266             return _t('operations.connect.annotation.from_' + nodeGeometry + '.to_' + targetGeometry);
33267           }
33268
33269           function shouldSnapToNode(target) {
33270             if (!_activeEntity) return false;
33271             return _activeEntity.geometry(context.graph()) !== 'vertex' || target.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(target, context.graph());
33272           }
33273
33274           function origin(entity) {
33275             return context.projection(entity.loc);
33276           }
33277
33278           function keydown(d3_event) {
33279             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33280               if (context.surface().classed('nope')) {
33281                 context.surface().classed('nope-suppressed', true);
33282               }
33283
33284               context.surface().classed('nope', false).classed('nope-disabled', true);
33285             }
33286           }
33287
33288           function keyup(d3_event) {
33289             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33290               if (context.surface().classed('nope-suppressed')) {
33291                 context.surface().classed('nope', true);
33292               }
33293
33294               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
33295             }
33296           }
33297
33298           function start(d3_event, entity) {
33299             _wasMidpoint = entity.type === 'midpoint';
33300             var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
33301             _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
33302
33303             if (_isCancelled) {
33304               if (hasHidden) {
33305                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('modes.drag_node.connected_to_hidden'))();
33306               }
33307
33308               return drag.cancel();
33309             }
33310
33311             if (_wasMidpoint) {
33312               var midpoint = entity;
33313               entity = osmNode();
33314               context.perform(actionAddMidpoint(midpoint, entity));
33315               entity = context.entity(entity.id); // get post-action entity
33316
33317               var vertex = context.surface().selectAll('.' + entity.id);
33318               drag.targetNode(vertex.node()).targetEntity(entity);
33319             } else {
33320               context.perform(actionNoop());
33321             }
33322
33323             _activeEntity = entity;
33324             _startLoc = entity.loc;
33325             hover.ignoreVertex(entity.geometry(context.graph()) === 'vertex');
33326             context.surface().selectAll('.' + _activeEntity.id).classed('active', true);
33327             context.enter(mode);
33328           } // related code
33329           // - `behavior/draw.js` `datum()`
33330
33331
33332           function datum(d3_event) {
33333             if (!d3_event || d3_event.altKey) {
33334               return {};
33335             } else {
33336               // When dragging, snap only to touch targets..
33337               // (this excludes area fills and active drawing elements)
33338               var d = d3_event.target.__data__;
33339               return d && d.properties && d.properties.target ? d : {};
33340             }
33341           }
33342
33343           function doMove(d3_event, entity, nudge) {
33344             nudge = nudge || [0, 0];
33345             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
33346             var currMouse = geoVecSubtract(currPoint, nudge);
33347             var loc = context.projection.invert(currMouse);
33348             var target, edge;
33349
33350             if (!_nudgeInterval) {
33351               // If not nudging at the edge of the viewport, try to snap..
33352               // related code
33353               // - `mode/drag_node.js`     `doMove()`
33354               // - `behavior/draw.js`      `click()`
33355               // - `behavior/draw_way.js`  `move()`
33356               var d = datum(d3_event);
33357               target = d && d.properties && d.properties.entity;
33358               var targetLoc = target && target.loc;
33359               var targetNodes = d && d.properties && d.properties.nodes;
33360
33361               if (targetLoc) {
33362                 // snap to node/vertex - a point target with `.loc`
33363                 if (shouldSnapToNode(target)) {
33364                   loc = targetLoc;
33365                 }
33366               } else if (targetNodes) {
33367                 // snap to way - a line target with `.nodes`
33368                 edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
33369
33370                 if (edge) {
33371                   loc = edge.loc;
33372                 }
33373               }
33374             }
33375
33376             context.replace(actionMoveNode(entity.id, loc)); // Below here: validations
33377
33378             var isInvalid = false; // Check if this connection to `target` could cause relations to break..
33379
33380             if (target) {
33381               isInvalid = hasRelationConflict(entity, target, edge, context.graph());
33382             } // Check if this drag causes the geometry to break..
33383
33384
33385             if (!isInvalid) {
33386               isInvalid = hasInvalidGeometry(entity, context.graph());
33387             }
33388
33389             var nope = context.surface().classed('nope');
33390
33391             if (isInvalid === 'relation' || isInvalid === 'restriction') {
33392               if (!nope) {
33393                 // about to nope - show hint
33394                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.connect.' + isInvalid, {
33395                   relation: _mainPresetIndex.item('type/restriction').name()
33396                 }))();
33397               }
33398             } else if (isInvalid) {
33399               var errorID = isInvalid === 'line' ? 'lines' : 'areas';
33400               context.ui().flash.duration(3000).iconName('#iD-icon-no').label(_t('self_intersection.error.' + errorID))();
33401             } else {
33402               if (nope) {
33403                 // about to un-nope, remove hint
33404                 context.ui().flash.duration(1).label('')();
33405               }
33406             }
33407
33408             var nopeDisabled = context.surface().classed('nope-disabled');
33409
33410             if (nopeDisabled) {
33411               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
33412             } else {
33413               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
33414             }
33415
33416             _lastLoc = loc;
33417           } // Uses `actionConnect.disabled()` to know whether this connection is ok..
33418
33419
33420           function hasRelationConflict(entity, target, edge, graph) {
33421             var testGraph = graph.update(); // copy
33422             // if snapping to way - add midpoint there and consider that the target..
33423
33424             if (edge) {
33425               var midpoint = osmNode();
33426               var action = actionAddMidpoint({
33427                 loc: edge.loc,
33428                 edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
33429               }, midpoint);
33430               testGraph = action(testGraph);
33431               target = midpoint;
33432             } // can we connect to it?
33433
33434
33435             var ids = [entity.id, target.id];
33436             return actionConnect(ids).disabled(testGraph);
33437           }
33438
33439           function hasInvalidGeometry(entity, graph) {
33440             var parents = graph.parentWays(entity);
33441             var i, j, k;
33442
33443             for (i = 0; i < parents.length; i++) {
33444               var parent = parents[i];
33445               var nodes = [];
33446               var activeIndex = null; // which multipolygon ring contains node being dragged
33447               // test any parent multipolygons for valid geometry
33448
33449               var relations = graph.parentRelations(parent);
33450
33451               for (j = 0; j < relations.length; j++) {
33452                 if (!relations[j].isMultipolygon()) continue;
33453                 var rings = osmJoinWays(relations[j].members, graph); // find active ring and test it for self intersections
33454
33455                 for (k = 0; k < rings.length; k++) {
33456                   nodes = rings[k].nodes;
33457
33458                   if (nodes.find(function (n) {
33459                     return n.id === entity.id;
33460                   })) {
33461                     activeIndex = k;
33462
33463                     if (geoHasSelfIntersections(nodes, entity.id)) {
33464                       return 'multipolygonMember';
33465                     }
33466                   }
33467
33468                   rings[k].coords = nodes.map(function (n) {
33469                     return n.loc;
33470                   });
33471                 } // test active ring for intersections with other rings in the multipolygon
33472
33473
33474                 for (k = 0; k < rings.length; k++) {
33475                   if (k === activeIndex) continue; // make sure active ring doesn't cross passive rings
33476
33477                   if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
33478                     return 'multipolygonRing';
33479                   }
33480                 }
33481               } // If we still haven't tested this node's parent way for self-intersections.
33482               // (because it's not a member of a multipolygon), test it now.
33483
33484
33485               if (activeIndex === null) {
33486                 nodes = parent.nodes.map(function (nodeID) {
33487                   return graph.entity(nodeID);
33488                 });
33489
33490                 if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
33491                   return parent.geometry(graph);
33492                 }
33493               }
33494             }
33495
33496             return false;
33497           }
33498
33499           function move(d3_event, entity, point) {
33500             if (_isCancelled) return;
33501             d3_event.stopPropagation();
33502             context.surface().classed('nope-disabled', d3_event.altKey);
33503             _lastLoc = context.projection.invert(point);
33504             doMove(d3_event, entity);
33505             var nudge = geoViewportEdge(point, context.map().dimensions());
33506
33507             if (nudge) {
33508               startNudge(d3_event, entity, nudge);
33509             } else {
33510               stopNudge();
33511             }
33512           }
33513
33514           function end(d3_event, entity) {
33515             if (_isCancelled) return;
33516             var wasPoint = entity.geometry(context.graph()) === 'point';
33517             var d = datum(d3_event);
33518             var nope = d && d.properties && d.properties.nope || context.surface().classed('nope');
33519             var target = d && d.properties && d.properties.entity; // entity to snap to
33520
33521             if (nope) {
33522               // bounce back
33523               context.perform(_actionBounceBack(entity.id, _startLoc));
33524             } else if (target && target.type === 'way') {
33525               var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
33526               context.replace(actionAddMidpoint({
33527                 loc: choice.loc,
33528                 edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
33529               }, entity), connectAnnotation(entity, target));
33530             } else if (target && target.type === 'node' && shouldSnapToNode(target)) {
33531               context.replace(actionConnect([target.id, entity.id]), connectAnnotation(entity, target));
33532             } else if (_wasMidpoint) {
33533               context.replace(actionNoop(), _t('operations.add.annotation.vertex'));
33534             } else {
33535               context.replace(actionNoop(), moveAnnotation(entity));
33536             }
33537
33538             if (wasPoint) {
33539               context.enter(modeSelect(context, [entity.id]));
33540             } else {
33541               var reselection = _restoreSelectedIDs.filter(function (id) {
33542                 return context.graph().hasEntity(id);
33543               });
33544
33545               if (reselection.length) {
33546                 context.enter(modeSelect(context, reselection));
33547               } else {
33548                 context.enter(modeBrowse(context));
33549               }
33550             }
33551           }
33552
33553           function _actionBounceBack(nodeID, toLoc) {
33554             var moveNode = actionMoveNode(nodeID, toLoc);
33555
33556             var action = function action(graph, t) {
33557               // last time through, pop off the bounceback perform.
33558               // it will then overwrite the initial perform with a moveNode that does nothing
33559               if (t === 1) context.pop();
33560               return moveNode(graph, t);
33561             };
33562
33563             action.transitionable = true;
33564             return action;
33565           }
33566
33567           function cancel() {
33568             drag.cancel();
33569             context.enter(modeBrowse(context));
33570           }
33571
33572           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);
33573
33574           mode.enter = function () {
33575             context.install(hover);
33576             context.install(edit);
33577             select(window).on('keydown.dragNode', keydown).on('keyup.dragNode', keyup);
33578             context.history().on('undone.drag-node', cancel);
33579           };
33580
33581           mode.exit = function () {
33582             context.ui().sidebar.hover.cancel();
33583             context.uninstall(hover);
33584             context.uninstall(edit);
33585             select(window).on('keydown.dragNode', null).on('keyup.dragNode', null);
33586             context.history().on('undone.drag-node', null);
33587             _activeEntity = null;
33588             context.surface().classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false).selectAll('.active').classed('active', false);
33589             stopNudge();
33590           };
33591
33592           mode.selectedIDs = function () {
33593             if (!arguments.length) return _activeEntity ? [_activeEntity.id] : []; // no assign
33594
33595             return mode;
33596           };
33597
33598           mode.activeID = function () {
33599             if (!arguments.length) return _activeEntity && _activeEntity.id; // no assign
33600
33601             return mode;
33602           };
33603
33604           mode.restoreSelectedIDs = function (_) {
33605             if (!arguments.length) return _restoreSelectedIDs;
33606             _restoreSelectedIDs = _;
33607             return mode;
33608           };
33609
33610           mode.behavior = drag;
33611           return mode;
33612         }
33613
33614         // Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
33615         var NON_GENERIC = !!nativePromiseConstructor && fails(function () {
33616           nativePromiseConstructor.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
33617         });
33618
33619         // `Promise.prototype.finally` method
33620         // https://tc39.github.io/ecma262/#sec-promise.prototype.finally
33621         _export({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
33622           'finally': function (onFinally) {
33623             var C = speciesConstructor(this, getBuiltIn('Promise'));
33624             var isFunction = typeof onFinally == 'function';
33625             return this.then(
33626               isFunction ? function (x) {
33627                 return promiseResolve(C, onFinally()).then(function () { return x; });
33628               } : onFinally,
33629               isFunction ? function (e) {
33630                 return promiseResolve(C, onFinally()).then(function () { throw e; });
33631               } : onFinally
33632             );
33633           }
33634         });
33635
33636         // patch native Promise.prototype for native async functions
33637         if ( typeof nativePromiseConstructor == 'function' && !nativePromiseConstructor.prototype['finally']) {
33638           redefine(nativePromiseConstructor.prototype, 'finally', getBuiltIn('Promise').prototype['finally']);
33639         }
33640
33641         // @@search logic
33642         fixRegexpWellKnownSymbolLogic('search', 1, function (SEARCH, nativeSearch, maybeCallNative) {
33643           return [
33644             // `String.prototype.search` method
33645             // https://tc39.github.io/ecma262/#sec-string.prototype.search
33646             function search(regexp) {
33647               var O = requireObjectCoercible(this);
33648               var searcher = regexp == undefined ? undefined : regexp[SEARCH];
33649               return searcher !== undefined ? searcher.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
33650             },
33651             // `RegExp.prototype[@@search]` method
33652             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@search
33653             function (regexp) {
33654               var res = maybeCallNative(nativeSearch, regexp, this);
33655               if (res.done) return res.value;
33656
33657               var rx = anObject(regexp);
33658               var S = String(this);
33659
33660               var previousLastIndex = rx.lastIndex;
33661               if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;
33662               var result = regexpExecAbstract(rx, S);
33663               if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;
33664               return result === null ? -1 : result.index;
33665             }
33666           ];
33667         });
33668
33669         function quickselect$1(arr, k, left, right, compare) {
33670           quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
33671         }
33672
33673         function quickselectStep(arr, k, left, right, compare) {
33674           while (right > left) {
33675             if (right - left > 600) {
33676               var n = right - left + 1;
33677               var m = k - left + 1;
33678               var z = Math.log(n);
33679               var s = 0.5 * Math.exp(2 * z / 3);
33680               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
33681               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
33682               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
33683               quickselectStep(arr, k, newLeft, newRight, compare);
33684             }
33685
33686             var t = arr[k];
33687             var i = left;
33688             var j = right;
33689             swap$1(arr, left, k);
33690             if (compare(arr[right], t) > 0) swap$1(arr, left, right);
33691
33692             while (i < j) {
33693               swap$1(arr, i, j);
33694               i++;
33695               j--;
33696
33697               while (compare(arr[i], t) < 0) {
33698                 i++;
33699               }
33700
33701               while (compare(arr[j], t) > 0) {
33702                 j--;
33703               }
33704             }
33705
33706             if (compare(arr[left], t) === 0) swap$1(arr, left, j);else {
33707               j++;
33708               swap$1(arr, j, right);
33709             }
33710             if (j <= k) left = j + 1;
33711             if (k <= j) right = j - 1;
33712           }
33713         }
33714
33715         function swap$1(arr, i, j) {
33716           var tmp = arr[i];
33717           arr[i] = arr[j];
33718           arr[j] = tmp;
33719         }
33720
33721         function defaultCompare(a, b) {
33722           return a < b ? -1 : a > b ? 1 : 0;
33723         }
33724
33725         var RBush = /*#__PURE__*/function () {
33726           function RBush() {
33727             var maxEntries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 9;
33728
33729             _classCallCheck(this, RBush);
33730
33731             // max entries in a node is 9 by default; min node fill is 40% for best performance
33732             this._maxEntries = Math.max(4, maxEntries);
33733             this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
33734             this.clear();
33735           }
33736
33737           _createClass(RBush, [{
33738             key: "all",
33739             value: function all() {
33740               return this._all(this.data, []);
33741             }
33742           }, {
33743             key: "search",
33744             value: function search(bbox) {
33745               var node = this.data;
33746               var result = [];
33747               if (!intersects(bbox, node)) return result;
33748               var toBBox = this.toBBox;
33749               var nodesToSearch = [];
33750
33751               while (node) {
33752                 for (var i = 0; i < node.children.length; i++) {
33753                   var child = node.children[i];
33754                   var childBBox = node.leaf ? toBBox(child) : child;
33755
33756                   if (intersects(bbox, childBBox)) {
33757                     if (node.leaf) result.push(child);else if (contains(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
33758                   }
33759                 }
33760
33761                 node = nodesToSearch.pop();
33762               }
33763
33764               return result;
33765             }
33766           }, {
33767             key: "collides",
33768             value: function collides(bbox) {
33769               var node = this.data;
33770               if (!intersects(bbox, node)) return false;
33771               var nodesToSearch = [];
33772
33773               while (node) {
33774                 for (var i = 0; i < node.children.length; i++) {
33775                   var child = node.children[i];
33776                   var childBBox = node.leaf ? this.toBBox(child) : child;
33777
33778                   if (intersects(bbox, childBBox)) {
33779                     if (node.leaf || contains(bbox, childBBox)) return true;
33780                     nodesToSearch.push(child);
33781                   }
33782                 }
33783
33784                 node = nodesToSearch.pop();
33785               }
33786
33787               return false;
33788             }
33789           }, {
33790             key: "load",
33791             value: function load(data) {
33792               if (!(data && data.length)) return this;
33793
33794               if (data.length < this._minEntries) {
33795                 for (var i = 0; i < data.length; i++) {
33796                   this.insert(data[i]);
33797                 }
33798
33799                 return this;
33800               } // recursively build the tree with the given data from scratch using OMT algorithm
33801
33802
33803               var node = this._build(data.slice(), 0, data.length - 1, 0);
33804
33805               if (!this.data.children.length) {
33806                 // save as is if tree is empty
33807                 this.data = node;
33808               } else if (this.data.height === node.height) {
33809                 // split root if trees have the same height
33810                 this._splitRoot(this.data, node);
33811               } else {
33812                 if (this.data.height < node.height) {
33813                   // swap trees if inserted one is bigger
33814                   var tmpNode = this.data;
33815                   this.data = node;
33816                   node = tmpNode;
33817                 } // insert the small tree into the large tree at appropriate level
33818
33819
33820                 this._insert(node, this.data.height - node.height - 1, true);
33821               }
33822
33823               return this;
33824             }
33825           }, {
33826             key: "insert",
33827             value: function insert(item) {
33828               if (item) this._insert(item, this.data.height - 1);
33829               return this;
33830             }
33831           }, {
33832             key: "clear",
33833             value: function clear() {
33834               this.data = createNode([]);
33835               return this;
33836             }
33837           }, {
33838             key: "remove",
33839             value: function remove(item, equalsFn) {
33840               if (!item) return this;
33841               var node = this.data;
33842               var bbox = this.toBBox(item);
33843               var path = [];
33844               var indexes = [];
33845               var i, parent, goingUp; // depth-first iterative tree traversal
33846
33847               while (node || path.length) {
33848                 if (!node) {
33849                   // go up
33850                   node = path.pop();
33851                   parent = path[path.length - 1];
33852                   i = indexes.pop();
33853                   goingUp = true;
33854                 }
33855
33856                 if (node.leaf) {
33857                   // check current node
33858                   var index = findItem(item, node.children, equalsFn);
33859
33860                   if (index !== -1) {
33861                     // item found, remove the item and condense tree upwards
33862                     node.children.splice(index, 1);
33863                     path.push(node);
33864
33865                     this._condense(path);
33866
33867                     return this;
33868                   }
33869                 }
33870
33871                 if (!goingUp && !node.leaf && contains(node, bbox)) {
33872                   // go down
33873                   path.push(node);
33874                   indexes.push(i);
33875                   i = 0;
33876                   parent = node;
33877                   node = node.children[0];
33878                 } else if (parent) {
33879                   // go right
33880                   i++;
33881                   node = parent.children[i];
33882                   goingUp = false;
33883                 } else node = null; // nothing found
33884
33885               }
33886
33887               return this;
33888             }
33889           }, {
33890             key: "toBBox",
33891             value: function toBBox(item) {
33892               return item;
33893             }
33894           }, {
33895             key: "compareMinX",
33896             value: function compareMinX(a, b) {
33897               return a.minX - b.minX;
33898             }
33899           }, {
33900             key: "compareMinY",
33901             value: function compareMinY(a, b) {
33902               return a.minY - b.minY;
33903             }
33904           }, {
33905             key: "toJSON",
33906             value: function toJSON() {
33907               return this.data;
33908             }
33909           }, {
33910             key: "fromJSON",
33911             value: function fromJSON(data) {
33912               this.data = data;
33913               return this;
33914             }
33915           }, {
33916             key: "_all",
33917             value: function _all(node, result) {
33918               var nodesToSearch = [];
33919
33920               while (node) {
33921                 if (node.leaf) result.push.apply(result, _toConsumableArray(node.children));else nodesToSearch.push.apply(nodesToSearch, _toConsumableArray(node.children));
33922                 node = nodesToSearch.pop();
33923               }
33924
33925               return result;
33926             }
33927           }, {
33928             key: "_build",
33929             value: function _build(items, left, right, height) {
33930               var N = right - left + 1;
33931               var M = this._maxEntries;
33932               var node;
33933
33934               if (N <= M) {
33935                 // reached leaf level; return leaf
33936                 node = createNode(items.slice(left, right + 1));
33937                 calcBBox(node, this.toBBox);
33938                 return node;
33939               }
33940
33941               if (!height) {
33942                 // target height of the bulk-loaded tree
33943                 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
33944
33945                 M = Math.ceil(N / Math.pow(M, height - 1));
33946               }
33947
33948               node = createNode([]);
33949               node.leaf = false;
33950               node.height = height; // split the items into M mostly square tiles
33951
33952               var N2 = Math.ceil(N / M);
33953               var N1 = N2 * Math.ceil(Math.sqrt(M));
33954               multiSelect(items, left, right, N1, this.compareMinX);
33955
33956               for (var i = left; i <= right; i += N1) {
33957                 var right2 = Math.min(i + N1 - 1, right);
33958                 multiSelect(items, i, right2, N2, this.compareMinY);
33959
33960                 for (var j = i; j <= right2; j += N2) {
33961                   var right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
33962
33963                   node.children.push(this._build(items, j, right3, height - 1));
33964                 }
33965               }
33966
33967               calcBBox(node, this.toBBox);
33968               return node;
33969             }
33970           }, {
33971             key: "_chooseSubtree",
33972             value: function _chooseSubtree(bbox, node, level, path) {
33973               while (true) {
33974                 path.push(node);
33975                 if (node.leaf || path.length - 1 === level) break;
33976                 var minArea = Infinity;
33977                 var minEnlargement = Infinity;
33978                 var targetNode = void 0;
33979
33980                 for (var i = 0; i < node.children.length; i++) {
33981                   var child = node.children[i];
33982                   var area = bboxArea(child);
33983                   var enlargement = enlargedArea(bbox, child) - area; // choose entry with the least area enlargement
33984
33985                   if (enlargement < minEnlargement) {
33986                     minEnlargement = enlargement;
33987                     minArea = area < minArea ? area : minArea;
33988                     targetNode = child;
33989                   } else if (enlargement === minEnlargement) {
33990                     // otherwise choose one with the smallest area
33991                     if (area < minArea) {
33992                       minArea = area;
33993                       targetNode = child;
33994                     }
33995                   }
33996                 }
33997
33998                 node = targetNode || node.children[0];
33999               }
34000
34001               return node;
34002             }
34003           }, {
34004             key: "_insert",
34005             value: function _insert(item, level, isNode) {
34006               var bbox = isNode ? item : this.toBBox(item);
34007               var insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
34008
34009               var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
34010
34011
34012               node.children.push(item);
34013               extend$1(node, bbox); // split on node overflow; propagate upwards if necessary
34014
34015               while (level >= 0) {
34016                 if (insertPath[level].children.length > this._maxEntries) {
34017                   this._split(insertPath, level);
34018
34019                   level--;
34020                 } else break;
34021               } // adjust bboxes along the insertion path
34022
34023
34024               this._adjustParentBBoxes(bbox, insertPath, level);
34025             } // split overflowed node into two
34026
34027           }, {
34028             key: "_split",
34029             value: function _split(insertPath, level) {
34030               var node = insertPath[level];
34031               var M = node.children.length;
34032               var m = this._minEntries;
34033
34034               this._chooseSplitAxis(node, m, M);
34035
34036               var splitIndex = this._chooseSplitIndex(node, m, M);
34037
34038               var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
34039               newNode.height = node.height;
34040               newNode.leaf = node.leaf;
34041               calcBBox(node, this.toBBox);
34042               calcBBox(newNode, this.toBBox);
34043               if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
34044             }
34045           }, {
34046             key: "_splitRoot",
34047             value: function _splitRoot(node, newNode) {
34048               // split root node
34049               this.data = createNode([node, newNode]);
34050               this.data.height = node.height + 1;
34051               this.data.leaf = false;
34052               calcBBox(this.data, this.toBBox);
34053             }
34054           }, {
34055             key: "_chooseSplitIndex",
34056             value: function _chooseSplitIndex(node, m, M) {
34057               var index;
34058               var minOverlap = Infinity;
34059               var minArea = Infinity;
34060
34061               for (var i = m; i <= M - m; i++) {
34062                 var bbox1 = distBBox(node, 0, i, this.toBBox);
34063                 var bbox2 = distBBox(node, i, M, this.toBBox);
34064                 var overlap = intersectionArea(bbox1, bbox2);
34065                 var area = bboxArea(bbox1) + bboxArea(bbox2); // choose distribution with minimum overlap
34066
34067                 if (overlap < minOverlap) {
34068                   minOverlap = overlap;
34069                   index = i;
34070                   minArea = area < minArea ? area : minArea;
34071                 } else if (overlap === minOverlap) {
34072                   // otherwise choose distribution with minimum area
34073                   if (area < minArea) {
34074                     minArea = area;
34075                     index = i;
34076                   }
34077                 }
34078               }
34079
34080               return index || M - m;
34081             } // sorts node children by the best axis for split
34082
34083           }, {
34084             key: "_chooseSplitAxis",
34085             value: function _chooseSplitAxis(node, m, M) {
34086               var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
34087               var compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
34088
34089               var xMargin = this._allDistMargin(node, m, M, compareMinX);
34090
34091               var yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
34092               // otherwise it's already sorted by minY
34093
34094
34095               if (xMargin < yMargin) node.children.sort(compareMinX);
34096             } // total margin of all possible split distributions where each node is at least m full
34097
34098           }, {
34099             key: "_allDistMargin",
34100             value: function _allDistMargin(node, m, M, compare) {
34101               node.children.sort(compare);
34102               var toBBox = this.toBBox;
34103               var leftBBox = distBBox(node, 0, m, toBBox);
34104               var rightBBox = distBBox(node, M - m, M, toBBox);
34105               var margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
34106
34107               for (var i = m; i < M - m; i++) {
34108                 var child = node.children[i];
34109                 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
34110                 margin += bboxMargin(leftBBox);
34111               }
34112
34113               for (var _i = M - m - 1; _i >= m; _i--) {
34114                 var _child = node.children[_i];
34115                 extend$1(rightBBox, node.leaf ? toBBox(_child) : _child);
34116                 margin += bboxMargin(rightBBox);
34117               }
34118
34119               return margin;
34120             }
34121           }, {
34122             key: "_adjustParentBBoxes",
34123             value: function _adjustParentBBoxes(bbox, path, level) {
34124               // adjust bboxes along the given tree path
34125               for (var i = level; i >= 0; i--) {
34126                 extend$1(path[i], bbox);
34127               }
34128             }
34129           }, {
34130             key: "_condense",
34131             value: function _condense(path) {
34132               // go through the path, removing empty nodes and updating bboxes
34133               for (var i = path.length - 1, siblings; i >= 0; i--) {
34134                 if (path[i].children.length === 0) {
34135                   if (i > 0) {
34136                     siblings = path[i - 1].children;
34137                     siblings.splice(siblings.indexOf(path[i]), 1);
34138                   } else this.clear();
34139                 } else calcBBox(path[i], this.toBBox);
34140               }
34141             }
34142           }]);
34143
34144           return RBush;
34145         }();
34146
34147         function findItem(item, items, equalsFn) {
34148           if (!equalsFn) return items.indexOf(item);
34149
34150           for (var i = 0; i < items.length; i++) {
34151             if (equalsFn(item, items[i])) return i;
34152           }
34153
34154           return -1;
34155         } // calculate node's bbox from bboxes of its children
34156
34157
34158         function calcBBox(node, toBBox) {
34159           distBBox(node, 0, node.children.length, toBBox, node);
34160         } // min bounding rectangle of node children from k to p-1
34161
34162
34163         function distBBox(node, k, p, toBBox, destNode) {
34164           if (!destNode) destNode = createNode(null);
34165           destNode.minX = Infinity;
34166           destNode.minY = Infinity;
34167           destNode.maxX = -Infinity;
34168           destNode.maxY = -Infinity;
34169
34170           for (var i = k; i < p; i++) {
34171             var child = node.children[i];
34172             extend$1(destNode, node.leaf ? toBBox(child) : child);
34173           }
34174
34175           return destNode;
34176         }
34177
34178         function extend$1(a, b) {
34179           a.minX = Math.min(a.minX, b.minX);
34180           a.minY = Math.min(a.minY, b.minY);
34181           a.maxX = Math.max(a.maxX, b.maxX);
34182           a.maxY = Math.max(a.maxY, b.maxY);
34183           return a;
34184         }
34185
34186         function compareNodeMinX(a, b) {
34187           return a.minX - b.minX;
34188         }
34189
34190         function compareNodeMinY(a, b) {
34191           return a.minY - b.minY;
34192         }
34193
34194         function bboxArea(a) {
34195           return (a.maxX - a.minX) * (a.maxY - a.minY);
34196         }
34197
34198         function bboxMargin(a) {
34199           return a.maxX - a.minX + (a.maxY - a.minY);
34200         }
34201
34202         function enlargedArea(a, b) {
34203           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));
34204         }
34205
34206         function intersectionArea(a, b) {
34207           var minX = Math.max(a.minX, b.minX);
34208           var minY = Math.max(a.minY, b.minY);
34209           var maxX = Math.min(a.maxX, b.maxX);
34210           var maxY = Math.min(a.maxY, b.maxY);
34211           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
34212         }
34213
34214         function contains(a, b) {
34215           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
34216         }
34217
34218         function intersects(a, b) {
34219           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
34220         }
34221
34222         function createNode(children) {
34223           return {
34224             children: children,
34225             height: 1,
34226             leaf: true,
34227             minX: Infinity,
34228             minY: Infinity,
34229             maxX: -Infinity,
34230             maxY: -Infinity
34231           };
34232         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
34233         // combines selection algorithm with binary divide & conquer approach
34234
34235
34236         function multiSelect(arr, left, right, n, compare) {
34237           var stack = [left, right];
34238
34239           while (stack.length) {
34240             right = stack.pop();
34241             left = stack.pop();
34242             if (right - left <= n) continue;
34243             var mid = left + Math.ceil((right - left) / n / 2) * n;
34244             quickselect$1(arr, mid, left, right, compare);
34245             stack.push(left, mid, mid, right);
34246           }
34247         }
34248
34249         var tiler = utilTiler();
34250         var dispatch$1 = dispatch('loaded');
34251         var _tileZoom = 14;
34252         var _krUrlRoot = 'https://www.keepright.at';
34253         var _krData = {
34254           errorTypes: {},
34255           localizeStrings: {}
34256         }; // This gets reassigned if reset
34257
34258         var _cache;
34259
34260         var _krRuleset = [// no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
34261         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];
34262
34263         function abortRequest(controller) {
34264           if (controller) {
34265             controller.abort();
34266           }
34267         }
34268
34269         function abortUnwantedRequests(cache, tiles) {
34270           Object.keys(cache.inflightTile).forEach(function (k) {
34271             var wanted = tiles.find(function (tile) {
34272               return k === tile.id;
34273             });
34274
34275             if (!wanted) {
34276               abortRequest(cache.inflightTile[k]);
34277               delete cache.inflightTile[k];
34278             }
34279           });
34280         }
34281
34282         function encodeIssueRtree(d) {
34283           return {
34284             minX: d.loc[0],
34285             minY: d.loc[1],
34286             maxX: d.loc[0],
34287             maxY: d.loc[1],
34288             data: d
34289           };
34290         } // Replace or remove QAItem from rtree
34291
34292
34293         function updateRtree(item, replace) {
34294           _cache.rtree.remove(item, function (a, b) {
34295             return a.data.id === b.data.id;
34296           });
34297
34298           if (replace) {
34299             _cache.rtree.insert(item);
34300           }
34301         }
34302
34303         function tokenReplacements(d) {
34304           if (!(d instanceof QAItem)) return;
34305           var htmlRegex = new RegExp(/<\/[a-z][\s\S]*>/);
34306           var replacements = {};
34307           var issueTemplate = _krData.errorTypes[d.whichType];
34308
34309           if (!issueTemplate) {
34310             /* eslint-disable no-console */
34311             console.log('No Template: ', d.whichType);
34312             console.log('  ', d.description);
34313             /* eslint-enable no-console */
34314
34315             return;
34316           } // some descriptions are just fixed text
34317
34318
34319           if (!issueTemplate.regex) return; // regex pattern should match description with variable details captured
34320
34321           var errorRegex = new RegExp(issueTemplate.regex, 'i');
34322           var errorMatch = errorRegex.exec(d.description);
34323
34324           if (!errorMatch) {
34325             /* eslint-disable no-console */
34326             console.log('Unmatched: ', d.whichType);
34327             console.log('  ', d.description);
34328             console.log('  ', errorRegex);
34329             /* eslint-enable no-console */
34330
34331             return;
34332           }
34333
34334           for (var i = 1; i < errorMatch.length; i++) {
34335             // skip first
34336             var capture = errorMatch[i];
34337             var idType = void 0;
34338             idType = 'IDs' in issueTemplate ? issueTemplate.IDs[i - 1] : '';
34339
34340             if (idType && capture) {
34341               // link IDs if present in the capture
34342               capture = parseError(capture, idType);
34343             } else if (htmlRegex.test(capture)) {
34344               // escape any html in non-IDs
34345               capture = '\\' + capture + '\\';
34346             } else {
34347               var compare = capture.toLowerCase();
34348
34349               if (_krData.localizeStrings[compare]) {
34350                 // some replacement strings can be localized
34351                 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34352               }
34353             }
34354
34355             replacements['var' + i] = capture;
34356           }
34357
34358           return replacements;
34359         }
34360
34361         function parseError(capture, idType) {
34362           var compare = capture.toLowerCase();
34363
34364           if (_krData.localizeStrings[compare]) {
34365             // some replacement strings can be localized
34366             capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34367           }
34368
34369           switch (idType) {
34370             // link a string like "this node"
34371             case 'this':
34372               capture = linkErrorObject(capture);
34373               break;
34374
34375             case 'url':
34376               capture = linkURL(capture);
34377               break;
34378             // link an entity ID
34379
34380             case 'n':
34381             case 'w':
34382             case 'r':
34383               capture = linkEntity(idType + capture);
34384               break;
34385             // some errors have more complex ID lists/variance
34386
34387             case '20':
34388               capture = parse20(capture);
34389               break;
34390
34391             case '211':
34392               capture = parse211(capture);
34393               break;
34394
34395             case '231':
34396               capture = parse231(capture);
34397               break;
34398
34399             case '294':
34400               capture = parse294(capture);
34401               break;
34402
34403             case '370':
34404               capture = parse370(capture);
34405               break;
34406           }
34407
34408           return capture;
34409
34410           function linkErrorObject(d) {
34411             return "<a class=\"error_object_link\">".concat(d, "</a>");
34412           }
34413
34414           function linkEntity(d) {
34415             return "<a class=\"error_entity_link\">".concat(d, "</a>");
34416           }
34417
34418           function linkURL(d) {
34419             return "<a class=\"kr_external_link\" target=\"_blank\" href=\"".concat(d, "\">").concat(d, "</a>");
34420           } // arbitrary node list of form: #ID, #ID, #ID...
34421
34422
34423           function parse211(capture) {
34424             var newList = [];
34425             var items = capture.split(', ');
34426             items.forEach(function (item) {
34427               // ID has # at the front
34428               var id = linkEntity('n' + item.slice(1));
34429               newList.push(id);
34430             });
34431             return newList.join(', ');
34432           } // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
34433
34434
34435           function parse231(capture) {
34436             var newList = []; // unfortunately 'layer' can itself contain commas, so we split on '),'
34437
34438             var items = capture.split('),');
34439             items.forEach(function (item) {
34440               var match = item.match(/\#(\d+)\((.+)\)?/);
34441
34442               if (match !== null && match.length > 2) {
34443                 newList.push(linkEntity('w' + match[1]) + ' ' + _t('QA.keepRight.errorTypes.231.layer', {
34444                   layer: match[2]
34445                 }));
34446               }
34447             });
34448             return newList.join(', ');
34449           } // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
34450
34451
34452           function parse294(capture) {
34453             var newList = [];
34454             var items = capture.split(',');
34455             items.forEach(function (item) {
34456               // item of form "from/to node/relation #ID"
34457               item = item.split(' '); // to/from role is more clear in quotes
34458
34459               var role = "\"".concat(item[0], "\""); // first letter of node/relation provides the type
34460
34461               var idType = item[1].slice(0, 1); // ID has # at the front
34462
34463               var id = item[2].slice(1);
34464               id = linkEntity(idType + id);
34465               newList.push("".concat(role, " ").concat(item[1], " ").concat(id));
34466             });
34467             return newList.join(', ');
34468           } // may or may not include the string "(including the name 'name')"
34469
34470
34471           function parse370(capture) {
34472             if (!capture) return '';
34473             var match = capture.match(/\(including the name (\'.+\')\)/);
34474
34475             if (match && match.length) {
34476               return _t('QA.keepRight.errorTypes.370.including_the_name', {
34477                 name: match[1]
34478               });
34479             }
34480
34481             return '';
34482           } // arbitrary node list of form: #ID,#ID,#ID...
34483
34484
34485           function parse20(capture) {
34486             var newList = [];
34487             var items = capture.split(',');
34488             items.forEach(function (item) {
34489               // ID has # at the front
34490               var id = linkEntity('n' + item.slice(1));
34491               newList.push(id);
34492             });
34493             return newList.join(', ');
34494           }
34495         }
34496
34497         var serviceKeepRight = {
34498           title: 'keepRight',
34499           init: function init() {
34500             _mainFileFetcher.get('keepRight').then(function (d) {
34501               return _krData = d;
34502             });
34503
34504             if (!_cache) {
34505               this.reset();
34506             }
34507
34508             this.event = utilRebind(this, dispatch$1, 'on');
34509           },
34510           reset: function reset() {
34511             if (_cache) {
34512               Object.values(_cache.inflightTile).forEach(abortRequest);
34513             }
34514
34515             _cache = {
34516               data: {},
34517               loadedTile: {},
34518               inflightTile: {},
34519               inflightPost: {},
34520               closed: {},
34521               rtree: new RBush()
34522             };
34523           },
34524           // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
34525           loadIssues: function loadIssues(projection) {
34526             var _this = this;
34527
34528             var options = {
34529               format: 'geojson',
34530               ch: _krRuleset
34531             }; // determine the needed tiles to cover the view
34532
34533             var tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection); // abort inflight requests that are no longer needed
34534
34535             abortUnwantedRequests(_cache, tiles); // issue new requests..
34536
34537             tiles.forEach(function (tile) {
34538               if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
34539
34540               var _tile$extent$rectangl = tile.extent.rectangle(),
34541                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
34542                   left = _tile$extent$rectangl2[0],
34543                   top = _tile$extent$rectangl2[1],
34544                   right = _tile$extent$rectangl2[2],
34545                   bottom = _tile$extent$rectangl2[3];
34546
34547               var params = Object.assign({}, options, {
34548                 left: left,
34549                 bottom: bottom,
34550                 right: right,
34551                 top: top
34552               });
34553               var url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
34554               var controller = new AbortController();
34555               _cache.inflightTile[tile.id] = controller;
34556               d3_json(url, {
34557                 signal: controller.signal
34558               }).then(function (data) {
34559                 delete _cache.inflightTile[tile.id];
34560                 _cache.loadedTile[tile.id] = true;
34561
34562                 if (!data || !data.features || !data.features.length) {
34563                   throw new Error('No Data');
34564                 }
34565
34566                 data.features.forEach(function (feature) {
34567                   var _feature$properties = feature.properties,
34568                       itemType = _feature$properties.error_type,
34569                       id = _feature$properties.error_id,
34570                       _feature$properties$c = _feature$properties.comment,
34571                       comment = _feature$properties$c === void 0 ? null : _feature$properties$c,
34572                       objectId = _feature$properties.object_id,
34573                       objectType = _feature$properties.object_type,
34574                       schema = _feature$properties.schema,
34575                       title = _feature$properties.title;
34576                   var loc = feature.geometry.coordinates,
34577                       _feature$properties$d = feature.properties.description,
34578                       description = _feature$properties$d === void 0 ? '' : _feature$properties$d; // if there is a parent, save its error type e.g.:
34579                   //  Error 191 = "highway-highway"
34580                   //  Error 190 = "intersections without junctions"  (parent)
34581
34582                   var issueTemplate = _krData.errorTypes[itemType];
34583                   var parentIssueType = (Math.floor(itemType / 10) * 10).toString(); // try to handle error type directly, fallback to parent error type.
34584
34585                   var whichType = issueTemplate ? itemType : parentIssueType;
34586                   var whichTemplate = _krData.errorTypes[whichType]; // Rewrite a few of the errors at this point..
34587                   // This is done to make them easier to linkify and translate.
34588
34589                   switch (whichType) {
34590                     case '170':
34591                       description = "This feature has a FIXME tag: ".concat(description);
34592                       break;
34593
34594                     case '292':
34595                     case '293':
34596                       description = description.replace('A turn-', 'This turn-');
34597                       break;
34598
34599                     case '294':
34600                     case '295':
34601                     case '296':
34602                     case '297':
34603                     case '298':
34604                       description = "This turn-restriction~".concat(description);
34605                       break;
34606
34607                     case '300':
34608                       description = 'This highway is missing a maxspeed tag';
34609                       break;
34610
34611                     case '411':
34612                     case '412':
34613                     case '413':
34614                       description = "This feature~".concat(description);
34615                       break;
34616                   } // move markers slightly so it doesn't obscure the geometry,
34617                   // then move markers away from other coincident markers
34618
34619
34620                   var coincident = false;
34621
34622                   do {
34623                     // first time, move marker up. after that, move marker right.
34624                     var delta = coincident ? [0.00001, 0] : [0, 0.00001];
34625                     loc = geoVecAdd(loc, delta);
34626                     var bbox = geoExtent(loc).bbox();
34627                     coincident = _cache.rtree.search(bbox).length;
34628                   } while (coincident);
34629
34630                   var d = new QAItem(loc, _this, itemType, id, {
34631                     comment: comment,
34632                     description: description,
34633                     whichType: whichType,
34634                     parentIssueType: parentIssueType,
34635                     severity: whichTemplate.severity || 'error',
34636                     objectId: objectId,
34637                     objectType: objectType,
34638                     schema: schema,
34639                     title: title
34640                   });
34641                   d.replacements = tokenReplacements(d);
34642                   _cache.data[id] = d;
34643
34644                   _cache.rtree.insert(encodeIssueRtree(d));
34645                 });
34646                 dispatch$1.call('loaded');
34647               })["catch"](function () {
34648                 delete _cache.inflightTile[tile.id];
34649                 _cache.loadedTile[tile.id] = true;
34650               });
34651             });
34652           },
34653           postUpdate: function postUpdate(d, callback) {
34654             var _this2 = this;
34655
34656             if (_cache.inflightPost[d.id]) {
34657               return callback({
34658                 message: 'Error update already inflight',
34659                 status: -2
34660               }, d);
34661             }
34662
34663             var params = {
34664               schema: d.schema,
34665               id: d.id
34666             };
34667
34668             if (d.newStatus) {
34669               params.st = d.newStatus;
34670             }
34671
34672             if (d.newComment !== undefined) {
34673               params.co = d.newComment;
34674             } // NOTE: This throws a CORS err, but it seems successful.
34675             // We don't care too much about the response, so this is fine.
34676
34677
34678             var url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
34679             var controller = new AbortController();
34680             _cache.inflightPost[d.id] = controller; // Since this is expected to throw an error just continue as if it worked
34681             // (worst case scenario the request truly fails and issue will show up if iD restarts)
34682
34683             d3_json(url, {
34684               signal: controller.signal
34685             })["finally"](function () {
34686               delete _cache.inflightPost[d.id];
34687
34688               if (d.newStatus === 'ignore') {
34689                 // ignore permanently (false positive)
34690                 _this2.removeItem(d);
34691               } else if (d.newStatus === 'ignore_t') {
34692                 // ignore temporarily (error fixed)
34693                 _this2.removeItem(d);
34694
34695                 _cache.closed["".concat(d.schema, ":").concat(d.id)] = true;
34696               } else {
34697                 d = _this2.replaceItem(d.update({
34698                   comment: d.newComment,
34699                   newComment: undefined,
34700                   newState: undefined
34701                 }));
34702               }
34703
34704               if (callback) callback(null, d);
34705             });
34706           },
34707           // Get all cached QAItems covering the viewport
34708           getItems: function getItems(projection) {
34709             var viewport = projection.clipExtent();
34710             var min = [viewport[0][0], viewport[1][1]];
34711             var max = [viewport[1][0], viewport[0][1]];
34712             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
34713             return _cache.rtree.search(bbox).map(function (d) {
34714               return d.data;
34715             });
34716           },
34717           // Get a QAItem from cache
34718           // NOTE: Don't change method name until UI v3 is merged
34719           getError: function getError(id) {
34720             return _cache.data[id];
34721           },
34722           // Replace a single QAItem in the cache
34723           replaceItem: function replaceItem(item) {
34724             if (!(item instanceof QAItem) || !item.id) return;
34725             _cache.data[item.id] = item;
34726             updateRtree(encodeIssueRtree(item), true); // true = replace
34727
34728             return item;
34729           },
34730           // Remove a single QAItem from the cache
34731           removeItem: function removeItem(item) {
34732             if (!(item instanceof QAItem) || !item.id) return;
34733             delete _cache.data[item.id];
34734             updateRtree(encodeIssueRtree(item), false); // false = remove
34735           },
34736           issueURL: function issueURL(item) {
34737             return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
34738           },
34739           // Get an array of issues closed during this session.
34740           // Used to populate `closed:keepright` changeset tag
34741           getClosedIDs: function getClosedIDs() {
34742             return Object.keys(_cache.closed).sort();
34743           }
34744         };
34745
34746         var tiler$1 = utilTiler();
34747         var dispatch$2 = dispatch('loaded');
34748         var _tileZoom$1 = 14;
34749         var _impOsmUrls = {
34750           ow: 'https://grab.community.improve-osm.org/directionOfFlowService',
34751           mr: 'https://grab.community.improve-osm.org/missingGeoService',
34752           tr: 'https://grab.community.improve-osm.org/turnRestrictionService'
34753         };
34754         var _impOsmData = {
34755           icons: {}
34756         }; // This gets reassigned if reset
34757
34758         var _cache$1;
34759
34760         function abortRequest$1(i) {
34761           Object.values(i).forEach(function (controller) {
34762             if (controller) {
34763               controller.abort();
34764             }
34765           });
34766         }
34767
34768         function abortUnwantedRequests$1(cache, tiles) {
34769           Object.keys(cache.inflightTile).forEach(function (k) {
34770             var wanted = tiles.find(function (tile) {
34771               return k === tile.id;
34772             });
34773
34774             if (!wanted) {
34775               abortRequest$1(cache.inflightTile[k]);
34776               delete cache.inflightTile[k];
34777             }
34778           });
34779         }
34780
34781         function encodeIssueRtree$1(d) {
34782           return {
34783             minX: d.loc[0],
34784             minY: d.loc[1],
34785             maxX: d.loc[0],
34786             maxY: d.loc[1],
34787             data: d
34788           };
34789         } // Replace or remove QAItem from rtree
34790
34791
34792         function updateRtree$1(item, replace) {
34793           _cache$1.rtree.remove(item, function (a, b) {
34794             return a.data.id === b.data.id;
34795           });
34796
34797           if (replace) {
34798             _cache$1.rtree.insert(item);
34799           }
34800         }
34801
34802         function linkErrorObject(d) {
34803           return "<a class=\"error_object_link\">".concat(d, "</a>");
34804         }
34805
34806         function linkEntity(d) {
34807           return "<a class=\"error_entity_link\">".concat(d, "</a>");
34808         }
34809
34810         function pointAverage(points) {
34811           if (points.length) {
34812             var sum = points.reduce(function (acc, point) {
34813               return geoVecAdd(acc, [point.lon, point.lat]);
34814             }, [0, 0]);
34815             return geoVecScale(sum, 1 / points.length);
34816           } else {
34817             return [0, 0];
34818           }
34819         }
34820
34821         function relativeBearing(p1, p2) {
34822           var angle = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
34823
34824           if (angle < 0) {
34825             angle += 2 * Math.PI;
34826           } // Return degrees
34827
34828
34829           return angle * 180 / Math.PI;
34830         } // Assuming range [0,360)
34831
34832
34833         function cardinalDirection(bearing) {
34834           var dir = 45 * Math.round(bearing / 45);
34835           var compass = {
34836             0: 'north',
34837             45: 'northeast',
34838             90: 'east',
34839             135: 'southeast',
34840             180: 'south',
34841             225: 'southwest',
34842             270: 'west',
34843             315: 'northwest',
34844             360: 'north'
34845           };
34846           return _t("QA.improveOSM.directions.".concat(compass[dir]));
34847         } // Errors shouldn't obscure each other
34848
34849
34850         function preventCoincident(loc, bumpUp) {
34851           var coincident = false;
34852
34853           do {
34854             // first time, move marker up. after that, move marker right.
34855             var delta = coincident ? [0.00001, 0] : bumpUp ? [0, 0.00001] : [0, 0];
34856             loc = geoVecAdd(loc, delta);
34857             var bbox = geoExtent(loc).bbox();
34858             coincident = _cache$1.rtree.search(bbox).length;
34859           } while (coincident);
34860
34861           return loc;
34862         }
34863
34864         var serviceImproveOSM = {
34865           title: 'improveOSM',
34866           init: function init() {
34867             _mainFileFetcher.get('qa_data').then(function (d) {
34868               return _impOsmData = d.improveOSM;
34869             });
34870
34871             if (!_cache$1) {
34872               this.reset();
34873             }
34874
34875             this.event = utilRebind(this, dispatch$2, 'on');
34876           },
34877           reset: function reset() {
34878             if (_cache$1) {
34879               Object.values(_cache$1.inflightTile).forEach(abortRequest$1);
34880             }
34881
34882             _cache$1 = {
34883               data: {},
34884               loadedTile: {},
34885               inflightTile: {},
34886               inflightPost: {},
34887               closed: {},
34888               rtree: new RBush()
34889             };
34890           },
34891           loadIssues: function loadIssues(projection) {
34892             var _this = this;
34893
34894             var options = {
34895               client: 'iD',
34896               status: 'OPEN',
34897               zoom: '19' // Use a high zoom so that clusters aren't returned
34898
34899             }; // determine the needed tiles to cover the view
34900
34901             var tiles = tiler$1.zoomExtent([_tileZoom$1, _tileZoom$1]).getTiles(projection); // abort inflight requests that are no longer needed
34902
34903             abortUnwantedRequests$1(_cache$1, tiles); // issue new requests..
34904
34905             tiles.forEach(function (tile) {
34906               if (_cache$1.loadedTile[tile.id] || _cache$1.inflightTile[tile.id]) return;
34907
34908               var _tile$extent$rectangl = tile.extent.rectangle(),
34909                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
34910                   east = _tile$extent$rectangl2[0],
34911                   north = _tile$extent$rectangl2[1],
34912                   west = _tile$extent$rectangl2[2],
34913                   south = _tile$extent$rectangl2[3];
34914
34915               var params = Object.assign({}, options, {
34916                 east: east,
34917                 south: south,
34918                 west: west,
34919                 north: north
34920               }); // 3 separate requests to store for each tile
34921
34922               var requests = {};
34923               Object.keys(_impOsmUrls).forEach(function (k) {
34924                 // We exclude WATER from missing geometry as it doesn't seem useful
34925                 // We use most confident one-way and turn restrictions only, still have false positives
34926                 var kParams = Object.assign({}, params, k === 'mr' ? {
34927                   type: 'PARKING,ROAD,BOTH,PATH'
34928                 } : {
34929                   confidenceLevel: 'C1'
34930                 });
34931                 var url = "".concat(_impOsmUrls[k], "/search?") + utilQsString(kParams);
34932                 var controller = new AbortController();
34933                 requests[k] = controller;
34934                 d3_json(url, {
34935                   signal: controller.signal
34936                 }).then(function (data) {
34937                   delete _cache$1.inflightTile[tile.id][k];
34938
34939                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
34940                     delete _cache$1.inflightTile[tile.id];
34941                     _cache$1.loadedTile[tile.id] = true;
34942                   } // Road segments at high zoom == oneways
34943
34944
34945                   if (data.roadSegments) {
34946                     data.roadSegments.forEach(function (feature) {
34947                       // Position error at the approximate middle of the segment
34948                       var points = feature.points,
34949                           wayId = feature.wayId,
34950                           fromNodeId = feature.fromNodeId,
34951                           toNodeId = feature.toNodeId;
34952                       var itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
34953                       var mid = points.length / 2;
34954                       var loc; // Even number of points, find midpoint of the middle two
34955                       // Odd number of points, use position of very middle point
34956
34957                       if (mid % 1 === 0) {
34958                         loc = pointAverage([points[mid - 1], points[mid]]);
34959                       } else {
34960                         mid = points[Math.floor(mid)];
34961                         loc = [mid.lon, mid.lat];
34962                       } // One-ways can land on same segment in opposite direction
34963
34964
34965                       loc = preventCoincident(loc, false);
34966                       var d = new QAItem(loc, _this, k, itemId, {
34967                         issueKey: k,
34968                         // used as a category
34969                         identifier: {
34970                           // used to post changes
34971                           wayId: wayId,
34972                           fromNodeId: fromNodeId,
34973                           toNodeId: toNodeId
34974                         },
34975                         objectId: wayId,
34976                         objectType: 'way'
34977                       }); // Variables used in the description
34978
34979                       d.replacements = {
34980                         percentage: feature.percentOfTrips,
34981                         num_trips: feature.numberOfTrips,
34982                         highway: linkErrorObject(_t('QA.keepRight.error_parts.highway')),
34983                         from_node: linkEntity('n' + feature.fromNodeId),
34984                         to_node: linkEntity('n' + feature.toNodeId)
34985                       };
34986                       _cache$1.data[d.id] = d;
34987
34988                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
34989                     });
34990                   } // Tiles at high zoom == missing roads
34991
34992
34993                   if (data.tiles) {
34994                     data.tiles.forEach(function (feature) {
34995                       var type = feature.type,
34996                           x = feature.x,
34997                           y = feature.y,
34998                           numberOfTrips = feature.numberOfTrips;
34999                       var geoType = type.toLowerCase();
35000                       var itemId = "".concat(geoType).concat(x).concat(y).concat(numberOfTrips); // Average of recorded points should land on the missing geometry
35001                       // Missing geometry could happen to land on another error
35002
35003                       var loc = pointAverage(feature.points);
35004                       loc = preventCoincident(loc, false);
35005                       var d = new QAItem(loc, _this, "".concat(k, "-").concat(geoType), itemId, {
35006                         issueKey: k,
35007                         identifier: {
35008                           x: x,
35009                           y: y
35010                         }
35011                       });
35012                       d.replacements = {
35013                         num_trips: numberOfTrips,
35014                         geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
35015                       }; // -1 trips indicates data came from a 3rd party
35016
35017                       if (numberOfTrips === -1) {
35018                         d.desc = _t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
35019                       }
35020
35021                       _cache$1.data[d.id] = d;
35022
35023                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35024                     });
35025                   } // Entities at high zoom == turn restrictions
35026
35027
35028                   if (data.entities) {
35029                     data.entities.forEach(function (feature) {
35030                       var point = feature.point,
35031                           id = feature.id,
35032                           segments = feature.segments,
35033                           numberOfPasses = feature.numberOfPasses,
35034                           turnType = feature.turnType;
35035                       var itemId = "".concat(id.replace(/[,:+#]/g, '_')); // Turn restrictions could be missing at same junction
35036                       // We also want to bump the error up so node is accessible
35037
35038                       var loc = preventCoincident([point.lon, point.lat], true); // Elements are presented in a strange way
35039
35040                       var ids = id.split(',');
35041                       var from_way = ids[0];
35042                       var via_node = ids[3];
35043                       var to_way = ids[2].split(':')[1];
35044                       var d = new QAItem(loc, _this, k, itemId, {
35045                         issueKey: k,
35046                         identifier: id,
35047                         objectId: via_node,
35048                         objectType: 'node'
35049                       }); // Travel direction along from_way clarifies the turn restriction
35050
35051                       var _segments$0$points = _slicedToArray(segments[0].points, 2),
35052                           p1 = _segments$0$points[0],
35053                           p2 = _segments$0$points[1];
35054
35055                       var dir_of_travel = cardinalDirection(relativeBearing(p1, p2)); // Variables used in the description
35056
35057                       d.replacements = {
35058                         num_passed: numberOfPasses,
35059                         num_trips: segments[0].numberOfTrips,
35060                         turn_restriction: turnType.toLowerCase(),
35061                         from_way: linkEntity('w' + from_way),
35062                         to_way: linkEntity('w' + to_way),
35063                         travel_direction: dir_of_travel,
35064                         junction: linkErrorObject(_t('QA.keepRight.error_parts.this_node'))
35065                       };
35066                       _cache$1.data[d.id] = d;
35067
35068                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35069
35070                       dispatch$2.call('loaded');
35071                     });
35072                   }
35073                 })["catch"](function () {
35074                   delete _cache$1.inflightTile[tile.id][k];
35075
35076                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
35077                     delete _cache$1.inflightTile[tile.id];
35078                     _cache$1.loadedTile[tile.id] = true;
35079                   }
35080                 });
35081               });
35082               _cache$1.inflightTile[tile.id] = requests;
35083             });
35084           },
35085           getComments: function getComments(item) {
35086             var _this2 = this;
35087
35088             // If comments already retrieved no need to do so again
35089             if (item.comments) {
35090               return Promise.resolve(item);
35091             }
35092
35093             var key = item.issueKey;
35094             var qParams = {};
35095
35096             if (key === 'ow') {
35097               qParams = item.identifier;
35098             } else if (key === 'mr') {
35099               qParams.tileX = item.identifier.x;
35100               qParams.tileY = item.identifier.y;
35101             } else if (key === 'tr') {
35102               qParams.targetId = item.identifier;
35103             }
35104
35105             var url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
35106
35107             var cacheComments = function cacheComments(data) {
35108               // Assign directly for immediate use afterwards
35109               // comments are served newest to oldest
35110               item.comments = data.comments ? data.comments.reverse() : [];
35111
35112               _this2.replaceItem(item);
35113             };
35114
35115             return d3_json(url).then(cacheComments).then(function () {
35116               return item;
35117             });
35118           },
35119           postUpdate: function postUpdate(d, callback) {
35120             if (!serviceOsm.authenticated()) {
35121               // Username required in payload
35122               return callback({
35123                 message: 'Not Authenticated',
35124                 status: -3
35125               }, d);
35126             }
35127
35128             if (_cache$1.inflightPost[d.id]) {
35129               return callback({
35130                 message: 'Error update already inflight',
35131                 status: -2
35132               }, d);
35133             } // Payload can only be sent once username is established
35134
35135
35136             serviceOsm.userDetails(sendPayload.bind(this));
35137
35138             function sendPayload(err, user) {
35139               var _this3 = this;
35140
35141               if (err) {
35142                 return callback(err, d);
35143               }
35144
35145               var key = d.issueKey;
35146               var url = "".concat(_impOsmUrls[key], "/comment");
35147               var payload = {
35148                 username: user.display_name,
35149                 targetIds: [d.identifier]
35150               };
35151
35152               if (d.newStatus) {
35153                 payload.status = d.newStatus;
35154                 payload.text = 'status changed';
35155               } // Comment take place of default text
35156
35157
35158               if (d.newComment) {
35159                 payload.text = d.newComment;
35160               }
35161
35162               var controller = new AbortController();
35163               _cache$1.inflightPost[d.id] = controller;
35164               var options = {
35165                 method: 'POST',
35166                 signal: controller.signal,
35167                 body: JSON.stringify(payload)
35168               };
35169               d3_json(url, options).then(function () {
35170                 delete _cache$1.inflightPost[d.id]; // Just a comment, update error in cache
35171
35172                 if (!d.newStatus) {
35173                   var now = new Date();
35174                   var comments = d.comments ? d.comments : [];
35175                   comments.push({
35176                     username: payload.username,
35177                     text: payload.text,
35178                     timestamp: now.getTime() / 1000
35179                   });
35180
35181                   _this3.replaceItem(d.update({
35182                     comments: comments,
35183                     newComment: undefined
35184                   }));
35185                 } else {
35186                   _this3.removeItem(d);
35187
35188                   if (d.newStatus === 'SOLVED') {
35189                     // Keep track of the number of issues closed per type to tag the changeset
35190                     if (!(d.issueKey in _cache$1.closed)) {
35191                       _cache$1.closed[d.issueKey] = 0;
35192                     }
35193
35194                     _cache$1.closed[d.issueKey] += 1;
35195                   }
35196                 }
35197
35198                 if (callback) callback(null, d);
35199               })["catch"](function (err) {
35200                 delete _cache$1.inflightPost[d.id];
35201                 if (callback) callback(err.message);
35202               });
35203             }
35204           },
35205           // Get all cached QAItems covering the viewport
35206           getItems: function getItems(projection) {
35207             var viewport = projection.clipExtent();
35208             var min = [viewport[0][0], viewport[1][1]];
35209             var max = [viewport[1][0], viewport[0][1]];
35210             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
35211             return _cache$1.rtree.search(bbox).map(function (d) {
35212               return d.data;
35213             });
35214           },
35215           // Get a QAItem from cache
35216           // NOTE: Don't change method name until UI v3 is merged
35217           getError: function getError(id) {
35218             return _cache$1.data[id];
35219           },
35220           // get the name of the icon to display for this item
35221           getIcon: function getIcon(itemType) {
35222             return _impOsmData.icons[itemType];
35223           },
35224           // Replace a single QAItem in the cache
35225           replaceItem: function replaceItem(issue) {
35226             if (!(issue instanceof QAItem) || !issue.id) return;
35227             _cache$1.data[issue.id] = issue;
35228             updateRtree$1(encodeIssueRtree$1(issue), true); // true = replace
35229
35230             return issue;
35231           },
35232           // Remove a single QAItem from the cache
35233           removeItem: function removeItem(issue) {
35234             if (!(issue instanceof QAItem) || !issue.id) return;
35235             delete _cache$1.data[issue.id];
35236             updateRtree$1(encodeIssueRtree$1(issue), false); // false = remove
35237           },
35238           // Used to populate `closed:improveosm:*` changeset tags
35239           getClosedCounts: function getClosedCounts() {
35240             return _cache$1.closed;
35241           }
35242         };
35243
35244         var quot = /"/g;
35245
35246         // B.2.3.2.1 CreateHTML(string, tag, attribute, value)
35247         // https://tc39.github.io/ecma262/#sec-createhtml
35248         var createHtml = function (string, tag, attribute, value) {
35249           var S = String(requireObjectCoercible(string));
35250           var p1 = '<' + tag;
35251           if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
35252           return p1 + '>' + S + '</' + tag + '>';
35253         };
35254
35255         // check the existence of a method, lowercase
35256         // of a tag and escaping quotes in arguments
35257         var stringHtmlForced = function (METHOD_NAME) {
35258           return fails(function () {
35259             var test = ''[METHOD_NAME]('"');
35260             return test !== test.toLowerCase() || test.split('"').length > 3;
35261           });
35262         };
35263
35264         // `String.prototype.link` method
35265         // https://tc39.github.io/ecma262/#sec-string.prototype.link
35266         _export({ target: 'String', proto: true, forced: stringHtmlForced('link') }, {
35267           link: function link(url) {
35268             return createHtml(this, 'a', 'href', url);
35269           }
35270         });
35271
35272         var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
35273
35274
35275
35276
35277
35278
35279         var nativeEndsWith = ''.endsWith;
35280         var min$8 = Math.min;
35281
35282         var CORRECT_IS_REGEXP_LOGIC = correctIsRegexpLogic('endsWith');
35283         // https://github.com/zloirock/core-js/pull/702
35284         var MDN_POLYFILL_BUG =  !CORRECT_IS_REGEXP_LOGIC && !!function () {
35285           var descriptor = getOwnPropertyDescriptor$4(String.prototype, 'endsWith');
35286           return descriptor && !descriptor.writable;
35287         }();
35288
35289         // `String.prototype.endsWith` method
35290         // https://tc39.github.io/ecma262/#sec-string.prototype.endswith
35291         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
35292           endsWith: function endsWith(searchString /* , endPosition = @length */) {
35293             var that = String(requireObjectCoercible(this));
35294             notARegexp(searchString);
35295             var endPosition = arguments.length > 1 ? arguments[1] : undefined;
35296             var len = toLength(that.length);
35297             var end = endPosition === undefined ? len : min$8(toLength(endPosition), len);
35298             var search = String(searchString);
35299             return nativeEndsWith
35300               ? nativeEndsWith.call(that, search, end)
35301               : that.slice(end - search.length, end) === search;
35302           }
35303         });
35304
35305         var getOwnPropertyDescriptor$5 = objectGetOwnPropertyDescriptor.f;
35306
35307
35308
35309
35310
35311
35312         var nativeStartsWith = ''.startsWith;
35313         var min$9 = Math.min;
35314
35315         var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegexpLogic('startsWith');
35316         // https://github.com/zloirock/core-js/pull/702
35317         var MDN_POLYFILL_BUG$1 =  !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
35318           var descriptor = getOwnPropertyDescriptor$5(String.prototype, 'startsWith');
35319           return descriptor && !descriptor.writable;
35320         }();
35321
35322         // `String.prototype.startsWith` method
35323         // https://tc39.github.io/ecma262/#sec-string.prototype.startswith
35324         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1 }, {
35325           startsWith: function startsWith(searchString /* , position = 0 */) {
35326             var that = String(requireObjectCoercible(this));
35327             notARegexp(searchString);
35328             var index = toLength(min$9(arguments.length > 1 ? arguments[1] : undefined, that.length));
35329             var search = String(searchString);
35330             return nativeStartsWith
35331               ? nativeStartsWith.call(that, search, index)
35332               : that.slice(index, index + search.length) === search;
35333           }
35334         });
35335
35336         var $trimEnd = stringTrim.end;
35337
35338
35339         var FORCED$e = stringTrimForced('trimEnd');
35340
35341         var trimEnd = FORCED$e ? function trimEnd() {
35342           return $trimEnd(this);
35343         } : ''.trimEnd;
35344
35345         // `String.prototype.{ trimEnd, trimRight }` methods
35346         // https://github.com/tc39/ecmascript-string-left-right-trim
35347         _export({ target: 'String', proto: true, forced: FORCED$e }, {
35348           trimEnd: trimEnd,
35349           trimRight: trimEnd
35350         });
35351
35352         var defaults = createCommonjsModule(function (module) {
35353           function getDefaults() {
35354             return {
35355               baseUrl: null,
35356               breaks: false,
35357               gfm: true,
35358               headerIds: true,
35359               headerPrefix: '',
35360               highlight: null,
35361               langPrefix: 'language-',
35362               mangle: true,
35363               pedantic: false,
35364               renderer: null,
35365               sanitize: false,
35366               sanitizer: null,
35367               silent: false,
35368               smartLists: false,
35369               smartypants: false,
35370               tokenizer: null,
35371               walkTokens: null,
35372               xhtml: false
35373             };
35374           }
35375
35376           function changeDefaults(newDefaults) {
35377             module.exports.defaults = newDefaults;
35378           }
35379
35380           module.exports = {
35381             defaults: getDefaults(),
35382             getDefaults: getDefaults,
35383             changeDefaults: changeDefaults
35384           };
35385         });
35386
35387         /**
35388          * Helpers
35389          */
35390         var escapeTest = /[&<>"']/;
35391         var escapeReplace = /[&<>"']/g;
35392         var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
35393         var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
35394         var escapeReplacements = {
35395           '&': '&amp;',
35396           '<': '&lt;',
35397           '>': '&gt;',
35398           '"': '&quot;',
35399           "'": '&#39;'
35400         };
35401
35402         var getEscapeReplacement = function getEscapeReplacement(ch) {
35403           return escapeReplacements[ch];
35404         };
35405
35406         function escape$1(html, encode) {
35407           if (encode) {
35408             if (escapeTest.test(html)) {
35409               return html.replace(escapeReplace, getEscapeReplacement);
35410             }
35411           } else {
35412             if (escapeTestNoEncode.test(html)) {
35413               return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
35414             }
35415           }
35416
35417           return html;
35418         }
35419
35420         var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
35421
35422         function unescape$1(html) {
35423           // explicitly match decimal, hex, and named HTML entities
35424           return html.replace(unescapeTest, function (_, n) {
35425             n = n.toLowerCase();
35426             if (n === 'colon') return ':';
35427
35428             if (n.charAt(0) === '#') {
35429               return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));
35430             }
35431
35432             return '';
35433           });
35434         }
35435
35436         var caret = /(^|[^\[])\^/g;
35437
35438         function edit(regex, opt) {
35439           regex = regex.source || regex;
35440           opt = opt || '';
35441           var obj = {
35442             replace: function replace(name, val) {
35443               val = val.source || val;
35444               val = val.replace(caret, '$1');
35445               regex = regex.replace(name, val);
35446               return obj;
35447             },
35448             getRegex: function getRegex() {
35449               return new RegExp(regex, opt);
35450             }
35451           };
35452           return obj;
35453         }
35454
35455         var nonWordAndColonTest = /[^\w:]/g;
35456         var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
35457
35458         function cleanUrl(sanitize, base, href) {
35459           if (sanitize) {
35460             var prot;
35461
35462             try {
35463               prot = decodeURIComponent(unescape$1(href)).replace(nonWordAndColonTest, '').toLowerCase();
35464             } catch (e) {
35465               return null;
35466             }
35467
35468             if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
35469               return null;
35470             }
35471           }
35472
35473           if (base && !originIndependentUrl.test(href)) {
35474             href = resolveUrl(base, href);
35475           }
35476
35477           try {
35478             href = encodeURI(href).replace(/%25/g, '%');
35479           } catch (e) {
35480             return null;
35481           }
35482
35483           return href;
35484         }
35485
35486         var baseUrls = {};
35487         var justDomain = /^[^:]+:\/*[^/]*$/;
35488         var protocol = /^([^:]+:)[\s\S]*$/;
35489         var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
35490
35491         function resolveUrl(base, href) {
35492           if (!baseUrls[' ' + base]) {
35493             // we can ignore everything in base after the last slash of its path component,
35494             // but we might need to add _that_
35495             // https://tools.ietf.org/html/rfc3986#section-3
35496             if (justDomain.test(base)) {
35497               baseUrls[' ' + base] = base + '/';
35498             } else {
35499               baseUrls[' ' + base] = rtrim$1(base, '/', true);
35500             }
35501           }
35502
35503           base = baseUrls[' ' + base];
35504           var relativeBase = base.indexOf(':') === -1;
35505
35506           if (href.substring(0, 2) === '//') {
35507             if (relativeBase) {
35508               return href;
35509             }
35510
35511             return base.replace(protocol, '$1') + href;
35512           } else if (href.charAt(0) === '/') {
35513             if (relativeBase) {
35514               return href;
35515             }
35516
35517             return base.replace(domain, '$1') + href;
35518           } else {
35519             return base + href;
35520           }
35521         }
35522
35523         var noopTest = {
35524           exec: function noopTest() {}
35525         };
35526
35527         function merge$1(obj) {
35528           var i = 1,
35529               target,
35530               key;
35531
35532           for (; i < arguments.length; i++) {
35533             target = arguments[i];
35534
35535             for (key in target) {
35536               if (Object.prototype.hasOwnProperty.call(target, key)) {
35537                 obj[key] = target[key];
35538               }
35539             }
35540           }
35541
35542           return obj;
35543         }
35544
35545         function splitCells(tableRow, count) {
35546           // ensure that every cell-delimiting pipe has a space
35547           // before it to distinguish it from an escaped pipe
35548           var row = tableRow.replace(/\|/g, function (match, offset, str) {
35549             var escaped = false,
35550                 curr = offset;
35551
35552             while (--curr >= 0 && str[curr] === '\\') {
35553               escaped = !escaped;
35554             }
35555
35556             if (escaped) {
35557               // odd number of slashes means | is escaped
35558               // so we leave it alone
35559               return '|';
35560             } else {
35561               // add space before unescaped |
35562               return ' |';
35563             }
35564           }),
35565               cells = row.split(/ \|/);
35566           var i = 0;
35567
35568           if (cells.length > count) {
35569             cells.splice(count);
35570           } else {
35571             while (cells.length < count) {
35572               cells.push('');
35573             }
35574           }
35575
35576           for (; i < cells.length; i++) {
35577             // leading or trailing whitespace is ignored per the gfm spec
35578             cells[i] = cells[i].trim().replace(/\\\|/g, '|');
35579           }
35580
35581           return cells;
35582         } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
35583         // /c*$/ is vulnerable to REDOS.
35584         // invert: Remove suffix of non-c chars instead. Default falsey.
35585
35586
35587         function rtrim$1(str, c, invert) {
35588           var l = str.length;
35589
35590           if (l === 0) {
35591             return '';
35592           } // Length of suffix matching the invert condition.
35593
35594
35595           var suffLen = 0; // Step left until we fail to match the invert condition.
35596
35597           while (suffLen < l) {
35598             var currChar = str.charAt(l - suffLen - 1);
35599
35600             if (currChar === c && !invert) {
35601               suffLen++;
35602             } else if (currChar !== c && invert) {
35603               suffLen++;
35604             } else {
35605               break;
35606             }
35607           }
35608
35609           return str.substr(0, l - suffLen);
35610         }
35611
35612         function findClosingBracket(str, b) {
35613           if (str.indexOf(b[1]) === -1) {
35614             return -1;
35615           }
35616
35617           var l = str.length;
35618           var level = 0,
35619               i = 0;
35620
35621           for (; i < l; i++) {
35622             if (str[i] === '\\') {
35623               i++;
35624             } else if (str[i] === b[0]) {
35625               level++;
35626             } else if (str[i] === b[1]) {
35627               level--;
35628
35629               if (level < 0) {
35630                 return i;
35631               }
35632             }
35633           }
35634
35635           return -1;
35636         }
35637
35638         function checkSanitizeDeprecation(opt) {
35639           if (opt && opt.sanitize && !opt.silent) {
35640             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');
35641           }
35642         } // copied from https://stackoverflow.com/a/5450113/806777
35643
35644
35645         function repeatString(pattern, count) {
35646           if (count < 1) {
35647             return '';
35648           }
35649
35650           var result = '';
35651
35652           while (count > 1) {
35653             if (count & 1) {
35654               result += pattern;
35655             }
35656
35657             count >>= 1;
35658             pattern += pattern;
35659           }
35660
35661           return result + pattern;
35662         }
35663
35664         var helpers = {
35665           escape: escape$1,
35666           unescape: unescape$1,
35667           edit: edit,
35668           cleanUrl: cleanUrl,
35669           resolveUrl: resolveUrl,
35670           noopTest: noopTest,
35671           merge: merge$1,
35672           splitCells: splitCells,
35673           rtrim: rtrim$1,
35674           findClosingBracket: findClosingBracket,
35675           checkSanitizeDeprecation: checkSanitizeDeprecation,
35676           repeatString: repeatString
35677         };
35678
35679         var defaults$1 = defaults.defaults;
35680         var rtrim$2 = helpers.rtrim,
35681             splitCells$1 = helpers.splitCells,
35682             _escape = helpers.escape,
35683             findClosingBracket$1 = helpers.findClosingBracket;
35684
35685         function outputLink(cap, link, raw) {
35686           var href = link.href;
35687           var title = link.title ? _escape(link.title) : null;
35688           var text = cap[1].replace(/\\([\[\]])/g, '$1');
35689
35690           if (cap[0].charAt(0) !== '!') {
35691             return {
35692               type: 'link',
35693               raw: raw,
35694               href: href,
35695               title: title,
35696               text: text
35697             };
35698           } else {
35699             return {
35700               type: 'image',
35701               raw: raw,
35702               href: href,
35703               title: title,
35704               text: _escape(text)
35705             };
35706           }
35707         }
35708
35709         function indentCodeCompensation(raw, text) {
35710           var matchIndentToCode = raw.match(/^(\s+)(?:```)/);
35711
35712           if (matchIndentToCode === null) {
35713             return text;
35714           }
35715
35716           var indentToCode = matchIndentToCode[1];
35717           return text.split('\n').map(function (node) {
35718             var matchIndentInNode = node.match(/^\s+/);
35719
35720             if (matchIndentInNode === null) {
35721               return node;
35722             }
35723
35724             var _matchIndentInNode = _slicedToArray(matchIndentInNode, 1),
35725                 indentInNode = _matchIndentInNode[0];
35726
35727             if (indentInNode.length >= indentToCode.length) {
35728               return node.slice(indentToCode.length);
35729             }
35730
35731             return node;
35732           }).join('\n');
35733         }
35734         /**
35735          * Tokenizer
35736          */
35737
35738
35739         var Tokenizer_1 = /*#__PURE__*/function () {
35740           function Tokenizer(options) {
35741             _classCallCheck(this, Tokenizer);
35742
35743             this.options = options || defaults$1;
35744           }
35745
35746           _createClass(Tokenizer, [{
35747             key: "space",
35748             value: function space(src) {
35749               var cap = this.rules.block.newline.exec(src);
35750
35751               if (cap) {
35752                 if (cap[0].length > 1) {
35753                   return {
35754                     type: 'space',
35755                     raw: cap[0]
35756                   };
35757                 }
35758
35759                 return {
35760                   raw: '\n'
35761                 };
35762               }
35763             }
35764           }, {
35765             key: "code",
35766             value: function code(src, tokens) {
35767               var cap = this.rules.block.code.exec(src);
35768
35769               if (cap) {
35770                 var lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.
35771
35772                 if (lastToken && lastToken.type === 'paragraph') {
35773                   return {
35774                     raw: cap[0],
35775                     text: cap[0].trimRight()
35776                   };
35777                 }
35778
35779                 var text = cap[0].replace(/^ {4}/gm, '');
35780                 return {
35781                   type: 'code',
35782                   raw: cap[0],
35783                   codeBlockStyle: 'indented',
35784                   text: !this.options.pedantic ? rtrim$2(text, '\n') : text
35785                 };
35786               }
35787             }
35788           }, {
35789             key: "fences",
35790             value: function fences(src) {
35791               var cap = this.rules.block.fences.exec(src);
35792
35793               if (cap) {
35794                 var raw = cap[0];
35795                 var text = indentCodeCompensation(raw, cap[3] || '');
35796                 return {
35797                   type: 'code',
35798                   raw: raw,
35799                   lang: cap[2] ? cap[2].trim() : cap[2],
35800                   text: text
35801                 };
35802               }
35803             }
35804           }, {
35805             key: "heading",
35806             value: function heading(src) {
35807               var cap = this.rules.block.heading.exec(src);
35808
35809               if (cap) {
35810                 return {
35811                   type: 'heading',
35812                   raw: cap[0],
35813                   depth: cap[1].length,
35814                   text: cap[2]
35815                 };
35816               }
35817             }
35818           }, {
35819             key: "nptable",
35820             value: function nptable(src) {
35821               var cap = this.rules.block.nptable.exec(src);
35822
35823               if (cap) {
35824                 var item = {
35825                   type: 'table',
35826                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
35827                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
35828                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
35829                   raw: cap[0]
35830                 };
35831
35832                 if (item.header.length === item.align.length) {
35833                   var l = item.align.length;
35834                   var i;
35835
35836                   for (i = 0; i < l; i++) {
35837                     if (/^ *-+: *$/.test(item.align[i])) {
35838                       item.align[i] = 'right';
35839                     } else if (/^ *:-+: *$/.test(item.align[i])) {
35840                       item.align[i] = 'center';
35841                     } else if (/^ *:-+ *$/.test(item.align[i])) {
35842                       item.align[i] = 'left';
35843                     } else {
35844                       item.align[i] = null;
35845                     }
35846                   }
35847
35848                   l = item.cells.length;
35849
35850                   for (i = 0; i < l; i++) {
35851                     item.cells[i] = splitCells$1(item.cells[i], item.header.length);
35852                   }
35853
35854                   return item;
35855                 }
35856               }
35857             }
35858           }, {
35859             key: "hr",
35860             value: function hr(src) {
35861               var cap = this.rules.block.hr.exec(src);
35862
35863               if (cap) {
35864                 return {
35865                   type: 'hr',
35866                   raw: cap[0]
35867                 };
35868               }
35869             }
35870           }, {
35871             key: "blockquote",
35872             value: function blockquote(src) {
35873               var cap = this.rules.block.blockquote.exec(src);
35874
35875               if (cap) {
35876                 var text = cap[0].replace(/^ *> ?/gm, '');
35877                 return {
35878                   type: 'blockquote',
35879                   raw: cap[0],
35880                   text: text
35881                 };
35882               }
35883             }
35884           }, {
35885             key: "list",
35886             value: function list(src) {
35887               var cap = this.rules.block.list.exec(src);
35888
35889               if (cap) {
35890                 var raw = cap[0];
35891                 var bull = cap[2];
35892                 var isordered = bull.length > 1;
35893                 var isparen = bull[bull.length - 1] === ')';
35894                 var list = {
35895                   type: 'list',
35896                   raw: raw,
35897                   ordered: isordered,
35898                   start: isordered ? +bull.slice(0, -1) : '',
35899                   loose: false,
35900                   items: []
35901                 }; // Get each top-level item.
35902
35903                 var itemMatch = cap[0].match(this.rules.block.item);
35904                 var next = false,
35905                     item,
35906                     space,
35907                     b,
35908                     addBack,
35909                     loose,
35910                     istask,
35911                     ischecked;
35912                 var l = itemMatch.length;
35913
35914                 for (var i = 0; i < l; i++) {
35915                   item = itemMatch[i];
35916                   raw = item; // Remove the list item's bullet
35917                   // so it is seen as the next token.
35918
35919                   space = item.length;
35920                   item = item.replace(/^ *([*+-]|\d+[.)]) ?/, ''); // Outdent whatever the
35921                   // list item contains. Hacky.
35922
35923                   if (~item.indexOf('\n ')) {
35924                     space -= item.length;
35925                     item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');
35926                   } // Determine whether the next list item belongs here.
35927                   // Backpedal if it does not belong in this list.
35928
35929
35930                   if (i !== l - 1) {
35931                     b = this.rules.block.bullet.exec(itemMatch[i + 1])[0];
35932
35933                     if (isordered ? b.length === 1 || !isparen && b[b.length - 1] === ')' : b.length > 1 || this.options.smartLists && b !== bull) {
35934                       addBack = itemMatch.slice(i + 1).join('\n');
35935                       list.raw = list.raw.substring(0, list.raw.length - addBack.length);
35936                       i = l - 1;
35937                     }
35938                   } // Determine whether item is loose or not.
35939                   // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
35940                   // for discount behavior.
35941
35942
35943                   loose = next || /\n\n(?!\s*$)/.test(item);
35944
35945                   if (i !== l - 1) {
35946                     next = item.charAt(item.length - 1) === '\n';
35947                     if (!loose) loose = next;
35948                   }
35949
35950                   if (loose) {
35951                     list.loose = true;
35952                   } // Check for task list items
35953
35954
35955                   istask = /^\[[ xX]\] /.test(item);
35956                   ischecked = undefined;
35957
35958                   if (istask) {
35959                     ischecked = item[1] !== ' ';
35960                     item = item.replace(/^\[[ xX]\] +/, '');
35961                   }
35962
35963                   list.items.push({
35964                     type: 'list_item',
35965                     raw: raw,
35966                     task: istask,
35967                     checked: ischecked,
35968                     loose: loose,
35969                     text: item
35970                   });
35971                 }
35972
35973                 return list;
35974               }
35975             }
35976           }, {
35977             key: "html",
35978             value: function html(src) {
35979               var cap = this.rules.block.html.exec(src);
35980
35981               if (cap) {
35982                 return {
35983                   type: this.options.sanitize ? 'paragraph' : 'html',
35984                   raw: cap[0],
35985                   pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
35986                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
35987                 };
35988               }
35989             }
35990           }, {
35991             key: "def",
35992             value: function def(src) {
35993               var cap = this.rules.block.def.exec(src);
35994
35995               if (cap) {
35996                 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
35997                 var tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
35998                 return {
35999                   tag: tag,
36000                   raw: cap[0],
36001                   href: cap[2],
36002                   title: cap[3]
36003                 };
36004               }
36005             }
36006           }, {
36007             key: "table",
36008             value: function table(src) {
36009               var cap = this.rules.block.table.exec(src);
36010
36011               if (cap) {
36012                 var item = {
36013                   type: 'table',
36014                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
36015                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
36016                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
36017                 };
36018
36019                 if (item.header.length === item.align.length) {
36020                   item.raw = cap[0];
36021                   var l = item.align.length;
36022                   var i;
36023
36024                   for (i = 0; i < l; i++) {
36025                     if (/^ *-+: *$/.test(item.align[i])) {
36026                       item.align[i] = 'right';
36027                     } else if (/^ *:-+: *$/.test(item.align[i])) {
36028                       item.align[i] = 'center';
36029                     } else if (/^ *:-+ *$/.test(item.align[i])) {
36030                       item.align[i] = 'left';
36031                     } else {
36032                       item.align[i] = null;
36033                     }
36034                   }
36035
36036                   l = item.cells.length;
36037
36038                   for (i = 0; i < l; i++) {
36039                     item.cells[i] = splitCells$1(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length);
36040                   }
36041
36042                   return item;
36043                 }
36044               }
36045             }
36046           }, {
36047             key: "lheading",
36048             value: function lheading(src) {
36049               var cap = this.rules.block.lheading.exec(src);
36050
36051               if (cap) {
36052                 return {
36053                   type: 'heading',
36054                   raw: cap[0],
36055                   depth: cap[2].charAt(0) === '=' ? 1 : 2,
36056                   text: cap[1]
36057                 };
36058               }
36059             }
36060           }, {
36061             key: "paragraph",
36062             value: function paragraph(src) {
36063               var cap = this.rules.block.paragraph.exec(src);
36064
36065               if (cap) {
36066                 return {
36067                   type: 'paragraph',
36068                   raw: cap[0],
36069                   text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
36070                 };
36071               }
36072             }
36073           }, {
36074             key: "text",
36075             value: function text(src, tokens) {
36076               var cap = this.rules.block.text.exec(src);
36077
36078               if (cap) {
36079                 var lastToken = tokens[tokens.length - 1];
36080
36081                 if (lastToken && lastToken.type === 'text') {
36082                   return {
36083                     raw: cap[0],
36084                     text: cap[0]
36085                   };
36086                 }
36087
36088                 return {
36089                   type: 'text',
36090                   raw: cap[0],
36091                   text: cap[0]
36092                 };
36093               }
36094             }
36095           }, {
36096             key: "escape",
36097             value: function escape(src) {
36098               var cap = this.rules.inline.escape.exec(src);
36099
36100               if (cap) {
36101                 return {
36102                   type: 'escape',
36103                   raw: cap[0],
36104                   text: _escape(cap[1])
36105                 };
36106               }
36107             }
36108           }, {
36109             key: "tag",
36110             value: function tag(src, inLink, inRawBlock) {
36111               var cap = this.rules.inline.tag.exec(src);
36112
36113               if (cap) {
36114                 if (!inLink && /^<a /i.test(cap[0])) {
36115                   inLink = true;
36116                 } else if (inLink && /^<\/a>/i.test(cap[0])) {
36117                   inLink = false;
36118                 }
36119
36120                 if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36121                   inRawBlock = true;
36122                 } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36123                   inRawBlock = false;
36124                 }
36125
36126                 return {
36127                   type: this.options.sanitize ? 'text' : 'html',
36128                   raw: cap[0],
36129                   inLink: inLink,
36130                   inRawBlock: inRawBlock,
36131                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
36132                 };
36133               }
36134             }
36135           }, {
36136             key: "link",
36137             value: function link(src) {
36138               var cap = this.rules.inline.link.exec(src);
36139
36140               if (cap) {
36141                 var lastParenIndex = findClosingBracket$1(cap[2], '()');
36142
36143                 if (lastParenIndex > -1) {
36144                   var start = cap[0].indexOf('!') === 0 ? 5 : 4;
36145                   var linkLen = start + cap[1].length + lastParenIndex;
36146                   cap[2] = cap[2].substring(0, lastParenIndex);
36147                   cap[0] = cap[0].substring(0, linkLen).trim();
36148                   cap[3] = '';
36149                 }
36150
36151                 var href = cap[2];
36152                 var title = '';
36153
36154                 if (this.options.pedantic) {
36155                   var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
36156
36157                   if (link) {
36158                     href = link[1];
36159                     title = link[3];
36160                   } else {
36161                     title = '';
36162                   }
36163                 } else {
36164                   title = cap[3] ? cap[3].slice(1, -1) : '';
36165                 }
36166
36167                 href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
36168                 var token = outputLink(cap, {
36169                   href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
36170                   title: title ? title.replace(this.rules.inline._escapes, '$1') : title
36171                 }, cap[0]);
36172                 return token;
36173               }
36174             }
36175           }, {
36176             key: "reflink",
36177             value: function reflink(src, links) {
36178               var cap;
36179
36180               if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
36181                 var link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
36182                 link = links[link.toLowerCase()];
36183
36184                 if (!link || !link.href) {
36185                   var text = cap[0].charAt(0);
36186                   return {
36187                     type: 'text',
36188                     raw: text,
36189                     text: text
36190                   };
36191                 }
36192
36193                 var token = outputLink(cap, link, cap[0]);
36194                 return token;
36195               }
36196             }
36197           }, {
36198             key: "strong",
36199             value: function strong(src, maskedSrc) {
36200               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36201               var match = this.rules.inline.strong.start.exec(src);
36202
36203               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36204                 maskedSrc = maskedSrc.slice(-1 * src.length);
36205                 var endReg = match[0] === '**' ? this.rules.inline.strong.endAst : this.rules.inline.strong.endUnd;
36206                 endReg.lastIndex = 0;
36207                 var cap;
36208
36209                 while ((match = endReg.exec(maskedSrc)) != null) {
36210                   cap = this.rules.inline.strong.middle.exec(maskedSrc.slice(0, match.index + 3));
36211
36212                   if (cap) {
36213                     return {
36214                       type: 'strong',
36215                       raw: src.slice(0, cap[0].length),
36216                       text: src.slice(2, cap[0].length - 2)
36217                     };
36218                   }
36219                 }
36220               }
36221             }
36222           }, {
36223             key: "em",
36224             value: function em(src, maskedSrc) {
36225               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36226               var match = this.rules.inline.em.start.exec(src);
36227
36228               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36229                 maskedSrc = maskedSrc.slice(-1 * src.length);
36230                 var endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;
36231                 endReg.lastIndex = 0;
36232                 var cap;
36233
36234                 while ((match = endReg.exec(maskedSrc)) != null) {
36235                   cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));
36236
36237                   if (cap) {
36238                     return {
36239                       type: 'em',
36240                       raw: src.slice(0, cap[0].length),
36241                       text: src.slice(1, cap[0].length - 1)
36242                     };
36243                   }
36244                 }
36245               }
36246             }
36247           }, {
36248             key: "codespan",
36249             value: function codespan(src) {
36250               var cap = this.rules.inline.code.exec(src);
36251
36252               if (cap) {
36253                 var text = cap[2].replace(/\n/g, ' ');
36254                 var hasNonSpaceChars = /[^ ]/.test(text);
36255                 var hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
36256
36257                 if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
36258                   text = text.substring(1, text.length - 1);
36259                 }
36260
36261                 text = _escape(text, true);
36262                 return {
36263                   type: 'codespan',
36264                   raw: cap[0],
36265                   text: text
36266                 };
36267               }
36268             }
36269           }, {
36270             key: "br",
36271             value: function br(src) {
36272               var cap = this.rules.inline.br.exec(src);
36273
36274               if (cap) {
36275                 return {
36276                   type: 'br',
36277                   raw: cap[0]
36278                 };
36279               }
36280             }
36281           }, {
36282             key: "del",
36283             value: function del(src) {
36284               var cap = this.rules.inline.del.exec(src);
36285
36286               if (cap) {
36287                 return {
36288                   type: 'del',
36289                   raw: cap[0],
36290                   text: cap[1]
36291                 };
36292               }
36293             }
36294           }, {
36295             key: "autolink",
36296             value: function autolink(src, mangle) {
36297               var cap = this.rules.inline.autolink.exec(src);
36298
36299               if (cap) {
36300                 var text, href;
36301
36302                 if (cap[2] === '@') {
36303                   text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
36304                   href = 'mailto:' + text;
36305                 } else {
36306                   text = _escape(cap[1]);
36307                   href = text;
36308                 }
36309
36310                 return {
36311                   type: 'link',
36312                   raw: cap[0],
36313                   text: text,
36314                   href: href,
36315                   tokens: [{
36316                     type: 'text',
36317                     raw: text,
36318                     text: text
36319                   }]
36320                 };
36321               }
36322             }
36323           }, {
36324             key: "url",
36325             value: function url(src, mangle) {
36326               var cap;
36327
36328               if (cap = this.rules.inline.url.exec(src)) {
36329                 var text, href;
36330
36331                 if (cap[2] === '@') {
36332                   text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
36333                   href = 'mailto:' + text;
36334                 } else {
36335                   // do extended autolink path validation
36336                   var prevCapZero;
36337
36338                   do {
36339                     prevCapZero = cap[0];
36340                     cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
36341                   } while (prevCapZero !== cap[0]);
36342
36343                   text = _escape(cap[0]);
36344
36345                   if (cap[1] === 'www.') {
36346                     href = 'http://' + text;
36347                   } else {
36348                     href = text;
36349                   }
36350                 }
36351
36352                 return {
36353                   type: 'link',
36354                   raw: cap[0],
36355                   text: text,
36356                   href: href,
36357                   tokens: [{
36358                     type: 'text',
36359                     raw: text,
36360                     text: text
36361                   }]
36362                 };
36363               }
36364             }
36365           }, {
36366             key: "inlineText",
36367             value: function inlineText(src, inRawBlock, smartypants) {
36368               var cap = this.rules.inline.text.exec(src);
36369
36370               if (cap) {
36371                 var text;
36372
36373                 if (inRawBlock) {
36374                   text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];
36375                 } else {
36376                   text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
36377                 }
36378
36379                 return {
36380                   type: 'text',
36381                   raw: cap[0],
36382                   text: text
36383                 };
36384               }
36385             }
36386           }]);
36387
36388           return Tokenizer;
36389         }();
36390
36391         var noopTest$1 = helpers.noopTest,
36392             edit$1 = helpers.edit,
36393             merge$2 = helpers.merge;
36394         /**
36395          * Block-Level Grammar
36396          */
36397
36398         var block = {
36399           newline: /^\n+/,
36400           code: /^( {4}[^\n]+\n*)+/,
36401           fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
36402           hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
36403           heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
36404           blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
36405           list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
36406           html: '^ {0,3}(?:' // optional indentation
36407           + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
36408           + '|comment[^\\n]*(\\n+|$)' // (2)
36409           + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
36410           + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
36411           + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
36412           + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
36413           + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
36414           + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
36415           + ')',
36416           def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
36417           nptable: noopTest$1,
36418           table: noopTest$1,
36419           lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
36420           // regex template, placeholders will be replaced according to different paragraph
36421           // interruption rules of commonmark and the original markdown spec:
36422           _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,
36423           text: /^[^\n]+/
36424         };
36425         block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
36426         block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
36427         block.def = edit$1(block.def).replace('label', block._label).replace('title', block._title).getRegex();
36428         block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
36429         block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/;
36430         block.item = edit$1(block.item, 'gm').replace(/bull/g, block.bullet).getRegex();
36431         block.list = edit$1(block.list).replace(/bull/g, block.bullet).replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))').replace('def', '\\n+(?=' + block.def.source + ')').getRegex();
36432         block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' + '|track|ul';
36433         block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
36434         block.html = edit$1(block.html, 'i').replace('comment', block._comment).replace('tag', block._tag).replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
36435         block.paragraph = edit$1(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
36436         .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
36437         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
36438         .getRegex();
36439         block.blockquote = edit$1(block.blockquote).replace('paragraph', block.paragraph).getRegex();
36440         /**
36441          * Normal Block Grammar
36442          */
36443
36444         block.normal = merge$2({}, block);
36445         /**
36446          * GFM Block Grammar
36447          */
36448
36449         block.gfm = merge$2({}, block.normal, {
36450           nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
36451           + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
36452           + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)',
36453           // Cells
36454           table: '^ *\\|(.+)\\n' // Header
36455           + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
36456           + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
36457
36458         });
36459         block.gfm.nptable = edit$1(block.gfm.nptable).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
36460         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36461         .getRegex();
36462         block.gfm.table = edit$1(block.gfm.table).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
36463         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36464         .getRegex();
36465         /**
36466          * Pedantic grammar (original John Gruber's loose markdown specification)
36467          */
36468
36469         block.pedantic = merge$2({}, block.normal, {
36470           html: edit$1('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
36471           + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))').replace('comment', block._comment).replace(/tag/g, '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b').getRegex(),
36472           def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
36473           heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
36474           fences: noopTest$1,
36475           // fences not supported
36476           paragraph: edit$1(block.normal._paragraph).replace('hr', block.hr).replace('heading', ' *#{1,6} *[^\n]').replace('lheading', block.lheading).replace('blockquote', ' {0,3}>').replace('|fences', '').replace('|list', '').replace('|html', '').getRegex()
36477         });
36478         /**
36479          * Inline-Level Grammar
36480          */
36481
36482         var inline = {
36483           escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
36484           autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
36485           url: noopTest$1,
36486           tag: '^comment' + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
36487           + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
36488           + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
36489           + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
36490           + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
36491           // CDATA section
36492           link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
36493           reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
36494           nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
36495           reflinkSearch: 'reflink|nolink(?!\\()',
36496           strong: {
36497             start: /^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,
36498             // (1) returns if starts w/ punctuation
36499             middle: /^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,
36500             endAst: /[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36501             // last char can't be punct, or final * must also be followed by punct (or endline)
36502             endUnd: /[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36503
36504           },
36505           em: {
36506             start: /^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,
36507             // (1) returns if starts w/ punctuation
36508             middle: /^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,
36509             endAst: /[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36510             // last char can't be punct, or final * must also be followed by punct (or endline)
36511             endUnd: /[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36512
36513           },
36514           code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
36515           br: /^( {2,}|\\)\n(?!\s*$)/,
36516           del: noopTest$1,
36517           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n)))/,
36518           punctuation: /^([\s*punctuation])/
36519         }; // list of punctuation marks from common mark spec
36520         // without * and _ to workaround cases with double emphasis
36521
36522         inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
36523         inline.punctuation = edit$1(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, <html>
36524
36525         inline._blockSkip = '\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>';
36526         inline._overlapSkip = '__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*';
36527         inline._comment = edit$1(block._comment).replace('(?:-->|$)', '-->').getRegex();
36528         inline.em.start = edit$1(inline.em.start).replace(/punctuation/g, inline._punctuation).getRegex();
36529         inline.em.middle = edit$1(inline.em.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36530         inline.em.endAst = edit$1(inline.em.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36531         inline.em.endUnd = edit$1(inline.em.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36532         inline.strong.start = edit$1(inline.strong.start).replace(/punctuation/g, inline._punctuation).getRegex();
36533         inline.strong.middle = edit$1(inline.strong.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36534         inline.strong.endAst = edit$1(inline.strong.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36535         inline.strong.endUnd = edit$1(inline.strong.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36536         inline.blockSkip = edit$1(inline._blockSkip, 'g').getRegex();
36537         inline.overlapSkip = edit$1(inline._overlapSkip, 'g').getRegex();
36538         inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
36539         inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
36540         inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
36541         inline.autolink = edit$1(inline.autolink).replace('scheme', inline._scheme).replace('email', inline._email).getRegex();
36542         inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
36543         inline.tag = edit$1(inline.tag).replace('comment', inline._comment).replace('attribute', inline._attribute).getRegex();
36544         inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
36545         inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
36546         inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
36547         inline.link = edit$1(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex();
36548         inline.reflink = edit$1(inline.reflink).replace('label', inline._label).getRegex();
36549         inline.reflinkSearch = edit$1(inline.reflinkSearch, 'g').replace('reflink', inline.reflink).replace('nolink', inline.nolink).getRegex();
36550         /**
36551          * Normal Inline Grammar
36552          */
36553
36554         inline.normal = merge$2({}, inline);
36555         /**
36556          * Pedantic Inline Grammar
36557          */
36558
36559         inline.pedantic = merge$2({}, inline.normal, {
36560           strong: {
36561             start: /^__|\*\*/,
36562             middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
36563             endAst: /\*\*(?!\*)/g,
36564             endUnd: /__(?!_)/g
36565           },
36566           em: {
36567             start: /^_|\*/,
36568             middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
36569             endAst: /\*(?!\*)/g,
36570             endUnd: /_(?!_)/g
36571           },
36572           link: edit$1(/^!?\[(label)\]\((.*?)\)/).replace('label', inline._label).getRegex(),
36573           reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline._label).getRegex()
36574         });
36575         /**
36576          * GFM Inline Grammar
36577          */
36578
36579         inline.gfm = merge$2({}, inline.normal, {
36580           escape: edit$1(inline.escape).replace('])', '~|])').getRegex(),
36581           _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
36582           url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
36583           _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
36584           del: /^~+(?=\S)([\s\S]*?\S)~+/,
36585           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
36586         });
36587         inline.gfm.url = edit$1(inline.gfm.url, 'i').replace('email', inline.gfm._extended_email).getRegex();
36588         /**
36589          * GFM + Line Breaks Inline Grammar
36590          */
36591
36592         inline.breaks = merge$2({}, inline.gfm, {
36593           br: edit$1(inline.br).replace('{2,}', '*').getRegex(),
36594           text: edit$1(inline.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
36595         });
36596         var rules = {
36597           block: block,
36598           inline: inline
36599         };
36600
36601         var defaults$2 = defaults.defaults;
36602         var block$1 = rules.block,
36603             inline$1 = rules.inline;
36604         var repeatString$1 = helpers.repeatString;
36605         /**
36606          * smartypants text replacement
36607          */
36608
36609         function smartypants(text) {
36610           return text // em-dashes
36611           .replace(/---/g, "\u2014") // en-dashes
36612           .replace(/--/g, "\u2013") // opening singles
36613           .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes
36614           .replace(/'/g, "\u2019") // opening doubles
36615           .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles
36616           .replace(/"/g, "\u201D") // ellipses
36617           .replace(/\.{3}/g, "\u2026");
36618         }
36619         /**
36620          * mangle email addresses
36621          */
36622
36623
36624         function mangle(text) {
36625           var out = '',
36626               i,
36627               ch;
36628           var l = text.length;
36629
36630           for (i = 0; i < l; i++) {
36631             ch = text.charCodeAt(i);
36632
36633             if (Math.random() > 0.5) {
36634               ch = 'x' + ch.toString(16);
36635             }
36636
36637             out += '&#' + ch + ';';
36638           }
36639
36640           return out;
36641         }
36642         /**
36643          * Block Lexer
36644          */
36645
36646
36647         var Lexer_1 = /*#__PURE__*/function () {
36648           function Lexer(options) {
36649             _classCallCheck(this, Lexer);
36650
36651             this.tokens = [];
36652             this.tokens.links = Object.create(null);
36653             this.options = options || defaults$2;
36654             this.options.tokenizer = this.options.tokenizer || new Tokenizer_1();
36655             this.tokenizer = this.options.tokenizer;
36656             this.tokenizer.options = this.options;
36657             var rules = {
36658               block: block$1.normal,
36659               inline: inline$1.normal
36660             };
36661
36662             if (this.options.pedantic) {
36663               rules.block = block$1.pedantic;
36664               rules.inline = inline$1.pedantic;
36665             } else if (this.options.gfm) {
36666               rules.block = block$1.gfm;
36667
36668               if (this.options.breaks) {
36669                 rules.inline = inline$1.breaks;
36670               } else {
36671                 rules.inline = inline$1.gfm;
36672               }
36673             }
36674
36675             this.tokenizer.rules = rules;
36676           }
36677           /**
36678            * Expose Rules
36679            */
36680
36681
36682           _createClass(Lexer, [{
36683             key: "lex",
36684
36685             /**
36686              * Preprocessing
36687              */
36688             value: function lex(src) {
36689               src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, '    ');
36690               this.blockTokens(src, this.tokens, true);
36691               this.inline(this.tokens);
36692               return this.tokens;
36693             }
36694             /**
36695              * Lexing
36696              */
36697
36698           }, {
36699             key: "blockTokens",
36700             value: function blockTokens(src) {
36701               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
36702               var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
36703               src = src.replace(/^ +$/gm, '');
36704               var token, i, l, lastToken;
36705
36706               while (src) {
36707                 // newline
36708                 if (token = this.tokenizer.space(src)) {
36709                   src = src.substring(token.raw.length);
36710
36711                   if (token.type) {
36712                     tokens.push(token);
36713                   }
36714
36715                   continue;
36716                 } // code
36717
36718
36719                 if (token = this.tokenizer.code(src, tokens)) {
36720                   src = src.substring(token.raw.length);
36721
36722                   if (token.type) {
36723                     tokens.push(token);
36724                   } else {
36725                     lastToken = tokens[tokens.length - 1];
36726                     lastToken.raw += '\n' + token.raw;
36727                     lastToken.text += '\n' + token.text;
36728                   }
36729
36730                   continue;
36731                 } // fences
36732
36733
36734                 if (token = this.tokenizer.fences(src)) {
36735                   src = src.substring(token.raw.length);
36736                   tokens.push(token);
36737                   continue;
36738                 } // heading
36739
36740
36741                 if (token = this.tokenizer.heading(src)) {
36742                   src = src.substring(token.raw.length);
36743                   tokens.push(token);
36744                   continue;
36745                 } // table no leading pipe (gfm)
36746
36747
36748                 if (token = this.tokenizer.nptable(src)) {
36749                   src = src.substring(token.raw.length);
36750                   tokens.push(token);
36751                   continue;
36752                 } // hr
36753
36754
36755                 if (token = this.tokenizer.hr(src)) {
36756                   src = src.substring(token.raw.length);
36757                   tokens.push(token);
36758                   continue;
36759                 } // blockquote
36760
36761
36762                 if (token = this.tokenizer.blockquote(src)) {
36763                   src = src.substring(token.raw.length);
36764                   token.tokens = this.blockTokens(token.text, [], top);
36765                   tokens.push(token);
36766                   continue;
36767                 } // list
36768
36769
36770                 if (token = this.tokenizer.list(src)) {
36771                   src = src.substring(token.raw.length);
36772                   l = token.items.length;
36773
36774                   for (i = 0; i < l; i++) {
36775                     token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
36776                   }
36777
36778                   tokens.push(token);
36779                   continue;
36780                 } // html
36781
36782
36783                 if (token = this.tokenizer.html(src)) {
36784                   src = src.substring(token.raw.length);
36785                   tokens.push(token);
36786                   continue;
36787                 } // def
36788
36789
36790                 if (top && (token = this.tokenizer.def(src))) {
36791                   src = src.substring(token.raw.length);
36792
36793                   if (!this.tokens.links[token.tag]) {
36794                     this.tokens.links[token.tag] = {
36795                       href: token.href,
36796                       title: token.title
36797                     };
36798                   }
36799
36800                   continue;
36801                 } // table (gfm)
36802
36803
36804                 if (token = this.tokenizer.table(src)) {
36805                   src = src.substring(token.raw.length);
36806                   tokens.push(token);
36807                   continue;
36808                 } // lheading
36809
36810
36811                 if (token = this.tokenizer.lheading(src)) {
36812                   src = src.substring(token.raw.length);
36813                   tokens.push(token);
36814                   continue;
36815                 } // top-level paragraph
36816
36817
36818                 if (top && (token = this.tokenizer.paragraph(src))) {
36819                   src = src.substring(token.raw.length);
36820                   tokens.push(token);
36821                   continue;
36822                 } // text
36823
36824
36825                 if (token = this.tokenizer.text(src, tokens)) {
36826                   src = src.substring(token.raw.length);
36827
36828                   if (token.type) {
36829                     tokens.push(token);
36830                   } else {
36831                     lastToken = tokens[tokens.length - 1];
36832                     lastToken.raw += '\n' + token.raw;
36833                     lastToken.text += '\n' + token.text;
36834                   }
36835
36836                   continue;
36837                 }
36838
36839                 if (src) {
36840                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
36841
36842                   if (this.options.silent) {
36843                     console.error(errMsg);
36844                     break;
36845                   } else {
36846                     throw new Error(errMsg);
36847                   }
36848                 }
36849               }
36850
36851               return tokens;
36852             }
36853           }, {
36854             key: "inline",
36855             value: function inline(tokens) {
36856               var i, j, k, l2, row, token;
36857               var l = tokens.length;
36858
36859               for (i = 0; i < l; i++) {
36860                 token = tokens[i];
36861
36862                 switch (token.type) {
36863                   case 'paragraph':
36864                   case 'text':
36865                   case 'heading':
36866                     {
36867                       token.tokens = [];
36868                       this.inlineTokens(token.text, token.tokens);
36869                       break;
36870                     }
36871
36872                   case 'table':
36873                     {
36874                       token.tokens = {
36875                         header: [],
36876                         cells: []
36877                       }; // header
36878
36879                       l2 = token.header.length;
36880
36881                       for (j = 0; j < l2; j++) {
36882                         token.tokens.header[j] = [];
36883                         this.inlineTokens(token.header[j], token.tokens.header[j]);
36884                       } // cells
36885
36886
36887                       l2 = token.cells.length;
36888
36889                       for (j = 0; j < l2; j++) {
36890                         row = token.cells[j];
36891                         token.tokens.cells[j] = [];
36892
36893                         for (k = 0; k < row.length; k++) {
36894                           token.tokens.cells[j][k] = [];
36895                           this.inlineTokens(row[k], token.tokens.cells[j][k]);
36896                         }
36897                       }
36898
36899                       break;
36900                     }
36901
36902                   case 'blockquote':
36903                     {
36904                       this.inline(token.tokens);
36905                       break;
36906                     }
36907
36908                   case 'list':
36909                     {
36910                       l2 = token.items.length;
36911
36912                       for (j = 0; j < l2; j++) {
36913                         this.inline(token.items[j].tokens);
36914                       }
36915
36916                       break;
36917                     }
36918                 }
36919               }
36920
36921               return tokens;
36922             }
36923             /**
36924              * Lexing/Compiling
36925              */
36926
36927           }, {
36928             key: "inlineTokens",
36929             value: function inlineTokens(src) {
36930               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
36931               var inLink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
36932               var inRawBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
36933               var prevChar = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : '';
36934               var token; // String with links masked to avoid interference with em and strong
36935
36936               var maskedSrc = src;
36937               var match; // Mask out reflinks
36938
36939               if (this.tokens.links) {
36940                 var links = Object.keys(this.tokens.links);
36941
36942                 if (links.length > 0) {
36943                   while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
36944                     if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
36945                       maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
36946                     }
36947                   }
36948                 }
36949               } // Mask out other blocks
36950
36951
36952               while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
36953                 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
36954               }
36955
36956               while (src) {
36957                 // escape
36958                 if (token = this.tokenizer.escape(src)) {
36959                   src = src.substring(token.raw.length);
36960                   tokens.push(token);
36961                   continue;
36962                 } // tag
36963
36964
36965                 if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {
36966                   src = src.substring(token.raw.length);
36967                   inLink = token.inLink;
36968                   inRawBlock = token.inRawBlock;
36969                   tokens.push(token);
36970                   continue;
36971                 } // link
36972
36973
36974                 if (token = this.tokenizer.link(src)) {
36975                   src = src.substring(token.raw.length);
36976
36977                   if (token.type === 'link') {
36978                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
36979                   }
36980
36981                   tokens.push(token);
36982                   continue;
36983                 } // reflink, nolink
36984
36985
36986                 if (token = this.tokenizer.reflink(src, this.tokens.links)) {
36987                   src = src.substring(token.raw.length);
36988
36989                   if (token.type === 'link') {
36990                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
36991                   }
36992
36993                   tokens.push(token);
36994                   continue;
36995                 } // strong
36996
36997
36998                 if (token = this.tokenizer.strong(src, maskedSrc, prevChar)) {
36999                   src = src.substring(token.raw.length);
37000                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37001                   tokens.push(token);
37002                   continue;
37003                 } // em
37004
37005
37006                 if (token = this.tokenizer.em(src, maskedSrc, prevChar)) {
37007                   src = src.substring(token.raw.length);
37008                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37009                   tokens.push(token);
37010                   continue;
37011                 } // code
37012
37013
37014                 if (token = this.tokenizer.codespan(src)) {
37015                   src = src.substring(token.raw.length);
37016                   tokens.push(token);
37017                   continue;
37018                 } // br
37019
37020
37021                 if (token = this.tokenizer.br(src)) {
37022                   src = src.substring(token.raw.length);
37023                   tokens.push(token);
37024                   continue;
37025                 } // del (gfm)
37026
37027
37028                 if (token = this.tokenizer.del(src)) {
37029                   src = src.substring(token.raw.length);
37030                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37031                   tokens.push(token);
37032                   continue;
37033                 } // autolink
37034
37035
37036                 if (token = this.tokenizer.autolink(src, mangle)) {
37037                   src = src.substring(token.raw.length);
37038                   tokens.push(token);
37039                   continue;
37040                 } // url (gfm)
37041
37042
37043                 if (!inLink && (token = this.tokenizer.url(src, mangle))) {
37044                   src = src.substring(token.raw.length);
37045                   tokens.push(token);
37046                   continue;
37047                 } // text
37048
37049
37050                 if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
37051                   src = src.substring(token.raw.length);
37052                   prevChar = token.raw.slice(-1);
37053                   tokens.push(token);
37054                   continue;
37055                 }
37056
37057                 if (src) {
37058                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
37059
37060                   if (this.options.silent) {
37061                     console.error(errMsg);
37062                     break;
37063                   } else {
37064                     throw new Error(errMsg);
37065                   }
37066                 }
37067               }
37068
37069               return tokens;
37070             }
37071           }], [{
37072             key: "lex",
37073
37074             /**
37075              * Static Lex Method
37076              */
37077             value: function lex(src, options) {
37078               var lexer = new Lexer(options);
37079               return lexer.lex(src);
37080             }
37081             /**
37082              * Static Lex Inline Method
37083              */
37084
37085           }, {
37086             key: "lexInline",
37087             value: function lexInline(src, options) {
37088               var lexer = new Lexer(options);
37089               return lexer.inlineTokens(src);
37090             }
37091           }, {
37092             key: "rules",
37093             get: function get() {
37094               return {
37095                 block: block$1,
37096                 inline: inline$1
37097               };
37098             }
37099           }]);
37100
37101           return Lexer;
37102         }();
37103
37104         var defaults$3 = defaults.defaults;
37105         var cleanUrl$1 = helpers.cleanUrl,
37106             escape$2 = helpers.escape;
37107         /**
37108          * Renderer
37109          */
37110
37111         var Renderer_1 = /*#__PURE__*/function () {
37112           function Renderer(options) {
37113             _classCallCheck(this, Renderer);
37114
37115             this.options = options || defaults$3;
37116           }
37117
37118           _createClass(Renderer, [{
37119             key: "code",
37120             value: function code(_code, infostring, escaped) {
37121               var lang = (infostring || '').match(/\S*/)[0];
37122
37123               if (this.options.highlight) {
37124                 var out = this.options.highlight(_code, lang);
37125
37126                 if (out != null && out !== _code) {
37127                   escaped = true;
37128                   _code = out;
37129                 }
37130               }
37131
37132               if (!lang) {
37133                 return '<pre><code>' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37134               }
37135
37136               return '<pre><code class="' + this.options.langPrefix + escape$2(lang, true) + '">' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37137             }
37138           }, {
37139             key: "blockquote",
37140             value: function blockquote(quote) {
37141               return '<blockquote>\n' + quote + '</blockquote>\n';
37142             }
37143           }, {
37144             key: "html",
37145             value: function html(_html) {
37146               return _html;
37147             }
37148           }, {
37149             key: "heading",
37150             value: function heading(text, level, raw, slugger) {
37151               if (this.options.headerIds) {
37152                 return '<h' + level + ' id="' + this.options.headerPrefix + slugger.slug(raw) + '">' + text + '</h' + level + '>\n';
37153               } // ignore IDs
37154
37155
37156               return '<h' + level + '>' + text + '</h' + level + '>\n';
37157             }
37158           }, {
37159             key: "hr",
37160             value: function hr() {
37161               return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
37162             }
37163           }, {
37164             key: "list",
37165             value: function list(body, ordered, start) {
37166               var type = ordered ? 'ol' : 'ul',
37167                   startatt = ordered && start !== 1 ? ' start="' + start + '"' : '';
37168               return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
37169             }
37170           }, {
37171             key: "listitem",
37172             value: function listitem(text) {
37173               return '<li>' + text + '</li>\n';
37174             }
37175           }, {
37176             key: "checkbox",
37177             value: function checkbox(checked) {
37178               return '<input ' + (checked ? 'checked="" ' : '') + 'disabled="" type="checkbox"' + (this.options.xhtml ? ' /' : '') + '> ';
37179             }
37180           }, {
37181             key: "paragraph",
37182             value: function paragraph(text) {
37183               return '<p>' + text + '</p>\n';
37184             }
37185           }, {
37186             key: "table",
37187             value: function table(header, body) {
37188               if (body) body = '<tbody>' + body + '</tbody>';
37189               return '<table>\n' + '<thead>\n' + header + '</thead>\n' + body + '</table>\n';
37190             }
37191           }, {
37192             key: "tablerow",
37193             value: function tablerow(content) {
37194               return '<tr>\n' + content + '</tr>\n';
37195             }
37196           }, {
37197             key: "tablecell",
37198             value: function tablecell(content, flags) {
37199               var type = flags.header ? 'th' : 'td';
37200               var tag = flags.align ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
37201               return tag + content + '</' + type + '>\n';
37202             } // span level renderer
37203
37204           }, {
37205             key: "strong",
37206             value: function strong(text) {
37207               return '<strong>' + text + '</strong>';
37208             }
37209           }, {
37210             key: "em",
37211             value: function em(text) {
37212               return '<em>' + text + '</em>';
37213             }
37214           }, {
37215             key: "codespan",
37216             value: function codespan(text) {
37217               return '<code>' + text + '</code>';
37218             }
37219           }, {
37220             key: "br",
37221             value: function br() {
37222               return this.options.xhtml ? '<br/>' : '<br>';
37223             }
37224           }, {
37225             key: "del",
37226             value: function del(text) {
37227               return '<del>' + text + '</del>';
37228             }
37229           }, {
37230             key: "link",
37231             value: function link(href, title, text) {
37232               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37233
37234               if (href === null) {
37235                 return text;
37236               }
37237
37238               var out = '<a href="' + escape$2(href) + '"';
37239
37240               if (title) {
37241                 out += ' title="' + title + '"';
37242               }
37243
37244               out += '>' + text + '</a>';
37245               return out;
37246             }
37247           }, {
37248             key: "image",
37249             value: function image(href, title, text) {
37250               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37251
37252               if (href === null) {
37253                 return text;
37254               }
37255
37256               var out = '<img src="' + href + '" alt="' + text + '"';
37257
37258               if (title) {
37259                 out += ' title="' + title + '"';
37260               }
37261
37262               out += this.options.xhtml ? '/>' : '>';
37263               return out;
37264             }
37265           }, {
37266             key: "text",
37267             value: function text(_text) {
37268               return _text;
37269             }
37270           }]);
37271
37272           return Renderer;
37273         }();
37274
37275         /**
37276          * TextRenderer
37277          * returns only the textual part of the token
37278          */
37279         var TextRenderer_1 = /*#__PURE__*/function () {
37280           function TextRenderer() {
37281             _classCallCheck(this, TextRenderer);
37282           }
37283
37284           _createClass(TextRenderer, [{
37285             key: "strong",
37286             // no need for block level renderers
37287             value: function strong(text) {
37288               return text;
37289             }
37290           }, {
37291             key: "em",
37292             value: function em(text) {
37293               return text;
37294             }
37295           }, {
37296             key: "codespan",
37297             value: function codespan(text) {
37298               return text;
37299             }
37300           }, {
37301             key: "del",
37302             value: function del(text) {
37303               return text;
37304             }
37305           }, {
37306             key: "html",
37307             value: function html(text) {
37308               return text;
37309             }
37310           }, {
37311             key: "text",
37312             value: function text(_text) {
37313               return _text;
37314             }
37315           }, {
37316             key: "link",
37317             value: function link(href, title, text) {
37318               return '' + text;
37319             }
37320           }, {
37321             key: "image",
37322             value: function image(href, title, text) {
37323               return '' + text;
37324             }
37325           }, {
37326             key: "br",
37327             value: function br() {
37328               return '';
37329             }
37330           }]);
37331
37332           return TextRenderer;
37333         }();
37334
37335         /**
37336          * Slugger generates header id
37337          */
37338         var Slugger_1 = /*#__PURE__*/function () {
37339           function Slugger() {
37340             _classCallCheck(this, Slugger);
37341
37342             this.seen = {};
37343           }
37344
37345           _createClass(Slugger, [{
37346             key: "serialize",
37347             value: function serialize(value) {
37348               return value.toLowerCase().trim() // remove html tags
37349               .replace(/<[!\/a-z].*?>/ig, '') // remove unwanted chars
37350               .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '').replace(/\s/g, '-');
37351             }
37352             /**
37353              * Finds the next safe (unique) slug to use
37354              */
37355
37356           }, {
37357             key: "getNextSafeSlug",
37358             value: function getNextSafeSlug(originalSlug, isDryRun) {
37359               var slug = originalSlug;
37360               var occurenceAccumulator = 0;
37361
37362               if (this.seen.hasOwnProperty(slug)) {
37363                 occurenceAccumulator = this.seen[originalSlug];
37364
37365                 do {
37366                   occurenceAccumulator++;
37367                   slug = originalSlug + '-' + occurenceAccumulator;
37368                 } while (this.seen.hasOwnProperty(slug));
37369               }
37370
37371               if (!isDryRun) {
37372                 this.seen[originalSlug] = occurenceAccumulator;
37373                 this.seen[slug] = 0;
37374               }
37375
37376               return slug;
37377             }
37378             /**
37379              * Convert string to unique id
37380              * @param {object} options
37381              * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.
37382              */
37383
37384           }, {
37385             key: "slug",
37386             value: function slug(value) {
37387               var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
37388               var slug = this.serialize(value);
37389               return this.getNextSafeSlug(slug, options.dryrun);
37390             }
37391           }]);
37392
37393           return Slugger;
37394         }();
37395
37396         var defaults$4 = defaults.defaults;
37397         var unescape$2 = helpers.unescape;
37398         /**
37399          * Parsing & Compiling
37400          */
37401
37402         var Parser_1 = /*#__PURE__*/function () {
37403           function Parser(options) {
37404             _classCallCheck(this, Parser);
37405
37406             this.options = options || defaults$4;
37407             this.options.renderer = this.options.renderer || new Renderer_1();
37408             this.renderer = this.options.renderer;
37409             this.renderer.options = this.options;
37410             this.textRenderer = new TextRenderer_1();
37411             this.slugger = new Slugger_1();
37412           }
37413           /**
37414            * Static Parse Method
37415            */
37416
37417
37418           _createClass(Parser, [{
37419             key: "parse",
37420
37421             /**
37422              * Parse Loop
37423              */
37424             value: function parse(tokens) {
37425               var top = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
37426               var out = '',
37427                   i,
37428                   j,
37429                   k,
37430                   l2,
37431                   l3,
37432                   row,
37433                   cell,
37434                   header,
37435                   body,
37436                   token,
37437                   ordered,
37438                   start,
37439                   loose,
37440                   itemBody,
37441                   item,
37442                   checked,
37443                   task,
37444                   checkbox;
37445               var l = tokens.length;
37446
37447               for (i = 0; i < l; i++) {
37448                 token = tokens[i];
37449
37450                 switch (token.type) {
37451                   case 'space':
37452                     {
37453                       continue;
37454                     }
37455
37456                   case 'hr':
37457                     {
37458                       out += this.renderer.hr();
37459                       continue;
37460                     }
37461
37462                   case 'heading':
37463                     {
37464                       out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$2(this.parseInline(token.tokens, this.textRenderer)), this.slugger);
37465                       continue;
37466                     }
37467
37468                   case 'code':
37469                     {
37470                       out += this.renderer.code(token.text, token.lang, token.escaped);
37471                       continue;
37472                     }
37473
37474                   case 'table':
37475                     {
37476                       header = ''; // header
37477
37478                       cell = '';
37479                       l2 = token.header.length;
37480
37481                       for (j = 0; j < l2; j++) {
37482                         cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {
37483                           header: true,
37484                           align: token.align[j]
37485                         });
37486                       }
37487
37488                       header += this.renderer.tablerow(cell);
37489                       body = '';
37490                       l2 = token.cells.length;
37491
37492                       for (j = 0; j < l2; j++) {
37493                         row = token.tokens.cells[j];
37494                         cell = '';
37495                         l3 = row.length;
37496
37497                         for (k = 0; k < l3; k++) {
37498                           cell += this.renderer.tablecell(this.parseInline(row[k]), {
37499                             header: false,
37500                             align: token.align[k]
37501                           });
37502                         }
37503
37504                         body += this.renderer.tablerow(cell);
37505                       }
37506
37507                       out += this.renderer.table(header, body);
37508                       continue;
37509                     }
37510
37511                   case 'blockquote':
37512                     {
37513                       body = this.parse(token.tokens);
37514                       out += this.renderer.blockquote(body);
37515                       continue;
37516                     }
37517
37518                   case 'list':
37519                     {
37520                       ordered = token.ordered;
37521                       start = token.start;
37522                       loose = token.loose;
37523                       l2 = token.items.length;
37524                       body = '';
37525
37526                       for (j = 0; j < l2; j++) {
37527                         item = token.items[j];
37528                         checked = item.checked;
37529                         task = item.task;
37530                         itemBody = '';
37531
37532                         if (item.task) {
37533                           checkbox = this.renderer.checkbox(checked);
37534
37535                           if (loose) {
37536                             if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
37537                               item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
37538
37539                               if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
37540                                 item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
37541                               }
37542                             } else {
37543                               item.tokens.unshift({
37544                                 type: 'text',
37545                                 text: checkbox
37546                               });
37547                             }
37548                           } else {
37549                             itemBody += checkbox;
37550                           }
37551                         }
37552
37553                         itemBody += this.parse(item.tokens, loose);
37554                         body += this.renderer.listitem(itemBody, task, checked);
37555                       }
37556
37557                       out += this.renderer.list(body, ordered, start);
37558                       continue;
37559                     }
37560
37561                   case 'html':
37562                     {
37563                       // TODO parse inline content if parameter markdown=1
37564                       out += this.renderer.html(token.text);
37565                       continue;
37566                     }
37567
37568                   case 'paragraph':
37569                     {
37570                       out += this.renderer.paragraph(this.parseInline(token.tokens));
37571                       continue;
37572                     }
37573
37574                   case 'text':
37575                     {
37576                       body = token.tokens ? this.parseInline(token.tokens) : token.text;
37577
37578                       while (i + 1 < l && tokens[i + 1].type === 'text') {
37579                         token = tokens[++i];
37580                         body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
37581                       }
37582
37583                       out += top ? this.renderer.paragraph(body) : body;
37584                       continue;
37585                     }
37586
37587                   default:
37588                     {
37589                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37590
37591                       if (this.options.silent) {
37592                         console.error(errMsg);
37593                         return;
37594                       } else {
37595                         throw new Error(errMsg);
37596                       }
37597                     }
37598                 }
37599               }
37600
37601               return out;
37602             }
37603             /**
37604              * Parse Inline Tokens
37605              */
37606
37607           }, {
37608             key: "parseInline",
37609             value: function parseInline(tokens, renderer) {
37610               renderer = renderer || this.renderer;
37611               var out = '',
37612                   i,
37613                   token;
37614               var l = tokens.length;
37615
37616               for (i = 0; i < l; i++) {
37617                 token = tokens[i];
37618
37619                 switch (token.type) {
37620                   case 'escape':
37621                     {
37622                       out += renderer.text(token.text);
37623                       break;
37624                     }
37625
37626                   case 'html':
37627                     {
37628                       out += renderer.html(token.text);
37629                       break;
37630                     }
37631
37632                   case 'link':
37633                     {
37634                       out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
37635                       break;
37636                     }
37637
37638                   case 'image':
37639                     {
37640                       out += renderer.image(token.href, token.title, token.text);
37641                       break;
37642                     }
37643
37644                   case 'strong':
37645                     {
37646                       out += renderer.strong(this.parseInline(token.tokens, renderer));
37647                       break;
37648                     }
37649
37650                   case 'em':
37651                     {
37652                       out += renderer.em(this.parseInline(token.tokens, renderer));
37653                       break;
37654                     }
37655
37656                   case 'codespan':
37657                     {
37658                       out += renderer.codespan(token.text);
37659                       break;
37660                     }
37661
37662                   case 'br':
37663                     {
37664                       out += renderer.br();
37665                       break;
37666                     }
37667
37668                   case 'del':
37669                     {
37670                       out += renderer.del(this.parseInline(token.tokens, renderer));
37671                       break;
37672                     }
37673
37674                   case 'text':
37675                     {
37676                       out += renderer.text(token.text);
37677                       break;
37678                     }
37679
37680                   default:
37681                     {
37682                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37683
37684                       if (this.options.silent) {
37685                         console.error(errMsg);
37686                         return;
37687                       } else {
37688                         throw new Error(errMsg);
37689                       }
37690                     }
37691                 }
37692               }
37693
37694               return out;
37695             }
37696           }], [{
37697             key: "parse",
37698             value: function parse(tokens, options) {
37699               var parser = new Parser(options);
37700               return parser.parse(tokens);
37701             }
37702             /**
37703              * Static Parse Inline Method
37704              */
37705
37706           }, {
37707             key: "parseInline",
37708             value: function parseInline(tokens, options) {
37709               var parser = new Parser(options);
37710               return parser.parseInline(tokens);
37711             }
37712           }]);
37713
37714           return Parser;
37715         }();
37716
37717         var merge$3 = helpers.merge,
37718             checkSanitizeDeprecation$1 = helpers.checkSanitizeDeprecation,
37719             escape$3 = helpers.escape;
37720         var getDefaults = defaults.getDefaults,
37721             changeDefaults = defaults.changeDefaults,
37722             defaults$5 = defaults.defaults;
37723         /**
37724          * Marked
37725          */
37726
37727         function marked(src, opt, callback) {
37728           // throw error in case of non string input
37729           if (typeof src === 'undefined' || src === null) {
37730             throw new Error('marked(): input parameter is undefined or null');
37731           }
37732
37733           if (typeof src !== 'string') {
37734             throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
37735           }
37736
37737           if (typeof opt === 'function') {
37738             callback = opt;
37739             opt = null;
37740           }
37741
37742           opt = merge$3({}, marked.defaults, opt || {});
37743           checkSanitizeDeprecation$1(opt);
37744
37745           if (callback) {
37746             var highlight = opt.highlight;
37747             var tokens;
37748
37749             try {
37750               tokens = Lexer_1.lex(src, opt);
37751             } catch (e) {
37752               return callback(e);
37753             }
37754
37755             var done = function done(err) {
37756               var out;
37757
37758               if (!err) {
37759                 try {
37760                   out = Parser_1.parse(tokens, opt);
37761                 } catch (e) {
37762                   err = e;
37763                 }
37764               }
37765
37766               opt.highlight = highlight;
37767               return err ? callback(err) : callback(null, out);
37768             };
37769
37770             if (!highlight || highlight.length < 3) {
37771               return done();
37772             }
37773
37774             delete opt.highlight;
37775             if (!tokens.length) return done();
37776             var pending = 0;
37777             marked.walkTokens(tokens, function (token) {
37778               if (token.type === 'code') {
37779                 pending++;
37780                 setTimeout(function () {
37781                   highlight(token.text, token.lang, function (err, code) {
37782                     if (err) {
37783                       return done(err);
37784                     }
37785
37786                     if (code != null && code !== token.text) {
37787                       token.text = code;
37788                       token.escaped = true;
37789                     }
37790
37791                     pending--;
37792
37793                     if (pending === 0) {
37794                       done();
37795                     }
37796                   });
37797                 }, 0);
37798               }
37799             });
37800
37801             if (pending === 0) {
37802               done();
37803             }
37804
37805             return;
37806           }
37807
37808           try {
37809             var _tokens = Lexer_1.lex(src, opt);
37810
37811             if (opt.walkTokens) {
37812               marked.walkTokens(_tokens, opt.walkTokens);
37813             }
37814
37815             return Parser_1.parse(_tokens, opt);
37816           } catch (e) {
37817             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
37818
37819             if (opt.silent) {
37820               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
37821             }
37822
37823             throw e;
37824           }
37825         }
37826         /**
37827          * Options
37828          */
37829
37830
37831         marked.options = marked.setOptions = function (opt) {
37832           merge$3(marked.defaults, opt);
37833           changeDefaults(marked.defaults);
37834           return marked;
37835         };
37836
37837         marked.getDefaults = getDefaults;
37838         marked.defaults = defaults$5;
37839         /**
37840          * Use Extension
37841          */
37842
37843         marked.use = function (extension) {
37844           var opts = merge$3({}, extension);
37845
37846           if (extension.renderer) {
37847             (function () {
37848               var renderer = marked.defaults.renderer || new Renderer_1();
37849
37850               var _loop = function _loop(prop) {
37851                 var prevRenderer = renderer[prop];
37852
37853                 renderer[prop] = function () {
37854                   for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
37855                     args[_key] = arguments[_key];
37856                   }
37857
37858                   var ret = extension.renderer[prop].apply(renderer, args);
37859
37860                   if (ret === false) {
37861                     ret = prevRenderer.apply(renderer, args);
37862                   }
37863
37864                   return ret;
37865                 };
37866               };
37867
37868               for (var prop in extension.renderer) {
37869                 _loop(prop);
37870               }
37871
37872               opts.renderer = renderer;
37873             })();
37874           }
37875
37876           if (extension.tokenizer) {
37877             (function () {
37878               var tokenizer = marked.defaults.tokenizer || new Tokenizer_1();
37879
37880               var _loop2 = function _loop2(prop) {
37881                 var prevTokenizer = tokenizer[prop];
37882
37883                 tokenizer[prop] = function () {
37884                   for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
37885                     args[_key2] = arguments[_key2];
37886                   }
37887
37888                   var ret = extension.tokenizer[prop].apply(tokenizer, args);
37889
37890                   if (ret === false) {
37891                     ret = prevTokenizer.apply(tokenizer, args);
37892                   }
37893
37894                   return ret;
37895                 };
37896               };
37897
37898               for (var prop in extension.tokenizer) {
37899                 _loop2(prop);
37900               }
37901
37902               opts.tokenizer = tokenizer;
37903             })();
37904           }
37905
37906           if (extension.walkTokens) {
37907             var walkTokens = marked.defaults.walkTokens;
37908
37909             opts.walkTokens = function (token) {
37910               extension.walkTokens(token);
37911
37912               if (walkTokens) {
37913                 walkTokens(token);
37914               }
37915             };
37916           }
37917
37918           marked.setOptions(opts);
37919         };
37920         /**
37921          * Run callback for every token
37922          */
37923
37924
37925         marked.walkTokens = function (tokens, callback) {
37926           var _iterator = _createForOfIteratorHelper(tokens),
37927               _step;
37928
37929           try {
37930             for (_iterator.s(); !(_step = _iterator.n()).done;) {
37931               var token = _step.value;
37932               callback(token);
37933
37934               switch (token.type) {
37935                 case 'table':
37936                   {
37937                     var _iterator2 = _createForOfIteratorHelper(token.tokens.header),
37938                         _step2;
37939
37940                     try {
37941                       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
37942                         var cell = _step2.value;
37943                         marked.walkTokens(cell, callback);
37944                       }
37945                     } catch (err) {
37946                       _iterator2.e(err);
37947                     } finally {
37948                       _iterator2.f();
37949                     }
37950
37951                     var _iterator3 = _createForOfIteratorHelper(token.tokens.cells),
37952                         _step3;
37953
37954                     try {
37955                       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
37956                         var row = _step3.value;
37957
37958                         var _iterator4 = _createForOfIteratorHelper(row),
37959                             _step4;
37960
37961                         try {
37962                           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
37963                             var _cell = _step4.value;
37964                             marked.walkTokens(_cell, callback);
37965                           }
37966                         } catch (err) {
37967                           _iterator4.e(err);
37968                         } finally {
37969                           _iterator4.f();
37970                         }
37971                       }
37972                     } catch (err) {
37973                       _iterator3.e(err);
37974                     } finally {
37975                       _iterator3.f();
37976                     }
37977
37978                     break;
37979                   }
37980
37981                 case 'list':
37982                   {
37983                     marked.walkTokens(token.items, callback);
37984                     break;
37985                   }
37986
37987                 default:
37988                   {
37989                     if (token.tokens) {
37990                       marked.walkTokens(token.tokens, callback);
37991                     }
37992                   }
37993               }
37994             }
37995           } catch (err) {
37996             _iterator.e(err);
37997           } finally {
37998             _iterator.f();
37999           }
38000         };
38001         /**
38002          * Parse Inline
38003          */
38004
38005
38006         marked.parseInline = function (src, opt) {
38007           // throw error in case of non string input
38008           if (typeof src === 'undefined' || src === null) {
38009             throw new Error('marked.parseInline(): input parameter is undefined or null');
38010           }
38011
38012           if (typeof src !== 'string') {
38013             throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
38014           }
38015
38016           opt = merge$3({}, marked.defaults, opt || {});
38017           checkSanitizeDeprecation$1(opt);
38018
38019           try {
38020             var tokens = Lexer_1.lexInline(src, opt);
38021
38022             if (opt.walkTokens) {
38023               marked.walkTokens(tokens, opt.walkTokens);
38024             }
38025
38026             return Parser_1.parseInline(tokens, opt);
38027           } catch (e) {
38028             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
38029
38030             if (opt.silent) {
38031               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
38032             }
38033
38034             throw e;
38035           }
38036         };
38037         /**
38038          * Expose
38039          */
38040
38041
38042         marked.Parser = Parser_1;
38043         marked.parser = Parser_1.parse;
38044         marked.Renderer = Renderer_1;
38045         marked.TextRenderer = TextRenderer_1;
38046         marked.Lexer = Lexer_1;
38047         marked.lexer = Lexer_1.lex;
38048         marked.Tokenizer = Tokenizer_1;
38049         marked.Slugger = Slugger_1;
38050         marked.parse = marked;
38051         var marked_1 = marked;
38052
38053         var tiler$2 = utilTiler();
38054         var dispatch$3 = dispatch('loaded');
38055         var _tileZoom$2 = 14;
38056         var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/api/0.3';
38057         var _osmoseData = {
38058           icons: {},
38059           items: []
38060         }; // This gets reassigned if reset
38061
38062         var _cache$2;
38063
38064         function abortRequest$2(controller) {
38065           if (controller) {
38066             controller.abort();
38067           }
38068         }
38069
38070         function abortUnwantedRequests$2(cache, tiles) {
38071           Object.keys(cache.inflightTile).forEach(function (k) {
38072             var wanted = tiles.find(function (tile) {
38073               return k === tile.id;
38074             });
38075
38076             if (!wanted) {
38077               abortRequest$2(cache.inflightTile[k]);
38078               delete cache.inflightTile[k];
38079             }
38080           });
38081         }
38082
38083         function encodeIssueRtree$2(d) {
38084           return {
38085             minX: d.loc[0],
38086             minY: d.loc[1],
38087             maxX: d.loc[0],
38088             maxY: d.loc[1],
38089             data: d
38090           };
38091         } // Replace or remove QAItem from rtree
38092
38093
38094         function updateRtree$2(item, replace) {
38095           _cache$2.rtree.remove(item, function (a, b) {
38096             return a.data.id === b.data.id;
38097           });
38098
38099           if (replace) {
38100             _cache$2.rtree.insert(item);
38101           }
38102         } // Issues shouldn't obscure each other
38103
38104
38105         function preventCoincident$1(loc) {
38106           var coincident = false;
38107
38108           do {
38109             // first time, move marker up. after that, move marker right.
38110             var delta = coincident ? [0.00001, 0] : [0, 0.00001];
38111             loc = geoVecAdd(loc, delta);
38112             var bbox = geoExtent(loc).bbox();
38113             coincident = _cache$2.rtree.search(bbox).length;
38114           } while (coincident);
38115
38116           return loc;
38117         }
38118
38119         var serviceOsmose = {
38120           title: 'osmose',
38121           init: function init() {
38122             _mainFileFetcher.get('qa_data').then(function (d) {
38123               _osmoseData = d.osmose;
38124               _osmoseData.items = Object.keys(d.osmose.icons).map(function (s) {
38125                 return s.split('-')[0];
38126               }).reduce(function (unique, item) {
38127                 return unique.indexOf(item) !== -1 ? unique : [].concat(_toConsumableArray(unique), [item]);
38128               }, []);
38129             });
38130
38131             if (!_cache$2) {
38132               this.reset();
38133             }
38134
38135             this.event = utilRebind(this, dispatch$3, 'on');
38136           },
38137           reset: function reset() {
38138             var _strings = {};
38139             var _colors = {};
38140
38141             if (_cache$2) {
38142               Object.values(_cache$2.inflightTile).forEach(abortRequest$2); // Strings and colors are static and should not be re-populated
38143
38144               _strings = _cache$2.strings;
38145               _colors = _cache$2.colors;
38146             }
38147
38148             _cache$2 = {
38149               data: {},
38150               loadedTile: {},
38151               inflightTile: {},
38152               inflightPost: {},
38153               closed: {},
38154               rtree: new RBush(),
38155               strings: _strings,
38156               colors: _colors
38157             };
38158           },
38159           loadIssues: function loadIssues(projection) {
38160             var _this = this;
38161
38162             var params = {
38163               // Tiles return a maximum # of issues
38164               // So we want to filter our request for only types iD supports
38165               item: _osmoseData.items
38166             }; // determine the needed tiles to cover the view
38167
38168             var tiles = tiler$2.zoomExtent([_tileZoom$2, _tileZoom$2]).getTiles(projection); // abort inflight requests that are no longer needed
38169
38170             abortUnwantedRequests$2(_cache$2, tiles); // issue new requests..
38171
38172             tiles.forEach(function (tile) {
38173               if (_cache$2.loadedTile[tile.id] || _cache$2.inflightTile[tile.id]) return;
38174
38175               var _tile$xyz = _slicedToArray(tile.xyz, 3),
38176                   x = _tile$xyz[0],
38177                   y = _tile$xyz[1],
38178                   z = _tile$xyz[2];
38179
38180               var url = "".concat(_osmoseUrlRoot, "/issues/").concat(z, "/").concat(x, "/").concat(y, ".json?") + utilQsString(params);
38181               var controller = new AbortController();
38182               _cache$2.inflightTile[tile.id] = controller;
38183               d3_json(url, {
38184                 signal: controller.signal
38185               }).then(function (data) {
38186                 delete _cache$2.inflightTile[tile.id];
38187                 _cache$2.loadedTile[tile.id] = true;
38188
38189                 if (data.features) {
38190                   data.features.forEach(function (issue) {
38191                     var _issue$properties = issue.properties,
38192                         item = _issue$properties.item,
38193                         cl = _issue$properties["class"],
38194                         id = _issue$properties.uuid;
38195                     /* Osmose issues are uniquely identified by a unique
38196                       `item` and `class` combination (both integer values) */
38197
38198                     var itemType = "".concat(item, "-").concat(cl); // Filter out unsupported issue types (some are too specific or advanced)
38199
38200                     if (itemType in _osmoseData.icons) {
38201                       var loc = issue.geometry.coordinates; // lon, lat
38202
38203                       loc = preventCoincident$1(loc);
38204                       var d = new QAItem(loc, _this, itemType, id, {
38205                         item: item
38206                       }); // Setting elems here prevents UI detail requests
38207
38208                       if (item === 8300 || item === 8360) {
38209                         d.elems = [];
38210                       }
38211
38212                       _cache$2.data[d.id] = d;
38213
38214                       _cache$2.rtree.insert(encodeIssueRtree$2(d));
38215                     }
38216                   });
38217                 }
38218
38219                 dispatch$3.call('loaded');
38220               })["catch"](function () {
38221                 delete _cache$2.inflightTile[tile.id];
38222                 _cache$2.loadedTile[tile.id] = true;
38223               });
38224             });
38225           },
38226           loadIssueDetail: function loadIssueDetail(issue) {
38227             var _this2 = this;
38228
38229             // Issue details only need to be fetched once
38230             if (issue.elems !== undefined) {
38231               return Promise.resolve(issue);
38232             }
38233
38234             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
38235
38236             var cacheDetails = function cacheDetails(data) {
38237               // Associated elements used for highlighting
38238               // Assign directly for immediate use in the callback
38239               issue.elems = data.elems.map(function (e) {
38240                 return e.type.substring(0, 1) + e.id;
38241               }); // Some issues have instance specific detail in a subtitle
38242
38243               issue.detail = data.subtitle ? marked_1(data.subtitle.auto) : '';
38244
38245               _this2.replaceItem(issue);
38246             };
38247
38248             return d3_json(url).then(cacheDetails).then(function () {
38249               return issue;
38250             });
38251           },
38252           loadStrings: function loadStrings() {
38253             var locale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _mainLocalizer.localeCode();
38254             var items = Object.keys(_osmoseData.icons);
38255
38256             if (locale in _cache$2.strings && Object.keys(_cache$2.strings[locale]).length === items.length) {
38257               return Promise.resolve(_cache$2.strings[locale]);
38258             } // May be partially populated already if some requests were successful
38259
38260
38261             if (!(locale in _cache$2.strings)) {
38262               _cache$2.strings[locale] = {};
38263             } // Only need to cache strings for supported issue types
38264             // Using multiple individual item + class requests to reduce fetched data size
38265
38266
38267             var allRequests = items.map(function (itemType) {
38268               // No need to request data we already have
38269               if (itemType in _cache$2.strings[locale]) return null;
38270
38271               var cacheData = function cacheData(data) {
38272                 // Bunch of nested single value arrays of objects
38273                 var _data$categories = _slicedToArray(data.categories, 1),
38274                     _data$categories$ = _data$categories[0],
38275                     cat = _data$categories$ === void 0 ? {
38276                   items: []
38277                 } : _data$categories$;
38278
38279                 var _cat$items = _slicedToArray(cat.items, 1),
38280                     _cat$items$ = _cat$items[0],
38281                     item = _cat$items$ === void 0 ? {
38282                   "class": []
38283                 } : _cat$items$;
38284
38285                 var _item$class = _slicedToArray(item["class"], 1),
38286                     _item$class$ = _item$class[0],
38287                     cl = _item$class$ === void 0 ? null : _item$class$; // If null default value is reached, data wasn't as expected (or was empty)
38288
38289
38290                 if (!cl) {
38291                   /* eslint-disable no-console */
38292                   console.log("Osmose strings request (".concat(itemType, ") had unexpected data"));
38293                   /* eslint-enable no-console */
38294
38295                   return;
38296                 } // Cache served item colors to automatically style issue markers later
38297
38298
38299                 var itemInt = item.item,
38300                     color = item.color;
38301
38302                 if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
38303                   _cache$2.colors[itemInt] = color;
38304                 } // Value of root key will be null if no string exists
38305                 // If string exists, value is an object with key 'auto' for string
38306
38307
38308                 var title = cl.title,
38309                     detail = cl.detail,
38310                     fix = cl.fix,
38311                     trap = cl.trap; // Osmose titles shouldn't contain markdown
38312
38313                 var issueStrings = {};
38314                 if (title) issueStrings.title = title.auto;
38315                 if (detail) issueStrings.detail = marked_1(detail.auto);
38316                 if (trap) issueStrings.trap = marked_1(trap.auto);
38317                 if (fix) issueStrings.fix = marked_1(fix.auto);
38318                 _cache$2.strings[locale][itemType] = issueStrings;
38319               };
38320
38321               var _itemType$split = itemType.split('-'),
38322                   _itemType$split2 = _slicedToArray(_itemType$split, 2),
38323                   item = _itemType$split2[0],
38324                   cl = _itemType$split2[1]; // Osmose API falls back to English strings where untranslated or if locale doesn't exist
38325
38326
38327               var url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale);
38328               return d3_json(url).then(cacheData);
38329             }).filter(Boolean);
38330             return Promise.all(allRequests).then(function () {
38331               return _cache$2.strings[locale];
38332             });
38333           },
38334           getStrings: function getStrings(itemType) {
38335             var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _mainLocalizer.localeCode();
38336             // No need to fallback to English, Osmose API handles this for us
38337             return locale in _cache$2.strings ? _cache$2.strings[locale][itemType] : {};
38338           },
38339           getColor: function getColor(itemType) {
38340             return itemType in _cache$2.colors ? _cache$2.colors[itemType] : '#FFFFFF';
38341           },
38342           postUpdate: function postUpdate(issue, callback) {
38343             var _this3 = this;
38344
38345             if (_cache$2.inflightPost[issue.id]) {
38346               return callback({
38347                 message: 'Issue update already inflight',
38348                 status: -2
38349               }, issue);
38350             } // UI sets the status to either 'done' or 'false'
38351
38352
38353             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
38354             var controller = new AbortController();
38355
38356             var after = function after() {
38357               delete _cache$2.inflightPost[issue.id];
38358
38359               _this3.removeItem(issue);
38360
38361               if (issue.newStatus === 'done') {
38362                 // Keep track of the number of issues closed per `item` to tag the changeset
38363                 if (!(issue.item in _cache$2.closed)) {
38364                   _cache$2.closed[issue.item] = 0;
38365                 }
38366
38367                 _cache$2.closed[issue.item] += 1;
38368               }
38369
38370               if (callback) callback(null, issue);
38371             };
38372
38373             _cache$2.inflightPost[issue.id] = controller;
38374             fetch(url, {
38375               signal: controller.signal
38376             }).then(after)["catch"](function (err) {
38377               delete _cache$2.inflightPost[issue.id];
38378               if (callback) callback(err.message);
38379             });
38380           },
38381           // Get all cached QAItems covering the viewport
38382           getItems: function getItems(projection) {
38383             var viewport = projection.clipExtent();
38384             var min = [viewport[0][0], viewport[1][1]];
38385             var max = [viewport[1][0], viewport[0][1]];
38386             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38387             return _cache$2.rtree.search(bbox).map(function (d) {
38388               return d.data;
38389             });
38390           },
38391           // Get a QAItem from cache
38392           // NOTE: Don't change method name until UI v3 is merged
38393           getError: function getError(id) {
38394             return _cache$2.data[id];
38395           },
38396           // get the name of the icon to display for this item
38397           getIcon: function getIcon(itemType) {
38398             return _osmoseData.icons[itemType];
38399           },
38400           // Replace a single QAItem in the cache
38401           replaceItem: function replaceItem(item) {
38402             if (!(item instanceof QAItem) || !item.id) return;
38403             _cache$2.data[item.id] = item;
38404             updateRtree$2(encodeIssueRtree$2(item), true); // true = replace
38405
38406             return item;
38407           },
38408           // Remove a single QAItem from the cache
38409           removeItem: function removeItem(item) {
38410             if (!(item instanceof QAItem) || !item.id) return;
38411             delete _cache$2.data[item.id];
38412             updateRtree$2(encodeIssueRtree$2(item), false); // false = remove
38413           },
38414           // Used to populate `closed:osmose:*` changeset tags
38415           getClosedCounts: function getClosedCounts() {
38416             return _cache$2.closed;
38417           },
38418           itemURL: function itemURL(item) {
38419             return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
38420           }
38421         };
38422
38423         var apibase = 'https://a.mapillary.com/v3/';
38424         var viewercss = 'mapillary-js/mapillary.min.css';
38425         var viewerjs = 'mapillary-js/mapillary.min.js';
38426         var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
38427         var mapFeatureConfig = {
38428           values: ['construction--flat--crosswalk-plain', 'marking--discrete--crosswalk-zebra', 'object--banner', 'object--bench', 'object--bike-rack', 'object--billboard', 'object--catch-basin', 'object--cctv-camera', 'object--fire-hydrant', 'object--mailbox', 'object--manhole', 'object--phone-booth', 'object--sign--advertisement', 'object--sign--information', 'object--sign--store', 'object--street-light', 'object--support--utility-pole', 'object--traffic-light--*', 'object--traffic-light--pedestrians', 'object--trash-can'].join(',')
38429         };
38430         var maxResults = 1000;
38431         var tileZoom = 14;
38432         var tiler$3 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
38433         var dispatch$4 = dispatch('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'nodeChanged');
38434         var _mlyFallback = false;
38435
38436         var _mlyCache;
38437
38438         var _mlyClicks;
38439
38440         var _mlyActiveImage;
38441
38442         var _mlySelectedImageKey;
38443
38444         var _mlyViewer;
38445
38446         var _mlyViewerFilter = ['all'];
38447
38448         var _loadViewerPromise;
38449
38450         var _mlyHighlightedDetection;
38451
38452         var _mlyShowFeatureDetections = false;
38453         var _mlyShowSignDetections = false;
38454
38455         function abortRequest$3(controller) {
38456           controller.abort();
38457         }
38458
38459         function loadTiles(which, url, projection) {
38460           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
38461           var tiles = tiler$3.getTiles(projection); // abort inflight requests that are no longer needed
38462
38463           var cache = _mlyCache[which];
38464           Object.keys(cache.inflight).forEach(function (k) {
38465             var wanted = tiles.find(function (tile) {
38466               return k.indexOf(tile.id + ',') === 0;
38467             });
38468
38469             if (!wanted) {
38470               abortRequest$3(cache.inflight[k]);
38471               delete cache.inflight[k];
38472             }
38473           });
38474           tiles.forEach(function (tile) {
38475             loadNextTilePage(which, currZoom, url, tile);
38476           });
38477         }
38478
38479         function loadNextTilePage(which, currZoom, url, tile) {
38480           var cache = _mlyCache[which];
38481           var rect = tile.extent.rectangle();
38482           var maxPages = maxPageAtZoom(currZoom);
38483           var nextPage = cache.nextPage[tile.id] || 0;
38484           var nextURL = cache.nextURL[tile.id] || url + utilQsString({
38485             per_page: maxResults,
38486             page: nextPage,
38487             client_id: clientId,
38488             bbox: [rect[0], rect[1], rect[2], rect[3]].join(',')
38489           });
38490           if (nextPage > maxPages) return;
38491           var id = tile.id + ',' + String(nextPage);
38492           if (cache.loaded[id] || cache.inflight[id]) return;
38493           var controller = new AbortController();
38494           cache.inflight[id] = controller;
38495           var options = {
38496             method: 'GET',
38497             signal: controller.signal,
38498             headers: {
38499               'Content-Type': 'application/json'
38500             }
38501           };
38502           fetch(nextURL, options).then(function (response) {
38503             if (!response.ok) {
38504               throw new Error(response.status + ' ' + response.statusText);
38505             }
38506
38507             var linkHeader = response.headers.get('Link');
38508
38509             if (linkHeader) {
38510               var pagination = parsePagination(linkHeader);
38511
38512               if (pagination.next) {
38513                 cache.nextURL[tile.id] = pagination.next;
38514               }
38515             }
38516
38517             return response.json();
38518           }).then(function (data) {
38519             cache.loaded[id] = true;
38520             delete cache.inflight[id];
38521
38522             if (!data || !data.features || !data.features.length) {
38523               throw new Error('No Data');
38524             }
38525
38526             var features = data.features.map(function (feature) {
38527               var loc = feature.geometry.coordinates;
38528               var d; // An image (shown as a green dot on the map) is a single street photo with extra
38529               // information such as location, camera angle (CA), camera model, and so on.
38530               // Each image feature is a GeoJSON Point
38531
38532               if (which === 'images') {
38533                 d = {
38534                   loc: loc,
38535                   key: feature.properties.key,
38536                   ca: feature.properties.ca,
38537                   captured_at: feature.properties.captured_at,
38538                   captured_by: feature.properties.username,
38539                   pano: feature.properties.pano
38540                 };
38541                 cache.forImageKey[d.key] = d; // cache imageKey -> image
38542                 // Mapillary organizes images as sequences. A sequence of images are continuously captured
38543                 // by a user at a give time. Sequences are shown on the map as green lines.
38544                 // Each sequence feature is a GeoJSON LineString
38545               } else if (which === 'sequences') {
38546                 var sequenceKey = feature.properties.key;
38547                 cache.lineString[sequenceKey] = feature; // cache sequenceKey -> lineString
38548
38549                 feature.properties.coordinateProperties.image_keys.forEach(function (imageKey) {
38550                   cache.forImageKey[imageKey] = sequenceKey; // cache imageKey -> sequenceKey
38551                 });
38552                 return false; // because no `d` data worth loading into an rbush
38553                 // A map feature is a real world object that can be shown on a map. It could be any object
38554                 // recognized from images, manually added in images, or added on the map.
38555                 // Each map feature is a GeoJSON Point (located where the feature is)
38556               } else if (which === 'map_features' || which === 'points') {
38557                 d = {
38558                   loc: loc,
38559                   key: feature.properties.key,
38560                   value: feature.properties.value,
38561                   "package": feature.properties["package"],
38562                   detections: feature.properties.detections
38563                 };
38564               }
38565
38566               return {
38567                 minX: loc[0],
38568                 minY: loc[1],
38569                 maxX: loc[0],
38570                 maxY: loc[1],
38571                 data: d
38572               };
38573             }).filter(Boolean);
38574
38575             if (cache.rtree && features) {
38576               cache.rtree.load(features);
38577             }
38578
38579             if (data.features.length === maxResults) {
38580               // more pages to load
38581               cache.nextPage[tile.id] = nextPage + 1;
38582               loadNextTilePage(which, currZoom, url, tile);
38583             } else {
38584               cache.nextPage[tile.id] = Infinity; // no more pages to load
38585             }
38586
38587             if (which === 'images' || which === 'sequences') {
38588               dispatch$4.call('loadedImages');
38589             } else if (which === 'map_features') {
38590               dispatch$4.call('loadedSigns');
38591             } else if (which === 'points') {
38592               dispatch$4.call('loadedMapFeatures');
38593             }
38594           })["catch"](function () {
38595             cache.loaded[id] = true;
38596             delete cache.inflight[id];
38597           });
38598         }
38599
38600         function loadData(which, url) {
38601           var cache = _mlyCache[which];
38602           var options = {
38603             method: 'GET',
38604             headers: {
38605               'Content-Type': 'application/json'
38606             }
38607           };
38608           var nextUrl = url + '&client_id=' + clientId;
38609           return fetch(nextUrl, options).then(function (response) {
38610             if (!response.ok) {
38611               throw new Error(response.status + ' ' + response.statusText);
38612             }
38613
38614             return response.json();
38615           }).then(function (data) {
38616             if (!data || !data.features || !data.features.length) {
38617               throw new Error('No Data');
38618             }
38619
38620             data.features.forEach(function (feature) {
38621               var d;
38622
38623               if (which === 'image_detections') {
38624                 d = {
38625                   key: feature.properties.key,
38626                   image_key: feature.properties.image_key,
38627                   value: feature.properties.value,
38628                   "package": feature.properties["package"],
38629                   shape: feature.properties.shape
38630                 };
38631
38632                 if (!cache.forImageKey[d.image_key]) {
38633                   cache.forImageKey[d.image_key] = [];
38634                 }
38635
38636                 cache.forImageKey[d.image_key].push(d);
38637               }
38638             });
38639           });
38640         }
38641
38642         function maxPageAtZoom(z) {
38643           if (z < 15) return 2;
38644           if (z === 15) return 5;
38645           if (z === 16) return 10;
38646           if (z === 17) return 20;
38647           if (z === 18) return 40;
38648           if (z > 18) return 80;
38649         } // extract links to pages of API results
38650
38651
38652         function parsePagination(links) {
38653           return links.split(',').map(function (rel) {
38654             var elements = rel.split(';');
38655
38656             if (elements.length === 2) {
38657               return [/<(.+)>/.exec(elements[0])[1], /rel="(.+)"/.exec(elements[1])[1]];
38658             } else {
38659               return ['', ''];
38660             }
38661           }).reduce(function (pagination, val) {
38662             pagination[val[1]] = val[0];
38663             return pagination;
38664           }, {});
38665         } // partition viewport into higher zoom tiles
38666
38667
38668         function partitionViewport(projection) {
38669           var z = geoScaleToZoom(projection.scale());
38670           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
38671
38672           var tiler = utilTiler().zoomExtent([z2, z2]);
38673           return tiler.getTiles(projection).map(function (tile) {
38674             return tile.extent;
38675           });
38676         } // no more than `limit` results per partition.
38677
38678
38679         function searchLimited(limit, projection, rtree) {
38680           limit = limit || 5;
38681           return partitionViewport(projection).reduce(function (result, extent) {
38682             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
38683               return d.data;
38684             });
38685             return found.length ? result.concat(found) : result;
38686           }, []);
38687         }
38688
38689         var serviceMapillary = {
38690           init: function init() {
38691             if (!_mlyCache) {
38692               this.reset();
38693             }
38694
38695             this.event = utilRebind(this, dispatch$4, 'on');
38696           },
38697           reset: function reset() {
38698             if (_mlyCache) {
38699               Object.values(_mlyCache.images.inflight).forEach(abortRequest$3);
38700               Object.values(_mlyCache.image_detections.inflight).forEach(abortRequest$3);
38701               Object.values(_mlyCache.map_features.inflight).forEach(abortRequest$3);
38702               Object.values(_mlyCache.points.inflight).forEach(abortRequest$3);
38703               Object.values(_mlyCache.sequences.inflight).forEach(abortRequest$3);
38704             }
38705
38706             _mlyCache = {
38707               images: {
38708                 inflight: {},
38709                 loaded: {},
38710                 nextPage: {},
38711                 nextURL: {},
38712                 rtree: new RBush(),
38713                 forImageKey: {}
38714               },
38715               image_detections: {
38716                 inflight: {},
38717                 loaded: {},
38718                 nextPage: {},
38719                 nextURL: {},
38720                 forImageKey: {}
38721               },
38722               map_features: {
38723                 inflight: {},
38724                 loaded: {},
38725                 nextPage: {},
38726                 nextURL: {},
38727                 rtree: new RBush()
38728               },
38729               points: {
38730                 inflight: {},
38731                 loaded: {},
38732                 nextPage: {},
38733                 nextURL: {},
38734                 rtree: new RBush()
38735               },
38736               sequences: {
38737                 inflight: {},
38738                 loaded: {},
38739                 nextPage: {},
38740                 nextURL: {},
38741                 rtree: new RBush(),
38742                 forImageKey: {},
38743                 lineString: {}
38744               }
38745             };
38746             _mlySelectedImageKey = null;
38747             _mlyActiveImage = null;
38748             _mlyClicks = [];
38749           },
38750           images: function images(projection) {
38751             var limit = 5;
38752             return searchLimited(limit, projection, _mlyCache.images.rtree);
38753           },
38754           signs: function signs(projection) {
38755             var limit = 5;
38756             return searchLimited(limit, projection, _mlyCache.map_features.rtree);
38757           },
38758           mapFeatures: function mapFeatures(projection) {
38759             var limit = 5;
38760             return searchLimited(limit, projection, _mlyCache.points.rtree);
38761           },
38762           cachedImage: function cachedImage(imageKey) {
38763             return _mlyCache.images.forImageKey[imageKey];
38764           },
38765           sequences: function sequences(projection) {
38766             var viewport = projection.clipExtent();
38767             var min = [viewport[0][0], viewport[1][1]];
38768             var max = [viewport[1][0], viewport[0][1]];
38769             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38770             var sequenceKeys = {}; // all sequences for images in viewport
38771
38772             _mlyCache.images.rtree.search(bbox).forEach(function (d) {
38773               var sequenceKey = _mlyCache.sequences.forImageKey[d.data.key];
38774
38775               if (sequenceKey) {
38776                 sequenceKeys[sequenceKey] = true;
38777               }
38778             }); // Return lineStrings for the sequences
38779
38780
38781             return Object.keys(sequenceKeys).map(function (sequenceKey) {
38782               return _mlyCache.sequences.lineString[sequenceKey];
38783             });
38784           },
38785           signsSupported: function signsSupported() {
38786             return true;
38787           },
38788           loadImages: function loadImages(projection) {
38789             loadTiles('images', apibase + 'images?sort_by=key&', projection);
38790             loadTiles('sequences', apibase + 'sequences?sort_by=key&', projection);
38791           },
38792           loadSigns: function loadSigns(projection) {
38793             loadTiles('map_features', apibase + 'map_features?layers=trafficsigns&min_nbr_image_detections=2&sort_by=key&', projection);
38794           },
38795           loadMapFeatures: function loadMapFeatures(projection) {
38796             loadTiles('points', apibase + 'map_features?layers=points&min_nbr_image_detections=2&sort_by=key&values=' + mapFeatureConfig.values + '&', projection);
38797           },
38798           ensureViewerLoaded: function ensureViewerLoaded(context) {
38799             if (_loadViewerPromise) return _loadViewerPromise; // add mly-wrapper
38800
38801             var wrap = context.container().select('.photoviewer').selectAll('.mly-wrapper').data([0]);
38802             wrap.enter().append('div').attr('id', 'ideditor-mly').attr('class', 'photo-wrapper mly-wrapper').classed('hide', true);
38803             var that = this;
38804             _loadViewerPromise = new Promise(function (resolve, reject) {
38805               var loadedCount = 0;
38806
38807               function loaded() {
38808                 loadedCount += 1; // wait until both files are loaded
38809
38810                 if (loadedCount === 2) resolve();
38811               }
38812
38813               var head = select('head'); // load mapillary-viewercss
38814
38815               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 () {
38816                 reject();
38817               }); // load mapillary-viewerjs
38818
38819               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 () {
38820                 reject();
38821               });
38822             })["catch"](function () {
38823               _loadViewerPromise = null;
38824             }).then(function () {
38825               that.initViewer(context);
38826             });
38827             return _loadViewerPromise;
38828           },
38829           loadSignResources: function loadSignResources(context) {
38830             context.ui().svgDefs.addSprites(['mapillary-sprite'], false
38831             /* don't override colors */
38832             );
38833             return this;
38834           },
38835           loadObjectResources: function loadObjectResources(context) {
38836             context.ui().svgDefs.addSprites(['mapillary-object-sprite'], false
38837             /* don't override colors */
38838             );
38839             return this;
38840           },
38841           resetTags: function resetTags() {
38842             if (_mlyViewer && !_mlyFallback) {
38843               _mlyViewer.getComponent('tag').removeAll(); // remove previous detections
38844
38845             }
38846           },
38847           showFeatureDetections: function showFeatureDetections(value) {
38848             _mlyShowFeatureDetections = value;
38849
38850             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38851               this.resetTags();
38852             }
38853           },
38854           showSignDetections: function showSignDetections(value) {
38855             _mlyShowSignDetections = value;
38856
38857             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38858               this.resetTags();
38859             }
38860           },
38861           filterViewer: function filterViewer(context) {
38862             var showsPano = context.photos().showsPanoramic();
38863             var showsFlat = context.photos().showsFlat();
38864             var fromDate = context.photos().fromDate();
38865             var toDate = context.photos().toDate();
38866             var usernames = context.photos().usernames();
38867             var filter = ['all'];
38868             if (!showsPano) filter.push(['==', 'pano', false]);
38869             if (!showsFlat && showsPano) filter.push(['==', 'pano', true]);
38870             if (usernames && usernames.length) filter.push(['==', 'username', usernames[0]]);
38871
38872             if (fromDate) {
38873               var fromTimestamp = new Date(fromDate).getTime();
38874               filter.push(['>=', 'capturedAt', fromTimestamp]);
38875             }
38876
38877             if (toDate) {
38878               var toTimestamp = new Date(toDate).getTime();
38879               filter.push(['>=', 'capturedAt', toTimestamp]);
38880             }
38881
38882             if (_mlyViewer) {
38883               _mlyViewer.setFilter(filter);
38884             }
38885
38886             _mlyViewerFilter = filter;
38887             return filter;
38888           },
38889           showViewer: function showViewer(context) {
38890             var wrap = context.container().select('.photoviewer').classed('hide', false);
38891             var isHidden = wrap.selectAll('.photo-wrapper.mly-wrapper.hide').size();
38892
38893             if (isHidden && _mlyViewer) {
38894               wrap.selectAll('.photo-wrapper:not(.mly-wrapper)').classed('hide', true);
38895               wrap.selectAll('.photo-wrapper.mly-wrapper').classed('hide', false);
38896
38897               _mlyViewer.resize();
38898             }
38899
38900             return this;
38901           },
38902           hideViewer: function hideViewer(context) {
38903             _mlyActiveImage = null;
38904             _mlySelectedImageKey = null;
38905
38906             if (!_mlyFallback && _mlyViewer) {
38907               _mlyViewer.getComponent('sequence').stop();
38908             }
38909
38910             var viewer = context.container().select('.photoviewer');
38911             if (!viewer.empty()) viewer.datum(null);
38912             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
38913             this.updateUrlImage(null);
38914             dispatch$4.call('nodeChanged');
38915             return this.setStyles(context, null, true);
38916           },
38917           parsePagination: parsePagination,
38918           updateUrlImage: function updateUrlImage(imageKey) {
38919             if (!window.mocha) {
38920               var hash = utilStringQs(window.location.hash);
38921
38922               if (imageKey) {
38923                 hash.photo = 'mapillary/' + imageKey;
38924               } else {
38925                 delete hash.photo;
38926               }
38927
38928               window.location.replace('#' + utilQsString(hash, true));
38929             }
38930           },
38931           highlightDetection: function highlightDetection(detection) {
38932             if (detection) {
38933               _mlyHighlightedDetection = detection.detection_key;
38934             }
38935
38936             return this;
38937           },
38938           initViewer: function initViewer(context) {
38939             var that = this;
38940             if (!window.Mapillary) return;
38941             var opts = {
38942               baseImageSize: 320,
38943               component: {
38944                 cover: false,
38945                 keyboard: false,
38946                 tag: true
38947               }
38948             }; // Disable components requiring WebGL support
38949
38950             if (!Mapillary.isSupported() && Mapillary.isFallbackSupported()) {
38951               _mlyFallback = true;
38952               opts.component = {
38953                 cover: false,
38954                 direction: false,
38955                 imagePlane: false,
38956                 keyboard: false,
38957                 mouse: false,
38958                 sequence: false,
38959                 tag: false,
38960                 image: true,
38961                 // fallback
38962                 navigation: true // fallback
38963
38964               };
38965             }
38966
38967             _mlyViewer = new Mapillary.Viewer('ideditor-mly', clientId, null, opts);
38968
38969             _mlyViewer.on('nodechanged', nodeChanged);
38970
38971             _mlyViewer.on('bearingchanged', bearingChanged);
38972
38973             if (_mlyViewerFilter) {
38974               _mlyViewer.setFilter(_mlyViewerFilter);
38975             } // Register viewer resize handler
38976
38977
38978             context.ui().photoviewer.on('resize.mapillary', function () {
38979               if (_mlyViewer) _mlyViewer.resize();
38980             }); // nodeChanged: called after the viewer has changed images and is ready.
38981             //
38982             // There is some logic here to batch up clicks into a _mlyClicks array
38983             // because the user might click on a lot of markers quickly and nodechanged
38984             // may be called out of order asynchronously.
38985             //
38986             // Clicks are added to the array in `selectedImage` and removed here.
38987             //
38988
38989             function nodeChanged(node) {
38990               that.resetTags();
38991               var clicks = _mlyClicks;
38992               var index = clicks.indexOf(node.key);
38993               var selectedKey = _mlySelectedImageKey;
38994               that.setActiveImage(node);
38995
38996               if (index > -1) {
38997                 // `nodechanged` initiated from clicking on a marker..
38998                 clicks.splice(index, 1); // remove the click
38999                 // If `node.key` matches the current _mlySelectedImageKey, call `selectImage()`
39000                 // one more time to update the detections and attribution..
39001
39002                 if (node.key === selectedKey) {
39003                   that.selectImage(context, _mlySelectedImageKey, true);
39004                 }
39005               } else {
39006                 // `nodechanged` initiated from the Mapillary viewer controls..
39007                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
39008                 context.map().centerEase(loc);
39009                 that.selectImage(context, node.key, true);
39010               }
39011
39012               dispatch$4.call('nodeChanged');
39013             }
39014
39015             function bearingChanged(e) {
39016               dispatch$4.call('bearingChanged', undefined, e);
39017             }
39018           },
39019           // Pass in the image key string as `imageKey`.
39020           // This allows images to be selected from places that dont have access
39021           // to the full image datum (like the street signs layer or the js viewer)
39022           selectImage: function selectImage(context, imageKey, fromViewer) {
39023             _mlySelectedImageKey = imageKey;
39024             this.updateUrlImage(imageKey);
39025             var d = _mlyCache.images.forImageKey[imageKey];
39026             var viewer = context.container().select('.photoviewer');
39027             if (!viewer.empty()) viewer.datum(d);
39028             imageKey = d && d.key || imageKey;
39029
39030             if (!fromViewer && imageKey) {
39031               _mlyClicks.push(imageKey);
39032             }
39033
39034             this.setStyles(context, null, true);
39035
39036             if (_mlyShowFeatureDetections) {
39037               this.updateDetections(imageKey, apibase + 'image_detections?layers=points&values=' + mapFeatureConfig.values + '&image_keys=' + imageKey);
39038             }
39039
39040             if (_mlyShowSignDetections) {
39041               this.updateDetections(imageKey, apibase + 'image_detections?layers=trafficsigns&image_keys=' + imageKey);
39042             }
39043
39044             if (_mlyViewer && imageKey) {
39045               _mlyViewer.moveToKey(imageKey)["catch"](function (e) {
39046                 console.error('mly3', e);
39047               }); // eslint-disable-line no-console
39048
39049             }
39050
39051             return this;
39052           },
39053           getActiveImage: function getActiveImage() {
39054             return _mlyActiveImage;
39055           },
39056           getSelectedImageKey: function getSelectedImageKey() {
39057             return _mlySelectedImageKey;
39058           },
39059           getSequenceKeyForImageKey: function getSequenceKeyForImageKey(imageKey) {
39060             return _mlyCache.sequences.forImageKey[imageKey];
39061           },
39062           setActiveImage: function setActiveImage(node) {
39063             if (node) {
39064               _mlyActiveImage = {
39065                 ca: node.originalCA,
39066                 key: node.key,
39067                 loc: [node.originalLatLon.lon, node.originalLatLon.lat],
39068                 pano: node.pano
39069               };
39070             } else {
39071               _mlyActiveImage = null;
39072             }
39073           },
39074           // Updates the currently highlighted sequence and selected bubble.
39075           // Reset is only necessary when interacting with the viewport because
39076           // this implicitly changes the currently selected bubble/sequence
39077           setStyles: function setStyles(context, hovered, reset) {
39078             if (reset) {
39079               // reset all layers
39080               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false);
39081               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
39082             }
39083
39084             var hoveredImageKey = hovered && hovered.key;
39085             var hoveredSequenceKey = hoveredImageKey && this.getSequenceKeyForImageKey(hoveredImageKey);
39086             var hoveredLineString = hoveredSequenceKey && _mlyCache.sequences.lineString[hoveredSequenceKey];
39087             var hoveredImageKeys = hoveredLineString && hoveredLineString.properties.coordinateProperties.image_keys || [];
39088             var selectedImageKey = _mlySelectedImageKey;
39089             var selectedSequenceKey = selectedImageKey && this.getSequenceKeyForImageKey(selectedImageKey);
39090             var selectedLineString = selectedSequenceKey && _mlyCache.sequences.lineString[selectedSequenceKey];
39091             var selectedImageKeys = selectedLineString && selectedLineString.properties.coordinateProperties.image_keys || []; // highlight sibling viewfields on either the selected or the hovered sequences
39092
39093             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
39094             context.container().selectAll('.layer-mapillary .viewfield-group').classed('highlighted', function (d) {
39095               return highlightedImageKeys.indexOf(d.key) !== -1;
39096             }).classed('hovered', function (d) {
39097               return d.key === hoveredImageKey;
39098             });
39099             context.container().selectAll('.layer-mapillary .sequence').classed('highlighted', function (d) {
39100               return d.properties.key === hoveredSequenceKey;
39101             }).classed('currentView', function (d) {
39102               return d.properties.key === selectedSequenceKey;
39103             }); // update viewfields if needed
39104
39105             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
39106
39107             function viewfieldPath() {
39108               var d = this.parentNode.__data__;
39109
39110               if (d.pano && d.key !== selectedImageKey) {
39111                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
39112               } else {
39113                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
39114               }
39115             }
39116
39117             return this;
39118           },
39119           updateDetections: function updateDetections(imageKey, url) {
39120             if (!_mlyViewer || _mlyFallback) return;
39121             if (!imageKey) return;
39122
39123             if (!_mlyCache.image_detections.forImageKey[imageKey]) {
39124               loadData('image_detections', url).then(function () {
39125                 showDetections(_mlyCache.image_detections.forImageKey[imageKey] || []);
39126               });
39127             } else {
39128               showDetections(_mlyCache.image_detections.forImageKey[imageKey]);
39129             }
39130
39131             function showDetections(detections) {
39132               detections.forEach(function (data) {
39133                 var tag = makeTag(data);
39134
39135                 if (tag) {
39136                   var tagComponent = _mlyViewer.getComponent('tag');
39137
39138                   tagComponent.add([tag]);
39139                 }
39140               });
39141             }
39142
39143             function makeTag(data) {
39144               var valueParts = data.value.split('--');
39145               if (!valueParts.length) return;
39146               var tag;
39147               var text;
39148               var color = 0xffffff;
39149
39150               if (_mlyHighlightedDetection === data.key) {
39151                 color = 0xffff00;
39152                 text = valueParts[1];
39153
39154                 if (text === 'flat' || text === 'discrete' || text === 'sign') {
39155                   text = valueParts[2];
39156                 }
39157
39158                 text = text.replace(/-/g, ' ');
39159                 text = text.charAt(0).toUpperCase() + text.slice(1);
39160                 _mlyHighlightedDetection = null;
39161               }
39162
39163               if (data.shape.type === 'Polygon') {
39164                 var polygonGeometry = new Mapillary.TagComponent.PolygonGeometry(data.shape.coordinates[0]);
39165                 tag = new Mapillary.TagComponent.OutlineTag(data.key, polygonGeometry, {
39166                   text: text,
39167                   textColor: color,
39168                   lineColor: color,
39169                   lineWidth: 2,
39170                   fillColor: color,
39171                   fillOpacity: 0.3
39172                 });
39173               } else if (data.shape.type === 'Point') {
39174                 var pointGeometry = new Mapillary.TagComponent.PointGeometry(data.shape.coordinates[0]);
39175                 tag = new Mapillary.TagComponent.SpotTag(data.key, pointGeometry, {
39176                   text: text,
39177                   color: color,
39178                   textColor: color
39179                 });
39180               }
39181
39182               return tag;
39183             }
39184           },
39185           cache: function cache() {
39186             return _mlyCache;
39187           }
39188         };
39189
39190         function validationIssue(attrs) {
39191           this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag')
39192
39193           this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag')
39194
39195           this.severity = attrs.severity; // required - 'warning' or 'error'
39196
39197           this.message = attrs.message; // required - function returning localized string
39198
39199           this.reference = attrs.reference; // optional - function(selection) to render reference information
39200
39201           this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
39202
39203           this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
39204
39205           this.data = attrs.data; // optional - object containing extra data for the fixes
39206
39207           this.dynamicFixes = attrs.dynamicFixes; // optional - function(context) returning fixes
39208
39209           this.hash = attrs.hash; // optional - string to further differentiate the issue
39210
39211           this.id = generateID.apply(this); // generated - see below
39212
39213           this.autoFix = null; // generated - if autofix exists, will be set below
39214           // A unique, deterministic string hash.
39215           // Issues with identical id values are considered identical.
39216
39217           function generateID() {
39218             var parts = [this.type];
39219
39220             if (this.hash) {
39221               // subclasses can pass in their own differentiator
39222               parts.push(this.hash);
39223             }
39224
39225             if (this.subtype) {
39226               parts.push(this.subtype);
39227             } // include the entities this issue is for
39228             // (sort them so the id is deterministic)
39229
39230
39231             if (this.entityIds) {
39232               var entityKeys = this.entityIds.slice().sort();
39233               parts.push.apply(parts, entityKeys);
39234             }
39235
39236             return parts.join(':');
39237           }
39238
39239           this.extent = function (resolver) {
39240             if (this.loc) {
39241               return geoExtent(this.loc);
39242             }
39243
39244             if (this.entityIds && this.entityIds.length) {
39245               return this.entityIds.reduce(function (extent, entityId) {
39246                 return extent.extend(resolver.entity(entityId).extent(resolver));
39247               }, geoExtent());
39248             }
39249
39250             return null;
39251           };
39252
39253           this.fixes = function (context) {
39254             var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
39255             var issue = this;
39256
39257             if (issue.severity === 'warning') {
39258               // allow ignoring any issue that's not an error
39259               fixes.push(new validationIssueFix({
39260                 title: _t.html('issues.fix.ignore_issue.title'),
39261                 icon: 'iD-icon-close',
39262                 onClick: function onClick() {
39263                   context.validator().ignoreIssue(this.issue.id);
39264                 }
39265               }));
39266             }
39267
39268             fixes.forEach(function (fix) {
39269               // the id doesn't matter as long as it's unique to this issue/fix
39270               fix.id = fix.title; // add a reference to the issue for use in actions
39271
39272               fix.issue = issue;
39273
39274               if (fix.autoArgs) {
39275                 issue.autoFix = fix;
39276               }
39277             });
39278             return fixes;
39279           };
39280         }
39281         function validationIssueFix(attrs) {
39282           this.title = attrs.title; // Required
39283
39284           this.onClick = attrs.onClick; // Optional - the function to run to apply the fix
39285
39286           this.disabledReason = attrs.disabledReason; // Optional - a string explaining why the fix is unavailable, if any
39287
39288           this.icon = attrs.icon; // Optional - shows 'iD-icon-wrench' if not set
39289
39290           this.entityIds = attrs.entityIds || []; // Optional - used for hover-higlighting.
39291
39292           this.autoArgs = attrs.autoArgs; // Optional - pass [actions, annotation] arglist if this fix can automatically run
39293
39294           this.issue = null; // Generated link - added by validationIssue
39295         }
39296
39297         var buildRuleChecks = function buildRuleChecks() {
39298           return {
39299             equals: function equals(_equals) {
39300               return function (tags) {
39301                 return Object.keys(_equals).every(function (k) {
39302                   return _equals[k] === tags[k];
39303                 });
39304               };
39305             },
39306             notEquals: function notEquals(_notEquals) {
39307               return function (tags) {
39308                 return Object.keys(_notEquals).some(function (k) {
39309                   return _notEquals[k] !== tags[k];
39310                 });
39311               };
39312             },
39313             absence: function absence(_absence) {
39314               return function (tags) {
39315                 return Object.keys(tags).indexOf(_absence) === -1;
39316               };
39317             },
39318             presence: function presence(_presence) {
39319               return function (tags) {
39320                 return Object.keys(tags).indexOf(_presence) > -1;
39321               };
39322             },
39323             greaterThan: function greaterThan(_greaterThan) {
39324               var key = Object.keys(_greaterThan)[0];
39325               var value = _greaterThan[key];
39326               return function (tags) {
39327                 return tags[key] > value;
39328               };
39329             },
39330             greaterThanEqual: function greaterThanEqual(_greaterThanEqual) {
39331               var key = Object.keys(_greaterThanEqual)[0];
39332               var value = _greaterThanEqual[key];
39333               return function (tags) {
39334                 return tags[key] >= value;
39335               };
39336             },
39337             lessThan: function lessThan(_lessThan) {
39338               var key = Object.keys(_lessThan)[0];
39339               var value = _lessThan[key];
39340               return function (tags) {
39341                 return tags[key] < value;
39342               };
39343             },
39344             lessThanEqual: function lessThanEqual(_lessThanEqual) {
39345               var key = Object.keys(_lessThanEqual)[0];
39346               var value = _lessThanEqual[key];
39347               return function (tags) {
39348                 return tags[key] <= value;
39349               };
39350             },
39351             positiveRegex: function positiveRegex(_positiveRegex) {
39352               var tagKey = Object.keys(_positiveRegex)[0];
39353
39354               var expression = _positiveRegex[tagKey].join('|');
39355
39356               var regex = new RegExp(expression);
39357               return function (tags) {
39358                 return regex.test(tags[tagKey]);
39359               };
39360             },
39361             negativeRegex: function negativeRegex(_negativeRegex) {
39362               var tagKey = Object.keys(_negativeRegex)[0];
39363
39364               var expression = _negativeRegex[tagKey].join('|');
39365
39366               var regex = new RegExp(expression);
39367               return function (tags) {
39368                 return !regex.test(tags[tagKey]);
39369               };
39370             }
39371           };
39372         };
39373
39374         var buildLineKeys = function buildLineKeys() {
39375           return {
39376             highway: {
39377               rest_area: true,
39378               services: true
39379             },
39380             railway: {
39381               roundhouse: true,
39382               station: true,
39383               traverser: true,
39384               turntable: true,
39385               wash: true
39386             }
39387           };
39388         };
39389
39390         var serviceMapRules = {
39391           init: function init() {
39392             this._ruleChecks = buildRuleChecks();
39393             this._validationRules = [];
39394             this._areaKeys = osmAreaKeys;
39395             this._lineKeys = buildLineKeys();
39396           },
39397           // list of rules only relevant to tag checks...
39398           filterRuleChecks: function filterRuleChecks(selector) {
39399             var _ruleChecks = this._ruleChecks;
39400             return Object.keys(selector).reduce(function (rules, key) {
39401               if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
39402                 rules.push(_ruleChecks[key](selector[key]));
39403               }
39404
39405               return rules;
39406             }, []);
39407           },
39408           // builds tagMap from mapcss-parse selector object...
39409           buildTagMap: function buildTagMap(selector) {
39410             var getRegexValues = function getRegexValues(regexes) {
39411               return regexes.map(function (regex) {
39412                 return regex.replace(/\$|\^/g, '');
39413               });
39414             };
39415
39416             var tagMap = Object.keys(selector).reduce(function (expectedTags, key) {
39417               var values;
39418               var isRegex = /regex/gi.test(key);
39419               var isEqual = /equals/gi.test(key);
39420
39421               if (isRegex || isEqual) {
39422                 Object.keys(selector[key]).forEach(function (selectorKey) {
39423                   values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
39424
39425                   if (expectedTags.hasOwnProperty(selectorKey)) {
39426                     values = values.concat(expectedTags[selectorKey]);
39427                   }
39428
39429                   expectedTags[selectorKey] = values;
39430                 });
39431               } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
39432                 var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
39433                 values = [selector[key][tagKey]];
39434
39435                 if (expectedTags.hasOwnProperty(tagKey)) {
39436                   values = values.concat(expectedTags[tagKey]);
39437                 }
39438
39439                 expectedTags[tagKey] = values;
39440               }
39441
39442               return expectedTags;
39443             }, {});
39444             return tagMap;
39445           },
39446           // inspired by osmWay#isArea()
39447           inferGeometry: function inferGeometry(tagMap) {
39448             var _lineKeys = this._lineKeys;
39449             var _areaKeys = this._areaKeys;
39450
39451             var keyValueDoesNotImplyArea = function keyValueDoesNotImplyArea(key) {
39452               return utilArrayIntersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
39453             };
39454
39455             var keyValueImpliesLine = function keyValueImpliesLine(key) {
39456               return utilArrayIntersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
39457             };
39458
39459             if (tagMap.hasOwnProperty('area')) {
39460               if (tagMap.area.indexOf('yes') > -1) {
39461                 return 'area';
39462               }
39463
39464               if (tagMap.area.indexOf('no') > -1) {
39465                 return 'line';
39466               }
39467             }
39468
39469             for (var key in tagMap) {
39470               if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
39471                 return 'area';
39472               }
39473
39474               if (key in _lineKeys && keyValueImpliesLine(key)) {
39475                 return 'area';
39476               }
39477             }
39478
39479             return 'line';
39480           },
39481           // adds from mapcss-parse selector check...
39482           addRule: function addRule(selector) {
39483             var rule = {
39484               // checks relevant to mapcss-selector
39485               checks: this.filterRuleChecks(selector),
39486               // true if all conditions for a tag error are true..
39487               matches: function matches(entity) {
39488                 return this.checks.every(function (check) {
39489                   return check(entity.tags);
39490                 });
39491               },
39492               // borrowed from Way#isArea()
39493               inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
39494               geometryMatches: function geometryMatches(entity, graph) {
39495                 if (entity.type === 'node' || entity.type === 'relation') {
39496                   return selector.geometry === entity.type;
39497                 } else if (entity.type === 'way') {
39498                   return this.inferredGeometry === entity.geometry(graph);
39499                 }
39500               },
39501               // when geometries match and tag matches are present, return a warning...
39502               findIssues: function findIssues(entity, graph, issues) {
39503                 if (this.geometryMatches(entity, graph) && this.matches(entity)) {
39504                   var severity = Object.keys(selector).indexOf('error') > -1 ? 'error' : 'warning';
39505                   var _message = selector[severity];
39506                   issues.push(new validationIssue({
39507                     type: 'maprules',
39508                     severity: severity,
39509                     message: function message() {
39510                       return _message;
39511                     },
39512                     entityIds: [entity.id]
39513                   }));
39514                 }
39515               }
39516             };
39517
39518             this._validationRules.push(rule);
39519           },
39520           clearRules: function clearRules() {
39521             this._validationRules = [];
39522           },
39523           // returns validationRules...
39524           validationRules: function validationRules() {
39525             return this._validationRules;
39526           },
39527           // returns ruleChecks
39528           ruleChecks: function ruleChecks() {
39529             return this._ruleChecks;
39530           }
39531         };
39532
39533         var apibase$1 = 'https://nominatim.openstreetmap.org/';
39534         var _inflight = {};
39535
39536         var _nominatimCache;
39537
39538         var serviceNominatim = {
39539           init: function init() {
39540             _inflight = {};
39541             _nominatimCache = new RBush();
39542           },
39543           reset: function reset() {
39544             Object.values(_inflight).forEach(function (controller) {
39545               controller.abort();
39546             });
39547             _inflight = {};
39548             _nominatimCache = new RBush();
39549           },
39550           countryCode: function countryCode(location, callback) {
39551             this.reverse(location, function (err, result) {
39552               if (err) {
39553                 return callback(err);
39554               } else if (result.address) {
39555                 return callback(null, result.address.country_code);
39556               } else {
39557                 return callback('Unable to geocode', null);
39558               }
39559             });
39560           },
39561           reverse: function reverse(loc, callback) {
39562             var cached = _nominatimCache.search({
39563               minX: loc[0],
39564               minY: loc[1],
39565               maxX: loc[0],
39566               maxY: loc[1]
39567             });
39568
39569             if (cached.length > 0) {
39570               if (callback) callback(null, cached[0].data);
39571               return;
39572             }
39573
39574             var params = {
39575               zoom: 13,
39576               format: 'json',
39577               addressdetails: 1,
39578               lat: loc[1],
39579               lon: loc[0]
39580             };
39581             var url = apibase$1 + 'reverse?' + utilQsString(params);
39582             if (_inflight[url]) return;
39583             var controller = new AbortController();
39584             _inflight[url] = controller;
39585             d3_json(url, {
39586               signal: controller.signal
39587             }).then(function (result) {
39588               delete _inflight[url];
39589
39590               if (result && result.error) {
39591                 throw new Error(result.error);
39592               }
39593
39594               var extent = geoExtent(loc).padByMeters(200);
39595
39596               _nominatimCache.insert(Object.assign(extent.bbox(), {
39597                 data: result
39598               }));
39599
39600               if (callback) callback(null, result);
39601             })["catch"](function (err) {
39602               delete _inflight[url];
39603               if (err.name === 'AbortError') return;
39604               if (callback) callback(err.message);
39605             });
39606           },
39607           search: function search(val, callback) {
39608             var searchVal = encodeURIComponent(val);
39609             var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
39610             if (_inflight[url]) return;
39611             var controller = new AbortController();
39612             _inflight[url] = controller;
39613             d3_json(url, {
39614               signal: controller.signal
39615             }).then(function (result) {
39616               delete _inflight[url];
39617
39618               if (result && result.error) {
39619                 throw new Error(result.error);
39620               }
39621
39622               if (callback) callback(null, result);
39623             })["catch"](function (err) {
39624               delete _inflight[url];
39625               if (err.name === 'AbortError') return;
39626               if (callback) callback(err.message);
39627             });
39628           }
39629         };
39630
39631         var apibase$2 = 'https://openstreetcam.org';
39632         var maxResults$1 = 1000;
39633         var tileZoom$1 = 14;
39634         var tiler$4 = utilTiler().zoomExtent([tileZoom$1, tileZoom$1]).skipNullIsland(true);
39635         var dispatch$5 = dispatch('loadedImages');
39636         var imgZoom = d3_zoom().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
39637
39638         var _oscCache;
39639
39640         var _oscSelectedImage;
39641
39642         var _loadViewerPromise$1;
39643
39644         function abortRequest$4(controller) {
39645           controller.abort();
39646         }
39647
39648         function maxPageAtZoom$1(z) {
39649           if (z < 15) return 2;
39650           if (z === 15) return 5;
39651           if (z === 16) return 10;
39652           if (z === 17) return 20;
39653           if (z === 18) return 40;
39654           if (z > 18) return 80;
39655         }
39656
39657         function loadTiles$1(which, url, projection) {
39658           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
39659           var tiles = tiler$4.getTiles(projection); // abort inflight requests that are no longer needed
39660
39661           var cache = _oscCache[which];
39662           Object.keys(cache.inflight).forEach(function (k) {
39663             var wanted = tiles.find(function (tile) {
39664               return k.indexOf(tile.id + ',') === 0;
39665             });
39666
39667             if (!wanted) {
39668               abortRequest$4(cache.inflight[k]);
39669               delete cache.inflight[k];
39670             }
39671           });
39672           tiles.forEach(function (tile) {
39673             loadNextTilePage$1(which, currZoom, url, tile);
39674           });
39675         }
39676
39677         function loadNextTilePage$1(which, currZoom, url, tile) {
39678           var cache = _oscCache[which];
39679           var bbox = tile.extent.bbox();
39680           var maxPages = maxPageAtZoom$1(currZoom);
39681           var nextPage = cache.nextPage[tile.id] || 1;
39682           var params = utilQsString({
39683             ipp: maxResults$1,
39684             page: nextPage,
39685             // client_id: clientId,
39686             bbTopLeft: [bbox.maxY, bbox.minX].join(','),
39687             bbBottomRight: [bbox.minY, bbox.maxX].join(',')
39688           }, true);
39689           if (nextPage > maxPages) return;
39690           var id = tile.id + ',' + String(nextPage);
39691           if (cache.loaded[id] || cache.inflight[id]) return;
39692           var controller = new AbortController();
39693           cache.inflight[id] = controller;
39694           var options = {
39695             method: 'POST',
39696             signal: controller.signal,
39697             body: params,
39698             headers: {
39699               'Content-Type': 'application/x-www-form-urlencoded'
39700             }
39701           };
39702           d3_json(url, options).then(function (data) {
39703             cache.loaded[id] = true;
39704             delete cache.inflight[id];
39705
39706             if (!data || !data.currentPageItems || !data.currentPageItems.length) {
39707               throw new Error('No Data');
39708             }
39709
39710             var features = data.currentPageItems.map(function (item) {
39711               var loc = [+item.lng, +item.lat];
39712               var d;
39713
39714               if (which === 'images') {
39715                 d = {
39716                   loc: loc,
39717                   key: item.id,
39718                   ca: +item.heading,
39719                   captured_at: item.shot_date || item.date_added,
39720                   captured_by: item.username,
39721                   imagePath: item.lth_name,
39722                   sequence_id: item.sequence_id,
39723                   sequence_index: +item.sequence_index
39724                 }; // cache sequence info
39725
39726                 var seq = _oscCache.sequences[d.sequence_id];
39727
39728                 if (!seq) {
39729                   seq = {
39730                     rotation: 0,
39731                     images: []
39732                   };
39733                   _oscCache.sequences[d.sequence_id] = seq;
39734                 }
39735
39736                 seq.images[d.sequence_index] = d;
39737                 _oscCache.images.forImageKey[d.key] = d; // cache imageKey -> image
39738               }
39739
39740               return {
39741                 minX: loc[0],
39742                 minY: loc[1],
39743                 maxX: loc[0],
39744                 maxY: loc[1],
39745                 data: d
39746               };
39747             });
39748             cache.rtree.load(features);
39749
39750             if (data.currentPageItems.length === maxResults$1) {
39751               // more pages to load
39752               cache.nextPage[tile.id] = nextPage + 1;
39753               loadNextTilePage$1(which, currZoom, url, tile);
39754             } else {
39755               cache.nextPage[tile.id] = Infinity; // no more pages to load
39756             }
39757
39758             if (which === 'images') {
39759               dispatch$5.call('loadedImages');
39760             }
39761           })["catch"](function () {
39762             cache.loaded[id] = true;
39763             delete cache.inflight[id];
39764           });
39765         } // partition viewport into higher zoom tiles
39766
39767
39768         function partitionViewport$1(projection) {
39769           var z = geoScaleToZoom(projection.scale());
39770           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
39771
39772           var tiler = utilTiler().zoomExtent([z2, z2]);
39773           return tiler.getTiles(projection).map(function (tile) {
39774             return tile.extent;
39775           });
39776         } // no more than `limit` results per partition.
39777
39778
39779         function searchLimited$1(limit, projection, rtree) {
39780           limit = limit || 5;
39781           return partitionViewport$1(projection).reduce(function (result, extent) {
39782             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
39783               return d.data;
39784             });
39785             return found.length ? result.concat(found) : result;
39786           }, []);
39787         }
39788
39789         var serviceOpenstreetcam = {
39790           init: function init() {
39791             if (!_oscCache) {
39792               this.reset();
39793             }
39794
39795             this.event = utilRebind(this, dispatch$5, 'on');
39796           },
39797           reset: function reset() {
39798             if (_oscCache) {
39799               Object.values(_oscCache.images.inflight).forEach(abortRequest$4);
39800             }
39801
39802             _oscCache = {
39803               images: {
39804                 inflight: {},
39805                 loaded: {},
39806                 nextPage: {},
39807                 rtree: new RBush(),
39808                 forImageKey: {}
39809               },
39810               sequences: {}
39811             };
39812             _oscSelectedImage = null;
39813           },
39814           images: function images(projection) {
39815             var limit = 5;
39816             return searchLimited$1(limit, projection, _oscCache.images.rtree);
39817           },
39818           sequences: function sequences(projection) {
39819             var viewport = projection.clipExtent();
39820             var min = [viewport[0][0], viewport[1][1]];
39821             var max = [viewport[1][0], viewport[0][1]];
39822             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
39823             var sequenceKeys = {}; // all sequences for images in viewport
39824
39825             _oscCache.images.rtree.search(bbox).forEach(function (d) {
39826               sequenceKeys[d.data.sequence_id] = true;
39827             }); // make linestrings from those sequences
39828
39829
39830             var lineStrings = [];
39831             Object.keys(sequenceKeys).forEach(function (sequenceKey) {
39832               var seq = _oscCache.sequences[sequenceKey];
39833               var images = seq && seq.images;
39834
39835               if (images) {
39836                 lineStrings.push({
39837                   type: 'LineString',
39838                   coordinates: images.map(function (d) {
39839                     return d.loc;
39840                   }).filter(Boolean),
39841                   properties: {
39842                     captured_at: images[0] ? images[0].captured_at : null,
39843                     captured_by: images[0] ? images[0].captured_by : null,
39844                     key: sequenceKey
39845                   }
39846                 });
39847               }
39848             });
39849             return lineStrings;
39850           },
39851           cachedImage: function cachedImage(imageKey) {
39852             return _oscCache.images.forImageKey[imageKey];
39853           },
39854           loadImages: function loadImages(projection) {
39855             var url = apibase$2 + '/1.0/list/nearby-photos/';
39856             loadTiles$1('images', url, projection);
39857           },
39858           ensureViewerLoaded: function ensureViewerLoaded(context) {
39859             if (_loadViewerPromise$1) return _loadViewerPromise$1; // add osc-wrapper
39860
39861             var wrap = context.container().select('.photoviewer').selectAll('.osc-wrapper').data([0]);
39862             var that = this;
39863             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper osc-wrapper').classed('hide', true).call(imgZoom.on('zoom', zoomPan)).on('dblclick.zoom', null);
39864             wrapEnter.append('div').attr('class', 'photo-attribution fillD');
39865             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
39866             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
39867             controlsEnter.append('button').on('click.rotate-ccw', rotate(-90)).html('⤿');
39868             controlsEnter.append('button').on('click.rotate-cw', rotate(90)).html('⤾');
39869             controlsEnter.append('button').on('click.forward', step(1)).html('►');
39870             wrapEnter.append('div').attr('class', 'osc-image-wrap'); // Register viewer resize handler
39871
39872             context.ui().photoviewer.on('resize.openstreetcam', function (dimensions) {
39873               imgZoom = d3_zoom().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on('zoom', zoomPan);
39874             });
39875
39876             function zoomPan(d3_event) {
39877               var t = d3_event.transform;
39878               context.container().select('.photoviewer .osc-image-wrap').call(utilSetTransform, t.x, t.y, t.k);
39879             }
39880
39881             function rotate(deg) {
39882               return function () {
39883                 if (!_oscSelectedImage) return;
39884                 var sequenceKey = _oscSelectedImage.sequence_id;
39885                 var sequence = _oscCache.sequences[sequenceKey];
39886                 if (!sequence) return;
39887                 var r = sequence.rotation || 0;
39888                 r += deg;
39889                 if (r > 180) r -= 360;
39890                 if (r < -180) r += 360;
39891                 sequence.rotation = r;
39892                 var wrap = context.container().select('.photoviewer .osc-wrapper');
39893                 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
39894                 wrap.selectAll('.osc-image').transition().duration(100).style('transform', 'rotate(' + r + 'deg)');
39895               };
39896             }
39897
39898             function step(stepBy) {
39899               return function () {
39900                 if (!_oscSelectedImage) return;
39901                 var sequenceKey = _oscSelectedImage.sequence_id;
39902                 var sequence = _oscCache.sequences[sequenceKey];
39903                 if (!sequence) return;
39904                 var nextIndex = _oscSelectedImage.sequence_index + stepBy;
39905                 var nextImage = sequence.images[nextIndex];
39906                 if (!nextImage) return;
39907                 context.map().centerEase(nextImage.loc);
39908                 that.selectImage(context, nextImage.key);
39909               };
39910             } // don't need any async loading so resolve immediately
39911
39912
39913             _loadViewerPromise$1 = Promise.resolve();
39914             return _loadViewerPromise$1;
39915           },
39916           showViewer: function showViewer(context) {
39917             var viewer = context.container().select('.photoviewer').classed('hide', false);
39918             var isHidden = viewer.selectAll('.photo-wrapper.osc-wrapper.hide').size();
39919
39920             if (isHidden) {
39921               viewer.selectAll('.photo-wrapper:not(.osc-wrapper)').classed('hide', true);
39922               viewer.selectAll('.photo-wrapper.osc-wrapper').classed('hide', false);
39923             }
39924
39925             return this;
39926           },
39927           hideViewer: function hideViewer(context) {
39928             _oscSelectedImage = null;
39929             this.updateUrlImage(null);
39930             var viewer = context.container().select('.photoviewer');
39931             if (!viewer.empty()) viewer.datum(null);
39932             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
39933             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
39934             return this.setStyles(context, null, true);
39935           },
39936           selectImage: function selectImage(context, imageKey) {
39937             var d = this.cachedImage(imageKey);
39938             _oscSelectedImage = d;
39939             this.updateUrlImage(imageKey);
39940             var viewer = context.container().select('.photoviewer');
39941             if (!viewer.empty()) viewer.datum(d);
39942             this.setStyles(context, null, true);
39943             context.container().selectAll('.icon-sign').classed('currentView', false);
39944             if (!d) return this;
39945             var wrap = context.container().select('.photoviewer .osc-wrapper');
39946             var imageWrap = wrap.selectAll('.osc-image-wrap');
39947             var attribution = wrap.selectAll('.photo-attribution').html('');
39948             wrap.transition().duration(100).call(imgZoom.transform, identity$2);
39949             imageWrap.selectAll('.osc-image').remove();
39950
39951             if (d) {
39952               var sequence = _oscCache.sequences[d.sequence_id];
39953               var r = sequence && sequence.rotation || 0;
39954               imageWrap.append('img').attr('class', 'osc-image').attr('src', apibase$2 + '/' + d.imagePath).style('transform', 'rotate(' + r + 'deg)');
39955
39956               if (d.captured_by) {
39957                 attribution.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)).html('@' + d.captured_by);
39958                 attribution.append('span').html('|');
39959               }
39960
39961               if (d.captured_at) {
39962                 attribution.append('span').attr('class', 'captured_at').html(localeDateString(d.captured_at));
39963                 attribution.append('span').html('|');
39964               }
39965
39966               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');
39967             }
39968
39969             return this;
39970
39971             function localeDateString(s) {
39972               if (!s) return null;
39973               var options = {
39974                 day: 'numeric',
39975                 month: 'short',
39976                 year: 'numeric'
39977               };
39978               var d = new Date(s);
39979               if (isNaN(d.getTime())) return null;
39980               return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
39981             }
39982           },
39983           getSelectedImage: function getSelectedImage() {
39984             return _oscSelectedImage;
39985           },
39986           getSequenceKeyForImage: function getSequenceKeyForImage(d) {
39987             return d && d.sequence_id;
39988           },
39989           // Updates the currently highlighted sequence and selected bubble.
39990           // Reset is only necessary when interacting with the viewport because
39991           // this implicitly changes the currently selected bubble/sequence
39992           setStyles: function setStyles(context, hovered, reset) {
39993             if (reset) {
39994               // reset all layers
39995               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
39996               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
39997             }
39998
39999             var hoveredImageKey = hovered && hovered.key;
40000             var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
40001             var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
40002             var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function (d) {
40003               return d.key;
40004             }) || [];
40005             var viewer = context.container().select('.photoviewer');
40006             var selected = viewer.empty() ? undefined : viewer.datum();
40007             var selectedImageKey = selected && selected.key;
40008             var selectedSequenceKey = this.getSequenceKeyForImage(selected);
40009             var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
40010             var selectedImageKeys = selectedSequence && selectedSequence.images.map(function (d) {
40011               return d.key;
40012             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
40013
40014             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
40015             context.container().selectAll('.layer-openstreetcam .viewfield-group').classed('highlighted', function (d) {
40016               return highlightedImageKeys.indexOf(d.key) !== -1;
40017             }).classed('hovered', function (d) {
40018               return d.key === hoveredImageKey;
40019             }).classed('currentView', function (d) {
40020               return d.key === selectedImageKey;
40021             });
40022             context.container().selectAll('.layer-openstreetcam .sequence').classed('highlighted', function (d) {
40023               return d.properties.key === hoveredSequenceKey;
40024             }).classed('currentView', function (d) {
40025               return d.properties.key === selectedSequenceKey;
40026             }); // update viewfields if needed
40027
40028             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
40029
40030             function viewfieldPath() {
40031               var d = this.parentNode.__data__;
40032
40033               if (d.pano && d.key !== selectedImageKey) {
40034                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
40035               } else {
40036                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
40037               }
40038             }
40039
40040             return this;
40041           },
40042           updateUrlImage: function updateUrlImage(imageKey) {
40043             if (!window.mocha) {
40044               var hash = utilStringQs(window.location.hash);
40045
40046               if (imageKey) {
40047                 hash.photo = 'openstreetcam/' + imageKey;
40048               } else {
40049                 delete hash.photo;
40050               }
40051
40052               window.location.replace('#' + utilQsString(hash, true));
40053             }
40054           },
40055           cache: function cache() {
40056             return _oscCache;
40057           }
40058         };
40059
40060         var FORCED$f = fails(function () {
40061           return new Date(NaN).toJSON() !== null
40062             || Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) !== 1;
40063         });
40064
40065         // `Date.prototype.toJSON` method
40066         // https://tc39.github.io/ecma262/#sec-date.prototype.tojson
40067         _export({ target: 'Date', proto: true, forced: FORCED$f }, {
40068           // eslint-disable-next-line no-unused-vars
40069           toJSON: function toJSON(key) {
40070             var O = toObject(this);
40071             var pv = toPrimitive(O);
40072             return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString();
40073           }
40074         });
40075
40076         // `URL.prototype.toJSON` method
40077         // https://url.spec.whatwg.org/#dom-url-tojson
40078         _export({ target: 'URL', proto: true, enumerable: true }, {
40079           toJSON: function toJSON() {
40080             return URL.prototype.toString.call(this);
40081           }
40082         });
40083
40084         /**
40085          * Checks if `value` is the
40086          * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
40087          * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
40088          *
40089          * @static
40090          * @memberOf _
40091          * @since 0.1.0
40092          * @category Lang
40093          * @param {*} value The value to check.
40094          * @returns {boolean} Returns `true` if `value` is an object, else `false`.
40095          * @example
40096          *
40097          * _.isObject({});
40098          * // => true
40099          *
40100          * _.isObject([1, 2, 3]);
40101          * // => true
40102          *
40103          * _.isObject(_.noop);
40104          * // => true
40105          *
40106          * _.isObject(null);
40107          * // => false
40108          */
40109         function isObject$1(value) {
40110           var type = _typeof(value);
40111
40112           return value != null && (type == 'object' || type == 'function');
40113         }
40114
40115         /** Detect free variable `global` from Node.js. */
40116         var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) == 'object' && global && global.Object === Object && global;
40117
40118         /** Detect free variable `self`. */
40119
40120         var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self;
40121         /** Used as a reference to the global object. */
40122
40123         var root$1 = freeGlobal || freeSelf || Function('return this')();
40124
40125         /**
40126          * Gets the timestamp of the number of milliseconds that have elapsed since
40127          * the Unix epoch (1 January 1970 00:00:00 UTC).
40128          *
40129          * @static
40130          * @memberOf _
40131          * @since 2.4.0
40132          * @category Date
40133          * @returns {number} Returns the timestamp.
40134          * @example
40135          *
40136          * _.defer(function(stamp) {
40137          *   console.log(_.now() - stamp);
40138          * }, _.now());
40139          * // => Logs the number of milliseconds it took for the deferred invocation.
40140          */
40141
40142         var now$1 = function now() {
40143           return root$1.Date.now();
40144         };
40145
40146         /** Built-in value references. */
40147
40148         var _Symbol = root$1.Symbol;
40149
40150         /** Used for built-in method references. */
40151
40152         var objectProto = Object.prototype;
40153         /** Used to check objects for own properties. */
40154
40155         var hasOwnProperty$1 = objectProto.hasOwnProperty;
40156         /**
40157          * Used to resolve the
40158          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40159          * of values.
40160          */
40161
40162         var nativeObjectToString = objectProto.toString;
40163         /** Built-in value references. */
40164
40165         var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
40166         /**
40167          * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
40168          *
40169          * @private
40170          * @param {*} value The value to query.
40171          * @returns {string} Returns the raw `toStringTag`.
40172          */
40173
40174         function getRawTag(value) {
40175           var isOwn = hasOwnProperty$1.call(value, symToStringTag),
40176               tag = value[symToStringTag];
40177
40178           try {
40179             value[symToStringTag] = undefined;
40180             var unmasked = true;
40181           } catch (e) {}
40182
40183           var result = nativeObjectToString.call(value);
40184
40185           if (unmasked) {
40186             if (isOwn) {
40187               value[symToStringTag] = tag;
40188             } else {
40189               delete value[symToStringTag];
40190             }
40191           }
40192
40193           return result;
40194         }
40195
40196         /** Used for built-in method references. */
40197         var objectProto$1 = Object.prototype;
40198         /**
40199          * Used to resolve the
40200          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40201          * of values.
40202          */
40203
40204         var nativeObjectToString$1 = objectProto$1.toString;
40205         /**
40206          * Converts `value` to a string using `Object.prototype.toString`.
40207          *
40208          * @private
40209          * @param {*} value The value to convert.
40210          * @returns {string} Returns the converted string.
40211          */
40212
40213         function objectToString$1(value) {
40214           return nativeObjectToString$1.call(value);
40215         }
40216
40217         /** `Object#toString` result references. */
40218
40219         var nullTag = '[object Null]',
40220             undefinedTag = '[object Undefined]';
40221         /** Built-in value references. */
40222
40223         var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
40224         /**
40225          * The base implementation of `getTag` without fallbacks for buggy environments.
40226          *
40227          * @private
40228          * @param {*} value The value to query.
40229          * @returns {string} Returns the `toStringTag`.
40230          */
40231
40232         function baseGetTag(value) {
40233           if (value == null) {
40234             return value === undefined ? undefinedTag : nullTag;
40235           }
40236
40237           return symToStringTag$1 && symToStringTag$1 in Object(value) ? getRawTag(value) : objectToString$1(value);
40238         }
40239
40240         /**
40241          * Checks if `value` is object-like. A value is object-like if it's not `null`
40242          * and has a `typeof` result of "object".
40243          *
40244          * @static
40245          * @memberOf _
40246          * @since 4.0.0
40247          * @category Lang
40248          * @param {*} value The value to check.
40249          * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
40250          * @example
40251          *
40252          * _.isObjectLike({});
40253          * // => true
40254          *
40255          * _.isObjectLike([1, 2, 3]);
40256          * // => true
40257          *
40258          * _.isObjectLike(_.noop);
40259          * // => false
40260          *
40261          * _.isObjectLike(null);
40262          * // => false
40263          */
40264         function isObjectLike(value) {
40265           return value != null && _typeof(value) == 'object';
40266         }
40267
40268         /** `Object#toString` result references. */
40269
40270         var symbolTag = '[object Symbol]';
40271         /**
40272          * Checks if `value` is classified as a `Symbol` primitive or object.
40273          *
40274          * @static
40275          * @memberOf _
40276          * @since 4.0.0
40277          * @category Lang
40278          * @param {*} value The value to check.
40279          * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
40280          * @example
40281          *
40282          * _.isSymbol(Symbol.iterator);
40283          * // => true
40284          *
40285          * _.isSymbol('abc');
40286          * // => false
40287          */
40288
40289         function isSymbol$1(value) {
40290           return _typeof(value) == 'symbol' || isObjectLike(value) && baseGetTag(value) == symbolTag;
40291         }
40292
40293         /** Used as references for various `Number` constants. */
40294
40295         var NAN = 0 / 0;
40296         /** Used to match leading and trailing whitespace. */
40297
40298         var reTrim = /^\s+|\s+$/g;
40299         /** Used to detect bad signed hexadecimal string values. */
40300
40301         var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
40302         /** Used to detect binary string values. */
40303
40304         var reIsBinary = /^0b[01]+$/i;
40305         /** Used to detect octal string values. */
40306
40307         var reIsOctal = /^0o[0-7]+$/i;
40308         /** Built-in method references without a dependency on `root`. */
40309
40310         var freeParseInt = parseInt;
40311         /**
40312          * Converts `value` to a number.
40313          *
40314          * @static
40315          * @memberOf _
40316          * @since 4.0.0
40317          * @category Lang
40318          * @param {*} value The value to process.
40319          * @returns {number} Returns the number.
40320          * @example
40321          *
40322          * _.toNumber(3.2);
40323          * // => 3.2
40324          *
40325          * _.toNumber(Number.MIN_VALUE);
40326          * // => 5e-324
40327          *
40328          * _.toNumber(Infinity);
40329          * // => Infinity
40330          *
40331          * _.toNumber('3.2');
40332          * // => 3.2
40333          */
40334
40335         function toNumber$1(value) {
40336           if (typeof value == 'number') {
40337             return value;
40338           }
40339
40340           if (isSymbol$1(value)) {
40341             return NAN;
40342           }
40343
40344           if (isObject$1(value)) {
40345             var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
40346             value = isObject$1(other) ? other + '' : other;
40347           }
40348
40349           if (typeof value != 'string') {
40350             return value === 0 ? value : +value;
40351           }
40352
40353           value = value.replace(reTrim, '');
40354           var isBinary = reIsBinary.test(value);
40355           return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
40356         }
40357
40358         /** Error message constants. */
40359
40360         var FUNC_ERROR_TEXT = 'Expected a function';
40361         /* Built-in method references for those with the same name as other `lodash` methods. */
40362
40363         var nativeMax = Math.max,
40364             nativeMin = Math.min;
40365         /**
40366          * Creates a debounced function that delays invoking `func` until after `wait`
40367          * milliseconds have elapsed since the last time the debounced function was
40368          * invoked. The debounced function comes with a `cancel` method to cancel
40369          * delayed `func` invocations and a `flush` method to immediately invoke them.
40370          * Provide `options` to indicate whether `func` should be invoked on the
40371          * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
40372          * with the last arguments provided to the debounced function. Subsequent
40373          * calls to the debounced function return the result of the last `func`
40374          * invocation.
40375          *
40376          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40377          * invoked on the trailing edge of the timeout only if the debounced function
40378          * is invoked more than once during the `wait` timeout.
40379          *
40380          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40381          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40382          *
40383          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40384          * for details over the differences between `_.debounce` and `_.throttle`.
40385          *
40386          * @static
40387          * @memberOf _
40388          * @since 0.1.0
40389          * @category Function
40390          * @param {Function} func The function to debounce.
40391          * @param {number} [wait=0] The number of milliseconds to delay.
40392          * @param {Object} [options={}] The options object.
40393          * @param {boolean} [options.leading=false]
40394          *  Specify invoking on the leading edge of the timeout.
40395          * @param {number} [options.maxWait]
40396          *  The maximum time `func` is allowed to be delayed before it's invoked.
40397          * @param {boolean} [options.trailing=true]
40398          *  Specify invoking on the trailing edge of the timeout.
40399          * @returns {Function} Returns the new debounced function.
40400          * @example
40401          *
40402          * // Avoid costly calculations while the window size is in flux.
40403          * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
40404          *
40405          * // Invoke `sendMail` when clicked, debouncing subsequent calls.
40406          * jQuery(element).on('click', _.debounce(sendMail, 300, {
40407          *   'leading': true,
40408          *   'trailing': false
40409          * }));
40410          *
40411          * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
40412          * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
40413          * var source = new EventSource('/stream');
40414          * jQuery(source).on('message', debounced);
40415          *
40416          * // Cancel the trailing debounced invocation.
40417          * jQuery(window).on('popstate', debounced.cancel);
40418          */
40419
40420         function debounce(func, wait, options) {
40421           var lastArgs,
40422               lastThis,
40423               maxWait,
40424               result,
40425               timerId,
40426               lastCallTime,
40427               lastInvokeTime = 0,
40428               leading = false,
40429               maxing = false,
40430               trailing = true;
40431
40432           if (typeof func != 'function') {
40433             throw new TypeError(FUNC_ERROR_TEXT);
40434           }
40435
40436           wait = toNumber$1(wait) || 0;
40437
40438           if (isObject$1(options)) {
40439             leading = !!options.leading;
40440             maxing = 'maxWait' in options;
40441             maxWait = maxing ? nativeMax(toNumber$1(options.maxWait) || 0, wait) : maxWait;
40442             trailing = 'trailing' in options ? !!options.trailing : trailing;
40443           }
40444
40445           function invokeFunc(time) {
40446             var args = lastArgs,
40447                 thisArg = lastThis;
40448             lastArgs = lastThis = undefined;
40449             lastInvokeTime = time;
40450             result = func.apply(thisArg, args);
40451             return result;
40452           }
40453
40454           function leadingEdge(time) {
40455             // Reset any `maxWait` timer.
40456             lastInvokeTime = time; // Start the timer for the trailing edge.
40457
40458             timerId = setTimeout(timerExpired, wait); // Invoke the leading edge.
40459
40460             return leading ? invokeFunc(time) : result;
40461           }
40462
40463           function remainingWait(time) {
40464             var timeSinceLastCall = time - lastCallTime,
40465                 timeSinceLastInvoke = time - lastInvokeTime,
40466                 timeWaiting = wait - timeSinceLastCall;
40467             return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
40468           }
40469
40470           function shouldInvoke(time) {
40471             var timeSinceLastCall = time - lastCallTime,
40472                 timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
40473             // trailing edge, the system time has gone backwards and we're treating
40474             // it as the trailing edge, or we've hit the `maxWait` limit.
40475
40476             return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
40477           }
40478
40479           function timerExpired() {
40480             var time = now$1();
40481
40482             if (shouldInvoke(time)) {
40483               return trailingEdge(time);
40484             } // Restart the timer.
40485
40486
40487             timerId = setTimeout(timerExpired, remainingWait(time));
40488           }
40489
40490           function trailingEdge(time) {
40491             timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
40492             // debounced at least once.
40493
40494             if (trailing && lastArgs) {
40495               return invokeFunc(time);
40496             }
40497
40498             lastArgs = lastThis = undefined;
40499             return result;
40500           }
40501
40502           function cancel() {
40503             if (timerId !== undefined) {
40504               clearTimeout(timerId);
40505             }
40506
40507             lastInvokeTime = 0;
40508             lastArgs = lastCallTime = lastThis = timerId = undefined;
40509           }
40510
40511           function flush() {
40512             return timerId === undefined ? result : trailingEdge(now$1());
40513           }
40514
40515           function debounced() {
40516             var time = now$1(),
40517                 isInvoking = shouldInvoke(time);
40518             lastArgs = arguments;
40519             lastThis = this;
40520             lastCallTime = time;
40521
40522             if (isInvoking) {
40523               if (timerId === undefined) {
40524                 return leadingEdge(lastCallTime);
40525               }
40526
40527               if (maxing) {
40528                 // Handle invocations in a tight loop.
40529                 clearTimeout(timerId);
40530                 timerId = setTimeout(timerExpired, wait);
40531                 return invokeFunc(lastCallTime);
40532               }
40533             }
40534
40535             if (timerId === undefined) {
40536               timerId = setTimeout(timerExpired, wait);
40537             }
40538
40539             return result;
40540           }
40541
40542           debounced.cancel = cancel;
40543           debounced.flush = flush;
40544           return debounced;
40545         }
40546
40547         /** Error message constants. */
40548
40549         var FUNC_ERROR_TEXT$1 = 'Expected a function';
40550         /**
40551          * Creates a throttled function that only invokes `func` at most once per
40552          * every `wait` milliseconds. The throttled function comes with a `cancel`
40553          * method to cancel delayed `func` invocations and a `flush` method to
40554          * immediately invoke them. Provide `options` to indicate whether `func`
40555          * should be invoked on the leading and/or trailing edge of the `wait`
40556          * timeout. The `func` is invoked with the last arguments provided to the
40557          * throttled function. Subsequent calls to the throttled function return the
40558          * result of the last `func` invocation.
40559          *
40560          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40561          * invoked on the trailing edge of the timeout only if the throttled function
40562          * is invoked more than once during the `wait` timeout.
40563          *
40564          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40565          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40566          *
40567          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40568          * for details over the differences between `_.throttle` and `_.debounce`.
40569          *
40570          * @static
40571          * @memberOf _
40572          * @since 0.1.0
40573          * @category Function
40574          * @param {Function} func The function to throttle.
40575          * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
40576          * @param {Object} [options={}] The options object.
40577          * @param {boolean} [options.leading=true]
40578          *  Specify invoking on the leading edge of the timeout.
40579          * @param {boolean} [options.trailing=true]
40580          *  Specify invoking on the trailing edge of the timeout.
40581          * @returns {Function} Returns the new throttled function.
40582          * @example
40583          *
40584          * // Avoid excessively updating the position while scrolling.
40585          * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
40586          *
40587          * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
40588          * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
40589          * jQuery(element).on('click', throttled);
40590          *
40591          * // Cancel the trailing throttled invocation.
40592          * jQuery(window).on('popstate', throttled.cancel);
40593          */
40594
40595         function throttle(func, wait, options) {
40596           var leading = true,
40597               trailing = true;
40598
40599           if (typeof func != 'function') {
40600             throw new TypeError(FUNC_ERROR_TEXT$1);
40601           }
40602
40603           if (isObject$1(options)) {
40604             leading = 'leading' in options ? !!options.leading : leading;
40605             trailing = 'trailing' in options ? !!options.trailing : trailing;
40606           }
40607
40608           return debounce(func, wait, {
40609             'leading': leading,
40610             'maxWait': wait,
40611             'trailing': trailing
40612           });
40613         }
40614
40615         var hashes = createCommonjsModule(function (module, exports) {
40616           /**
40617            * jshashes - https://github.com/h2non/jshashes
40618            * Released under the "New BSD" license
40619            *
40620            * Algorithms specification:
40621            *
40622            * MD5 - http://www.ietf.org/rfc/rfc1321.txt
40623            * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
40624            * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40625            * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40626            * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40627            * HMAC - http://www.ietf.org/rfc/rfc2104.txt
40628            */
40629           (function () {
40630             var Hashes;
40631
40632             function utf8Encode(str) {
40633               var x,
40634                   y,
40635                   output = '',
40636                   i = -1,
40637                   l;
40638
40639               if (str && str.length) {
40640                 l = str.length;
40641
40642                 while ((i += 1) < l) {
40643                   /* Decode utf-16 surrogate pairs */
40644                   x = str.charCodeAt(i);
40645                   y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
40646
40647                   if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
40648                     x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
40649                     i += 1;
40650                   }
40651                   /* Encode output as utf-8 */
40652
40653
40654                   if (x <= 0x7F) {
40655                     output += String.fromCharCode(x);
40656                   } else if (x <= 0x7FF) {
40657                     output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F);
40658                   } else if (x <= 0xFFFF) {
40659                     output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40660                   } else if (x <= 0x1FFFFF) {
40661                     output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40662                   }
40663                 }
40664               }
40665
40666               return output;
40667             }
40668
40669             function utf8Decode(str) {
40670               var i,
40671                   ac,
40672                   c1,
40673                   c2,
40674                   c3,
40675                   arr = [],
40676                   l;
40677               i = ac = c1 = c2 = c3 = 0;
40678
40679               if (str && str.length) {
40680                 l = str.length;
40681                 str += '';
40682
40683                 while (i < l) {
40684                   c1 = str.charCodeAt(i);
40685                   ac += 1;
40686
40687                   if (c1 < 128) {
40688                     arr[ac] = String.fromCharCode(c1);
40689                     i += 1;
40690                   } else if (c1 > 191 && c1 < 224) {
40691                     c2 = str.charCodeAt(i + 1);
40692                     arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
40693                     i += 2;
40694                   } else {
40695                     c2 = str.charCodeAt(i + 1);
40696                     c3 = str.charCodeAt(i + 2);
40697                     arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
40698                     i += 3;
40699                   }
40700                 }
40701               }
40702
40703               return arr.join('');
40704             }
40705             /**
40706              * Add integers, wrapping at 2^32. This uses 16-bit operations internally
40707              * to work around bugs in some JS interpreters.
40708              */
40709
40710
40711             function safe_add(x, y) {
40712               var lsw = (x & 0xFFFF) + (y & 0xFFFF),
40713                   msw = (x >> 16) + (y >> 16) + (lsw >> 16);
40714               return msw << 16 | lsw & 0xFFFF;
40715             }
40716             /**
40717              * Bitwise rotate a 32-bit number to the left.
40718              */
40719
40720
40721             function bit_rol(num, cnt) {
40722               return num << cnt | num >>> 32 - cnt;
40723             }
40724             /**
40725              * Convert a raw string to a hex string
40726              */
40727
40728
40729             function rstr2hex(input, hexcase) {
40730               var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
40731                   output = '',
40732                   x,
40733                   i = 0,
40734                   l = input.length;
40735
40736               for (; i < l; i += 1) {
40737                 x = input.charCodeAt(i);
40738                 output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F);
40739               }
40740
40741               return output;
40742             }
40743             /**
40744              * Convert an array of big-endian words to a string
40745              */
40746
40747
40748             function binb2rstr(input) {
40749               var i,
40750                   l = input.length * 32,
40751                   output = '';
40752
40753               for (i = 0; i < l; i += 8) {
40754                 output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF);
40755               }
40756
40757               return output;
40758             }
40759             /**
40760              * Convert an array of little-endian words to a string
40761              */
40762
40763
40764             function binl2rstr(input) {
40765               var i,
40766                   l = input.length * 32,
40767                   output = '';
40768
40769               for (i = 0; i < l; i += 8) {
40770                 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
40771               }
40772
40773               return output;
40774             }
40775             /**
40776              * Convert a raw string to an array of little-endian words
40777              * Characters >255 have their high-byte silently ignored.
40778              */
40779
40780
40781             function rstr2binl(input) {
40782               var i,
40783                   l = input.length * 8,
40784                   output = Array(input.length >> 2),
40785                   lo = output.length;
40786
40787               for (i = 0; i < lo; i += 1) {
40788                 output[i] = 0;
40789               }
40790
40791               for (i = 0; i < l; i += 8) {
40792                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32;
40793               }
40794
40795               return output;
40796             }
40797             /**
40798              * Convert a raw string to an array of big-endian words
40799              * Characters >255 have their high-byte silently ignored.
40800              */
40801
40802
40803             function rstr2binb(input) {
40804               var i,
40805                   l = input.length * 8,
40806                   output = Array(input.length >> 2),
40807                   lo = output.length;
40808
40809               for (i = 0; i < lo; i += 1) {
40810                 output[i] = 0;
40811               }
40812
40813               for (i = 0; i < l; i += 8) {
40814                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32;
40815               }
40816
40817               return output;
40818             }
40819             /**
40820              * Convert a raw string to an arbitrary string encoding
40821              */
40822
40823
40824             function rstr2any(input, encoding) {
40825               var divisor = encoding.length,
40826                   remainders = Array(),
40827                   i,
40828                   q,
40829                   x,
40830                   ld,
40831                   quotient,
40832                   dividend,
40833                   output,
40834                   full_length;
40835               /* Convert to an array of 16-bit big-endian values, forming the dividend */
40836
40837               dividend = Array(Math.ceil(input.length / 2));
40838               ld = dividend.length;
40839
40840               for (i = 0; i < ld; i += 1) {
40841                 dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1);
40842               }
40843               /**
40844                * Repeatedly perform a long division. The binary array forms the dividend,
40845                * the length of the encoding is the divisor. Once computed, the quotient
40846                * forms the dividend for the next step. We stop when the dividend is zerHashes.
40847                * All remainders are stored for later use.
40848                */
40849
40850
40851               while (dividend.length > 0) {
40852                 quotient = Array();
40853                 x = 0;
40854
40855                 for (i = 0; i < dividend.length; i += 1) {
40856                   x = (x << 16) + dividend[i];
40857                   q = Math.floor(x / divisor);
40858                   x -= q * divisor;
40859
40860                   if (quotient.length > 0 || q > 0) {
40861                     quotient[quotient.length] = q;
40862                   }
40863                 }
40864
40865                 remainders[remainders.length] = x;
40866                 dividend = quotient;
40867               }
40868               /* Convert the remainders to the output string */
40869
40870
40871               output = '';
40872
40873               for (i = remainders.length - 1; i >= 0; i--) {
40874                 output += encoding.charAt(remainders[i]);
40875               }
40876               /* Append leading zero equivalents */
40877
40878
40879               full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
40880
40881               for (i = output.length; i < full_length; i += 1) {
40882                 output = encoding[0] + output;
40883               }
40884
40885               return output;
40886             }
40887             /**
40888              * Convert a raw string to a base-64 string
40889              */
40890
40891
40892             function rstr2b64(input, b64pad) {
40893               var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
40894                   output = '',
40895                   len = input.length,
40896                   i,
40897                   j,
40898                   triplet;
40899               b64pad = b64pad || '=';
40900
40901               for (i = 0; i < len; i += 3) {
40902                 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
40903
40904                 for (j = 0; j < 4; j += 1) {
40905                   if (i * 8 + j * 6 > input.length * 8) {
40906                     output += b64pad;
40907                   } else {
40908                     output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
40909                   }
40910                 }
40911               }
40912
40913               return output;
40914             }
40915
40916             Hashes = {
40917               /**
40918                * @property {String} version
40919                * @readonly
40920                */
40921               VERSION: '1.0.6',
40922
40923               /**
40924                * @member Hashes
40925                * @class Base64
40926                * @constructor
40927                */
40928               Base64: function Base64() {
40929                 // private properties
40930                 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
40931                     pad = '=',
40932                     // URL encoding support @todo
40933                 utf8 = true; // by default enable UTF-8 support encoding
40934                 // public method for encoding
40935
40936                 this.encode = function (input) {
40937                   var i,
40938                       j,
40939                       triplet,
40940                       output = '',
40941                       len = input.length;
40942                   pad = pad || '=';
40943                   input = utf8 ? utf8Encode(input) : input;
40944
40945                   for (i = 0; i < len; i += 3) {
40946                     triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
40947
40948                     for (j = 0; j < 4; j += 1) {
40949                       if (i * 8 + j * 6 > len * 8) {
40950                         output += pad;
40951                       } else {
40952                         output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
40953                       }
40954                     }
40955                   }
40956
40957                   return output;
40958                 }; // public method for decoding
40959
40960
40961                 this.decode = function (input) {
40962                   // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
40963                   var i,
40964                       o1,
40965                       o2,
40966                       o3,
40967                       h1,
40968                       h2,
40969                       h3,
40970                       h4,
40971                       bits,
40972                       ac,
40973                       dec = '',
40974                       arr = [];
40975
40976                   if (!input) {
40977                     return input;
40978                   }
40979
40980                   i = ac = 0;
40981                   input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
40982                   //input += '';
40983
40984                   do {
40985                     // unpack four hexets into three octets using index points in b64
40986                     h1 = tab.indexOf(input.charAt(i += 1));
40987                     h2 = tab.indexOf(input.charAt(i += 1));
40988                     h3 = tab.indexOf(input.charAt(i += 1));
40989                     h4 = tab.indexOf(input.charAt(i += 1));
40990                     bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
40991                     o1 = bits >> 16 & 0xff;
40992                     o2 = bits >> 8 & 0xff;
40993                     o3 = bits & 0xff;
40994                     ac += 1;
40995
40996                     if (h3 === 64) {
40997                       arr[ac] = String.fromCharCode(o1);
40998                     } else if (h4 === 64) {
40999                       arr[ac] = String.fromCharCode(o1, o2);
41000                     } else {
41001                       arr[ac] = String.fromCharCode(o1, o2, o3);
41002                     }
41003                   } while (i < input.length);
41004
41005                   dec = arr.join('');
41006                   dec = utf8 ? utf8Decode(dec) : dec;
41007                   return dec;
41008                 }; // set custom pad string
41009
41010
41011                 this.setPad = function (str) {
41012                   pad = str || pad;
41013                   return this;
41014                 }; // set custom tab string characters
41015
41016
41017                 this.setTab = function (str) {
41018                   tab = str || tab;
41019                   return this;
41020                 };
41021
41022                 this.setUTF8 = function (bool) {
41023                   if (typeof bool === 'boolean') {
41024                     utf8 = bool;
41025                   }
41026
41027                   return this;
41028                 };
41029               },
41030
41031               /**
41032                * CRC-32 calculation
41033                * @member Hashes
41034                * @method CRC32
41035                * @static
41036                * @param {String} str Input String
41037                * @return {String}
41038                */
41039               CRC32: function CRC32(str) {
41040                 var crc = 0,
41041                     x = 0,
41042                     y = 0,
41043                     table,
41044                     i,
41045                     iTop;
41046                 str = utf8Encode(str);
41047                 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('');
41048                 crc = crc ^ -1;
41049
41050                 for (i = 0, iTop = str.length; i < iTop; i += 1) {
41051                   y = (crc ^ str.charCodeAt(i)) & 0xFF;
41052                   x = '0x' + table.substr(y * 9, 8);
41053                   crc = crc >>> 8 ^ x;
41054                 } // always return a positive number (that's what >>> 0 does)
41055
41056
41057                 return (crc ^ -1) >>> 0;
41058               },
41059
41060               /**
41061                * @member Hashes
41062                * @class MD5
41063                * @constructor
41064                * @param {Object} [config]
41065                *
41066                * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
41067                * Digest Algorithm, as defined in RFC 1321.
41068                * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
41069                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41070                * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
41071                */
41072               MD5: function MD5(options) {
41073                 /**
41074                  * Private config properties. You may need to tweak these to be compatible with
41075                  * the server-side, but the defaults work in most cases.
41076                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41077                  */
41078                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41079                     // hexadecimal output case format. false - lowercase; true - uppercase
41080                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41081                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41082                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41083                 // privileged (public) methods
41084
41085                 this.hex = function (s) {
41086                   return rstr2hex(rstr(s), hexcase);
41087                 };
41088
41089                 this.b64 = function (s) {
41090                   return rstr2b64(rstr(s), b64pad);
41091                 };
41092
41093                 this.any = function (s, e) {
41094                   return rstr2any(rstr(s), e);
41095                 };
41096
41097                 this.raw = function (s) {
41098                   return rstr(s);
41099                 };
41100
41101                 this.hex_hmac = function (k, d) {
41102                   return rstr2hex(rstr_hmac(k, d), hexcase);
41103                 };
41104
41105                 this.b64_hmac = function (k, d) {
41106                   return rstr2b64(rstr_hmac(k, d), b64pad);
41107                 };
41108
41109                 this.any_hmac = function (k, d, e) {
41110                   return rstr2any(rstr_hmac(k, d), e);
41111                 };
41112                 /**
41113                  * Perform a simple self-test to see if the VM is working
41114                  * @return {String} Hexadecimal hash sample
41115                  */
41116
41117
41118                 this.vm_test = function () {
41119                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41120                 };
41121                 /**
41122                  * Enable/disable uppercase hexadecimal returned string
41123                  * @param {Boolean}
41124                  * @return {Object} this
41125                  */
41126
41127
41128                 this.setUpperCase = function (a) {
41129                   if (typeof a === 'boolean') {
41130                     hexcase = a;
41131                   }
41132
41133                   return this;
41134                 };
41135                 /**
41136                  * Defines a base64 pad string
41137                  * @param {String} Pad
41138                  * @return {Object} this
41139                  */
41140
41141
41142                 this.setPad = function (a) {
41143                   b64pad = a || b64pad;
41144                   return this;
41145                 };
41146                 /**
41147                  * Defines a base64 pad string
41148                  * @param {Boolean}
41149                  * @return {Object} [this]
41150                  */
41151
41152
41153                 this.setUTF8 = function (a) {
41154                   if (typeof a === 'boolean') {
41155                     utf8 = a;
41156                   }
41157
41158                   return this;
41159                 }; // private methods
41160
41161                 /**
41162                  * Calculate the MD5 of a raw string
41163                  */
41164
41165
41166                 function rstr(s) {
41167                   s = utf8 ? utf8Encode(s) : s;
41168                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
41169                 }
41170                 /**
41171                  * Calculate the HMAC-MD5, of a key and some data (raw strings)
41172                  */
41173
41174
41175                 function rstr_hmac(key, data) {
41176                   var bkey, ipad, opad, hash, i;
41177                   key = utf8 ? utf8Encode(key) : key;
41178                   data = utf8 ? utf8Encode(data) : data;
41179                   bkey = rstr2binl(key);
41180
41181                   if (bkey.length > 16) {
41182                     bkey = binl(bkey, key.length * 8);
41183                   }
41184
41185                   ipad = Array(16), opad = Array(16);
41186
41187                   for (i = 0; i < 16; i += 1) {
41188                     ipad[i] = bkey[i] ^ 0x36363636;
41189                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41190                   }
41191
41192                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
41193                   return binl2rstr(binl(opad.concat(hash), 512 + 128));
41194                 }
41195                 /**
41196                  * Calculate the MD5 of an array of little-endian words, and a bit length.
41197                  */
41198
41199
41200                 function binl(x, len) {
41201                   var i,
41202                       olda,
41203                       oldb,
41204                       oldc,
41205                       oldd,
41206                       a = 1732584193,
41207                       b = -271733879,
41208                       c = -1732584194,
41209                       d = 271733878;
41210                   /* append padding */
41211
41212                   x[len >> 5] |= 0x80 << len % 32;
41213                   x[(len + 64 >>> 9 << 4) + 14] = len;
41214
41215                   for (i = 0; i < x.length; i += 16) {
41216                     olda = a;
41217                     oldb = b;
41218                     oldc = c;
41219                     oldd = d;
41220                     a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
41221                     d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
41222                     c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
41223                     b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
41224                     a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
41225                     d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
41226                     c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
41227                     b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
41228                     a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
41229                     d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
41230                     c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
41231                     b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
41232                     a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
41233                     d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
41234                     c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
41235                     b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
41236                     a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
41237                     d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
41238                     c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
41239                     b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
41240                     a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
41241                     d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
41242                     c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
41243                     b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
41244                     a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
41245                     d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
41246                     c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
41247                     b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
41248                     a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
41249                     d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
41250                     c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
41251                     b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
41252                     a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
41253                     d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
41254                     c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
41255                     b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
41256                     a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
41257                     d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
41258                     c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
41259                     b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
41260                     a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
41261                     d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
41262                     c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
41263                     b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
41264                     a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
41265                     d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
41266                     c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
41267                     b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
41268                     a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
41269                     d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
41270                     c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
41271                     b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
41272                     a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
41273                     d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
41274                     c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
41275                     b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
41276                     a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
41277                     d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
41278                     c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
41279                     b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
41280                     a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
41281                     d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
41282                     c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
41283                     b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
41284                     a = safe_add(a, olda);
41285                     b = safe_add(b, oldb);
41286                     c = safe_add(c, oldc);
41287                     d = safe_add(d, oldd);
41288                   }
41289
41290                   return Array(a, b, c, d);
41291                 }
41292                 /**
41293                  * These functions implement the four basic operations the algorithm uses.
41294                  */
41295
41296
41297                 function md5_cmn(q, a, b, x, s, t) {
41298                   return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
41299                 }
41300
41301                 function md5_ff(a, b, c, d, x, s, t) {
41302                   return md5_cmn(b & c | ~b & d, a, b, x, s, t);
41303                 }
41304
41305                 function md5_gg(a, b, c, d, x, s, t) {
41306                   return md5_cmn(b & d | c & ~d, a, b, x, s, t);
41307                 }
41308
41309                 function md5_hh(a, b, c, d, x, s, t) {
41310                   return md5_cmn(b ^ c ^ d, a, b, x, s, t);
41311                 }
41312
41313                 function md5_ii(a, b, c, d, x, s, t) {
41314                   return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
41315                 }
41316               },
41317
41318               /**
41319                * @member Hashes
41320                * @class Hashes.SHA1
41321                * @param {Object} [config]
41322                * @constructor
41323                *
41324                * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
41325                * Version 2.2 Copyright Paul Johnston 2000 - 2009.
41326                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41327                * See http://pajhome.org.uk/crypt/md5 for details.
41328                */
41329               SHA1: function SHA1(options) {
41330                 /**
41331                  * Private config properties. You may need to tweak these to be compatible with
41332                  * the server-side, but the defaults work in most cases.
41333                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41334                  */
41335                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41336                     // hexadecimal output case format. false - lowercase; true - uppercase
41337                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41338                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41339                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41340                 // public methods
41341
41342                 this.hex = function (s) {
41343                   return rstr2hex(rstr(s), hexcase);
41344                 };
41345
41346                 this.b64 = function (s) {
41347                   return rstr2b64(rstr(s), b64pad);
41348                 };
41349
41350                 this.any = function (s, e) {
41351                   return rstr2any(rstr(s), e);
41352                 };
41353
41354                 this.raw = function (s) {
41355                   return rstr(s);
41356                 };
41357
41358                 this.hex_hmac = function (k, d) {
41359                   return rstr2hex(rstr_hmac(k, d));
41360                 };
41361
41362                 this.b64_hmac = function (k, d) {
41363                   return rstr2b64(rstr_hmac(k, d), b64pad);
41364                 };
41365
41366                 this.any_hmac = function (k, d, e) {
41367                   return rstr2any(rstr_hmac(k, d), e);
41368                 };
41369                 /**
41370                  * Perform a simple self-test to see if the VM is working
41371                  * @return {String} Hexadecimal hash sample
41372                  * @public
41373                  */
41374
41375
41376                 this.vm_test = function () {
41377                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41378                 };
41379                 /**
41380                  * @description Enable/disable uppercase hexadecimal returned string
41381                  * @param {boolean}
41382                  * @return {Object} this
41383                  * @public
41384                  */
41385
41386
41387                 this.setUpperCase = function (a) {
41388                   if (typeof a === 'boolean') {
41389                     hexcase = a;
41390                   }
41391
41392                   return this;
41393                 };
41394                 /**
41395                  * @description Defines a base64 pad string
41396                  * @param {string} Pad
41397                  * @return {Object} this
41398                  * @public
41399                  */
41400
41401
41402                 this.setPad = function (a) {
41403                   b64pad = a || b64pad;
41404                   return this;
41405                 };
41406                 /**
41407                  * @description Defines a base64 pad string
41408                  * @param {boolean}
41409                  * @return {Object} this
41410                  * @public
41411                  */
41412
41413
41414                 this.setUTF8 = function (a) {
41415                   if (typeof a === 'boolean') {
41416                     utf8 = a;
41417                   }
41418
41419                   return this;
41420                 }; // private methods
41421
41422                 /**
41423                  * Calculate the SHA-512 of a raw string
41424                  */
41425
41426
41427                 function rstr(s) {
41428                   s = utf8 ? utf8Encode(s) : s;
41429                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41430                 }
41431                 /**
41432                  * Calculate the HMAC-SHA1 of a key and some data (raw strings)
41433                  */
41434
41435
41436                 function rstr_hmac(key, data) {
41437                   var bkey, ipad, opad, i, hash;
41438                   key = utf8 ? utf8Encode(key) : key;
41439                   data = utf8 ? utf8Encode(data) : data;
41440                   bkey = rstr2binb(key);
41441
41442                   if (bkey.length > 16) {
41443                     bkey = binb(bkey, key.length * 8);
41444                   }
41445
41446                   ipad = Array(16), opad = Array(16);
41447
41448                   for (i = 0; i < 16; i += 1) {
41449                     ipad[i] = bkey[i] ^ 0x36363636;
41450                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41451                   }
41452
41453                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41454                   return binb2rstr(binb(opad.concat(hash), 512 + 160));
41455                 }
41456                 /**
41457                  * Calculate the SHA-1 of an array of big-endian words, and a bit length
41458                  */
41459
41460
41461                 function binb(x, len) {
41462                   var i,
41463                       j,
41464                       t,
41465                       olda,
41466                       oldb,
41467                       oldc,
41468                       oldd,
41469                       olde,
41470                       w = Array(80),
41471                       a = 1732584193,
41472                       b = -271733879,
41473                       c = -1732584194,
41474                       d = 271733878,
41475                       e = -1009589776;
41476                   /* append padding */
41477
41478                   x[len >> 5] |= 0x80 << 24 - len % 32;
41479                   x[(len + 64 >> 9 << 4) + 15] = len;
41480
41481                   for (i = 0; i < x.length; i += 16) {
41482                     olda = a;
41483                     oldb = b;
41484                     oldc = c;
41485                     oldd = d;
41486                     olde = e;
41487
41488                     for (j = 0; j < 80; j += 1) {
41489                       if (j < 16) {
41490                         w[j] = x[i + j];
41491                       } else {
41492                         w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
41493                       }
41494
41495                       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)));
41496                       e = d;
41497                       d = c;
41498                       c = bit_rol(b, 30);
41499                       b = a;
41500                       a = t;
41501                     }
41502
41503                     a = safe_add(a, olda);
41504                     b = safe_add(b, oldb);
41505                     c = safe_add(c, oldc);
41506                     d = safe_add(d, oldd);
41507                     e = safe_add(e, olde);
41508                   }
41509
41510                   return Array(a, b, c, d, e);
41511                 }
41512                 /**
41513                  * Perform the appropriate triplet combination function for the current
41514                  * iteration
41515                  */
41516
41517
41518                 function sha1_ft(t, b, c, d) {
41519                   if (t < 20) {
41520                     return b & c | ~b & d;
41521                   }
41522
41523                   if (t < 40) {
41524                     return b ^ c ^ d;
41525                   }
41526
41527                   if (t < 60) {
41528                     return b & c | b & d | c & d;
41529                   }
41530
41531                   return b ^ c ^ d;
41532                 }
41533                 /**
41534                  * Determine the appropriate additive constant for the current iteration
41535                  */
41536
41537
41538                 function sha1_kt(t) {
41539                   return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;
41540                 }
41541               },
41542
41543               /**
41544                * @class Hashes.SHA256
41545                * @param {config}
41546                *
41547                * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
41548                * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
41549                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41550                * See http://pajhome.org.uk/crypt/md5 for details.
41551                * Also http://anmar.eu.org/projects/jssha2/
41552                */
41553               SHA256: function SHA256(options) {
41554                 /**
41555                  * Private properties configuration variables. You may need to tweak these to be compatible with
41556                  * the server-side, but the defaults work in most cases.
41557                  * @see this.setUpperCase() method
41558                  * @see this.setPad() method
41559                  */
41560                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41561                     // hexadecimal output case format. false - lowercase; true - uppercase  */
41562                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41563
41564                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41565                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41566
41567                 /* enable/disable utf8 encoding */
41568                 sha256_K;
41569                 /* privileged (public) methods */
41570
41571                 this.hex = function (s) {
41572                   return rstr2hex(rstr(s, utf8));
41573                 };
41574
41575                 this.b64 = function (s) {
41576                   return rstr2b64(rstr(s, utf8), b64pad);
41577                 };
41578
41579                 this.any = function (s, e) {
41580                   return rstr2any(rstr(s, utf8), e);
41581                 };
41582
41583                 this.raw = function (s) {
41584                   return rstr(s, utf8);
41585                 };
41586
41587                 this.hex_hmac = function (k, d) {
41588                   return rstr2hex(rstr_hmac(k, d));
41589                 };
41590
41591                 this.b64_hmac = function (k, d) {
41592                   return rstr2b64(rstr_hmac(k, d), b64pad);
41593                 };
41594
41595                 this.any_hmac = function (k, d, e) {
41596                   return rstr2any(rstr_hmac(k, d), e);
41597                 };
41598                 /**
41599                  * Perform a simple self-test to see if the VM is working
41600                  * @return {String} Hexadecimal hash sample
41601                  * @public
41602                  */
41603
41604
41605                 this.vm_test = function () {
41606                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41607                 };
41608                 /**
41609                  * Enable/disable uppercase hexadecimal returned string
41610                  * @param {boolean}
41611                  * @return {Object} this
41612                  * @public
41613                  */
41614
41615
41616                 this.setUpperCase = function (a) {
41617                   if (typeof a === 'boolean') {
41618                     hexcase = a;
41619                   }
41620
41621                   return this;
41622                 };
41623                 /**
41624                  * @description Defines a base64 pad string
41625                  * @param {string} Pad
41626                  * @return {Object} this
41627                  * @public
41628                  */
41629
41630
41631                 this.setPad = function (a) {
41632                   b64pad = a || b64pad;
41633                   return this;
41634                 };
41635                 /**
41636                  * Defines a base64 pad string
41637                  * @param {boolean}
41638                  * @return {Object} this
41639                  * @public
41640                  */
41641
41642
41643                 this.setUTF8 = function (a) {
41644                   if (typeof a === 'boolean') {
41645                     utf8 = a;
41646                   }
41647
41648                   return this;
41649                 }; // private methods
41650
41651                 /**
41652                  * Calculate the SHA-512 of a raw string
41653                  */
41654
41655
41656                 function rstr(s, utf8) {
41657                   s = utf8 ? utf8Encode(s) : s;
41658                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41659                 }
41660                 /**
41661                  * Calculate the HMAC-sha256 of a key and some data (raw strings)
41662                  */
41663
41664
41665                 function rstr_hmac(key, data) {
41666                   key = utf8 ? utf8Encode(key) : key;
41667                   data = utf8 ? utf8Encode(data) : data;
41668                   var hash,
41669                       i = 0,
41670                       bkey = rstr2binb(key),
41671                       ipad = Array(16),
41672                       opad = Array(16);
41673
41674                   if (bkey.length > 16) {
41675                     bkey = binb(bkey, key.length * 8);
41676                   }
41677
41678                   for (; i < 16; i += 1) {
41679                     ipad[i] = bkey[i] ^ 0x36363636;
41680                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41681                   }
41682
41683                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41684                   return binb2rstr(binb(opad.concat(hash), 512 + 256));
41685                 }
41686                 /*
41687                  * Main sha256 function, with its support functions
41688                  */
41689
41690
41691                 function sha256_S(X, n) {
41692                   return X >>> n | X << 32 - n;
41693                 }
41694
41695                 function sha256_R(X, n) {
41696                   return X >>> n;
41697                 }
41698
41699                 function sha256_Ch(x, y, z) {
41700                   return x & y ^ ~x & z;
41701                 }
41702
41703                 function sha256_Maj(x, y, z) {
41704                   return x & y ^ x & z ^ y & z;
41705                 }
41706
41707                 function sha256_Sigma0256(x) {
41708                   return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22);
41709                 }
41710
41711                 function sha256_Sigma1256(x) {
41712                   return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25);
41713                 }
41714
41715                 function sha256_Gamma0256(x) {
41716                   return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3);
41717                 }
41718
41719                 function sha256_Gamma1256(x) {
41720                   return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10);
41721                 }
41722
41723                 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];
41724
41725                 function binb(m, l) {
41726                   var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225];
41727                   var W = new Array(64);
41728                   var a, b, c, d, e, f, g, h;
41729                   var i, j, T1, T2;
41730                   /* append padding */
41731
41732                   m[l >> 5] |= 0x80 << 24 - l % 32;
41733                   m[(l + 64 >> 9 << 4) + 15] = l;
41734
41735                   for (i = 0; i < m.length; i += 16) {
41736                     a = HASH[0];
41737                     b = HASH[1];
41738                     c = HASH[2];
41739                     d = HASH[3];
41740                     e = HASH[4];
41741                     f = HASH[5];
41742                     g = HASH[6];
41743                     h = HASH[7];
41744
41745                     for (j = 0; j < 64; j += 1) {
41746                       if (j < 16) {
41747                         W[j] = m[j + i];
41748                       } else {
41749                         W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]);
41750                       }
41751
41752                       T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]);
41753                       T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
41754                       h = g;
41755                       g = f;
41756                       f = e;
41757                       e = safe_add(d, T1);
41758                       d = c;
41759                       c = b;
41760                       b = a;
41761                       a = safe_add(T1, T2);
41762                     }
41763
41764                     HASH[0] = safe_add(a, HASH[0]);
41765                     HASH[1] = safe_add(b, HASH[1]);
41766                     HASH[2] = safe_add(c, HASH[2]);
41767                     HASH[3] = safe_add(d, HASH[3]);
41768                     HASH[4] = safe_add(e, HASH[4]);
41769                     HASH[5] = safe_add(f, HASH[5]);
41770                     HASH[6] = safe_add(g, HASH[6]);
41771                     HASH[7] = safe_add(h, HASH[7]);
41772                   }
41773
41774                   return HASH;
41775                 }
41776               },
41777
41778               /**
41779                * @class Hashes.SHA512
41780                * @param {config}
41781                *
41782                * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
41783                * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
41784                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41785                * See http://pajhome.org.uk/crypt/md5 for details.
41786                */
41787               SHA512: function SHA512(options) {
41788                 /**
41789                  * Private properties configuration variables. You may need to tweak these to be compatible with
41790                  * the server-side, but the defaults work in most cases.
41791                  * @see this.setUpperCase() method
41792                  * @see this.setPad() method
41793                  */
41794                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41795
41796                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
41797                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41798
41799                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41800                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41801
41802                 /* enable/disable utf8 encoding */
41803                 sha512_k;
41804                 /* privileged (public) methods */
41805
41806                 this.hex = function (s) {
41807                   return rstr2hex(rstr(s));
41808                 };
41809
41810                 this.b64 = function (s) {
41811                   return rstr2b64(rstr(s), b64pad);
41812                 };
41813
41814                 this.any = function (s, e) {
41815                   return rstr2any(rstr(s), e);
41816                 };
41817
41818                 this.raw = function (s) {
41819                   return rstr(s);
41820                 };
41821
41822                 this.hex_hmac = function (k, d) {
41823                   return rstr2hex(rstr_hmac(k, d));
41824                 };
41825
41826                 this.b64_hmac = function (k, d) {
41827                   return rstr2b64(rstr_hmac(k, d), b64pad);
41828                 };
41829
41830                 this.any_hmac = function (k, d, e) {
41831                   return rstr2any(rstr_hmac(k, d), e);
41832                 };
41833                 /**
41834                  * Perform a simple self-test to see if the VM is working
41835                  * @return {String} Hexadecimal hash sample
41836                  * @public
41837                  */
41838
41839
41840                 this.vm_test = function () {
41841                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41842                 };
41843                 /**
41844                  * @description Enable/disable uppercase hexadecimal returned string
41845                  * @param {boolean}
41846                  * @return {Object} this
41847                  * @public
41848                  */
41849
41850
41851                 this.setUpperCase = function (a) {
41852                   if (typeof a === 'boolean') {
41853                     hexcase = a;
41854                   }
41855
41856                   return this;
41857                 };
41858                 /**
41859                  * @description Defines a base64 pad string
41860                  * @param {string} Pad
41861                  * @return {Object} this
41862                  * @public
41863                  */
41864
41865
41866                 this.setPad = function (a) {
41867                   b64pad = a || b64pad;
41868                   return this;
41869                 };
41870                 /**
41871                  * @description Defines a base64 pad string
41872                  * @param {boolean}
41873                  * @return {Object} this
41874                  * @public
41875                  */
41876
41877
41878                 this.setUTF8 = function (a) {
41879                   if (typeof a === 'boolean') {
41880                     utf8 = a;
41881                   }
41882
41883                   return this;
41884                 };
41885                 /* private methods */
41886
41887                 /**
41888                  * Calculate the SHA-512 of a raw string
41889                  */
41890
41891
41892                 function rstr(s) {
41893                   s = utf8 ? utf8Encode(s) : s;
41894                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41895                 }
41896                 /*
41897                  * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
41898                  */
41899
41900
41901                 function rstr_hmac(key, data) {
41902                   key = utf8 ? utf8Encode(key) : key;
41903                   data = utf8 ? utf8Encode(data) : data;
41904                   var hash,
41905                       i = 0,
41906                       bkey = rstr2binb(key),
41907                       ipad = Array(32),
41908                       opad = Array(32);
41909
41910                   if (bkey.length > 32) {
41911                     bkey = binb(bkey, key.length * 8);
41912                   }
41913
41914                   for (; i < 32; i += 1) {
41915                     ipad[i] = bkey[i] ^ 0x36363636;
41916                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41917                   }
41918
41919                   hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
41920                   return binb2rstr(binb(opad.concat(hash), 1024 + 512));
41921                 }
41922                 /**
41923                  * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
41924                  */
41925
41926
41927                 function binb(x, len) {
41928                   var j,
41929                       i,
41930                       l,
41931                       W = new Array(80),
41932                       hash = new Array(16),
41933                       //Initial hash values
41934                   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)],
41935                       T1 = new int64(0, 0),
41936                       T2 = new int64(0, 0),
41937                       a = new int64(0, 0),
41938                       b = new int64(0, 0),
41939                       c = new int64(0, 0),
41940                       d = new int64(0, 0),
41941                       e = new int64(0, 0),
41942                       f = new int64(0, 0),
41943                       g = new int64(0, 0),
41944                       h = new int64(0, 0),
41945                       //Temporary variables not specified by the document
41946                   s0 = new int64(0, 0),
41947                       s1 = new int64(0, 0),
41948                       Ch = new int64(0, 0),
41949                       Maj = new int64(0, 0),
41950                       r1 = new int64(0, 0),
41951                       r2 = new int64(0, 0),
41952                       r3 = new int64(0, 0);
41953
41954                   if (sha512_k === undefined) {
41955                     //SHA512 constants
41956                     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)];
41957                   }
41958
41959                   for (i = 0; i < 80; i += 1) {
41960                     W[i] = new int64(0, 0);
41961                   } // append padding to the source string. The format is described in the FIPS.
41962
41963
41964                   x[len >> 5] |= 0x80 << 24 - (len & 0x1f);
41965                   x[(len + 128 >> 10 << 5) + 31] = len;
41966                   l = x.length;
41967
41968                   for (i = 0; i < l; i += 32) {
41969                     //32 dwords is the block size
41970                     int64copy(a, H[0]);
41971                     int64copy(b, H[1]);
41972                     int64copy(c, H[2]);
41973                     int64copy(d, H[3]);
41974                     int64copy(e, H[4]);
41975                     int64copy(f, H[5]);
41976                     int64copy(g, H[6]);
41977                     int64copy(h, H[7]);
41978
41979                     for (j = 0; j < 16; j += 1) {
41980                       W[j].h = x[i + 2 * j];
41981                       W[j].l = x[i + 2 * j + 1];
41982                     }
41983
41984                     for (j = 16; j < 80; j += 1) {
41985                       //sigma1
41986                       int64rrot(r1, W[j - 2], 19);
41987                       int64revrrot(r2, W[j - 2], 29);
41988                       int64shr(r3, W[j - 2], 6);
41989                       s1.l = r1.l ^ r2.l ^ r3.l;
41990                       s1.h = r1.h ^ r2.h ^ r3.h; //sigma0
41991
41992                       int64rrot(r1, W[j - 15], 1);
41993                       int64rrot(r2, W[j - 15], 8);
41994                       int64shr(r3, W[j - 15], 7);
41995                       s0.l = r1.l ^ r2.l ^ r3.l;
41996                       s0.h = r1.h ^ r2.h ^ r3.h;
41997                       int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
41998                     }
41999
42000                     for (j = 0; j < 80; j += 1) {
42001                       //Ch
42002                       Ch.l = e.l & f.l ^ ~e.l & g.l;
42003                       Ch.h = e.h & f.h ^ ~e.h & g.h; //Sigma1
42004
42005                       int64rrot(r1, e, 14);
42006                       int64rrot(r2, e, 18);
42007                       int64revrrot(r3, e, 9);
42008                       s1.l = r1.l ^ r2.l ^ r3.l;
42009                       s1.h = r1.h ^ r2.h ^ r3.h; //Sigma0
42010
42011                       int64rrot(r1, a, 28);
42012                       int64revrrot(r2, a, 2);
42013                       int64revrrot(r3, a, 7);
42014                       s0.l = r1.l ^ r2.l ^ r3.l;
42015                       s0.h = r1.h ^ r2.h ^ r3.h; //Maj
42016
42017                       Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l;
42018                       Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h;
42019                       int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
42020                       int64add(T2, s0, Maj);
42021                       int64copy(h, g);
42022                       int64copy(g, f);
42023                       int64copy(f, e);
42024                       int64add(e, d, T1);
42025                       int64copy(d, c);
42026                       int64copy(c, b);
42027                       int64copy(b, a);
42028                       int64add(a, T1, T2);
42029                     }
42030
42031                     int64add(H[0], H[0], a);
42032                     int64add(H[1], H[1], b);
42033                     int64add(H[2], H[2], c);
42034                     int64add(H[3], H[3], d);
42035                     int64add(H[4], H[4], e);
42036                     int64add(H[5], H[5], f);
42037                     int64add(H[6], H[6], g);
42038                     int64add(H[7], H[7], h);
42039                   } //represent the hash as an array of 32-bit dwords
42040
42041
42042                   for (i = 0; i < 8; i += 1) {
42043                     hash[2 * i] = H[i].h;
42044                     hash[2 * i + 1] = H[i].l;
42045                   }
42046
42047                   return hash;
42048                 } //A constructor for 64-bit numbers
42049
42050
42051                 function int64(h, l) {
42052                   this.h = h;
42053                   this.l = l; //this.toString = int64toString;
42054                 } //Copies src into dst, assuming both are 64-bit numbers
42055
42056
42057                 function int64copy(dst, src) {
42058                   dst.h = src.h;
42059                   dst.l = src.l;
42060                 } //Right-rotates a 64-bit number by shift
42061                 //Won't handle cases of shift>=32
42062                 //The function revrrot() is for that
42063
42064
42065                 function int64rrot(dst, x, shift) {
42066                   dst.l = x.l >>> shift | x.h << 32 - shift;
42067                   dst.h = x.h >>> shift | x.l << 32 - shift;
42068                 } //Reverses the dwords of the source and then rotates right by shift.
42069                 //This is equivalent to rotation by 32+shift
42070
42071
42072                 function int64revrrot(dst, x, shift) {
42073                   dst.l = x.h >>> shift | x.l << 32 - shift;
42074                   dst.h = x.l >>> shift | x.h << 32 - shift;
42075                 } //Bitwise-shifts right a 64-bit number by shift
42076                 //Won't handle shift>=32, but it's never needed in SHA512
42077
42078
42079                 function int64shr(dst, x, shift) {
42080                   dst.l = x.l >>> shift | x.h << 32 - shift;
42081                   dst.h = x.h >>> shift;
42082                 } //Adds two 64-bit numbers
42083                 //Like the original implementation, does not rely on 32-bit operations
42084
42085
42086                 function int64add(dst, x, y) {
42087                   var w0 = (x.l & 0xffff) + (y.l & 0xffff);
42088                   var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
42089                   var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
42090                   var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
42091                   dst.l = w0 & 0xffff | w1 << 16;
42092                   dst.h = w2 & 0xffff | w3 << 16;
42093                 } //Same, except with 4 addends. Works faster than adding them one by one.
42094
42095
42096                 function int64add4(dst, a, b, c, d) {
42097                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
42098                   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
42099                   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
42100                   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
42101                   dst.l = w0 & 0xffff | w1 << 16;
42102                   dst.h = w2 & 0xffff | w3 << 16;
42103                 } //Same, except with 5 addends
42104
42105
42106                 function int64add5(dst, a, b, c, d, e) {
42107                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
42108                       w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
42109                       w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
42110                       w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
42111                   dst.l = w0 & 0xffff | w1 << 16;
42112                   dst.h = w2 & 0xffff | w3 << 16;
42113                 }
42114               },
42115
42116               /**
42117                * @class Hashes.RMD160
42118                * @constructor
42119                * @param {Object} [config]
42120                *
42121                * A JavaScript implementation of the RIPEMD-160 Algorithm
42122                * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
42123                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
42124                * See http://pajhome.org.uk/crypt/md5 for details.
42125                * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
42126                */
42127               RMD160: function RMD160(options) {
42128                 /**
42129                  * Private properties configuration variables. You may need to tweak these to be compatible with
42130                  * the server-side, but the defaults work in most cases.
42131                  * @see this.setUpperCase() method
42132                  * @see this.setPad() method
42133                  */
42134                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
42135
42136                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
42137                 b64pad = options && typeof options.pad === 'string' ? options.pa : '=',
42138
42139                 /* base-64 pad character. Default '=' for strict RFC compliance   */
42140                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
42141
42142                 /* enable/disable utf8 encoding */
42143                 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],
42144                     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],
42145                     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],
42146                     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];
42147                 /* privileged (public) methods */
42148
42149                 this.hex = function (s) {
42150                   return rstr2hex(rstr(s));
42151                 };
42152
42153                 this.b64 = function (s) {
42154                   return rstr2b64(rstr(s), b64pad);
42155                 };
42156
42157                 this.any = function (s, e) {
42158                   return rstr2any(rstr(s), e);
42159                 };
42160
42161                 this.raw = function (s) {
42162                   return rstr(s);
42163                 };
42164
42165                 this.hex_hmac = function (k, d) {
42166                   return rstr2hex(rstr_hmac(k, d));
42167                 };
42168
42169                 this.b64_hmac = function (k, d) {
42170                   return rstr2b64(rstr_hmac(k, d), b64pad);
42171                 };
42172
42173                 this.any_hmac = function (k, d, e) {
42174                   return rstr2any(rstr_hmac(k, d), e);
42175                 };
42176                 /**
42177                  * Perform a simple self-test to see if the VM is working
42178                  * @return {String} Hexadecimal hash sample
42179                  * @public
42180                  */
42181
42182
42183                 this.vm_test = function () {
42184                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
42185                 };
42186                 /**
42187                  * @description Enable/disable uppercase hexadecimal returned string
42188                  * @param {boolean}
42189                  * @return {Object} this
42190                  * @public
42191                  */
42192
42193
42194                 this.setUpperCase = function (a) {
42195                   if (typeof a === 'boolean') {
42196                     hexcase = a;
42197                   }
42198
42199                   return this;
42200                 };
42201                 /**
42202                  * @description Defines a base64 pad string
42203                  * @param {string} Pad
42204                  * @return {Object} this
42205                  * @public
42206                  */
42207
42208
42209                 this.setPad = function (a) {
42210                   if (typeof a !== 'undefined') {
42211                     b64pad = a;
42212                   }
42213
42214                   return this;
42215                 };
42216                 /**
42217                  * @description Defines a base64 pad string
42218                  * @param {boolean}
42219                  * @return {Object} this
42220                  * @public
42221                  */
42222
42223
42224                 this.setUTF8 = function (a) {
42225                   if (typeof a === 'boolean') {
42226                     utf8 = a;
42227                   }
42228
42229                   return this;
42230                 };
42231                 /* private methods */
42232
42233                 /**
42234                  * Calculate the rmd160 of a raw string
42235                  */
42236
42237
42238                 function rstr(s) {
42239                   s = utf8 ? utf8Encode(s) : s;
42240                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
42241                 }
42242                 /**
42243                  * Calculate the HMAC-rmd160 of a key and some data (raw strings)
42244                  */
42245
42246
42247                 function rstr_hmac(key, data) {
42248                   key = utf8 ? utf8Encode(key) : key;
42249                   data = utf8 ? utf8Encode(data) : data;
42250                   var i,
42251                       hash,
42252                       bkey = rstr2binl(key),
42253                       ipad = Array(16),
42254                       opad = Array(16);
42255
42256                   if (bkey.length > 16) {
42257                     bkey = binl(bkey, key.length * 8);
42258                   }
42259
42260                   for (i = 0; i < 16; i += 1) {
42261                     ipad[i] = bkey[i] ^ 0x36363636;
42262                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
42263                   }
42264
42265                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
42266                   return binl2rstr(binl(opad.concat(hash), 512 + 160));
42267                 }
42268                 /**
42269                  * Convert an array of little-endian words to a string
42270                  */
42271
42272
42273                 function binl2rstr(input) {
42274                   var i,
42275                       output = '',
42276                       l = input.length * 32;
42277
42278                   for (i = 0; i < l; i += 8) {
42279                     output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
42280                   }
42281
42282                   return output;
42283                 }
42284                 /**
42285                  * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
42286                  */
42287
42288
42289                 function binl(x, len) {
42290                   var T,
42291                       j,
42292                       i,
42293                       l,
42294                       h0 = 0x67452301,
42295                       h1 = 0xefcdab89,
42296                       h2 = 0x98badcfe,
42297                       h3 = 0x10325476,
42298                       h4 = 0xc3d2e1f0,
42299                       A1,
42300                       B1,
42301                       C1,
42302                       D1,
42303                       E1,
42304                       A2,
42305                       B2,
42306                       C2,
42307                       D2,
42308                       E2;
42309                   /* append padding */
42310
42311                   x[len >> 5] |= 0x80 << len % 32;
42312                   x[(len + 64 >>> 9 << 4) + 14] = len;
42313                   l = x.length;
42314
42315                   for (i = 0; i < l; i += 16) {
42316                     A1 = A2 = h0;
42317                     B1 = B2 = h1;
42318                     C1 = C2 = h2;
42319                     D1 = D2 = h3;
42320                     E1 = E2 = h4;
42321
42322                     for (j = 0; j <= 79; j += 1) {
42323                       T = safe_add(A1, rmd160_f(j, B1, C1, D1));
42324                       T = safe_add(T, x[i + rmd160_r1[j]]);
42325                       T = safe_add(T, rmd160_K1(j));
42326                       T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
42327                       A1 = E1;
42328                       E1 = D1;
42329                       D1 = bit_rol(C1, 10);
42330                       C1 = B1;
42331                       B1 = T;
42332                       T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
42333                       T = safe_add(T, x[i + rmd160_r2[j]]);
42334                       T = safe_add(T, rmd160_K2(j));
42335                       T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
42336                       A2 = E2;
42337                       E2 = D2;
42338                       D2 = bit_rol(C2, 10);
42339                       C2 = B2;
42340                       B2 = T;
42341                     }
42342
42343                     T = safe_add(h1, safe_add(C1, D2));
42344                     h1 = safe_add(h2, safe_add(D1, E2));
42345                     h2 = safe_add(h3, safe_add(E1, A2));
42346                     h3 = safe_add(h4, safe_add(A1, B2));
42347                     h4 = safe_add(h0, safe_add(B1, C2));
42348                     h0 = T;
42349                   }
42350
42351                   return [h0, h1, h2, h3, h4];
42352                 } // specific algorithm methods
42353
42354
42355                 function rmd160_f(j, x, y, z) {
42356                   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';
42357                 }
42358
42359                 function rmd160_K1(j) {
42360                   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';
42361                 }
42362
42363                 function rmd160_K2(j) {
42364                   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';
42365                 }
42366               }
42367             }; // exposes Hashes
42368
42369             (function (window, undefined$1) {
42370               var freeExports = false;
42371
42372               {
42373                 freeExports = exports;
42374
42375                 if (exports && _typeof(commonjsGlobal) === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
42376                   window = commonjsGlobal;
42377                 }
42378               }
42379
42380               if (typeof undefined$1 === 'function' && _typeof(undefined$1.amd) === 'object' && undefined$1.amd) {
42381                 // define as an anonymous module, so, through path mapping, it can be aliased
42382                 undefined$1(function () {
42383                   return Hashes;
42384                 });
42385               } else if (freeExports) {
42386                 // in Node.js or RingoJS v0.8.0+
42387                 if ( module && module.exports === freeExports) {
42388                   module.exports = Hashes;
42389                 } // in Narwhal or RingoJS v0.7.0-
42390                 else {
42391                     freeExports.Hashes = Hashes;
42392                   }
42393               } else {
42394                 // in a browser or Rhino
42395                 window.Hashes = Hashes;
42396               }
42397             })(this);
42398           })(); // IIFE
42399
42400         });
42401
42402         var immutable = extend$2;
42403         var hasOwnProperty$2 = Object.prototype.hasOwnProperty;
42404
42405         function extend$2() {
42406           var target = {};
42407
42408           for (var i = 0; i < arguments.length; i++) {
42409             var source = arguments[i];
42410
42411             for (var key in source) {
42412               if (hasOwnProperty$2.call(source, key)) {
42413                 target[key] = source[key];
42414               }
42415             }
42416           }
42417
42418           return target;
42419         }
42420
42421         var sha1 = new hashes.SHA1();
42422         var ohauth = {};
42423
42424         ohauth.qsString = function (obj) {
42425           return Object.keys(obj).sort().map(function (key) {
42426             return ohauth.percentEncode(key) + '=' + ohauth.percentEncode(obj[key]);
42427           }).join('&');
42428         };
42429
42430         ohauth.stringQs = function (str) {
42431           return str.split('&').filter(function (pair) {
42432             return pair !== '';
42433           }).reduce(function (obj, pair) {
42434             var parts = pair.split('=');
42435             obj[decodeURIComponent(parts[0])] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
42436             return obj;
42437           }, {});
42438         };
42439
42440         ohauth.rawxhr = function (method, url, data, headers, callback) {
42441           var xhr = new XMLHttpRequest(),
42442               twoHundred = /^20\d$/;
42443
42444           xhr.onreadystatechange = function () {
42445             if (4 === xhr.readyState && 0 !== xhr.status) {
42446               if (twoHundred.test(xhr.status)) callback(null, xhr);else return callback(xhr, null);
42447             }
42448           };
42449
42450           xhr.onerror = function (e) {
42451             return callback(e, null);
42452           };
42453
42454           xhr.open(method, url, true);
42455
42456           for (var h in headers) {
42457             xhr.setRequestHeader(h, headers[h]);
42458           }
42459
42460           xhr.send(data);
42461           return xhr;
42462         };
42463
42464         ohauth.xhr = function (method, url, auth, data, options, callback) {
42465           var headers = options && options.header || {
42466             'Content-Type': 'application/x-www-form-urlencoded'
42467           };
42468           headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
42469           return ohauth.rawxhr(method, url, data, headers, callback);
42470         };
42471
42472         ohauth.nonce = function () {
42473           for (var o = ''; o.length < 6;) {
42474             o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
42475           }
42476
42477           return o;
42478         };
42479
42480         ohauth.authHeader = function (obj) {
42481           return Object.keys(obj).sort().map(function (key) {
42482             return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
42483           }).join(', ');
42484         };
42485
42486         ohauth.timestamp = function () {
42487           return ~~(+new Date() / 1000);
42488         };
42489
42490         ohauth.percentEncode = function (s) {
42491           return encodeURIComponent(s).replace(/\!/g, '%21').replace(/\'/g, '%27').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
42492         };
42493
42494         ohauth.baseString = function (method, url, params) {
42495           if (params.oauth_signature) delete params.oauth_signature;
42496           return [method, ohauth.percentEncode(url), ohauth.percentEncode(ohauth.qsString(params))].join('&');
42497         };
42498
42499         ohauth.signature = function (oauth_secret, token_secret, baseString) {
42500           return sha1.b64_hmac(ohauth.percentEncode(oauth_secret) + '&' + ohauth.percentEncode(token_secret), baseString);
42501         };
42502         /**
42503          * Takes an options object for configuration (consumer_key,
42504          * consumer_secret, version, signature_method, token, token_secret)
42505          * and returns a function that generates the Authorization header
42506          * for given data.
42507          *
42508          * The returned function takes these parameters:
42509          * - method: GET/POST/...
42510          * - uri: full URI with protocol, port, path and query string
42511          * - extra_params: any extra parameters (that are passed in the POST data),
42512          *   can be an object or a from-urlencoded string.
42513          *
42514          * Returned function returns full OAuth header with "OAuth" string in it.
42515          */
42516
42517
42518         ohauth.headerGenerator = function (options) {
42519           options = options || {};
42520           var consumer_key = options.consumer_key || '',
42521               consumer_secret = options.consumer_secret || '',
42522               signature_method = options.signature_method || 'HMAC-SHA1',
42523               version = options.version || '1.0',
42524               token = options.token || '',
42525               token_secret = options.token_secret || '';
42526           return function (method, uri, extra_params) {
42527             method = method.toUpperCase();
42528
42529             if (typeof extra_params === 'string' && extra_params.length > 0) {
42530               extra_params = ohauth.stringQs(extra_params);
42531             }
42532
42533             var uri_parts = uri.split('?', 2),
42534                 base_uri = uri_parts[0];
42535             var query_params = uri_parts.length === 2 ? ohauth.stringQs(uri_parts[1]) : {};
42536             var oauth_params = {
42537               oauth_consumer_key: consumer_key,
42538               oauth_signature_method: signature_method,
42539               oauth_version: version,
42540               oauth_timestamp: ohauth.timestamp(),
42541               oauth_nonce: ohauth.nonce()
42542             };
42543             if (token) oauth_params.oauth_token = token;
42544             var all_params = immutable({}, oauth_params, query_params, extra_params),
42545                 base_str = ohauth.baseString(method, base_uri, all_params);
42546             oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
42547             return 'OAuth ' + ohauth.authHeader(oauth_params);
42548           };
42549         };
42550
42551         var ohauth_1 = ohauth;
42552
42553         var resolveUrl$1 = createCommonjsModule(function (module, exports) {
42554           // Copyright 2014 Simon Lydell
42555           // X11 (“MIT”) Licensed. (See LICENSE.)
42556           void function (root, factory) {
42557             {
42558               module.exports = factory();
42559             }
42560           }(commonjsGlobal, function () {
42561             function resolveUrl()
42562             /* ...urls */
42563             {
42564               var numUrls = arguments.length;
42565
42566               if (numUrls === 0) {
42567                 throw new Error("resolveUrl requires at least one argument; got none.");
42568               }
42569
42570               var base = document.createElement("base");
42571               base.href = arguments[0];
42572
42573               if (numUrls === 1) {
42574                 return base.href;
42575               }
42576
42577               var head = document.getElementsByTagName("head")[0];
42578               head.insertBefore(base, head.firstChild);
42579               var a = document.createElement("a");
42580               var resolved;
42581
42582               for (var index = 1; index < numUrls; index++) {
42583                 a.href = arguments[index];
42584                 resolved = a.href;
42585                 base.href = resolved;
42586               }
42587
42588               head.removeChild(base);
42589               return resolved;
42590             }
42591
42592             return resolveUrl;
42593           });
42594         });
42595
42596         var assign = make_assign();
42597         var create$1 = make_create();
42598         var trim$3 = make_trim();
42599         var Global = typeof window !== 'undefined' ? window : commonjsGlobal;
42600         var util = {
42601           assign: assign,
42602           create: create$1,
42603           trim: trim$3,
42604           bind: bind$1,
42605           slice: slice$2,
42606           each: each,
42607           map: map$1,
42608           pluck: pluck,
42609           isList: isList,
42610           isFunction: isFunction,
42611           isObject: isObject$2,
42612           Global: Global
42613         };
42614
42615         function make_assign() {
42616           if (Object.assign) {
42617             return Object.assign;
42618           } else {
42619             return function shimAssign(obj, props1, props2, etc) {
42620               for (var i = 1; i < arguments.length; i++) {
42621                 each(Object(arguments[i]), function (val, key) {
42622                   obj[key] = val;
42623                 });
42624               }
42625
42626               return obj;
42627             };
42628           }
42629         }
42630
42631         function make_create() {
42632           if (Object.create) {
42633             return function create(obj, assignProps1, assignProps2, etc) {
42634               var assignArgsList = slice$2(arguments, 1);
42635               return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
42636             };
42637           } else {
42638             var F = function F() {}; // eslint-disable-line no-inner-declarations
42639
42640
42641             return function create(obj, assignProps1, assignProps2, etc) {
42642               var assignArgsList = slice$2(arguments, 1);
42643               F.prototype = obj;
42644               return assign.apply(this, [new F()].concat(assignArgsList));
42645             };
42646           }
42647         }
42648
42649         function make_trim() {
42650           if (String.prototype.trim) {
42651             return function trim(str) {
42652               return String.prototype.trim.call(str);
42653             };
42654           } else {
42655             return function trim(str) {
42656               return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
42657             };
42658           }
42659         }
42660
42661         function bind$1(obj, fn) {
42662           return function () {
42663             return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
42664           };
42665         }
42666
42667         function slice$2(arr, index) {
42668           return Array.prototype.slice.call(arr, index || 0);
42669         }
42670
42671         function each(obj, fn) {
42672           pluck(obj, function (val, key) {
42673             fn(val, key);
42674             return false;
42675           });
42676         }
42677
42678         function map$1(obj, fn) {
42679           var res = isList(obj) ? [] : {};
42680           pluck(obj, function (v, k) {
42681             res[k] = fn(v, k);
42682             return false;
42683           });
42684           return res;
42685         }
42686
42687         function pluck(obj, fn) {
42688           if (isList(obj)) {
42689             for (var i = 0; i < obj.length; i++) {
42690               if (fn(obj[i], i)) {
42691                 return obj[i];
42692               }
42693             }
42694           } else {
42695             for (var key in obj) {
42696               if (obj.hasOwnProperty(key)) {
42697                 if (fn(obj[key], key)) {
42698                   return obj[key];
42699                 }
42700               }
42701             }
42702           }
42703         }
42704
42705         function isList(val) {
42706           return val != null && typeof val != 'function' && typeof val.length == 'number';
42707         }
42708
42709         function isFunction(val) {
42710           return val && {}.toString.call(val) === '[object Function]';
42711         }
42712
42713         function isObject$2(val) {
42714           return val && {}.toString.call(val) === '[object Object]';
42715         }
42716
42717         var slice$3 = util.slice;
42718         var pluck$1 = util.pluck;
42719         var each$1 = util.each;
42720         var bind$2 = util.bind;
42721         var create$2 = util.create;
42722         var isList$1 = util.isList;
42723         var isFunction$1 = util.isFunction;
42724         var isObject$3 = util.isObject;
42725         var storeEngine = {
42726           createStore: _createStore
42727         };
42728         var storeAPI = {
42729           version: '2.0.12',
42730           enabled: false,
42731           // get returns the value of the given key. If that value
42732           // is undefined, it returns optionalDefaultValue instead.
42733           get: function get(key, optionalDefaultValue) {
42734             var data = this.storage.read(this._namespacePrefix + key);
42735             return this._deserialize(data, optionalDefaultValue);
42736           },
42737           // set will store the given value at key and returns value.
42738           // Calling set with value === undefined is equivalent to calling remove.
42739           set: function set(key, value) {
42740             if (value === undefined) {
42741               return this.remove(key);
42742             }
42743
42744             this.storage.write(this._namespacePrefix + key, this._serialize(value));
42745             return value;
42746           },
42747           // remove deletes the key and value stored at the given key.
42748           remove: function remove(key) {
42749             this.storage.remove(this._namespacePrefix + key);
42750           },
42751           // each will call the given callback once for each key-value pair
42752           // in this store.
42753           each: function each(callback) {
42754             var self = this;
42755             this.storage.each(function (val, namespacedKey) {
42756               callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
42757             });
42758           },
42759           // clearAll will remove all the stored key-value pairs in this store.
42760           clearAll: function clearAll() {
42761             this.storage.clearAll();
42762           },
42763           // additional functionality that can't live in plugins
42764           // ---------------------------------------------------
42765           // hasNamespace returns true if this store instance has the given namespace.
42766           hasNamespace: function hasNamespace(namespace) {
42767             return this._namespacePrefix == '__storejs_' + namespace + '_';
42768           },
42769           // createStore creates a store.js instance with the first
42770           // functioning storage in the list of storage candidates,
42771           // and applies the the given mixins to the instance.
42772           createStore: function createStore() {
42773             return _createStore.apply(this, arguments);
42774           },
42775           addPlugin: function addPlugin(plugin) {
42776             this._addPlugin(plugin);
42777           },
42778           namespace: function namespace(_namespace) {
42779             return _createStore(this.storage, this.plugins, _namespace);
42780           }
42781         };
42782
42783         function _warn() {
42784           var _console = typeof console == 'undefined' ? null : console;
42785
42786           if (!_console) {
42787             return;
42788           }
42789
42790           var fn = _console.warn ? _console.warn : _console.log;
42791           fn.apply(_console, arguments);
42792         }
42793
42794         function _createStore(storages, plugins, namespace) {
42795           if (!namespace) {
42796             namespace = '';
42797           }
42798
42799           if (storages && !isList$1(storages)) {
42800             storages = [storages];
42801           }
42802
42803           if (plugins && !isList$1(plugins)) {
42804             plugins = [plugins];
42805           }
42806
42807           var namespacePrefix = namespace ? '__storejs_' + namespace + '_' : '';
42808           var namespaceRegexp = namespace ? new RegExp('^' + namespacePrefix) : null;
42809           var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
42810
42811           if (!legalNamespaces.test(namespace)) {
42812             throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes');
42813           }
42814
42815           var _privateStoreProps = {
42816             _namespacePrefix: namespacePrefix,
42817             _namespaceRegexp: namespaceRegexp,
42818             _testStorage: function _testStorage(storage) {
42819               try {
42820                 var testStr = '__storejs__test__';
42821                 storage.write(testStr, testStr);
42822                 var ok = storage.read(testStr) === testStr;
42823                 storage.remove(testStr);
42824                 return ok;
42825               } catch (e) {
42826                 return false;
42827               }
42828             },
42829             _assignPluginFnProp: function _assignPluginFnProp(pluginFnProp, propName) {
42830               var oldFn = this[propName];
42831
42832               this[propName] = function pluginFn() {
42833                 var args = slice$3(arguments, 0);
42834                 var self = this; // super_fn calls the old function which was overwritten by
42835                 // this mixin.
42836
42837                 function super_fn() {
42838                   if (!oldFn) {
42839                     return;
42840                   }
42841
42842                   each$1(arguments, function (arg, i) {
42843                     args[i] = arg;
42844                   });
42845                   return oldFn.apply(self, args);
42846                 } // Give mixing function access to super_fn by prefixing all mixin function
42847                 // arguments with super_fn.
42848
42849
42850                 var newFnArgs = [super_fn].concat(args);
42851                 return pluginFnProp.apply(self, newFnArgs);
42852               };
42853             },
42854             _serialize: function _serialize(obj) {
42855               return JSON.stringify(obj);
42856             },
42857             _deserialize: function _deserialize(strVal, defaultVal) {
42858               if (!strVal) {
42859                 return defaultVal;
42860               } // It is possible that a raw string value has been previously stored
42861               // in a storage without using store.js, meaning it will be a raw
42862               // string value instead of a JSON serialized string. By defaulting
42863               // to the raw string value in case of a JSON parse error, we allow
42864               // for past stored values to be forwards-compatible with store.js
42865
42866
42867               var val = '';
42868
42869               try {
42870                 val = JSON.parse(strVal);
42871               } catch (e) {
42872                 val = strVal;
42873               }
42874
42875               return val !== undefined ? val : defaultVal;
42876             },
42877             _addStorage: function _addStorage(storage) {
42878               if (this.enabled) {
42879                 return;
42880               }
42881
42882               if (this._testStorage(storage)) {
42883                 this.storage = storage;
42884                 this.enabled = true;
42885               }
42886             },
42887             _addPlugin: function _addPlugin(plugin) {
42888               var self = this; // If the plugin is an array, then add all plugins in the array.
42889               // This allows for a plugin to depend on other plugins.
42890
42891               if (isList$1(plugin)) {
42892                 each$1(plugin, function (plugin) {
42893                   self._addPlugin(plugin);
42894                 });
42895                 return;
42896               } // Keep track of all plugins we've seen so far, so that we
42897               // don't add any of them twice.
42898
42899
42900               var seenPlugin = pluck$1(this.plugins, function (seenPlugin) {
42901                 return plugin === seenPlugin;
42902               });
42903
42904               if (seenPlugin) {
42905                 return;
42906               }
42907
42908               this.plugins.push(plugin); // Check that the plugin is properly formed
42909
42910               if (!isFunction$1(plugin)) {
42911                 throw new Error('Plugins must be function values that return objects');
42912               }
42913
42914               var pluginProperties = plugin.call(this);
42915
42916               if (!isObject$3(pluginProperties)) {
42917                 throw new Error('Plugins must return an object of function properties');
42918               } // Add the plugin function properties to this store instance.
42919
42920
42921               each$1(pluginProperties, function (pluginFnProp, propName) {
42922                 if (!isFunction$1(pluginFnProp)) {
42923                   throw new Error('Bad plugin property: ' + propName + ' from plugin ' + plugin.name + '. Plugins should only return functions.');
42924                 }
42925
42926                 self._assignPluginFnProp(pluginFnProp, propName);
42927               });
42928             },
42929             // Put deprecated properties in the private API, so as to not expose it to accidential
42930             // discovery through inspection of the store object.
42931             // Deprecated: addStorage
42932             addStorage: function addStorage(storage) {
42933               _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
42934
42935               this._addStorage(storage);
42936             }
42937           };
42938           var store = create$2(_privateStoreProps, storeAPI, {
42939             plugins: []
42940           });
42941           store.raw = {};
42942           each$1(store, function (prop, propName) {
42943             if (isFunction$1(prop)) {
42944               store.raw[propName] = bind$2(store, prop);
42945             }
42946           });
42947           each$1(storages, function (storage) {
42948             store._addStorage(storage);
42949           });
42950           each$1(plugins, function (plugin) {
42951             store._addPlugin(plugin);
42952           });
42953           return store;
42954         }
42955
42956         var Global$1 = util.Global;
42957         var localStorage_1 = {
42958           name: 'localStorage',
42959           read: read,
42960           write: write,
42961           each: each$2,
42962           remove: remove$2,
42963           clearAll: clearAll
42964         };
42965
42966         function localStorage$1() {
42967           return Global$1.localStorage;
42968         }
42969
42970         function read(key) {
42971           return localStorage$1().getItem(key);
42972         }
42973
42974         function write(key, data) {
42975           return localStorage$1().setItem(key, data);
42976         }
42977
42978         function each$2(fn) {
42979           for (var i = localStorage$1().length - 1; i >= 0; i--) {
42980             var key = localStorage$1().key(i);
42981             fn(read(key), key);
42982           }
42983         }
42984
42985         function remove$2(key) {
42986           return localStorage$1().removeItem(key);
42987         }
42988
42989         function clearAll() {
42990           return localStorage$1().clear();
42991         }
42992
42993         // versions 6 and 7, where no localStorage, etc
42994         // is available.
42995
42996         var Global$2 = util.Global;
42997         var oldFFGlobalStorage = {
42998           name: 'oldFF-globalStorage',
42999           read: read$1,
43000           write: write$1,
43001           each: each$3,
43002           remove: remove$3,
43003           clearAll: clearAll$1
43004         };
43005         var globalStorage = Global$2.globalStorage;
43006
43007         function read$1(key) {
43008           return globalStorage[key];
43009         }
43010
43011         function write$1(key, data) {
43012           globalStorage[key] = data;
43013         }
43014
43015         function each$3(fn) {
43016           for (var i = globalStorage.length - 1; i >= 0; i--) {
43017             var key = globalStorage.key(i);
43018             fn(globalStorage[key], key);
43019           }
43020         }
43021
43022         function remove$3(key) {
43023           return globalStorage.removeItem(key);
43024         }
43025
43026         function clearAll$1() {
43027           each$3(function (key, _) {
43028             delete globalStorage[key];
43029           });
43030         }
43031
43032         // versions 6 and 7, where no localStorage, sessionStorage, etc
43033         // is available.
43034
43035         var Global$3 = util.Global;
43036         var oldIEUserDataStorage = {
43037           name: 'oldIE-userDataStorage',
43038           write: write$2,
43039           read: read$2,
43040           each: each$4,
43041           remove: remove$4,
43042           clearAll: clearAll$2
43043         };
43044         var storageName = 'storejs';
43045         var doc = Global$3.document;
43046
43047         var _withStorageEl = _makeIEStorageElFunction();
43048
43049         var disable = (Global$3.navigator ? Global$3.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
43050
43051         function write$2(unfixedKey, data) {
43052           if (disable) {
43053             return;
43054           }
43055
43056           var fixedKey = fixKey(unfixedKey);
43057
43058           _withStorageEl(function (storageEl) {
43059             storageEl.setAttribute(fixedKey, data);
43060             storageEl.save(storageName);
43061           });
43062         }
43063
43064         function read$2(unfixedKey) {
43065           if (disable) {
43066             return;
43067           }
43068
43069           var fixedKey = fixKey(unfixedKey);
43070           var res = null;
43071
43072           _withStorageEl(function (storageEl) {
43073             res = storageEl.getAttribute(fixedKey);
43074           });
43075
43076           return res;
43077         }
43078
43079         function each$4(callback) {
43080           _withStorageEl(function (storageEl) {
43081             var attributes = storageEl.XMLDocument.documentElement.attributes;
43082
43083             for (var i = attributes.length - 1; i >= 0; i--) {
43084               var attr = attributes[i];
43085               callback(storageEl.getAttribute(attr.name), attr.name);
43086             }
43087           });
43088         }
43089
43090         function remove$4(unfixedKey) {
43091           var fixedKey = fixKey(unfixedKey);
43092
43093           _withStorageEl(function (storageEl) {
43094             storageEl.removeAttribute(fixedKey);
43095             storageEl.save(storageName);
43096           });
43097         }
43098
43099         function clearAll$2() {
43100           _withStorageEl(function (storageEl) {
43101             var attributes = storageEl.XMLDocument.documentElement.attributes;
43102             storageEl.load(storageName);
43103
43104             for (var i = attributes.length - 1; i >= 0; i--) {
43105               storageEl.removeAttribute(attributes[i].name);
43106             }
43107
43108             storageEl.save(storageName);
43109           });
43110         } // Helpers
43111         //////////
43112         // In IE7, keys cannot start with a digit or contain certain chars.
43113         // See https://github.com/marcuswestin/store.js/issues/40
43114         // See https://github.com/marcuswestin/store.js/issues/83
43115
43116
43117         var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
43118
43119         function fixKey(key) {
43120           return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___');
43121         }
43122
43123         function _makeIEStorageElFunction() {
43124           if (!doc || !doc.documentElement || !doc.documentElement.addBehavior) {
43125             return null;
43126           }
43127
43128           var scriptTag = 'script',
43129               storageOwner,
43130               storageContainer,
43131               storageEl; // Since #userData storage applies only to specific paths, we need to
43132           // somehow link our data to a specific path.  We choose /favicon.ico
43133           // as a pretty safe option, since all browsers already make a request to
43134           // this URL anyway and being a 404 will not hurt us here.  We wrap an
43135           // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
43136           // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
43137           // since the iframe access rules appear to allow direct access and
43138           // manipulation of the document element, even for a 404 page.  This
43139           // document can be used instead of the current document (which would
43140           // have been limited to the current path) to perform #userData storage.
43141
43142           try {
43143             /* global ActiveXObject */
43144             storageContainer = new ActiveXObject('htmlfile');
43145             storageContainer.open();
43146             storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
43147             storageContainer.close();
43148             storageOwner = storageContainer.w.frames[0].document;
43149             storageEl = storageOwner.createElement('div');
43150           } catch (e) {
43151             // somehow ActiveXObject instantiation failed (perhaps some special
43152             // security settings or otherwse), fall back to per-path storage
43153             storageEl = doc.createElement('div');
43154             storageOwner = doc.body;
43155           }
43156
43157           return function (storeFunction) {
43158             var args = [].slice.call(arguments, 0);
43159             args.unshift(storageEl); // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
43160             // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
43161
43162             storageOwner.appendChild(storageEl);
43163             storageEl.addBehavior('#default#userData');
43164             storageEl.load(storageName);
43165             storeFunction.apply(this, args);
43166             storageOwner.removeChild(storageEl);
43167             return;
43168           };
43169         }
43170
43171         // doesn't work but cookies do. This implementation is adopted from
43172         // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
43173
43174         var Global$4 = util.Global;
43175         var trim$4 = util.trim;
43176         var cookieStorage = {
43177           name: 'cookieStorage',
43178           read: read$3,
43179           write: write$3,
43180           each: each$5,
43181           remove: remove$5,
43182           clearAll: clearAll$3
43183         };
43184         var doc$1 = Global$4.document;
43185
43186         function read$3(key) {
43187           if (!key || !_has(key)) {
43188             return null;
43189           }
43190
43191           var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
43192           return unescape(doc$1.cookie.replace(new RegExp(regexpStr), "$1"));
43193         }
43194
43195         function each$5(callback) {
43196           var cookies = doc$1.cookie.split(/; ?/g);
43197
43198           for (var i = cookies.length - 1; i >= 0; i--) {
43199             if (!trim$4(cookies[i])) {
43200               continue;
43201             }
43202
43203             var kvp = cookies[i].split('=');
43204             var key = unescape(kvp[0]);
43205             var val = unescape(kvp[1]);
43206             callback(val, key);
43207           }
43208         }
43209
43210         function write$3(key, data) {
43211           if (!key) {
43212             return;
43213           }
43214
43215           doc$1.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
43216         }
43217
43218         function remove$5(key) {
43219           if (!key || !_has(key)) {
43220             return;
43221           }
43222
43223           doc$1.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
43224         }
43225
43226         function clearAll$3() {
43227           each$5(function (_, key) {
43228             remove$5(key);
43229           });
43230         }
43231
43232         function _has(key) {
43233           return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc$1.cookie);
43234         }
43235
43236         var Global$5 = util.Global;
43237         var sessionStorage_1 = {
43238           name: 'sessionStorage',
43239           read: read$4,
43240           write: write$4,
43241           each: each$6,
43242           remove: remove$6,
43243           clearAll: clearAll$4
43244         };
43245
43246         function sessionStorage() {
43247           return Global$5.sessionStorage;
43248         }
43249
43250         function read$4(key) {
43251           return sessionStorage().getItem(key);
43252         }
43253
43254         function write$4(key, data) {
43255           return sessionStorage().setItem(key, data);
43256         }
43257
43258         function each$6(fn) {
43259           for (var i = sessionStorage().length - 1; i >= 0; i--) {
43260             var key = sessionStorage().key(i);
43261             fn(read$4(key), key);
43262           }
43263         }
43264
43265         function remove$6(key) {
43266           return sessionStorage().removeItem(key);
43267         }
43268
43269         function clearAll$4() {
43270           return sessionStorage().clear();
43271         }
43272
43273         // memoryStorage is a useful last fallback to ensure that the store
43274         // is functions (meaning store.get(), store.set(), etc will all function).
43275         // However, stored values will not persist when the browser navigates to
43276         // a new page or reloads the current page.
43277         var memoryStorage_1 = {
43278           name: 'memoryStorage',
43279           read: read$5,
43280           write: write$5,
43281           each: each$7,
43282           remove: remove$7,
43283           clearAll: clearAll$5
43284         };
43285         var memoryStorage = {};
43286
43287         function read$5(key) {
43288           return memoryStorage[key];
43289         }
43290
43291         function write$5(key, data) {
43292           memoryStorage[key] = data;
43293         }
43294
43295         function each$7(callback) {
43296           for (var key in memoryStorage) {
43297             if (memoryStorage.hasOwnProperty(key)) {
43298               callback(memoryStorage[key], key);
43299             }
43300           }
43301         }
43302
43303         function remove$7(key) {
43304           delete memoryStorage[key];
43305         }
43306
43307         function clearAll$5(key) {
43308           memoryStorage = {};
43309         }
43310
43311         var all = [// Listed in order of usage preference
43312         localStorage_1, oldFFGlobalStorage, oldIEUserDataStorage, cookieStorage, sessionStorage_1, memoryStorage_1];
43313
43314         /* eslint-disable */
43315         //  json2.js
43316         //  2016-10-28
43317         //  Public Domain.
43318         //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
43319         //  See http://www.JSON.org/js.html
43320         //  This code should be minified before deployment.
43321         //  See http://javascript.crockford.com/jsmin.html
43322         //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
43323         //  NOT CONTROL.
43324         //  This file creates a global JSON object containing two methods: stringify
43325         //  and parse. This file provides the ES5 JSON capability to ES3 systems.
43326         //  If a project might run on IE8 or earlier, then this file should be included.
43327         //  This file does nothing on ES5 systems.
43328         //      JSON.stringify(value, replacer, space)
43329         //          value       any JavaScript value, usually an object or array.
43330         //          replacer    an optional parameter that determines how object
43331         //                      values are stringified for objects. It can be a
43332         //                      function or an array of strings.
43333         //          space       an optional parameter that specifies the indentation
43334         //                      of nested structures. If it is omitted, the text will
43335         //                      be packed without extra whitespace. If it is a number,
43336         //                      it will specify the number of spaces to indent at each
43337         //                      level. If it is a string (such as "\t" or "&nbsp;"),
43338         //                      it contains the characters used to indent at each level.
43339         //          This method produces a JSON text from a JavaScript value.
43340         //          When an object value is found, if the object contains a toJSON
43341         //          method, its toJSON method will be called and the result will be
43342         //          stringified. A toJSON method does not serialize: it returns the
43343         //          value represented by the name/value pair that should be serialized,
43344         //          or undefined if nothing should be serialized. The toJSON method
43345         //          will be passed the key associated with the value, and this will be
43346         //          bound to the value.
43347         //          For example, this would serialize Dates as ISO strings.
43348         //              Date.prototype.toJSON = function (key) {
43349         //                  function f(n) {
43350         //                      // Format integers to have at least two digits.
43351         //                      return (n < 10)
43352         //                          ? "0" + n
43353         //                          : n;
43354         //                  }
43355         //                  return this.getUTCFullYear()   + "-" +
43356         //                       f(this.getUTCMonth() + 1) + "-" +
43357         //                       f(this.getUTCDate())      + "T" +
43358         //                       f(this.getUTCHours())     + ":" +
43359         //                       f(this.getUTCMinutes())   + ":" +
43360         //                       f(this.getUTCSeconds())   + "Z";
43361         //              };
43362         //          You can provide an optional replacer method. It will be passed the
43363         //          key and value of each member, with this bound to the containing
43364         //          object. The value that is returned from your method will be
43365         //          serialized. If your method returns undefined, then the member will
43366         //          be excluded from the serialization.
43367         //          If the replacer parameter is an array of strings, then it will be
43368         //          used to select the members to be serialized. It filters the results
43369         //          such that only members with keys listed in the replacer array are
43370         //          stringified.
43371         //          Values that do not have JSON representations, such as undefined or
43372         //          functions, will not be serialized. Such values in objects will be
43373         //          dropped; in arrays they will be replaced with null. You can use
43374         //          a replacer function to replace those with JSON values.
43375         //          JSON.stringify(undefined) returns undefined.
43376         //          The optional space parameter produces a stringification of the
43377         //          value that is filled with line breaks and indentation to make it
43378         //          easier to read.
43379         //          If the space parameter is a non-empty string, then that string will
43380         //          be used for indentation. If the space parameter is a number, then
43381         //          the indentation will be that many spaces.
43382         //          Example:
43383         //          text = JSON.stringify(["e", {pluribus: "unum"}]);
43384         //          // text is '["e",{"pluribus":"unum"}]'
43385         //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
43386         //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
43387         //          text = JSON.stringify([new Date()], function (key, value) {
43388         //              return this[key] instanceof Date
43389         //                  ? "Date(" + this[key] + ")"
43390         //                  : value;
43391         //          });
43392         //          // text is '["Date(---current time---)"]'
43393         //      JSON.parse(text, reviver)
43394         //          This method parses a JSON text to produce an object or array.
43395         //          It can throw a SyntaxError exception.
43396         //          The optional reviver parameter is a function that can filter and
43397         //          transform the results. It receives each of the keys and values,
43398         //          and its return value is used instead of the original value.
43399         //          If it returns what it received, then the structure is not modified.
43400         //          If it returns undefined then the member is deleted.
43401         //          Example:
43402         //          // Parse the text. Values that look like ISO date strings will
43403         //          // be converted to Date objects.
43404         //          myData = JSON.parse(text, function (key, value) {
43405         //              var a;
43406         //              if (typeof value === "string") {
43407         //                  a =
43408         //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
43409         //                  if (a) {
43410         //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
43411         //                          +a[5], +a[6]));
43412         //                  }
43413         //              }
43414         //              return value;
43415         //          });
43416         //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
43417         //              var d;
43418         //              if (typeof value === "string" &&
43419         //                      value.slice(0, 5) === "Date(" &&
43420         //                      value.slice(-1) === ")") {
43421         //                  d = new Date(value.slice(5, -1));
43422         //                  if (d) {
43423         //                      return d;
43424         //                  }
43425         //              }
43426         //              return value;
43427         //          });
43428         //  This is a reference implementation. You are free to copy, modify, or
43429         //  redistribute.
43430
43431         /*jslint
43432             eval, for, this
43433         */
43434
43435         /*property
43436             JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
43437             getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
43438             lastIndex, length, parse, prototype, push, replace, slice, stringify,
43439             test, toJSON, toString, valueOf
43440         */
43441         // Create a JSON object only if one does not already exist. We create the
43442         // methods in a closure to avoid creating global variables.
43443         if ((typeof JSON === "undefined" ? "undefined" : _typeof(JSON)) !== "object") {
43444           JSON = {};
43445         }
43446
43447         (function () {
43448
43449           var rx_one = /^[\],:{}\s]*$/;
43450           var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
43451           var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
43452           var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
43453           var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43454           var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43455
43456           function f(n) {
43457             // Format integers to have at least two digits.
43458             return n < 10 ? "0" + n : n;
43459           }
43460
43461           function this_value() {
43462             return this.valueOf();
43463           }
43464
43465           if (typeof Date.prototype.toJSON !== "function") {
43466             Date.prototype.toJSON = function () {
43467               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;
43468             };
43469
43470             Boolean.prototype.toJSON = this_value;
43471             Number.prototype.toJSON = this_value;
43472             String.prototype.toJSON = this_value;
43473           }
43474
43475           var gap;
43476           var indent;
43477           var meta;
43478           var rep;
43479
43480           function quote(string) {
43481             // If the string contains no control characters, no quote characters, and no
43482             // backslash characters, then we can safely slap some quotes around it.
43483             // Otherwise we must also replace the offending characters with safe escape
43484             // sequences.
43485             rx_escapable.lastIndex = 0;
43486             return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) {
43487               var c = meta[a];
43488               return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43489             }) + "\"" : "\"" + string + "\"";
43490           }
43491
43492           function str(key, holder) {
43493             // Produce a string from holder[key].
43494             var i; // The loop counter.
43495
43496             var k; // The member key.
43497
43498             var v; // The member value.
43499
43500             var length;
43501             var mind = gap;
43502             var partial;
43503             var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value.
43504
43505             if (value && _typeof(value) === "object" && typeof value.toJSON === "function") {
43506               value = value.toJSON(key);
43507             } // If we were called with a replacer function, then call the replacer to
43508             // obtain a replacement value.
43509
43510
43511             if (typeof rep === "function") {
43512               value = rep.call(holder, key, value);
43513             } // What happens next depends on the value's type.
43514
43515
43516             switch (_typeof(value)) {
43517               case "string":
43518                 return quote(value);
43519
43520               case "number":
43521                 // JSON numbers must be finite. Encode non-finite numbers as null.
43522                 return isFinite(value) ? String(value) : "null";
43523
43524               case "boolean":
43525               case "null":
43526                 // If the value is a boolean or null, convert it to a string. Note:
43527                 // typeof null does not produce "null". The case is included here in
43528                 // the remote chance that this gets fixed someday.
43529                 return String(value);
43530               // If the type is "object", we might be dealing with an object or an array or
43531               // null.
43532
43533               case "object":
43534                 // Due to a specification blunder in ECMAScript, typeof null is "object",
43535                 // so watch out for that case.
43536                 if (!value) {
43537                   return "null";
43538                 } // Make an array to hold the partial results of stringifying this object value.
43539
43540
43541                 gap += indent;
43542                 partial = []; // Is the value an array?
43543
43544                 if (Object.prototype.toString.apply(value) === "[object Array]") {
43545                   // The value is an array. Stringify every element. Use null as a placeholder
43546                   // for non-JSON values.
43547                   length = value.length;
43548
43549                   for (i = 0; i < length; i += 1) {
43550                     partial[i] = str(i, value) || "null";
43551                   } // Join all of the elements together, separated with commas, and wrap them in
43552                   // brackets.
43553
43554
43555                   v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
43556                   gap = mind;
43557                   return v;
43558                 } // If the replacer is an array, use it to select the members to be stringified.
43559
43560
43561                 if (rep && _typeof(rep) === "object") {
43562                   length = rep.length;
43563
43564                   for (i = 0; i < length; i += 1) {
43565                     if (typeof rep[i] === "string") {
43566                       k = rep[i];
43567                       v = str(k, value);
43568
43569                       if (v) {
43570                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43571                       }
43572                     }
43573                   }
43574                 } else {
43575                   // Otherwise, iterate through all of the keys in the object.
43576                   for (k in value) {
43577                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43578                       v = str(k, value);
43579
43580                       if (v) {
43581                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43582                       }
43583                     }
43584                   }
43585                 } // Join all of the member texts together, separated with commas,
43586                 // and wrap them in braces.
43587
43588
43589                 v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
43590                 gap = mind;
43591                 return v;
43592             }
43593           } // If the JSON object does not yet have a stringify method, give it one.
43594
43595
43596           if (typeof JSON.stringify !== "function") {
43597             meta = {
43598               // table of character substitutions
43599               "\b": "\\b",
43600               "\t": "\\t",
43601               "\n": "\\n",
43602               "\f": "\\f",
43603               "\r": "\\r",
43604               "\"": "\\\"",
43605               "\\": "\\\\"
43606             };
43607
43608             JSON.stringify = function (value, replacer, space) {
43609               // The stringify method takes a value and an optional replacer, and an optional
43610               // space parameter, and returns a JSON text. The replacer can be a function
43611               // that can replace values, or an array of strings that will select the keys.
43612               // A default replacer method can be provided. Use of the space parameter can
43613               // produce text that is more easily readable.
43614               var i;
43615               gap = "";
43616               indent = ""; // If the space parameter is a number, make an indent string containing that
43617               // many spaces.
43618
43619               if (typeof space === "number") {
43620                 for (i = 0; i < space; i += 1) {
43621                   indent += " ";
43622                 } // If the space parameter is a string, it will be used as the indent string.
43623
43624               } else if (typeof space === "string") {
43625                 indent = space;
43626               } // If there is a replacer, it must be a function or an array.
43627               // Otherwise, throw an error.
43628
43629
43630               rep = replacer;
43631
43632               if (replacer && typeof replacer !== "function" && (_typeof(replacer) !== "object" || typeof replacer.length !== "number")) {
43633                 throw new Error("JSON.stringify");
43634               } // Make a fake root object containing our value under the key of "".
43635               // Return the result of stringifying the value.
43636
43637
43638               return str("", {
43639                 "": value
43640               });
43641             };
43642           } // If the JSON object does not yet have a parse method, give it one.
43643
43644
43645           if (typeof JSON.parse !== "function") {
43646             JSON.parse = function (text, reviver) {
43647               // The parse method takes a text and an optional reviver function, and returns
43648               // a JavaScript value if the text is a valid JSON text.
43649               var j;
43650
43651               function walk(holder, key) {
43652                 // The walk method is used to recursively walk the resulting structure so
43653                 // that modifications can be made.
43654                 var k;
43655                 var v;
43656                 var value = holder[key];
43657
43658                 if (value && _typeof(value) === "object") {
43659                   for (k in value) {
43660                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43661                       v = walk(value, k);
43662
43663                       if (v !== undefined) {
43664                         value[k] = v;
43665                       } else {
43666                         delete value[k];
43667                       }
43668                     }
43669                   }
43670                 }
43671
43672                 return reviver.call(holder, key, value);
43673               } // Parsing happens in four stages. In the first stage, we replace certain
43674               // Unicode characters with escape sequences. JavaScript handles many characters
43675               // incorrectly, either silently deleting them, or treating them as line endings.
43676
43677
43678               text = String(text);
43679               rx_dangerous.lastIndex = 0;
43680
43681               if (rx_dangerous.test(text)) {
43682                 text = text.replace(rx_dangerous, function (a) {
43683                   return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43684                 });
43685               } // In the second stage, we run the text against regular expressions that look
43686               // for non-JSON patterns. We are especially concerned with "()" and "new"
43687               // because they can cause invocation, and "=" because it can cause mutation.
43688               // But just to be safe, we want to reject all unexpected forms.
43689               // We split the second stage into 4 regexp operations in order to work around
43690               // crippling inefficiencies in IE's and Safari's regexp engines. First we
43691               // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
43692               // replace all simple value tokens with "]" characters. Third, we delete all
43693               // open brackets that follow a colon or comma or that begin the text. Finally,
43694               // we look to see that the remaining characters are only whitespace or "]" or
43695               // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
43696
43697
43698               if (rx_one.test(text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, ""))) {
43699                 // In the third stage we use the eval function to compile the text into a
43700                 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
43701                 // in JavaScript: it can begin a block or an object literal. We wrap the text
43702                 // in parens to eliminate the ambiguity.
43703                 j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing
43704                 // each name/value pair to a reviver function for possible transformation.
43705
43706                 return typeof reviver === "function" ? walk({
43707                   "": j
43708                 }, "") : j;
43709               } // If the text is not JSON parseable, then a SyntaxError is thrown.
43710
43711
43712               throw new SyntaxError("JSON.parse");
43713             };
43714           }
43715         })();
43716
43717         var json2 = json2Plugin;
43718
43719         function json2Plugin() {
43720           return {};
43721         }
43722
43723         var plugins = [json2];
43724         var store_legacy = storeEngine.createStore(all, plugins);
43725
43726         //
43727         // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
43728         // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
43729         // does not support custom headers, which this uses everywhere.
43730
43731
43732         var osmAuth = function osmAuth(o) {
43733           var oauth = {}; // authenticated users will also have a request token secret, but it's
43734           // not used in transactions with the server
43735
43736           oauth.authenticated = function () {
43737             return !!(token('oauth_token') && token('oauth_token_secret'));
43738           };
43739
43740           oauth.logout = function () {
43741             token('oauth_token', '');
43742             token('oauth_token_secret', '');
43743             token('oauth_request_token_secret', '');
43744             return oauth;
43745           }; // TODO: detect lack of click event
43746
43747
43748           oauth.authenticate = function (callback) {
43749             if (oauth.authenticated()) return callback();
43750             oauth.logout(); // ## Getting a request token
43751
43752             var params = timenonce(getAuth(o)),
43753                 url = o.url + '/oauth/request_token';
43754             params.oauth_signature = ohauth_1.signature(o.oauth_secret, '', ohauth_1.baseString('POST', url, params));
43755
43756             if (!o.singlepage) {
43757               // Create a 600x550 popup window in the center of the screen
43758               var w = 600,
43759                   h = 550,
43760                   settings = [['width', w], ['height', h], ['left', screen.width / 2 - w / 2], ['top', screen.height / 2 - h / 2]].map(function (x) {
43761                 return x.join('=');
43762               }).join(','),
43763                   popup = window.open('about:blank', 'oauth_window', settings);
43764               oauth.popupWindow = popup;
43765
43766               if (!popup) {
43767                 var error = new Error('Popup was blocked');
43768                 error.status = 'popup-blocked';
43769                 throw error;
43770               }
43771             } // Request a request token. When this is complete, the popup
43772             // window is redirected to OSM's authorization page.
43773
43774
43775             ohauth_1.xhr('POST', url, params, null, {}, reqTokenDone);
43776             o.loading();
43777
43778             function reqTokenDone(err, xhr) {
43779               o.done();
43780               if (err) return callback(err);
43781               var resp = ohauth_1.stringQs(xhr.response);
43782               token('oauth_request_token_secret', resp.oauth_token_secret);
43783               var authorize_url = o.url + '/oauth/authorize?' + ohauth_1.qsString({
43784                 oauth_token: resp.oauth_token,
43785                 oauth_callback: resolveUrl$1(o.landing)
43786               });
43787
43788               if (o.singlepage) {
43789                 location.href = authorize_url;
43790               } else {
43791                 popup.location = authorize_url;
43792               }
43793             } // Called by a function in a landing page, in the popup window. The
43794             // window closes itself.
43795
43796
43797             window.authComplete = function (token) {
43798               var oauth_token = ohauth_1.stringQs(token.split('?')[1]);
43799               get_access_token(oauth_token.oauth_token);
43800               delete window.authComplete;
43801             }; // ## Getting an request token
43802             //
43803             // At this point we have an `oauth_token`, brought in from a function
43804             // call on a landing page popup.
43805
43806
43807             function get_access_token(oauth_token) {
43808               var url = o.url + '/oauth/access_token',
43809                   params = timenonce(getAuth(o)),
43810                   request_token_secret = token('oauth_request_token_secret');
43811               params.oauth_token = oauth_token;
43812               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43813               //
43814               // The final token required for authentication. At this point
43815               // we have a `request token secret`
43816
43817               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43818               o.loading();
43819             }
43820
43821             function accessTokenDone(err, xhr) {
43822               o.done();
43823               if (err) return callback(err);
43824               var access_token = ohauth_1.stringQs(xhr.response);
43825               token('oauth_token', access_token.oauth_token);
43826               token('oauth_token_secret', access_token.oauth_token_secret);
43827               callback(null, oauth);
43828             }
43829           };
43830
43831           oauth.bringPopupWindowToFront = function () {
43832             var brougtPopupToFront = false;
43833
43834             try {
43835               // This may cause a cross-origin error:
43836               // `DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.`
43837               if (oauth.popupWindow && !oauth.popupWindow.closed) {
43838                 oauth.popupWindow.focus();
43839                 brougtPopupToFront = true;
43840               }
43841             } catch (err) {// Bringing popup window to front failed (probably because of the cross-origin error mentioned above)
43842             }
43843
43844             return brougtPopupToFront;
43845           };
43846
43847           oauth.bootstrapToken = function (oauth_token, callback) {
43848             // ## Getting an request token
43849             // At this point we have an `oauth_token`, brought in from a function
43850             // call on a landing page popup.
43851             function get_access_token(oauth_token) {
43852               var url = o.url + '/oauth/access_token',
43853                   params = timenonce(getAuth(o)),
43854                   request_token_secret = token('oauth_request_token_secret');
43855               params.oauth_token = oauth_token;
43856               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43857               // The final token required for authentication. At this point
43858               // we have a `request token secret`
43859
43860               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43861               o.loading();
43862             }
43863
43864             function accessTokenDone(err, xhr) {
43865               o.done();
43866               if (err) return callback(err);
43867               var access_token = ohauth_1.stringQs(xhr.response);
43868               token('oauth_token', access_token.oauth_token);
43869               token('oauth_token_secret', access_token.oauth_token_secret);
43870               callback(null, oauth);
43871             }
43872
43873             get_access_token(oauth_token);
43874           }; // # xhr
43875           //
43876           // A single XMLHttpRequest wrapper that does authenticated calls if the
43877           // user has logged in.
43878
43879
43880           oauth.xhr = function (options, callback) {
43881             if (!oauth.authenticated()) {
43882               if (o.auto) {
43883                 return oauth.authenticate(run);
43884               } else {
43885                 callback('not authenticated', null);
43886                 return;
43887               }
43888             } else {
43889               return run();
43890             }
43891
43892             function run() {
43893               var params = timenonce(getAuth(o)),
43894                   oauth_token_secret = token('oauth_token_secret'),
43895                   url = options.prefix !== false ? o.url + options.path : options.path,
43896                   url_parts = url.replace(/#.*$/, '').split('?', 2),
43897                   base_url = url_parts[0],
43898                   query = url_parts.length === 2 ? url_parts[1] : ''; // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
43899
43900               if ((!options.options || !options.options.header || options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') && options.content) {
43901                 params = immutable(params, ohauth_1.stringQs(options.content));
43902               }
43903
43904               params.oauth_token = token('oauth_token');
43905               params.oauth_signature = ohauth_1.signature(o.oauth_secret, oauth_token_secret, ohauth_1.baseString(options.method, base_url, immutable(params, ohauth_1.stringQs(query))));
43906               return ohauth_1.xhr(options.method, url, params, options.content, options.options, done);
43907             }
43908
43909             function done(err, xhr) {
43910               if (err) return callback(err);else if (xhr.responseXML) return callback(err, xhr.responseXML);else return callback(err, xhr.response);
43911             }
43912           }; // pre-authorize this object, if we can just get a token and token_secret
43913           // from the start
43914
43915
43916           oauth.preauth = function (c) {
43917             if (!c) return;
43918             if (c.oauth_token) token('oauth_token', c.oauth_token);
43919             if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
43920             return oauth;
43921           };
43922
43923           oauth.options = function (_) {
43924             if (!arguments.length) return o;
43925             o = _;
43926             o.url = o.url || 'https://www.openstreetmap.org';
43927             o.landing = o.landing || 'land.html';
43928             o.singlepage = o.singlepage || false; // Optional loading and loading-done functions for nice UI feedback.
43929             // by default, no-ops
43930
43931             o.loading = o.loading || function () {};
43932
43933             o.done = o.done || function () {};
43934
43935             return oauth.preauth(o);
43936           }; // 'stamp' an authentication object from `getAuth()`
43937           // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
43938           // and timestamp
43939
43940
43941           function timenonce(o) {
43942             o.oauth_timestamp = ohauth_1.timestamp();
43943             o.oauth_nonce = ohauth_1.nonce();
43944             return o;
43945           } // get/set tokens. These are prefixed with the base URL so that `osm-auth`
43946           // can be used with multiple APIs and the keys in `localStorage`
43947           // will not clash
43948
43949
43950           var token;
43951
43952           if (store_legacy.enabled) {
43953             token = function token(x, y) {
43954               if (arguments.length === 1) return store_legacy.get(o.url + x);else if (arguments.length === 2) return store_legacy.set(o.url + x, y);
43955             };
43956           } else {
43957             var storage = {};
43958
43959             token = function token(x, y) {
43960               if (arguments.length === 1) return storage[o.url + x];else if (arguments.length === 2) return storage[o.url + x] = y;
43961             };
43962           } // Get an authentication object. If you just add and remove properties
43963           // from a single object, you'll need to use `delete` to make sure that
43964           // it doesn't contain undesired properties for authentication
43965
43966
43967           function getAuth(o) {
43968             return {
43969               oauth_consumer_key: o.oauth_consumer_key,
43970               oauth_signature_method: 'HMAC-SHA1'
43971             };
43972           } // potentially pre-authorize
43973
43974
43975           oauth.options(o);
43976           return oauth;
43977         };
43978
43979         var JXON = new function () {
43980           var sValueProp = 'keyValue',
43981               sAttributesProp = 'keyAttributes',
43982               sAttrPref = '@',
43983
43984           /* you can customize these values */
43985           aCache = [],
43986               rIsNull = /^\s*$/,
43987               rIsBool = /^(?:true|false)$/i;
43988
43989           function parseText(sValue) {
43990             if (rIsNull.test(sValue)) {
43991               return null;
43992             }
43993
43994             if (rIsBool.test(sValue)) {
43995               return sValue.toLowerCase() === 'true';
43996             }
43997
43998             if (isFinite(sValue)) {
43999               return parseFloat(sValue);
44000             }
44001
44002             if (isFinite(Date.parse(sValue))) {
44003               return new Date(sValue);
44004             }
44005
44006             return sValue;
44007           }
44008
44009           function EmptyTree() {}
44010
44011           EmptyTree.prototype.toString = function () {
44012             return 'null';
44013           };
44014
44015           EmptyTree.prototype.valueOf = function () {
44016             return null;
44017           };
44018
44019           function objectify(vValue) {
44020             return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
44021           }
44022
44023           function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
44024             var nLevelStart = aCache.length,
44025                 bChildren = oParentNode.hasChildNodes(),
44026                 bAttributes = oParentNode.hasAttributes(),
44027                 bHighVerb = Boolean(nVerb & 2);
44028             var sProp,
44029                 vContent,
44030                 nLength = 0,
44031                 sCollectedTxt = '',
44032                 vResult = bHighVerb ? {} :
44033             /* put here the default value for empty nodes: */
44034             true;
44035
44036             if (bChildren) {
44037               for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
44038                 oNode = oParentNode.childNodes.item(nItem);
44039
44040                 if (oNode.nodeType === 4) {
44041                   sCollectedTxt += oNode.nodeValue;
44042                 }
44043                 /* nodeType is 'CDATASection' (4) */
44044                 else if (oNode.nodeType === 3) {
44045                     sCollectedTxt += oNode.nodeValue.trim();
44046                   }
44047                   /* nodeType is 'Text' (3) */
44048                   else if (oNode.nodeType === 1 && !oNode.prefix) {
44049                       aCache.push(oNode);
44050                     }
44051                 /* nodeType is 'Element' (1) */
44052
44053               }
44054             }
44055
44056             var nLevelEnd = aCache.length,
44057                 vBuiltVal = parseText(sCollectedTxt);
44058
44059             if (!bHighVerb && (bChildren || bAttributes)) {
44060               vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
44061             }
44062
44063             for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
44064               sProp = aCache[nElId].nodeName.toLowerCase();
44065               vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
44066
44067               if (vResult.hasOwnProperty(sProp)) {
44068                 if (vResult[sProp].constructor !== Array) {
44069                   vResult[sProp] = [vResult[sProp]];
44070                 }
44071
44072                 vResult[sProp].push(vContent);
44073               } else {
44074                 vResult[sProp] = vContent;
44075                 nLength++;
44076               }
44077             }
44078
44079             if (bAttributes) {
44080               var nAttrLen = oParentNode.attributes.length,
44081                   sAPrefix = bNesteAttr ? '' : sAttrPref,
44082                   oAttrParent = bNesteAttr ? {} : vResult;
44083
44084               for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
44085                 oAttrib = oParentNode.attributes.item(nAttrib);
44086                 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
44087               }
44088
44089               if (bNesteAttr) {
44090                 if (bFreeze) {
44091                   Object.freeze(oAttrParent);
44092                 }
44093
44094                 vResult[sAttributesProp] = oAttrParent;
44095                 nLength -= nAttrLen - 1;
44096               }
44097             }
44098
44099             if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
44100               vResult[sValueProp] = vBuiltVal;
44101             } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
44102               vResult = vBuiltVal;
44103             }
44104
44105             if (bFreeze && (bHighVerb || nLength > 0)) {
44106               Object.freeze(vResult);
44107             }
44108
44109             aCache.length = nLevelStart;
44110             return vResult;
44111           }
44112
44113           function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
44114             var vValue, oChild;
44115
44116             if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
44117               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
44118               /* verbosity level is 0 */
44119             } else if (oParentObj.constructor === Date) {
44120               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
44121             }
44122
44123             for (var sName in oParentObj) {
44124               vValue = oParentObj[sName];
44125
44126               if (isFinite(sName) || vValue instanceof Function) {
44127                 continue;
44128               }
44129               /* verbosity level is 0 */
44130
44131
44132               if (sName === sValueProp) {
44133                 if (vValue !== null && vValue !== true) {
44134                   oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
44135                 }
44136               } else if (sName === sAttributesProp) {
44137                 /* verbosity level is 3 */
44138                 for (var sAttrib in vValue) {
44139                   oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
44140                 }
44141               } else if (sName.charAt(0) === sAttrPref) {
44142                 oParentEl.setAttribute(sName.slice(1), vValue);
44143               } else if (vValue.constructor === Array) {
44144                 for (var nItem = 0; nItem < vValue.length; nItem++) {
44145                   oChild = oXMLDoc.createElement(sName);
44146                   loadObjTree(oXMLDoc, oChild, vValue[nItem]);
44147                   oParentEl.appendChild(oChild);
44148                 }
44149               } else {
44150                 oChild = oXMLDoc.createElement(sName);
44151
44152                 if (vValue instanceof Object) {
44153                   loadObjTree(oXMLDoc, oChild, vValue);
44154                 } else if (vValue !== null && vValue !== true) {
44155                   oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
44156                 }
44157
44158                 oParentEl.appendChild(oChild);
44159               }
44160             }
44161           }
44162
44163           this.build = function (oXMLParent, nVerbosity
44164           /* optional */
44165           , bFreeze
44166           /* optional */
44167           , bNesteAttributes
44168           /* optional */
44169           ) {
44170             var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 :
44171             /* put here the default verbosity level: */
44172             1;
44173
44174             return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
44175           };
44176
44177           this.unbuild = function (oObjTree) {
44178             var oNewDoc = document.implementation.createDocument('', '', null);
44179             loadObjTree(oNewDoc, oNewDoc, oObjTree);
44180             return oNewDoc;
44181           };
44182
44183           this.stringify = function (oObjTree) {
44184             return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
44185           };
44186         }(); // var myObject = JXON.build(doc);
44187         // we got our javascript object! try: alert(JSON.stringify(myObject));
44188         // var newDoc = JXON.unbuild(myObject);
44189         // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
44190
44191         var tiler$5 = utilTiler();
44192         var dispatch$6 = dispatch('apiStatusChange', 'authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedNotes');
44193         var urlroot = 'https://www.openstreetmap.org';
44194         var oauth = osmAuth({
44195           url: urlroot,
44196           oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
44197           oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
44198           loading: authLoading,
44199           done: authDone
44200         }); // hardcode default block of Google Maps
44201
44202         var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
44203         var _tileCache = {
44204           toLoad: {},
44205           loaded: {},
44206           inflight: {},
44207           seen: {},
44208           rtree: new RBush()
44209         };
44210         var _noteCache = {
44211           toLoad: {},
44212           loaded: {},
44213           inflight: {},
44214           inflightPost: {},
44215           note: {},
44216           closed: {},
44217           rtree: new RBush()
44218         };
44219         var _userCache = {
44220           toLoad: {},
44221           user: {}
44222         };
44223
44224         var _cachedApiStatus;
44225
44226         var _changeset = {};
44227
44228         var _deferred = new Set();
44229
44230         var _connectionID = 1;
44231         var _tileZoom$3 = 16;
44232         var _noteZoom = 12;
44233
44234         var _rateLimitError;
44235
44236         var _userChangesets;
44237
44238         var _userDetails;
44239
44240         var _off; // set a default but also load this from the API status
44241
44242
44243         var _maxWayNodes = 2000;
44244
44245         function authLoading() {
44246           dispatch$6.call('authLoading');
44247         }
44248
44249         function authDone() {
44250           dispatch$6.call('authDone');
44251         }
44252
44253         function abortRequest$5(controllerOrXHR) {
44254           if (controllerOrXHR) {
44255             controllerOrXHR.abort();
44256           }
44257         }
44258
44259         function hasInflightRequests(cache) {
44260           return Object.keys(cache.inflight).length;
44261         }
44262
44263         function abortUnwantedRequests$3(cache, visibleTiles) {
44264           Object.keys(cache.inflight).forEach(function (k) {
44265             if (cache.toLoad[k]) return;
44266             if (visibleTiles.find(function (tile) {
44267               return k === tile.id;
44268             })) return;
44269             abortRequest$5(cache.inflight[k]);
44270             delete cache.inflight[k];
44271           });
44272         }
44273
44274         function getLoc(attrs) {
44275           var lon = attrs.lon && attrs.lon.value;
44276           var lat = attrs.lat && attrs.lat.value;
44277           return [parseFloat(lon), parseFloat(lat)];
44278         }
44279
44280         function getNodes(obj) {
44281           var elems = obj.getElementsByTagName('nd');
44282           var nodes = new Array(elems.length);
44283
44284           for (var i = 0, l = elems.length; i < l; i++) {
44285             nodes[i] = 'n' + elems[i].attributes.ref.value;
44286           }
44287
44288           return nodes;
44289         }
44290
44291         function getNodesJSON(obj) {
44292           var elems = obj.nodes;
44293           var nodes = new Array(elems.length);
44294
44295           for (var i = 0, l = elems.length; i < l; i++) {
44296             nodes[i] = 'n' + elems[i];
44297           }
44298
44299           return nodes;
44300         }
44301
44302         function getTags(obj) {
44303           var elems = obj.getElementsByTagName('tag');
44304           var tags = {};
44305
44306           for (var i = 0, l = elems.length; i < l; i++) {
44307             var attrs = elems[i].attributes;
44308             tags[attrs.k.value] = attrs.v.value;
44309           }
44310
44311           return tags;
44312         }
44313
44314         function getMembers(obj) {
44315           var elems = obj.getElementsByTagName('member');
44316           var members = new Array(elems.length);
44317
44318           for (var i = 0, l = elems.length; i < l; i++) {
44319             var attrs = elems[i].attributes;
44320             members[i] = {
44321               id: attrs.type.value[0] + attrs.ref.value,
44322               type: attrs.type.value,
44323               role: attrs.role.value
44324             };
44325           }
44326
44327           return members;
44328         }
44329
44330         function getMembersJSON(obj) {
44331           var elems = obj.members;
44332           var members = new Array(elems.length);
44333
44334           for (var i = 0, l = elems.length; i < l; i++) {
44335             var attrs = elems[i];
44336             members[i] = {
44337               id: attrs.type[0] + attrs.ref,
44338               type: attrs.type,
44339               role: attrs.role
44340             };
44341           }
44342
44343           return members;
44344         }
44345
44346         function getVisible(attrs) {
44347           return !attrs.visible || attrs.visible.value !== 'false';
44348         }
44349
44350         function parseComments(comments) {
44351           var parsedComments = []; // for each comment
44352
44353           for (var i = 0; i < comments.length; i++) {
44354             var comment = comments[i];
44355
44356             if (comment.nodeName === 'comment') {
44357               var childNodes = comment.childNodes;
44358               var parsedComment = {};
44359
44360               for (var j = 0; j < childNodes.length; j++) {
44361                 var node = childNodes[j];
44362                 var nodeName = node.nodeName;
44363                 if (nodeName === '#text') continue;
44364                 parsedComment[nodeName] = node.textContent;
44365
44366                 if (nodeName === 'uid') {
44367                   var uid = node.textContent;
44368
44369                   if (uid && !_userCache.user[uid]) {
44370                     _userCache.toLoad[uid] = true;
44371                   }
44372                 }
44373               }
44374
44375               if (parsedComment) {
44376                 parsedComments.push(parsedComment);
44377               }
44378             }
44379           }
44380
44381           return parsedComments;
44382         }
44383
44384         function encodeNoteRtree(note) {
44385           return {
44386             minX: note.loc[0],
44387             minY: note.loc[1],
44388             maxX: note.loc[0],
44389             maxY: note.loc[1],
44390             data: note
44391           };
44392         }
44393
44394         var jsonparsers = {
44395           node: function nodeData(obj, uid) {
44396             return new osmNode({
44397               id: uid,
44398               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44399               version: obj.version && obj.version.toString(),
44400               changeset: obj.changeset && obj.changeset.toString(),
44401               timestamp: obj.timestamp,
44402               user: obj.user,
44403               uid: obj.uid && obj.uid.toString(),
44404               loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
44405               tags: obj.tags
44406             });
44407           },
44408           way: function wayData(obj, uid) {
44409             return new osmWay({
44410               id: uid,
44411               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44412               version: obj.version && obj.version.toString(),
44413               changeset: obj.changeset && obj.changeset.toString(),
44414               timestamp: obj.timestamp,
44415               user: obj.user,
44416               uid: obj.uid && obj.uid.toString(),
44417               tags: obj.tags,
44418               nodes: getNodesJSON(obj)
44419             });
44420           },
44421           relation: function relationData(obj, uid) {
44422             return new osmRelation({
44423               id: uid,
44424               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44425               version: obj.version && obj.version.toString(),
44426               changeset: obj.changeset && obj.changeset.toString(),
44427               timestamp: obj.timestamp,
44428               user: obj.user,
44429               uid: obj.uid && obj.uid.toString(),
44430               tags: obj.tags,
44431               members: getMembersJSON(obj)
44432             });
44433           }
44434         };
44435
44436         function parseJSON(payload, callback, options) {
44437           options = Object.assign({
44438             skipSeen: true
44439           }, options);
44440
44441           if (!payload) {
44442             return callback({
44443               message: 'No JSON',
44444               status: -1
44445             });
44446           }
44447
44448           var json = payload;
44449           if (_typeof(json) !== 'object') json = JSON.parse(payload);
44450           if (!json.elements) return callback({
44451             message: 'No JSON',
44452             status: -1
44453           });
44454           var children = json.elements;
44455           var handle = window.requestIdleCallback(function () {
44456             var results = [];
44457             var result;
44458
44459             for (var i = 0; i < children.length; i++) {
44460               result = parseChild(children[i]);
44461               if (result) results.push(result);
44462             }
44463
44464             callback(null, results);
44465           });
44466
44467           _deferred.add(handle);
44468
44469           function parseChild(child) {
44470             var parser = jsonparsers[child.type];
44471             if (!parser) return null;
44472             var uid;
44473             uid = osmEntity.id.fromOSM(child.type, child.id);
44474
44475             if (options.skipSeen) {
44476               if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44477
44478               _tileCache.seen[uid] = true;
44479             }
44480
44481             return parser(child, uid);
44482           }
44483         }
44484
44485         var parsers = {
44486           node: function nodeData(obj, uid) {
44487             var attrs = obj.attributes;
44488             return new osmNode({
44489               id: uid,
44490               visible: getVisible(attrs),
44491               version: attrs.version.value,
44492               changeset: attrs.changeset && attrs.changeset.value,
44493               timestamp: attrs.timestamp && attrs.timestamp.value,
44494               user: attrs.user && attrs.user.value,
44495               uid: attrs.uid && attrs.uid.value,
44496               loc: getLoc(attrs),
44497               tags: getTags(obj)
44498             });
44499           },
44500           way: function wayData(obj, uid) {
44501             var attrs = obj.attributes;
44502             return new osmWay({
44503               id: uid,
44504               visible: getVisible(attrs),
44505               version: attrs.version.value,
44506               changeset: attrs.changeset && attrs.changeset.value,
44507               timestamp: attrs.timestamp && attrs.timestamp.value,
44508               user: attrs.user && attrs.user.value,
44509               uid: attrs.uid && attrs.uid.value,
44510               tags: getTags(obj),
44511               nodes: getNodes(obj)
44512             });
44513           },
44514           relation: function relationData(obj, uid) {
44515             var attrs = obj.attributes;
44516             return new osmRelation({
44517               id: uid,
44518               visible: getVisible(attrs),
44519               version: attrs.version.value,
44520               changeset: attrs.changeset && attrs.changeset.value,
44521               timestamp: attrs.timestamp && attrs.timestamp.value,
44522               user: attrs.user && attrs.user.value,
44523               uid: attrs.uid && attrs.uid.value,
44524               tags: getTags(obj),
44525               members: getMembers(obj)
44526             });
44527           },
44528           note: function parseNote(obj, uid) {
44529             var attrs = obj.attributes;
44530             var childNodes = obj.childNodes;
44531             var props = {};
44532             props.id = uid;
44533             props.loc = getLoc(attrs); // if notes are coincident, move them apart slightly
44534
44535             var coincident = false;
44536             var epsilon = 0.00001;
44537
44538             do {
44539               if (coincident) {
44540                 props.loc = geoVecAdd(props.loc, [epsilon, epsilon]);
44541               }
44542
44543               var bbox = geoExtent(props.loc).bbox();
44544               coincident = _noteCache.rtree.search(bbox).length;
44545             } while (coincident); // parse note contents
44546
44547
44548             for (var i = 0; i < childNodes.length; i++) {
44549               var node = childNodes[i];
44550               var nodeName = node.nodeName;
44551               if (nodeName === '#text') continue; // if the element is comments, parse the comments
44552
44553               if (nodeName === 'comments') {
44554                 props[nodeName] = parseComments(node.childNodes);
44555               } else {
44556                 props[nodeName] = node.textContent;
44557               }
44558             }
44559
44560             var note = new osmNote(props);
44561             var item = encodeNoteRtree(note);
44562             _noteCache.note[note.id] = note;
44563
44564             _noteCache.rtree.insert(item);
44565
44566             return note;
44567           },
44568           user: function parseUser(obj, uid) {
44569             var attrs = obj.attributes;
44570             var user = {
44571               id: uid,
44572               display_name: attrs.display_name && attrs.display_name.value,
44573               account_created: attrs.account_created && attrs.account_created.value,
44574               changesets_count: '0',
44575               active_blocks: '0'
44576             };
44577             var img = obj.getElementsByTagName('img');
44578
44579             if (img && img[0] && img[0].getAttribute('href')) {
44580               user.image_url = img[0].getAttribute('href');
44581             }
44582
44583             var changesets = obj.getElementsByTagName('changesets');
44584
44585             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
44586               user.changesets_count = changesets[0].getAttribute('count');
44587             }
44588
44589             var blocks = obj.getElementsByTagName('blocks');
44590
44591             if (blocks && blocks[0]) {
44592               var received = blocks[0].getElementsByTagName('received');
44593
44594               if (received && received[0] && received[0].getAttribute('active')) {
44595                 user.active_blocks = received[0].getAttribute('active');
44596               }
44597             }
44598
44599             _userCache.user[uid] = user;
44600             delete _userCache.toLoad[uid];
44601             return user;
44602           }
44603         };
44604
44605         function parseXML(xml, callback, options) {
44606           options = Object.assign({
44607             skipSeen: true
44608           }, options);
44609
44610           if (!xml || !xml.childNodes) {
44611             return callback({
44612               message: 'No XML',
44613               status: -1
44614             });
44615           }
44616
44617           var root = xml.childNodes[0];
44618           var children = root.childNodes;
44619           var handle = window.requestIdleCallback(function () {
44620             var results = [];
44621             var result;
44622
44623             for (var i = 0; i < children.length; i++) {
44624               result = parseChild(children[i]);
44625               if (result) results.push(result);
44626             }
44627
44628             callback(null, results);
44629           });
44630
44631           _deferred.add(handle);
44632
44633           function parseChild(child) {
44634             var parser = parsers[child.nodeName];
44635             if (!parser) return null;
44636             var uid;
44637
44638             if (child.nodeName === 'user') {
44639               uid = child.attributes.id.value;
44640
44641               if (options.skipSeen && _userCache.user[uid]) {
44642                 delete _userCache.toLoad[uid];
44643                 return null;
44644               }
44645             } else if (child.nodeName === 'note') {
44646               uid = child.getElementsByTagName('id')[0].textContent;
44647             } else {
44648               uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
44649
44650               if (options.skipSeen) {
44651                 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44652
44653                 _tileCache.seen[uid] = true;
44654               }
44655             }
44656
44657             return parser(child, uid);
44658           }
44659         } // replace or remove note from rtree
44660
44661
44662         function updateRtree$3(item, replace) {
44663           _noteCache.rtree.remove(item, function isEql(a, b) {
44664             return a.data.id === b.data.id;
44665           });
44666
44667           if (replace) {
44668             _noteCache.rtree.insert(item);
44669           }
44670         }
44671
44672         function wrapcb(thisArg, callback, cid) {
44673           return function (err, result) {
44674             if (err) {
44675               // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
44676               if (err.status === 400 || err.status === 401 || err.status === 403) {
44677                 thisArg.logout();
44678               }
44679
44680               return callback.call(thisArg, err);
44681             } else if (thisArg.getConnectionId() !== cid) {
44682               return callback.call(thisArg, {
44683                 message: 'Connection Switched',
44684                 status: -1
44685               });
44686             } else {
44687               return callback.call(thisArg, err, result);
44688             }
44689           };
44690         }
44691
44692         var serviceOsm = {
44693           init: function init() {
44694             utilRebind(this, dispatch$6, 'on');
44695           },
44696           reset: function reset() {
44697             Array.from(_deferred).forEach(function (handle) {
44698               window.cancelIdleCallback(handle);
44699
44700               _deferred["delete"](handle);
44701             });
44702             _connectionID++;
44703             _userChangesets = undefined;
44704             _userDetails = undefined;
44705             _rateLimitError = undefined;
44706             Object.values(_tileCache.inflight).forEach(abortRequest$5);
44707             Object.values(_noteCache.inflight).forEach(abortRequest$5);
44708             Object.values(_noteCache.inflightPost).forEach(abortRequest$5);
44709             if (_changeset.inflight) abortRequest$5(_changeset.inflight);
44710             _tileCache = {
44711               toLoad: {},
44712               loaded: {},
44713               inflight: {},
44714               seen: {},
44715               rtree: new RBush()
44716             };
44717             _noteCache = {
44718               toLoad: {},
44719               loaded: {},
44720               inflight: {},
44721               inflightPost: {},
44722               note: {},
44723               closed: {},
44724               rtree: new RBush()
44725             };
44726             _userCache = {
44727               toLoad: {},
44728               user: {}
44729             };
44730             _cachedApiStatus = undefined;
44731             _changeset = {};
44732             return this;
44733           },
44734           getConnectionId: function getConnectionId() {
44735             return _connectionID;
44736           },
44737           changesetURL: function changesetURL(changesetID) {
44738             return urlroot + '/changeset/' + changesetID;
44739           },
44740           changesetsURL: function changesetsURL(center, zoom) {
44741             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
44742             return urlroot + '/history#map=' + Math.floor(zoom) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
44743           },
44744           entityURL: function entityURL(entity) {
44745             return urlroot + '/' + entity.type + '/' + entity.osmId();
44746           },
44747           historyURL: function historyURL(entity) {
44748             return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
44749           },
44750           userURL: function userURL(username) {
44751             return urlroot + '/user/' + username;
44752           },
44753           noteURL: function noteURL(note) {
44754             return urlroot + '/note/' + note.id;
44755           },
44756           noteReportURL: function noteReportURL(note) {
44757             return urlroot + '/reports/new?reportable_type=Note&reportable_id=' + note.id;
44758           },
44759           // Generic method to load data from the OSM API
44760           // Can handle either auth or unauth calls.
44761           loadFromAPI: function loadFromAPI(path, callback, options) {
44762             options = Object.assign({
44763               skipSeen: true
44764             }, options);
44765             var that = this;
44766             var cid = _connectionID;
44767
44768             function done(err, payload) {
44769               if (that.getConnectionId() !== cid) {
44770                 if (callback) callback({
44771                   message: 'Connection Switched',
44772                   status: -1
44773                 });
44774                 return;
44775               }
44776
44777               var isAuthenticated = that.authenticated(); // 400 Bad Request, 401 Unauthorized, 403 Forbidden
44778               // Logout and retry the request..
44779
44780               if (isAuthenticated && err && err.status && (err.status === 400 || err.status === 401 || err.status === 403)) {
44781                 that.logout();
44782                 that.loadFromAPI(path, callback, options); // else, no retry..
44783               } else {
44784                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
44785                 // Set the rateLimitError flag and trigger a warning..
44786                 if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
44787                   _rateLimitError = err;
44788                   dispatch$6.call('change');
44789                   that.reloadApiStatus();
44790                 } else if (err && _cachedApiStatus === 'online' || !err && _cachedApiStatus !== 'online') {
44791                   // If the response's error state doesn't match the status,
44792                   // it's likely we lost or gained the connection so reload the status
44793                   that.reloadApiStatus();
44794                 }
44795
44796                 if (callback) {
44797                   if (err) {
44798                     return callback(err);
44799                   } else {
44800                     if (path.indexOf('.json') !== -1) {
44801                       return parseJSON(payload, callback, options);
44802                     } else {
44803                       return parseXML(payload, callback, options);
44804                     }
44805                   }
44806                 }
44807               }
44808             }
44809
44810             if (this.authenticated()) {
44811               return oauth.xhr({
44812                 method: 'GET',
44813                 path: path
44814               }, done);
44815             } else {
44816               var url = urlroot + path;
44817               var controller = new AbortController();
44818               d3_json(url, {
44819                 signal: controller.signal
44820               }).then(function (data) {
44821                 done(null, data);
44822               })["catch"](function (err) {
44823                 if (err.name === 'AbortError') return; // d3-fetch includes status in the error message,
44824                 // but we can't access the response itself
44825                 // https://github.com/d3/d3-fetch/issues/27
44826
44827                 var match = err.message.match(/^\d{3}/);
44828
44829                 if (match) {
44830                   done({
44831                     status: +match[0],
44832                     statusText: err.message
44833                   });
44834                 } else {
44835                   done(err.message);
44836                 }
44837               });
44838               return controller;
44839             }
44840           },
44841           // Load a single entity by id (ways and relations use the `/full` call)
44842           // GET /api/0.6/node/#id
44843           // GET /api/0.6/[way|relation]/#id/full
44844           loadEntity: function loadEntity(id, callback) {
44845             var type = osmEntity.id.type(id);
44846             var osmID = osmEntity.id.toOSM(id);
44847             var options = {
44848               skipSeen: false
44849             };
44850             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : '') + '.json', function (err, entities) {
44851               if (callback) callback(err, {
44852                 data: entities
44853               });
44854             }, options);
44855           },
44856           // Load a single entity with a specific version
44857           // GET /api/0.6/[node|way|relation]/#id/#version
44858           loadEntityVersion: function loadEntityVersion(id, version, callback) {
44859             var type = osmEntity.id.type(id);
44860             var osmID = osmEntity.id.toOSM(id);
44861             var options = {
44862               skipSeen: false
44863             };
44864             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/' + version + '.json', function (err, entities) {
44865               if (callback) callback(err, {
44866                 data: entities
44867               });
44868             }, options);
44869           },
44870           // Load multiple entities in chunks
44871           // (note: callback may be called multiple times)
44872           // Unlike `loadEntity`, child nodes and members are not fetched
44873           // GET /api/0.6/[nodes|ways|relations]?#parameters
44874           loadMultiple: function loadMultiple(ids, callback) {
44875             var that = this;
44876             var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
44877             Object.keys(groups).forEach(function (k) {
44878               var type = k + 's'; // nodes, ways, relations
44879
44880               var osmIDs = groups[k].map(function (id) {
44881                 return osmEntity.id.toOSM(id);
44882               });
44883               var options = {
44884                 skipSeen: false
44885               };
44886               utilArrayChunk(osmIDs, 150).forEach(function (arr) {
44887                 that.loadFromAPI('/api/0.6/' + type + '.json?' + type + '=' + arr.join(), function (err, entities) {
44888                   if (callback) callback(err, {
44889                     data: entities
44890                   });
44891                 }, options);
44892               });
44893             });
44894           },
44895           // Create, upload, and close a changeset
44896           // PUT /api/0.6/changeset/create
44897           // POST /api/0.6/changeset/#id/upload
44898           // PUT /api/0.6/changeset/#id/close
44899           putChangeset: function putChangeset(changeset, changes, callback) {
44900             var cid = _connectionID;
44901
44902             if (_changeset.inflight) {
44903               return callback({
44904                 message: 'Changeset already inflight',
44905                 status: -2
44906               }, changeset);
44907             } else if (_changeset.open) {
44908               // reuse existing open changeset..
44909               return createdChangeset.call(this, null, _changeset.open);
44910             } else {
44911               // Open a new changeset..
44912               var options = {
44913                 method: 'PUT',
44914                 path: '/api/0.6/changeset/create',
44915                 options: {
44916                   header: {
44917                     'Content-Type': 'text/xml'
44918                   }
44919                 },
44920                 content: JXON.stringify(changeset.asJXON())
44921               };
44922               _changeset.inflight = oauth.xhr(options, wrapcb(this, createdChangeset, cid));
44923             }
44924
44925             function createdChangeset(err, changesetID) {
44926               _changeset.inflight = null;
44927
44928               if (err) {
44929                 return callback(err, changeset);
44930               }
44931
44932               _changeset.open = changesetID;
44933               changeset = changeset.update({
44934                 id: changesetID
44935               }); // Upload the changeset..
44936
44937               var options = {
44938                 method: 'POST',
44939                 path: '/api/0.6/changeset/' + changesetID + '/upload',
44940                 options: {
44941                   header: {
44942                     'Content-Type': 'text/xml'
44943                   }
44944                 },
44945                 content: JXON.stringify(changeset.osmChangeJXON(changes))
44946               };
44947               _changeset.inflight = oauth.xhr(options, wrapcb(this, uploadedChangeset, cid));
44948             }
44949
44950             function uploadedChangeset(err) {
44951               _changeset.inflight = null;
44952               if (err) return callback(err, changeset); // Upload was successful, safe to call the callback.
44953               // Add delay to allow for postgres replication #1646 #2678
44954
44955               window.setTimeout(function () {
44956                 callback(null, changeset);
44957               }, 2500);
44958               _changeset.open = null; // At this point, we don't really care if the connection was switched..
44959               // Only try to close the changeset if we're still talking to the same server.
44960
44961               if (this.getConnectionId() === cid) {
44962                 // Still attempt to close changeset, but ignore response because #2667
44963                 oauth.xhr({
44964                   method: 'PUT',
44965                   path: '/api/0.6/changeset/' + changeset.id + '/close',
44966                   options: {
44967                     header: {
44968                       'Content-Type': 'text/xml'
44969                     }
44970                   }
44971                 }, function () {
44972                   return true;
44973                 });
44974               }
44975             }
44976           },
44977           // Load multiple users in chunks
44978           // (note: callback may be called multiple times)
44979           // GET /api/0.6/users?users=#id1,#id2,...,#idn
44980           loadUsers: function loadUsers(uids, callback) {
44981             var toLoad = [];
44982             var cached = [];
44983             utilArrayUniq(uids).forEach(function (uid) {
44984               if (_userCache.user[uid]) {
44985                 delete _userCache.toLoad[uid];
44986                 cached.push(_userCache.user[uid]);
44987               } else {
44988                 toLoad.push(uid);
44989               }
44990             });
44991
44992             if (cached.length || !this.authenticated()) {
44993               callback(undefined, cached);
44994               if (!this.authenticated()) return; // require auth
44995             }
44996
44997             utilArrayChunk(toLoad, 150).forEach(function (arr) {
44998               oauth.xhr({
44999                 method: 'GET',
45000                 path: '/api/0.6/users?users=' + arr.join()
45001               }, wrapcb(this, done, _connectionID));
45002             }.bind(this));
45003
45004             function done(err, xml) {
45005               if (err) {
45006                 return callback(err);
45007               }
45008
45009               var options = {
45010                 skipSeen: true
45011               };
45012               return parseXML(xml, function (err, results) {
45013                 if (err) {
45014                   return callback(err);
45015                 } else {
45016                   return callback(undefined, results);
45017                 }
45018               }, options);
45019             }
45020           },
45021           // Load a given user by id
45022           // GET /api/0.6/user/#id
45023           loadUser: function loadUser(uid, callback) {
45024             if (_userCache.user[uid] || !this.authenticated()) {
45025               // require auth
45026               delete _userCache.toLoad[uid];
45027               return callback(undefined, _userCache.user[uid]);
45028             }
45029
45030             oauth.xhr({
45031               method: 'GET',
45032               path: '/api/0.6/user/' + uid
45033             }, wrapcb(this, done, _connectionID));
45034
45035             function done(err, xml) {
45036               if (err) {
45037                 return callback(err);
45038               }
45039
45040               var options = {
45041                 skipSeen: true
45042               };
45043               return parseXML(xml, function (err, results) {
45044                 if (err) {
45045                   return callback(err);
45046                 } else {
45047                   return callback(undefined, results[0]);
45048                 }
45049               }, options);
45050             }
45051           },
45052           // Load the details of the logged-in user
45053           // GET /api/0.6/user/details
45054           userDetails: function userDetails(callback) {
45055             if (_userDetails) {
45056               // retrieve cached
45057               return callback(undefined, _userDetails);
45058             }
45059
45060             oauth.xhr({
45061               method: 'GET',
45062               path: '/api/0.6/user/details'
45063             }, wrapcb(this, done, _connectionID));
45064
45065             function done(err, xml) {
45066               if (err) {
45067                 return callback(err);
45068               }
45069
45070               var options = {
45071                 skipSeen: false
45072               };
45073               return parseXML(xml, function (err, results) {
45074                 if (err) {
45075                   return callback(err);
45076                 } else {
45077                   _userDetails = results[0];
45078                   return callback(undefined, _userDetails);
45079                 }
45080               }, options);
45081             }
45082           },
45083           // Load previous changesets for the logged in user
45084           // GET /api/0.6/changesets?user=#id
45085           userChangesets: function userChangesets(callback) {
45086             if (_userChangesets) {
45087               // retrieve cached
45088               return callback(undefined, _userChangesets);
45089             }
45090
45091             this.userDetails(wrapcb(this, gotDetails, _connectionID));
45092
45093             function gotDetails(err, user) {
45094               if (err) {
45095                 return callback(err);
45096               }
45097
45098               oauth.xhr({
45099                 method: 'GET',
45100                 path: '/api/0.6/changesets?user=' + user.id
45101               }, wrapcb(this, done, _connectionID));
45102             }
45103
45104             function done(err, xml) {
45105               if (err) {
45106                 return callback(err);
45107               }
45108
45109               _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
45110                 return {
45111                   tags: getTags(changeset)
45112                 };
45113               }).filter(function (changeset) {
45114                 var comment = changeset.tags.comment;
45115                 return comment && comment !== '';
45116               });
45117               return callback(undefined, _userChangesets);
45118             }
45119           },
45120           // Fetch the status of the OSM API
45121           // GET /api/capabilities
45122           status: function status(callback) {
45123             var url = urlroot + '/api/capabilities';
45124             var errback = wrapcb(this, done, _connectionID);
45125             d3_xml(url).then(function (data) {
45126               errback(null, data);
45127             })["catch"](function (err) {
45128               errback(err.message);
45129             });
45130
45131             function done(err, xml) {
45132               if (err) {
45133                 // the status is null if no response could be retrieved
45134                 return callback(err, null);
45135               } // update blocklists
45136
45137
45138               var elements = xml.getElementsByTagName('blacklist');
45139               var regexes = [];
45140
45141               for (var i = 0; i < elements.length; i++) {
45142                 var regexString = elements[i].getAttribute('regex'); // needs unencode?
45143
45144                 if (regexString) {
45145                   try {
45146                     var regex = new RegExp(regexString);
45147                     regexes.push(regex);
45148                   } catch (e) {
45149                     /* noop */
45150                   }
45151                 }
45152               }
45153
45154               if (regexes.length) {
45155                 _imageryBlocklists = regexes;
45156               }
45157
45158               if (_rateLimitError) {
45159                 return callback(_rateLimitError, 'rateLimited');
45160               } else {
45161                 var waynodes = xml.getElementsByTagName('waynodes');
45162                 var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
45163                 if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
45164                 var apiStatus = xml.getElementsByTagName('status');
45165                 var val = apiStatus[0].getAttribute('api');
45166                 return callback(undefined, val);
45167               }
45168             }
45169           },
45170           // Calls `status` and dispatches an `apiStatusChange` event if the returned
45171           // status differs from the cached status.
45172           reloadApiStatus: function reloadApiStatus() {
45173             // throttle to avoid unnecessary API calls
45174             if (!this.throttledReloadApiStatus) {
45175               var that = this;
45176               this.throttledReloadApiStatus = throttle(function () {
45177                 that.status(function (err, status) {
45178                   if (status !== _cachedApiStatus) {
45179                     _cachedApiStatus = status;
45180                     dispatch$6.call('apiStatusChange', that, err, status);
45181                   }
45182                 });
45183               }, 500);
45184             }
45185
45186             this.throttledReloadApiStatus();
45187           },
45188           // Returns the maximum number of nodes a single way can have
45189           maxWayNodes: function maxWayNodes() {
45190             return _maxWayNodes;
45191           },
45192           // Load data (entities) from the API in tiles
45193           // GET /api/0.6/map?bbox=
45194           loadTiles: function loadTiles(projection, callback) {
45195             if (_off) return; // determine the needed tiles to cover the view
45196
45197             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
45198
45199             var hadRequests = hasInflightRequests(_tileCache);
45200             abortUnwantedRequests$3(_tileCache, tiles);
45201
45202             if (hadRequests && !hasInflightRequests(_tileCache)) {
45203               dispatch$6.call('loaded'); // stop the spinner
45204             } // issue new requests..
45205
45206
45207             tiles.forEach(function (tile) {
45208               this.loadTile(tile, callback);
45209             }, this);
45210           },
45211           // Load a single data tile
45212           // GET /api/0.6/map?bbox=
45213           loadTile: function loadTile(tile, callback) {
45214             if (_off) return;
45215             if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45216
45217             if (!hasInflightRequests(_tileCache)) {
45218               dispatch$6.call('loading'); // start the spinner
45219             }
45220
45221             var path = '/api/0.6/map.json?bbox=';
45222             var options = {
45223               skipSeen: true
45224             };
45225             _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
45226
45227             function tileCallback(err, parsed) {
45228               delete _tileCache.inflight[tile.id];
45229
45230               if (!err) {
45231                 delete _tileCache.toLoad[tile.id];
45232                 _tileCache.loaded[tile.id] = true;
45233                 var bbox = tile.extent.bbox();
45234                 bbox.id = tile.id;
45235
45236                 _tileCache.rtree.insert(bbox);
45237               }
45238
45239               if (callback) {
45240                 callback(err, Object.assign({
45241                   data: parsed
45242                 }, tile));
45243               }
45244
45245               if (!hasInflightRequests(_tileCache)) {
45246                 dispatch$6.call('loaded'); // stop the spinner
45247               }
45248             }
45249           },
45250           isDataLoaded: function isDataLoaded(loc) {
45251             var bbox = {
45252               minX: loc[0],
45253               minY: loc[1],
45254               maxX: loc[0],
45255               maxY: loc[1]
45256             };
45257             return _tileCache.rtree.collides(bbox);
45258           },
45259           // load the tile that covers the given `loc`
45260           loadTileAtLoc: function loadTileAtLoc(loc, callback) {
45261             // Back off if the toLoad queue is filling up.. re #6417
45262             // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
45263             // let users safely edit geometries which extend to unloaded tiles.  We can drop some.)
45264             if (Object.keys(_tileCache.toLoad).length > 50) return;
45265             var k = geoZoomToScale(_tileZoom$3 + 1);
45266             var offset = geoRawMercator().scale(k)(loc);
45267             var projection = geoRawMercator().transform({
45268               k: k,
45269               x: -offset[0],
45270               y: -offset[1]
45271             });
45272             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection);
45273             tiles.forEach(function (tile) {
45274               if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45275               _tileCache.toLoad[tile.id] = true;
45276               this.loadTile(tile, callback);
45277             }, this);
45278           },
45279           // Load notes from the API in tiles
45280           // GET /api/0.6/notes?bbox=
45281           loadNotes: function loadNotes(projection, noteOptions) {
45282             noteOptions = Object.assign({
45283               limit: 10000,
45284               closed: 7
45285             }, noteOptions);
45286             if (_off) return;
45287             var that = this;
45288             var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
45289
45290             var throttleLoadUsers = throttle(function () {
45291               var uids = Object.keys(_userCache.toLoad);
45292               if (!uids.length) return;
45293               that.loadUsers(uids, function () {}); // eagerly load user details
45294             }, 750); // determine the needed tiles to cover the view
45295
45296
45297             var tiles = tiler$5.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
45298
45299             abortUnwantedRequests$3(_noteCache, tiles); // issue new requests..
45300
45301             tiles.forEach(function (tile) {
45302               if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
45303               var options = {
45304                 skipSeen: false
45305               };
45306               _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
45307                 delete _noteCache.inflight[tile.id];
45308
45309                 if (!err) {
45310                   _noteCache.loaded[tile.id] = true;
45311                 }
45312
45313                 throttleLoadUsers();
45314                 dispatch$6.call('loadedNotes');
45315               }, options);
45316             });
45317           },
45318           // Create a note
45319           // POST /api/0.6/notes?params
45320           postNoteCreate: function postNoteCreate(note, callback) {
45321             if (!this.authenticated()) {
45322               return callback({
45323                 message: 'Not Authenticated',
45324                 status: -3
45325               }, note);
45326             }
45327
45328             if (_noteCache.inflightPost[note.id]) {
45329               return callback({
45330                 message: 'Note update already inflight',
45331                 status: -2
45332               }, note);
45333             }
45334
45335             if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
45336
45337             var comment = note.newComment;
45338
45339             if (note.newCategory && note.newCategory !== 'None') {
45340               comment += ' #' + note.newCategory;
45341             }
45342
45343             var path = '/api/0.6/notes?' + utilQsString({
45344               lon: note.loc[0],
45345               lat: note.loc[1],
45346               text: comment
45347             });
45348             _noteCache.inflightPost[note.id] = oauth.xhr({
45349               method: 'POST',
45350               path: path
45351             }, wrapcb(this, done, _connectionID));
45352
45353             function done(err, xml) {
45354               delete _noteCache.inflightPost[note.id];
45355
45356               if (err) {
45357                 return callback(err);
45358               } // we get the updated note back, remove from caches and reparse..
45359
45360
45361               this.removeNote(note);
45362               var options = {
45363                 skipSeen: false
45364               };
45365               return parseXML(xml, function (err, results) {
45366                 if (err) {
45367                   return callback(err);
45368                 } else {
45369                   return callback(undefined, results[0]);
45370                 }
45371               }, options);
45372             }
45373           },
45374           // Update a note
45375           // POST /api/0.6/notes/#id/comment?text=comment
45376           // POST /api/0.6/notes/#id/close?text=comment
45377           // POST /api/0.6/notes/#id/reopen?text=comment
45378           postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
45379             if (!this.authenticated()) {
45380               return callback({
45381                 message: 'Not Authenticated',
45382                 status: -3
45383               }, note);
45384             }
45385
45386             if (_noteCache.inflightPost[note.id]) {
45387               return callback({
45388                 message: 'Note update already inflight',
45389                 status: -2
45390               }, note);
45391             }
45392
45393             var action;
45394
45395             if (note.status !== 'closed' && newStatus === 'closed') {
45396               action = 'close';
45397             } else if (note.status !== 'open' && newStatus === 'open') {
45398               action = 'reopen';
45399             } else {
45400               action = 'comment';
45401               if (!note.newComment) return; // when commenting, comment required
45402             }
45403
45404             var path = '/api/0.6/notes/' + note.id + '/' + action;
45405
45406             if (note.newComment) {
45407               path += '?' + utilQsString({
45408                 text: note.newComment
45409               });
45410             }
45411
45412             _noteCache.inflightPost[note.id] = oauth.xhr({
45413               method: 'POST',
45414               path: path
45415             }, wrapcb(this, done, _connectionID));
45416
45417             function done(err, xml) {
45418               delete _noteCache.inflightPost[note.id];
45419
45420               if (err) {
45421                 return callback(err);
45422               } // we get the updated note back, remove from caches and reparse..
45423
45424
45425               this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
45426
45427               if (action === 'close') {
45428                 _noteCache.closed[note.id] = true;
45429               } else if (action === 'reopen') {
45430                 delete _noteCache.closed[note.id];
45431               }
45432
45433               var options = {
45434                 skipSeen: false
45435               };
45436               return parseXML(xml, function (err, results) {
45437                 if (err) {
45438                   return callback(err);
45439                 } else {
45440                   return callback(undefined, results[0]);
45441                 }
45442               }, options);
45443             }
45444           },
45445           "switch": function _switch(options) {
45446             urlroot = options.urlroot;
45447             oauth.options(Object.assign({
45448               url: urlroot,
45449               loading: authLoading,
45450               done: authDone
45451             }, options));
45452             this.reset();
45453             this.userChangesets(function () {}); // eagerly load user details/changesets
45454
45455             dispatch$6.call('change');
45456             return this;
45457           },
45458           toggle: function toggle(val) {
45459             _off = !val;
45460             return this;
45461           },
45462           isChangesetInflight: function isChangesetInflight() {
45463             return !!_changeset.inflight;
45464           },
45465           // get/set cached data
45466           // This is used to save/restore the state when entering/exiting the walkthrough
45467           // Also used for testing purposes.
45468           caches: function caches(obj) {
45469             function cloneCache(source) {
45470               var target = {};
45471               Object.keys(source).forEach(function (k) {
45472                 if (k === 'rtree') {
45473                   target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
45474                 } else if (k === 'note') {
45475                   target.note = {};
45476                   Object.keys(source.note).forEach(function (id) {
45477                     target.note[id] = osmNote(source.note[id]); // copy notes
45478                   });
45479                 } else {
45480                   target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
45481                 }
45482               });
45483               return target;
45484             }
45485
45486             if (!arguments.length) {
45487               return {
45488                 tile: cloneCache(_tileCache),
45489                 note: cloneCache(_noteCache),
45490                 user: cloneCache(_userCache)
45491               };
45492             } // access caches directly for testing (e.g., loading notes rtree)
45493
45494
45495             if (obj === 'get') {
45496               return {
45497                 tile: _tileCache,
45498                 note: _noteCache,
45499                 user: _userCache
45500               };
45501             }
45502
45503             if (obj.tile) {
45504               _tileCache = obj.tile;
45505               _tileCache.inflight = {};
45506             }
45507
45508             if (obj.note) {
45509               _noteCache = obj.note;
45510               _noteCache.inflight = {};
45511               _noteCache.inflightPost = {};
45512             }
45513
45514             if (obj.user) {
45515               _userCache = obj.user;
45516             }
45517
45518             return this;
45519           },
45520           logout: function logout() {
45521             _userChangesets = undefined;
45522             _userDetails = undefined;
45523             oauth.logout();
45524             dispatch$6.call('change');
45525             return this;
45526           },
45527           authenticated: function authenticated() {
45528             return oauth.authenticated();
45529           },
45530           authenticate: function authenticate(callback) {
45531             var that = this;
45532             var cid = _connectionID;
45533             _userChangesets = undefined;
45534             _userDetails = undefined;
45535
45536             function done(err, res) {
45537               if (err) {
45538                 if (callback) callback(err);
45539                 return;
45540               }
45541
45542               if (that.getConnectionId() !== cid) {
45543                 if (callback) callback({
45544                   message: 'Connection Switched',
45545                   status: -1
45546                 });
45547                 return;
45548               }
45549
45550               _rateLimitError = undefined;
45551               dispatch$6.call('change');
45552               if (callback) callback(err, res);
45553               that.userChangesets(function () {}); // eagerly load user details/changesets
45554             }
45555
45556             return oauth.authenticate(done);
45557           },
45558           imageryBlocklists: function imageryBlocklists() {
45559             return _imageryBlocklists;
45560           },
45561           tileZoom: function tileZoom(val) {
45562             if (!arguments.length) return _tileZoom$3;
45563             _tileZoom$3 = val;
45564             return this;
45565           },
45566           // get all cached notes covering the viewport
45567           notes: function notes(projection) {
45568             var viewport = projection.clipExtent();
45569             var min = [viewport[0][0], viewport[1][1]];
45570             var max = [viewport[1][0], viewport[0][1]];
45571             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
45572             return _noteCache.rtree.search(bbox).map(function (d) {
45573               return d.data;
45574             });
45575           },
45576           // get a single note from the cache
45577           getNote: function getNote(id) {
45578             return _noteCache.note[id];
45579           },
45580           // remove a single note from the cache
45581           removeNote: function removeNote(note) {
45582             if (!(note instanceof osmNote) || !note.id) return;
45583             delete _noteCache.note[note.id];
45584             updateRtree$3(encodeNoteRtree(note), false); // false = remove
45585           },
45586           // replace a single note in the cache
45587           replaceNote: function replaceNote(note) {
45588             if (!(note instanceof osmNote) || !note.id) return;
45589             _noteCache.note[note.id] = note;
45590             updateRtree$3(encodeNoteRtree(note), true); // true = replace
45591
45592             return note;
45593           },
45594           // Get an array of note IDs closed during this session.
45595           // Used to populate `closed:note` changeset tag
45596           getClosedIDs: function getClosedIDs() {
45597             return Object.keys(_noteCache.closed).sort();
45598           }
45599         };
45600
45601         var _apibase = 'https://wiki.openstreetmap.org/w/api.php';
45602         var _inflight$1 = {};
45603         var _wikibaseCache = {};
45604         var _localeIDs = {
45605           en: false
45606         };
45607
45608         var debouncedRequest = debounce(request, 500, {
45609           leading: false
45610         });
45611
45612         function request(url, callback) {
45613           if (_inflight$1[url]) return;
45614           var controller = new AbortController();
45615           _inflight$1[url] = controller;
45616           d3_json(url, {
45617             signal: controller.signal
45618           }).then(function (result) {
45619             delete _inflight$1[url];
45620             if (callback) callback(null, result);
45621           })["catch"](function (err) {
45622             delete _inflight$1[url];
45623             if (err.name === 'AbortError') return;
45624             if (callback) callback(err.message);
45625           });
45626         }
45627
45628         var serviceOsmWikibase = {
45629           init: function init() {
45630             _inflight$1 = {};
45631             _wikibaseCache = {};
45632             _localeIDs = {};
45633           },
45634           reset: function reset() {
45635             Object.values(_inflight$1).forEach(function (controller) {
45636               controller.abort();
45637             });
45638             _inflight$1 = {};
45639           },
45640
45641           /**
45642            * Get the best value for the property, or undefined if not found
45643            * @param entity object from wikibase
45644            * @param property string e.g. 'P4' for image
45645            * @param langCode string e.g. 'fr' for French
45646            */
45647           claimToValue: function claimToValue(entity, property, langCode) {
45648             if (!entity.claims[property]) return undefined;
45649             var locale = _localeIDs[langCode];
45650             var preferredPick, localePick;
45651             entity.claims[property].forEach(function (stmt) {
45652               // If exists, use value limited to the needed language (has a qualifier P26 = locale)
45653               // Or if not found, use the first value with the "preferred" rank
45654               if (!preferredPick && stmt.rank === 'preferred') {
45655                 preferredPick = stmt;
45656               }
45657
45658               if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
45659                 localePick = stmt;
45660               }
45661             });
45662             var result = localePick || preferredPick;
45663
45664             if (result) {
45665               var datavalue = result.mainsnak.datavalue;
45666               return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
45667             } else {
45668               return undefined;
45669             }
45670           },
45671
45672           /**
45673            * Convert monolingual property into a key-value object (language -> value)
45674            * @param entity object from wikibase
45675            * @param property string e.g. 'P31' for monolingual wiki page title
45676            */
45677           monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
45678             if (!entity || !entity.claims[property]) return undefined;
45679             return entity.claims[property].reduce(function (acc, obj) {
45680               var value = obj.mainsnak.datavalue.value;
45681               acc[value.language] = value.text;
45682               return acc;
45683             }, {});
45684           },
45685           toSitelink: function toSitelink(key, value) {
45686             var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
45687             return result.replace(/_/g, ' ').trim();
45688           },
45689           //
45690           // Pass params object of the form:
45691           // {
45692           //   key: 'string',
45693           //   value: 'string',
45694           //   langCode: 'string'
45695           // }
45696           //
45697           getEntity: function getEntity(params, callback) {
45698             var doRequest = params.debounce ? debouncedRequest : request;
45699             var that = this;
45700             var titles = [];
45701             var result = {};
45702             var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
45703             var keySitelink = params.key ? this.toSitelink(params.key) : false;
45704             var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
45705             var localeSitelink;
45706
45707             if (params.langCodes) {
45708               params.langCodes.forEach(function (langCode) {
45709                 if (_localeIDs[langCode] === undefined) {
45710                   // If this is the first time we are asking about this locale,
45711                   // fetch corresponding entity (if it exists), and cache it.
45712                   // If there is no such entry, cache `false` value to avoid re-requesting it.
45713                   localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
45714                   titles.push(localeSitelink);
45715                 }
45716               });
45717             }
45718
45719             if (rtypeSitelink) {
45720               if (_wikibaseCache[rtypeSitelink]) {
45721                 result.rtype = _wikibaseCache[rtypeSitelink];
45722               } else {
45723                 titles.push(rtypeSitelink);
45724               }
45725             }
45726
45727             if (keySitelink) {
45728               if (_wikibaseCache[keySitelink]) {
45729                 result.key = _wikibaseCache[keySitelink];
45730               } else {
45731                 titles.push(keySitelink);
45732               }
45733             }
45734
45735             if (tagSitelink) {
45736               if (_wikibaseCache[tagSitelink]) {
45737                 result.tag = _wikibaseCache[tagSitelink];
45738               } else {
45739                 titles.push(tagSitelink);
45740               }
45741             }
45742
45743             if (!titles.length) {
45744               // Nothing to do, we already had everything in the cache
45745               return callback(null, result);
45746             } // Requesting just the user language code
45747             // If backend recognizes the code, it will perform proper fallbacks,
45748             // and the result will contain the requested code. If not, all values are returned:
45749             // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
45750             // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
45751
45752
45753             var obj = {
45754               action: 'wbgetentities',
45755               sites: 'wiki',
45756               titles: titles.join('|'),
45757               languages: params.langCodes.join('|'),
45758               languagefallback: 1,
45759               origin: '*',
45760               format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
45761               // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
45762               // formatversion: 2,
45763
45764             };
45765             var url = _apibase + '?' + utilQsString(obj);
45766             doRequest(url, function (err, d) {
45767               if (err) {
45768                 callback(err);
45769               } else if (!d.success || d.error) {
45770                 callback(d.error.messages.map(function (v) {
45771                   return v.html['*'];
45772                 }).join('<br>'));
45773               } else {
45774                 var localeID = false;
45775                 Object.values(d.entities).forEach(function (res) {
45776                   if (res.missing !== '') {
45777                     var title = res.sitelinks.wiki.title;
45778
45779                     if (title === rtypeSitelink) {
45780                       _wikibaseCache[rtypeSitelink] = res;
45781                       result.rtype = res;
45782                     } else if (title === keySitelink) {
45783                       _wikibaseCache[keySitelink] = res;
45784                       result.key = res;
45785                     } else if (title === tagSitelink) {
45786                       _wikibaseCache[tagSitelink] = res;
45787                       result.tag = res;
45788                     } else if (title === localeSitelink) {
45789                       localeID = res.id;
45790                     } else {
45791                       console.log('Unexpected title ' + title); // eslint-disable-line no-console
45792                     }
45793                   }
45794                 });
45795
45796                 if (localeSitelink) {
45797                   // If locale ID is not found, store false to prevent repeated queries
45798                   that.addLocale(params.langCodes[0], localeID);
45799                 }
45800
45801                 callback(null, result);
45802               }
45803             });
45804           },
45805           //
45806           // Pass params object of the form:
45807           // {
45808           //   key: 'string',     // required
45809           //   value: 'string'    // optional
45810           // }
45811           //
45812           // Get an result object used to display tag documentation
45813           // {
45814           //   title:        'string',
45815           //   description:  'string',
45816           //   editURL:      'string',
45817           //   imageURL:     'string',
45818           //   wiki:         { title: 'string', text: 'string', url: 'string' }
45819           // }
45820           //
45821           getDocs: function getDocs(params, callback) {
45822             var that = this;
45823             var langCodes = _mainLocalizer.localeCodes().map(function (code) {
45824               return code.toLowerCase();
45825             });
45826             params.langCodes = langCodes;
45827             this.getEntity(params, function (err, data) {
45828               if (err) {
45829                 callback(err);
45830                 return;
45831               }
45832
45833               var entity = data.rtype || data.tag || data.key;
45834
45835               if (!entity) {
45836                 callback('No entity');
45837                 return;
45838               }
45839
45840               var i;
45841               var description;
45842
45843               for (i in langCodes) {
45844                 var _code = langCodes[i];
45845
45846                 if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
45847                   description = entity.descriptions[_code];
45848                   break;
45849                 }
45850               }
45851
45852               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
45853
45854               var result = {
45855                 title: entity.title,
45856                 description: description ? description.value : '',
45857                 descriptionLocaleCode: description ? description.language : '',
45858                 editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
45859               }; // add image
45860
45861               if (entity.claims) {
45862                 var imageroot;
45863                 var image = that.claimToValue(entity, 'P4', langCodes[0]);
45864
45865                 if (image) {
45866                   imageroot = 'https://commons.wikimedia.org/w/index.php';
45867                 } else {
45868                   image = that.claimToValue(entity, 'P28', langCodes[0]);
45869
45870                   if (image) {
45871                     imageroot = 'https://wiki.openstreetmap.org/w/index.php';
45872                   }
45873                 }
45874
45875                 if (imageroot && image) {
45876                   result.imageURL = imageroot + '?' + utilQsString({
45877                     title: 'Special:Redirect/file/' + image,
45878                     width: 400
45879                   });
45880                 }
45881               } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
45882               // If neither tag nor key data item contain a wiki page in the needed language nor English,
45883               // get the first found wiki page from either the tag or the key item.
45884
45885
45886               var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
45887               var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
45888               var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
45889               var wikis = [rtypeWiki, tagWiki, keyWiki];
45890
45891               for (i in wikis) {
45892                 var wiki = wikis[i];
45893
45894                 for (var j in langCodes) {
45895                   var code = langCodes[j];
45896                   var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
45897                   var info = getWikiInfo(wiki, code, referenceId);
45898
45899                   if (info) {
45900                     result.wiki = info;
45901                     break;
45902                   }
45903                 }
45904
45905                 if (result.wiki) break;
45906               }
45907
45908               callback(null, result); // Helper method to get wiki info if a given language exists
45909
45910               function getWikiInfo(wiki, langCode, tKey) {
45911                 if (wiki && wiki[langCode]) {
45912                   return {
45913                     title: wiki[langCode],
45914                     text: tKey,
45915                     url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
45916                   };
45917                 }
45918               }
45919             });
45920           },
45921           addLocale: function addLocale(langCode, qid) {
45922             // Makes it easier to unit test
45923             _localeIDs[langCode] = qid;
45924           },
45925           apibase: function apibase(val) {
45926             if (!arguments.length) return _apibase;
45927             _apibase = val;
45928             return this;
45929           }
45930         };
45931
45932         var jsonpCache = {};
45933         window.jsonpCache = jsonpCache;
45934         function jsonpRequest(url, callback) {
45935           var request = {
45936             abort: function abort() {}
45937           };
45938
45939           if (window.JSONP_FIX) {
45940             if (window.JSONP_DELAY === 0) {
45941               callback(window.JSONP_FIX);
45942             } else {
45943               var t = window.setTimeout(function () {
45944                 callback(window.JSONP_FIX);
45945               }, window.JSONP_DELAY || 0);
45946
45947               request.abort = function () {
45948                 window.clearTimeout(t);
45949               };
45950             }
45951
45952             return request;
45953           }
45954
45955           function rand() {
45956             var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
45957             var c = '';
45958             var i = -1;
45959
45960             while (++i < 15) {
45961               c += chars.charAt(Math.floor(Math.random() * 52));
45962             }
45963
45964             return c;
45965           }
45966
45967           function create(url) {
45968             var e = url.match(/callback=(\w+)/);
45969             var c = e ? e[1] : rand();
45970
45971             jsonpCache[c] = function (data) {
45972               if (jsonpCache[c]) {
45973                 callback(data);
45974               }
45975
45976               finalize();
45977             };
45978
45979             function finalize() {
45980               delete jsonpCache[c];
45981               script.remove();
45982             }
45983
45984             request.abort = finalize;
45985             return 'jsonpCache.' + c;
45986           }
45987
45988           var cb = create(url);
45989           var script = select('head').append('script').attr('type', 'text/javascript').attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
45990           return request;
45991         }
45992
45993         var bubbleApi = 'https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?';
45994         var streetsideImagesApi = 'https://t.ssl.ak.tiles.virtualearth.net/tiles/';
45995         var bubbleAppKey = 'AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm';
45996         var pannellumViewerCSS = 'pannellum-streetside/pannellum.css';
45997         var pannellumViewerJS = 'pannellum-streetside/pannellum.js';
45998         var maxResults$2 = 2000;
45999         var tileZoom$2 = 16.5;
46000         var tiler$6 = utilTiler().zoomExtent([tileZoom$2, tileZoom$2]).skipNullIsland(true);
46001         var dispatch$7 = dispatch('loadedImages', 'viewerChanged');
46002         var minHfov = 10; // zoom in degrees:  20, 10, 5
46003
46004         var maxHfov = 90; // zoom out degrees
46005
46006         var defaultHfov = 45;
46007         var _hires = false;
46008         var _resolution = 512; // higher numbers are slower - 512, 1024, 2048, 4096
46009
46010         var _currScene = 0;
46011
46012         var _ssCache;
46013
46014         var _pannellumViewer;
46015
46016         var _sceneOptions = {
46017           showFullscreenCtrl: false,
46018           autoLoad: true,
46019           compass: true,
46020           yaw: 0,
46021           minHfov: minHfov,
46022           maxHfov: maxHfov,
46023           hfov: defaultHfov,
46024           type: 'cubemap',
46025           cubeMap: []
46026         };
46027
46028         var _loadViewerPromise$2;
46029         /**
46030          * abortRequest().
46031          */
46032
46033
46034         function abortRequest$6(i) {
46035           i.abort();
46036         }
46037         /**
46038          * localeTimeStamp().
46039          */
46040
46041
46042         function localeTimestamp(s) {
46043           if (!s) return null;
46044           var options = {
46045             day: 'numeric',
46046             month: 'short',
46047             year: 'numeric'
46048           };
46049           var d = new Date(s);
46050           if (isNaN(d.getTime())) return null;
46051           return d.toLocaleString(_mainLocalizer.localeCode(), options);
46052         }
46053         /**
46054          * loadTiles() wraps the process of generating tiles and then fetching image points for each tile.
46055          */
46056
46057
46058         function loadTiles$2(which, url, projection, margin) {
46059           var tiles = tiler$6.margin(margin).getTiles(projection); // abort inflight requests that are no longer needed
46060
46061           var cache = _ssCache[which];
46062           Object.keys(cache.inflight).forEach(function (k) {
46063             var wanted = tiles.find(function (tile) {
46064               return k.indexOf(tile.id + ',') === 0;
46065             });
46066
46067             if (!wanted) {
46068               abortRequest$6(cache.inflight[k]);
46069               delete cache.inflight[k];
46070             }
46071           });
46072           tiles.forEach(function (tile) {
46073             return loadNextTilePage$2(which, url, tile);
46074           });
46075         }
46076         /**
46077          * loadNextTilePage() load data for the next tile page in line.
46078          */
46079
46080
46081         function loadNextTilePage$2(which, url, tile) {
46082           var cache = _ssCache[which];
46083           var nextPage = cache.nextPage[tile.id] || 0;
46084           var id = tile.id + ',' + String(nextPage);
46085           if (cache.loaded[id] || cache.inflight[id]) return;
46086           cache.inflight[id] = getBubbles(url, tile, function (bubbles) {
46087             cache.loaded[id] = true;
46088             delete cache.inflight[id];
46089             if (!bubbles) return; // [].shift() removes the first element, some statistics info, not a bubble point
46090
46091             bubbles.shift();
46092             var features = bubbles.map(function (bubble) {
46093               if (cache.points[bubble.id]) return null; // skip duplicates
46094
46095               var loc = [bubble.lo, bubble.la];
46096               var d = {
46097                 loc: loc,
46098                 key: bubble.id,
46099                 ca: bubble.he,
46100                 captured_at: bubble.cd,
46101                 captured_by: 'microsoft',
46102                 // nbn: bubble.nbn,
46103                 // pbn: bubble.pbn,
46104                 // ad: bubble.ad,
46105                 // rn: bubble.rn,
46106                 pr: bubble.pr,
46107                 // previous
46108                 ne: bubble.ne,
46109                 // next
46110                 pano: true,
46111                 sequenceKey: null
46112               };
46113               cache.points[bubble.id] = d; // a sequence starts here
46114
46115               if (bubble.pr === undefined) {
46116                 cache.leaders.push(bubble.id);
46117               }
46118
46119               return {
46120                 minX: loc[0],
46121                 minY: loc[1],
46122                 maxX: loc[0],
46123                 maxY: loc[1],
46124                 data: d
46125               };
46126             }).filter(Boolean);
46127             cache.rtree.load(features);
46128             connectSequences();
46129
46130             if (which === 'bubbles') {
46131               dispatch$7.call('loadedImages');
46132             }
46133           });
46134         } // call this sometimes to connect the bubbles into sequences
46135
46136
46137         function connectSequences() {
46138           var cache = _ssCache.bubbles;
46139           var keepLeaders = [];
46140
46141           for (var i = 0; i < cache.leaders.length; i++) {
46142             var bubble = cache.points[cache.leaders[i]];
46143             var seen = {}; // try to make a sequence.. use the key of the leader bubble.
46144
46145             var sequence = {
46146               key: bubble.key,
46147               bubbles: []
46148             };
46149             var complete = false;
46150
46151             do {
46152               sequence.bubbles.push(bubble);
46153               seen[bubble.key] = true;
46154
46155               if (bubble.ne === undefined) {
46156                 complete = true;
46157               } else {
46158                 bubble = cache.points[bubble.ne]; // advance to next
46159               }
46160             } while (bubble && !seen[bubble.key] && !complete);
46161
46162             if (complete) {
46163               _ssCache.sequences[sequence.key] = sequence; // assign bubbles to the sequence
46164
46165               for (var j = 0; j < sequence.bubbles.length; j++) {
46166                 sequence.bubbles[j].sequenceKey = sequence.key;
46167               } // create a GeoJSON LineString
46168
46169
46170               sequence.geojson = {
46171                 type: 'LineString',
46172                 properties: {
46173                   captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
46174                   captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
46175                   key: sequence.key
46176                 },
46177                 coordinates: sequence.bubbles.map(function (d) {
46178                   return d.loc;
46179                 })
46180               };
46181             } else {
46182               keepLeaders.push(cache.leaders[i]);
46183             }
46184           } // couldn't complete these, save for later
46185
46186
46187           cache.leaders = keepLeaders;
46188         }
46189         /**
46190          * getBubbles() handles the request to the server for a tile extent of 'bubbles' (streetside image locations).
46191          */
46192
46193
46194         function getBubbles(url, tile, callback) {
46195           var rect = tile.extent.rectangle();
46196           var urlForRequest = url + utilQsString({
46197             n: rect[3],
46198             s: rect[1],
46199             e: rect[2],
46200             w: rect[0],
46201             c: maxResults$2,
46202             appkey: bubbleAppKey,
46203             jsCallback: '{callback}'
46204           });
46205           return jsonpRequest(urlForRequest, function (data) {
46206             if (!data || data.error) {
46207               callback(null);
46208             } else {
46209               callback(data);
46210             }
46211           });
46212         } // partition viewport into higher zoom tiles
46213
46214
46215         function partitionViewport$2(projection) {
46216           var z = geoScaleToZoom(projection.scale());
46217           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
46218
46219           var tiler = utilTiler().zoomExtent([z2, z2]);
46220           return tiler.getTiles(projection).map(function (tile) {
46221             return tile.extent;
46222           });
46223         } // no more than `limit` results per partition.
46224
46225
46226         function searchLimited$2(limit, projection, rtree) {
46227           limit = limit || 5;
46228           return partitionViewport$2(projection).reduce(function (result, extent) {
46229             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
46230               return d.data;
46231             });
46232             return found.length ? result.concat(found) : result;
46233           }, []);
46234         }
46235         /**
46236          * loadImage()
46237          */
46238
46239
46240         function loadImage(imgInfo) {
46241           return new Promise(function (resolve) {
46242             var img = new Image();
46243
46244             img.onload = function () {
46245               var canvas = document.getElementById('ideditor-canvas' + imgInfo.face);
46246               var ctx = canvas.getContext('2d');
46247               ctx.drawImage(img, imgInfo.x, imgInfo.y);
46248               resolve({
46249                 imgInfo: imgInfo,
46250                 status: 'ok'
46251               });
46252             };
46253
46254             img.onerror = function () {
46255               resolve({
46256                 data: imgInfo,
46257                 status: 'error'
46258               });
46259             };
46260
46261             img.setAttribute('crossorigin', '');
46262             img.src = imgInfo.url;
46263           });
46264         }
46265         /**
46266          * loadCanvas()
46267          */
46268
46269
46270         function loadCanvas(imageGroup) {
46271           return Promise.all(imageGroup.map(loadImage)).then(function (data) {
46272             var canvas = document.getElementById('ideditor-canvas' + data[0].imgInfo.face);
46273             var which = {
46274               '01': 0,
46275               '02': 1,
46276               '03': 2,
46277               '10': 3,
46278               '11': 4,
46279               '12': 5
46280             };
46281             var face = data[0].imgInfo.face;
46282             _sceneOptions.cubeMap[which[face]] = canvas.toDataURL('image/jpeg', 1.0);
46283             return {
46284               status: 'loadCanvas for face ' + data[0].imgInfo.face + 'ok'
46285             };
46286           });
46287         }
46288         /**
46289          * loadFaces()
46290          */
46291
46292
46293         function loadFaces(faceGroup) {
46294           return Promise.all(faceGroup.map(loadCanvas)).then(function () {
46295             return {
46296               status: 'loadFaces done'
46297             };
46298           });
46299         }
46300
46301         function setupCanvas(selection, reset) {
46302           if (reset) {
46303             selection.selectAll('#ideditor-stitcher-canvases').remove();
46304           } // Add the Streetside working canvases. These are used for 'stitching', or combining,
46305           // multiple images for each of the six faces, before passing to the Pannellum control as DataUrls
46306
46307
46308           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) {
46309             return 'ideditor-' + d;
46310           }).attr('width', _resolution).attr('height', _resolution);
46311         }
46312
46313         function qkToXY(qk) {
46314           var x = 0;
46315           var y = 0;
46316           var scale = 256;
46317
46318           for (var i = qk.length; i > 0; i--) {
46319             var key = qk[i - 1];
46320             x += +(key === '1' || key === '3') * scale;
46321             y += +(key === '2' || key === '3') * scale;
46322             scale *= 2;
46323           }
46324
46325           return [x, y];
46326         }
46327
46328         function getQuadKeys() {
46329           var dim = _resolution / 256;
46330           var quadKeys;
46331
46332           if (dim === 16) {
46333             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'];
46334           } else if (dim === 8) {
46335             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'];
46336           } else if (dim === 4) {
46337             quadKeys = ['00', '01', '10', '11', '02', '03', '12', '13', '20', '21', '30', '31', '22', '23', '32', '33'];
46338           } else {
46339             // dim === 2
46340             quadKeys = ['0', '1', '2', '3'];
46341           }
46342
46343           return quadKeys;
46344         }
46345
46346         var serviceStreetside = {
46347           /**
46348            * init() initialize streetside.
46349            */
46350           init: function init() {
46351             if (!_ssCache) {
46352               this.reset();
46353             }
46354
46355             this.event = utilRebind(this, dispatch$7, 'on');
46356           },
46357
46358           /**
46359            * reset() reset the cache.
46360            */
46361           reset: function reset() {
46362             if (_ssCache) {
46363               Object.values(_ssCache.bubbles.inflight).forEach(abortRequest$6);
46364             }
46365
46366             _ssCache = {
46367               bubbles: {
46368                 inflight: {},
46369                 loaded: {},
46370                 nextPage: {},
46371                 rtree: new RBush(),
46372                 points: {},
46373                 leaders: []
46374               },
46375               sequences: {}
46376             };
46377           },
46378
46379           /**
46380            * bubbles()
46381            */
46382           bubbles: function bubbles(projection) {
46383             var limit = 5;
46384             return searchLimited$2(limit, projection, _ssCache.bubbles.rtree);
46385           },
46386           cachedImage: function cachedImage(imageKey) {
46387             return _ssCache.bubbles.points[imageKey];
46388           },
46389           sequences: function sequences(projection) {
46390             var viewport = projection.clipExtent();
46391             var min = [viewport[0][0], viewport[1][1]];
46392             var max = [viewport[1][0], viewport[0][1]];
46393             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
46394             var seen = {};
46395             var results = []; // all sequences for bubbles in viewport
46396
46397             _ssCache.bubbles.rtree.search(bbox).forEach(function (d) {
46398               var key = d.data.sequenceKey;
46399
46400               if (key && !seen[key]) {
46401                 seen[key] = true;
46402                 results.push(_ssCache.sequences[key].geojson);
46403               }
46404             });
46405
46406             return results;
46407           },
46408
46409           /**
46410            * loadBubbles()
46411            */
46412           loadBubbles: function loadBubbles(projection, margin) {
46413             // by default: request 2 nearby tiles so we can connect sequences.
46414             if (margin === undefined) margin = 2;
46415             loadTiles$2('bubbles', bubbleApi, projection, margin);
46416           },
46417           viewer: function viewer() {
46418             return _pannellumViewer;
46419           },
46420           initViewer: function initViewer() {
46421             if (!window.pannellum) return;
46422             if (_pannellumViewer) return;
46423             _currScene += 1;
46424
46425             var sceneID = _currScene.toString();
46426
46427             var options = {
46428               'default': {
46429                 firstScene: sceneID
46430               },
46431               scenes: {}
46432             };
46433             options.scenes[sceneID] = _sceneOptions;
46434             _pannellumViewer = window.pannellum.viewer('ideditor-viewer-streetside', options);
46435           },
46436           ensureViewerLoaded: function ensureViewerLoaded(context) {
46437             if (_loadViewerPromise$2) return _loadViewerPromise$2; // create ms-wrapper, a photo wrapper class
46438
46439             var wrap = context.container().select('.photoviewer').selectAll('.ms-wrapper').data([0]); // inject ms-wrapper into the photoviewer div
46440             // (used by all to house each custom photo viewer)
46441
46442             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper ms-wrapper').classed('hide', true);
46443             var that = this;
46444             var pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // inject div to support streetside viewer (pannellum) and attribution line
46445
46446             wrapEnter.append('div').attr('id', 'ideditor-viewer-streetside').on(pointerPrefix + 'down.streetside', function () {
46447               select(window).on(pointerPrefix + 'move.streetside', function () {
46448                 dispatch$7.call('viewerChanged');
46449               }, true);
46450             }).on(pointerPrefix + 'up.streetside pointercancel.streetside', function () {
46451               select(window).on(pointerPrefix + 'move.streetside', null); // continue dispatching events for a few seconds, in case viewer has inertia.
46452
46453               var t = timer(function (elapsed) {
46454                 dispatch$7.call('viewerChanged');
46455
46456                 if (elapsed > 2000) {
46457                   t.stop();
46458                 }
46459               });
46460             }).append('div').attr('class', 'photo-attribution fillD');
46461             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
46462             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
46463             controlsEnter.append('button').on('click.forward', step(1)).html('►'); // create working canvas for stitching together images
46464
46465             wrap = wrap.merge(wrapEnter).call(setupCanvas, true); // Register viewer resize handler
46466
46467             context.ui().photoviewer.on('resize.streetside', function () {
46468               if (_pannellumViewer) {
46469                 _pannellumViewer.resize();
46470               }
46471             });
46472             _loadViewerPromise$2 = new Promise(function (resolve, reject) {
46473               var loadedCount = 0;
46474
46475               function loaded() {
46476                 loadedCount += 1; // wait until both files are loaded
46477
46478                 if (loadedCount === 2) resolve();
46479               }
46480
46481               var head = select('head'); // load streetside pannellum viewer css
46482
46483               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 () {
46484                 reject();
46485               }); // load streetside pannellum viewer js
46486
46487               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 () {
46488                 reject();
46489               });
46490             })["catch"](function () {
46491               _loadViewerPromise$2 = null;
46492             });
46493             return _loadViewerPromise$2;
46494
46495             function step(stepBy) {
46496               return function () {
46497                 var viewer = context.container().select('.photoviewer');
46498                 var selected = viewer.empty() ? undefined : viewer.datum();
46499                 if (!selected) return;
46500                 var nextID = stepBy === 1 ? selected.ne : selected.pr;
46501
46502                 var yaw = _pannellumViewer.getYaw();
46503
46504                 var ca = selected.ca + yaw;
46505                 var origin = selected.loc; // construct a search trapezoid pointing out from current bubble
46506
46507                 var meters = 35;
46508                 var p1 = [origin[0] + geoMetersToLon(meters / 5, origin[1]), origin[1]];
46509                 var p2 = [origin[0] + geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46510                 var p3 = [origin[0] - geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46511                 var p4 = [origin[0] - geoMetersToLon(meters / 5, origin[1]), origin[1]];
46512                 var poly = [p1, p2, p3, p4, p1]; // rotate it to face forward/backward
46513
46514                 var angle = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
46515                 poly = geoRotate(poly, -angle, origin);
46516                 var extent = poly.reduce(function (extent, point) {
46517                   return extent.extend(geoExtent(point));
46518                 }, geoExtent()); // find nearest other bubble in the search polygon
46519
46520                 var minDist = Infinity;
46521
46522                 _ssCache.bubbles.rtree.search(extent.bbox()).forEach(function (d) {
46523                   if (d.data.key === selected.key) return;
46524                   if (!geoPointInPolygon(d.data.loc, poly)) return;
46525                   var dist = geoVecLength(d.data.loc, selected.loc);
46526                   var theta = selected.ca - d.data.ca;
46527                   var minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
46528
46529                   if (minTheta > 20) {
46530                     dist += 5; // penalize distance if camera angles don't match
46531                   }
46532
46533                   if (dist < minDist) {
46534                     nextID = d.data.key;
46535                     minDist = dist;
46536                   }
46537                 });
46538
46539                 var nextBubble = nextID && that.cachedImage(nextID);
46540                 if (!nextBubble) return;
46541                 context.map().centerEase(nextBubble.loc);
46542                 that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
46543               };
46544             }
46545           },
46546           yaw: function yaw(_yaw) {
46547             if (typeof _yaw !== 'number') return _yaw;
46548             _sceneOptions.yaw = _yaw;
46549             return this;
46550           },
46551
46552           /**
46553            * showViewer()
46554            */
46555           showViewer: function showViewer(context) {
46556             var wrap = context.container().select('.photoviewer').classed('hide', false);
46557             var isHidden = wrap.selectAll('.photo-wrapper.ms-wrapper.hide').size();
46558
46559             if (isHidden) {
46560               wrap.selectAll('.photo-wrapper:not(.ms-wrapper)').classed('hide', true);
46561               wrap.selectAll('.photo-wrapper.ms-wrapper').classed('hide', false);
46562             }
46563
46564             return this;
46565           },
46566
46567           /**
46568            * hideViewer()
46569            */
46570           hideViewer: function hideViewer(context) {
46571             var viewer = context.container().select('.photoviewer');
46572             if (!viewer.empty()) viewer.datum(null);
46573             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
46574             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
46575             this.updateUrlImage(null);
46576             return this.setStyles(context, null, true);
46577           },
46578
46579           /**
46580            * selectImage().
46581            */
46582           selectImage: function selectImage(context, key) {
46583             var that = this;
46584             var d = this.cachedImage(key);
46585             var viewer = context.container().select('.photoviewer');
46586             if (!viewer.empty()) viewer.datum(d);
46587             this.setStyles(context, null, true);
46588             var wrap = context.container().select('.photoviewer .ms-wrapper');
46589             var attribution = wrap.selectAll('.photo-attribution').html('');
46590             wrap.selectAll('.pnlm-load-box') // display "loading.."
46591             .style('display', 'block');
46592             if (!d) return this;
46593             this.updateUrlImage(key);
46594             _sceneOptions.northOffset = d.ca;
46595             var line1 = attribution.append('div').attr('class', 'attribution-row');
46596             var hiresDomId = utilUniqueDomId('streetside-hires'); // Add hires checkbox
46597
46598             var label = line1.append('label').attr('for', hiresDomId).attr('class', 'streetside-hires');
46599             label.append('input').attr('type', 'checkbox').attr('id', hiresDomId).property('checked', _hires).on('click', function (d3_event) {
46600               d3_event.stopPropagation();
46601               _hires = !_hires;
46602               _resolution = _hires ? 1024 : 512;
46603               wrap.call(setupCanvas, true);
46604               var viewstate = {
46605                 yaw: _pannellumViewer.getYaw(),
46606                 pitch: _pannellumViewer.getPitch(),
46607                 hfov: _pannellumViewer.getHfov()
46608               };
46609               _sceneOptions = Object.assign(_sceneOptions, viewstate);
46610               that.selectImage(context, d.key).showViewer(context);
46611             });
46612             label.append('span').html(_t.html('streetside.hires'));
46613             var captureInfo = line1.append('div').attr('class', 'attribution-capture-info'); // Add capture date
46614
46615             if (d.captured_by) {
46616               var yyyy = new Date().getFullYear();
46617               captureInfo.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://www.microsoft.com/en-us/maps/streetside').html('©' + yyyy + ' Microsoft');
46618               captureInfo.append('span').html('|');
46619             }
46620
46621             if (d.captured_at) {
46622               captureInfo.append('span').attr('class', 'captured_at').html(localeTimestamp(d.captured_at));
46623             } // Add image links
46624
46625
46626             var line2 = attribution.append('div').attr('class', 'attribution-row');
46627             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'));
46628             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'));
46629             var bubbleIdQuadKey = d.key.toString(4);
46630             var paddingNeeded = 16 - bubbleIdQuadKey.length;
46631
46632             for (var i = 0; i < paddingNeeded; i++) {
46633               bubbleIdQuadKey = '0' + bubbleIdQuadKey;
46634             }
46635
46636             var imgUrlPrefix = streetsideImagesApi + 'hs' + bubbleIdQuadKey;
46637             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
46638
46639             var faceKeys = ['01', '02', '03', '10', '11', '12']; // Map images to cube faces
46640
46641             var quadKeys = getQuadKeys();
46642             var faces = faceKeys.map(function (faceKey) {
46643               return quadKeys.map(function (quadKey) {
46644                 var xy = qkToXY(quadKey);
46645                 return {
46646                   face: faceKey,
46647                   url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
46648                   x: xy[0],
46649                   y: xy[1]
46650                 };
46651               });
46652             });
46653             loadFaces(faces).then(function () {
46654               if (!_pannellumViewer) {
46655                 that.initViewer();
46656               } else {
46657                 // make a new scene
46658                 _currScene += 1;
46659
46660                 var sceneID = _currScene.toString();
46661
46662                 _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID); // remove previous scene
46663
46664
46665                 if (_currScene > 2) {
46666                   sceneID = (_currScene - 1).toString();
46667
46668                   _pannellumViewer.removeScene(sceneID);
46669                 }
46670               }
46671             });
46672             return this;
46673           },
46674           getSequenceKeyForBubble: function getSequenceKeyForBubble(d) {
46675             return d && d.sequenceKey;
46676           },
46677           // Updates the currently highlighted sequence and selected bubble.
46678           // Reset is only necessary when interacting with the viewport because
46679           // this implicitly changes the currently selected bubble/sequence
46680           setStyles: function setStyles(context, hovered, reset) {
46681             if (reset) {
46682               // reset all layers
46683               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
46684               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
46685             }
46686
46687             var hoveredBubbleKey = hovered && hovered.key;
46688             var hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
46689             var hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
46690             var hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map(function (d) {
46691               return d.key;
46692             }) || [];
46693             var viewer = context.container().select('.photoviewer');
46694             var selected = viewer.empty() ? undefined : viewer.datum();
46695             var selectedBubbleKey = selected && selected.key;
46696             var selectedSequenceKey = this.getSequenceKeyForBubble(selected);
46697             var selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
46698             var selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map(function (d) {
46699               return d.key;
46700             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
46701
46702             var highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
46703             context.container().selectAll('.layer-streetside-images .viewfield-group').classed('highlighted', function (d) {
46704               return highlightedBubbleKeys.indexOf(d.key) !== -1;
46705             }).classed('hovered', function (d) {
46706               return d.key === hoveredBubbleKey;
46707             }).classed('currentView', function (d) {
46708               return d.key === selectedBubbleKey;
46709             });
46710             context.container().selectAll('.layer-streetside-images .sequence').classed('highlighted', function (d) {
46711               return d.properties.key === hoveredSequenceKey;
46712             }).classed('currentView', function (d) {
46713               return d.properties.key === selectedSequenceKey;
46714             }); // update viewfields if needed
46715
46716             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
46717
46718             function viewfieldPath() {
46719               var d = this.parentNode.__data__;
46720
46721               if (d.pano && d.key !== selectedBubbleKey) {
46722                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
46723               } else {
46724                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
46725               }
46726             }
46727
46728             return this;
46729           },
46730           updateUrlImage: function updateUrlImage(imageKey) {
46731             if (!window.mocha) {
46732               var hash = utilStringQs(window.location.hash);
46733
46734               if (imageKey) {
46735                 hash.photo = 'streetside/' + imageKey;
46736               } else {
46737                 delete hash.photo;
46738               }
46739
46740               window.location.replace('#' + utilQsString(hash, true));
46741             }
46742           },
46743
46744           /**
46745            * cache().
46746            */
46747           cache: function cache() {
46748             return _ssCache;
46749           }
46750         };
46751
46752         var _apibase$1 = 'https://taginfo.openstreetmap.org/api/4/';
46753         var _inflight$2 = {};
46754         var _popularKeys = {};
46755         var _taginfoCache = {};
46756         var tag_sorts = {
46757           point: 'count_nodes',
46758           vertex: 'count_nodes',
46759           area: 'count_ways',
46760           line: 'count_ways'
46761         };
46762         var tag_sort_members = {
46763           point: 'count_node_members',
46764           vertex: 'count_node_members',
46765           area: 'count_way_members',
46766           line: 'count_way_members',
46767           relation: 'count_relation_members'
46768         };
46769         var tag_filters = {
46770           point: 'nodes',
46771           vertex: 'nodes',
46772           area: 'ways',
46773           line: 'ways'
46774         };
46775         var tag_members_fractions = {
46776           point: 'count_node_members_fraction',
46777           vertex: 'count_node_members_fraction',
46778           area: 'count_way_members_fraction',
46779           line: 'count_way_members_fraction',
46780           relation: 'count_relation_members_fraction'
46781         };
46782
46783         function sets(params, n, o) {
46784           if (params.geometry && o[params.geometry]) {
46785             params[n] = o[params.geometry];
46786           }
46787
46788           return params;
46789         }
46790
46791         function setFilter(params) {
46792           return sets(params, 'filter', tag_filters);
46793         }
46794
46795         function setSort(params) {
46796           return sets(params, 'sortname', tag_sorts);
46797         }
46798
46799         function setSortMembers(params) {
46800           return sets(params, 'sortname', tag_sort_members);
46801         }
46802
46803         function clean(params) {
46804           return utilObjectOmit(params, ['geometry', 'debounce']);
46805         }
46806
46807         function filterKeys(type) {
46808           var count_type = type ? 'count_' + type : 'count_all';
46809           return function (d) {
46810             return parseFloat(d[count_type]) > 2500 || d.in_wiki;
46811           };
46812         }
46813
46814         function filterMultikeys(prefix) {
46815           return function (d) {
46816             // d.key begins with prefix, and d.key contains no additional ':'s
46817             var re = new RegExp('^' + prefix + '(.*)$');
46818             var matches = d.key.match(re) || [];
46819             return matches.length === 2 && matches[1].indexOf(':') === -1;
46820           };
46821         }
46822
46823         function filterValues(allowUpperCase) {
46824           return function (d) {
46825             if (d.value.match(/[;,]/) !== null) return false; // exclude some punctuation
46826
46827             if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false; // exclude uppercase letters
46828
46829             return parseFloat(d.fraction) > 0.0;
46830           };
46831         }
46832
46833         function filterRoles(geometry) {
46834           return function (d) {
46835             if (d.role === '') return false; // exclude empty role
46836
46837             if (d.role.match(/[A-Z*;,]/) !== null) return false; // exclude uppercase letters and some punctuation
46838
46839             return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
46840           };
46841         }
46842
46843         function valKey(d) {
46844           return {
46845             value: d.key,
46846             title: d.key
46847           };
46848         }
46849
46850         function valKeyDescription(d) {
46851           var obj = {
46852             value: d.value,
46853             title: d.description || d.value
46854           };
46855
46856           if (d.count) {
46857             obj.count = d.count;
46858           }
46859
46860           return obj;
46861         }
46862
46863         function roleKey(d) {
46864           return {
46865             value: d.role,
46866             title: d.role
46867           };
46868         } // sort keys with ':' lower than keys without ':'
46869
46870
46871         function sortKeys(a, b) {
46872           return a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1 ? -1 : a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1 ? 1 : 0;
46873         }
46874
46875         var debouncedRequest$1 = debounce(request$1, 300, {
46876           leading: false
46877         });
46878
46879         function request$1(url, params, exactMatch, callback, loaded) {
46880           if (_inflight$2[url]) return;
46881           if (checkCache(url, params, exactMatch, callback)) return;
46882           var controller = new AbortController();
46883           _inflight$2[url] = controller;
46884           d3_json(url, {
46885             signal: controller.signal
46886           }).then(function (result) {
46887             delete _inflight$2[url];
46888             if (loaded) loaded(null, result);
46889           })["catch"](function (err) {
46890             delete _inflight$2[url];
46891             if (err.name === 'AbortError') return;
46892             if (loaded) loaded(err.message);
46893           });
46894         }
46895
46896         function checkCache(url, params, exactMatch, callback) {
46897           var rp = params.rp || 25;
46898           var testQuery = params.query || '';
46899           var testUrl = url;
46900
46901           do {
46902             var hit = _taginfoCache[testUrl]; // exact match, or shorter match yielding fewer than max results (rp)
46903
46904             if (hit && (url === testUrl || hit.length < rp)) {
46905               callback(null, hit);
46906               return true;
46907             } // don't try to shorten the query
46908
46909
46910             if (exactMatch || !testQuery.length) return false; // do shorten the query to see if we already have a cached result
46911             // that has returned fewer than max results (rp)
46912
46913             testQuery = testQuery.slice(0, -1);
46914             testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
46915           } while (testQuery.length >= 0);
46916
46917           return false;
46918         }
46919
46920         var serviceTaginfo = {
46921           init: function init() {
46922             _inflight$2 = {};
46923             _taginfoCache = {};
46924             _popularKeys = {
46925               // manually exclude some keys – #5377, #7485
46926               postal_code: true,
46927               full_name: true,
46928               loc_name: true,
46929               reg_name: true,
46930               short_name: true,
46931               sorting_name: true,
46932               artist_name: true,
46933               nat_name: true,
46934               long_name: true,
46935               'bridge:name': true
46936             }; // Fetch popular keys.  We'll exclude these from `values`
46937             // lookups because they stress taginfo, and they aren't likely
46938             // to yield meaningful autocomplete results.. see #3955
46939
46940             var params = {
46941               rp: 100,
46942               sortname: 'values_all',
46943               sortorder: 'desc',
46944               page: 1,
46945               debounce: false,
46946               lang: _mainLocalizer.languageCode()
46947             };
46948             this.keys(params, function (err, data) {
46949               if (err) return;
46950               data.forEach(function (d) {
46951                 if (d.value === 'opening_hours') return; // exception
46952
46953                 _popularKeys[d.value] = true;
46954               });
46955             });
46956           },
46957           reset: function reset() {
46958             Object.values(_inflight$2).forEach(function (controller) {
46959               controller.abort();
46960             });
46961             _inflight$2 = {};
46962           },
46963           keys: function keys(params, callback) {
46964             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
46965             params = clean(setSort(params));
46966             params = Object.assign({
46967               rp: 10,
46968               sortname: 'count_all',
46969               sortorder: 'desc',
46970               page: 1,
46971               lang: _mainLocalizer.languageCode()
46972             }, params);
46973             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
46974             doRequest(url, params, false, callback, function (err, d) {
46975               if (err) {
46976                 callback(err);
46977               } else {
46978                 var f = filterKeys(params.filter);
46979                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
46980                 _taginfoCache[url] = result;
46981                 callback(null, result);
46982               }
46983             });
46984           },
46985           multikeys: function multikeys(params, callback) {
46986             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
46987             params = clean(setSort(params));
46988             params = Object.assign({
46989               rp: 25,
46990               sortname: 'count_all',
46991               sortorder: 'desc',
46992               page: 1,
46993               lang: _mainLocalizer.languageCode()
46994             }, params);
46995             var prefix = params.query;
46996             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
46997             doRequest(url, params, true, callback, function (err, d) {
46998               if (err) {
46999                 callback(err);
47000               } else {
47001                 var f = filterMultikeys(prefix);
47002                 var result = d.data.filter(f).map(valKey);
47003                 _taginfoCache[url] = result;
47004                 callback(null, result);
47005               }
47006             });
47007           },
47008           values: function values(params, callback) {
47009             // Exclude popular keys from values lookups.. see #3955
47010             var key = params.key;
47011
47012             if (key && _popularKeys[key]) {
47013               callback(null, []);
47014               return;
47015             }
47016
47017             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47018             params = clean(setSort(setFilter(params)));
47019             params = Object.assign({
47020               rp: 25,
47021               sortname: 'count_all',
47022               sortorder: 'desc',
47023               page: 1,
47024               lang: _mainLocalizer.languageCode()
47025             }, params);
47026             var url = _apibase$1 + 'key/values?' + utilQsString(params);
47027             doRequest(url, params, false, callback, function (err, d) {
47028               if (err) {
47029                 callback(err);
47030               } else {
47031                 // In most cases we prefer taginfo value results with lowercase letters.
47032                 // A few OSM keys expect values to contain uppercase values (see #3377).
47033                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
47034                 // but these are the fields where taginfo value lookup is most useful.
47035                 var re = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery/;
47036                 var allowUpperCase = re.test(params.key);
47037                 var f = filterValues(allowUpperCase);
47038                 var result = d.data.filter(f).map(valKeyDescription);
47039                 _taginfoCache[url] = result;
47040                 callback(null, result);
47041               }
47042             });
47043           },
47044           roles: function roles(params, callback) {
47045             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47046             var geometry = params.geometry;
47047             params = clean(setSortMembers(params));
47048             params = Object.assign({
47049               rp: 25,
47050               sortname: 'count_all_members',
47051               sortorder: 'desc',
47052               page: 1,
47053               lang: _mainLocalizer.languageCode()
47054             }, params);
47055             var url = _apibase$1 + 'relation/roles?' + utilQsString(params);
47056             doRequest(url, params, true, callback, function (err, d) {
47057               if (err) {
47058                 callback(err);
47059               } else {
47060                 var f = filterRoles(geometry);
47061                 var result = d.data.filter(f).map(roleKey);
47062                 _taginfoCache[url] = result;
47063                 callback(null, result);
47064               }
47065             });
47066           },
47067           docs: function docs(params, callback) {
47068             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47069             params = clean(setSort(params));
47070             var path = 'key/wiki_pages?';
47071
47072             if (params.value) {
47073               path = 'tag/wiki_pages?';
47074             } else if (params.rtype) {
47075               path = 'relation/wiki_pages?';
47076             }
47077
47078             var url = _apibase$1 + path + utilQsString(params);
47079             doRequest(url, params, true, callback, function (err, d) {
47080               if (err) {
47081                 callback(err);
47082               } else {
47083                 _taginfoCache[url] = d.data;
47084                 callback(null, d.data);
47085               }
47086             });
47087           },
47088           apibase: function apibase(_) {
47089             if (!arguments.length) return _apibase$1;
47090             _apibase$1 = _;
47091             return this;
47092           }
47093         };
47094
47095         var helpers$1 = createCommonjsModule(function (module, exports) {
47096
47097           Object.defineProperty(exports, "__esModule", {
47098             value: true
47099           });
47100           /**
47101            * @module helpers
47102            */
47103
47104           /**
47105            * Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth.
47106            *
47107            * @memberof helpers
47108            * @type {number}
47109            */
47110
47111           exports.earthRadius = 6371008.8;
47112           /**
47113            * Unit of measurement factors using a spherical (non-ellipsoid) earth radius.
47114            *
47115            * @memberof helpers
47116            * @type {Object}
47117            */
47118
47119           exports.factors = {
47120             centimeters: exports.earthRadius * 100,
47121             centimetres: exports.earthRadius * 100,
47122             degrees: exports.earthRadius / 111325,
47123             feet: exports.earthRadius * 3.28084,
47124             inches: exports.earthRadius * 39.370,
47125             kilometers: exports.earthRadius / 1000,
47126             kilometres: exports.earthRadius / 1000,
47127             meters: exports.earthRadius,
47128             metres: exports.earthRadius,
47129             miles: exports.earthRadius / 1609.344,
47130             millimeters: exports.earthRadius * 1000,
47131             millimetres: exports.earthRadius * 1000,
47132             nauticalmiles: exports.earthRadius / 1852,
47133             radians: 1,
47134             yards: exports.earthRadius / 1.0936
47135           };
47136           /**
47137            * Units of measurement factors based on 1 meter.
47138            *
47139            * @memberof helpers
47140            * @type {Object}
47141            */
47142
47143           exports.unitsFactors = {
47144             centimeters: 100,
47145             centimetres: 100,
47146             degrees: 1 / 111325,
47147             feet: 3.28084,
47148             inches: 39.370,
47149             kilometers: 1 / 1000,
47150             kilometres: 1 / 1000,
47151             meters: 1,
47152             metres: 1,
47153             miles: 1 / 1609.344,
47154             millimeters: 1000,
47155             millimetres: 1000,
47156             nauticalmiles: 1 / 1852,
47157             radians: 1 / exports.earthRadius,
47158             yards: 1 / 1.0936
47159           };
47160           /**
47161            * Area of measurement factors based on 1 square meter.
47162            *
47163            * @memberof helpers
47164            * @type {Object}
47165            */
47166
47167           exports.areaFactors = {
47168             acres: 0.000247105,
47169             centimeters: 10000,
47170             centimetres: 10000,
47171             feet: 10.763910417,
47172             inches: 1550.003100006,
47173             kilometers: 0.000001,
47174             kilometres: 0.000001,
47175             meters: 1,
47176             metres: 1,
47177             miles: 3.86e-7,
47178             millimeters: 1000000,
47179             millimetres: 1000000,
47180             yards: 1.195990046
47181           };
47182           /**
47183            * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
47184            *
47185            * @name feature
47186            * @param {Geometry} geometry input geometry
47187            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47188            * @param {Object} [options={}] Optional Parameters
47189            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47190            * @param {string|number} [options.id] Identifier associated with the Feature
47191            * @returns {Feature} a GeoJSON Feature
47192            * @example
47193            * var geometry = {
47194            *   "type": "Point",
47195            *   "coordinates": [110, 50]
47196            * };
47197            *
47198            * var feature = turf.feature(geometry);
47199            *
47200            * //=feature
47201            */
47202
47203           function feature(geom, properties, options) {
47204             if (options === void 0) {
47205               options = {};
47206             }
47207
47208             var feat = {
47209               type: "Feature"
47210             };
47211
47212             if (options.id === 0 || options.id) {
47213               feat.id = options.id;
47214             }
47215
47216             if (options.bbox) {
47217               feat.bbox = options.bbox;
47218             }
47219
47220             feat.properties = properties || {};
47221             feat.geometry = geom;
47222             return feat;
47223           }
47224
47225           exports.feature = feature;
47226           /**
47227            * Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
47228            * For GeometryCollection type use `helpers.geometryCollection`
47229            *
47230            * @name geometry
47231            * @param {string} type Geometry Type
47232            * @param {Array<any>} coordinates Coordinates
47233            * @param {Object} [options={}] Optional Parameters
47234            * @returns {Geometry} a GeoJSON Geometry
47235            * @example
47236            * var type = "Point";
47237            * var coordinates = [110, 50];
47238            * var geometry = turf.geometry(type, coordinates);
47239            * // => geometry
47240            */
47241
47242           function geometry(type, coordinates, options) {
47243
47244             switch (type) {
47245               case "Point":
47246                 return point(coordinates).geometry;
47247
47248               case "LineString":
47249                 return lineString(coordinates).geometry;
47250
47251               case "Polygon":
47252                 return polygon(coordinates).geometry;
47253
47254               case "MultiPoint":
47255                 return multiPoint(coordinates).geometry;
47256
47257               case "MultiLineString":
47258                 return multiLineString(coordinates).geometry;
47259
47260               case "MultiPolygon":
47261                 return multiPolygon(coordinates).geometry;
47262
47263               default:
47264                 throw new Error(type + " is invalid");
47265             }
47266           }
47267
47268           exports.geometry = geometry;
47269           /**
47270            * Creates a {@link Point} {@link Feature} from a Position.
47271            *
47272            * @name point
47273            * @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
47274            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47275            * @param {Object} [options={}] Optional Parameters
47276            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47277            * @param {string|number} [options.id] Identifier associated with the Feature
47278            * @returns {Feature<Point>} a Point feature
47279            * @example
47280            * var point = turf.point([-75.343, 39.984]);
47281            *
47282            * //=point
47283            */
47284
47285           function point(coordinates, properties, options) {
47286             if (options === void 0) {
47287               options = {};
47288             }
47289
47290             var geom = {
47291               type: "Point",
47292               coordinates: coordinates
47293             };
47294             return feature(geom, properties, options);
47295           }
47296
47297           exports.point = point;
47298           /**
47299            * Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates.
47300            *
47301            * @name points
47302            * @param {Array<Array<number>>} coordinates an array of Points
47303            * @param {Object} [properties={}] Translate these properties to each Feature
47304            * @param {Object} [options={}] Optional Parameters
47305            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
47306            * associated with the FeatureCollection
47307            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47308            * @returns {FeatureCollection<Point>} Point Feature
47309            * @example
47310            * var points = turf.points([
47311            *   [-75, 39],
47312            *   [-80, 45],
47313            *   [-78, 50]
47314            * ]);
47315            *
47316            * //=points
47317            */
47318
47319           function points(coordinates, properties, options) {
47320             if (options === void 0) {
47321               options = {};
47322             }
47323
47324             return featureCollection(coordinates.map(function (coords) {
47325               return point(coords, properties);
47326             }), options);
47327           }
47328
47329           exports.points = points;
47330           /**
47331            * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
47332            *
47333            * @name polygon
47334            * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
47335            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47336            * @param {Object} [options={}] Optional Parameters
47337            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47338            * @param {string|number} [options.id] Identifier associated with the Feature
47339            * @returns {Feature<Polygon>} Polygon Feature
47340            * @example
47341            * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
47342            *
47343            * //=polygon
47344            */
47345
47346           function polygon(coordinates, properties, options) {
47347             if (options === void 0) {
47348               options = {};
47349             }
47350
47351             for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
47352               var ring = coordinates_1[_i];
47353
47354               if (ring.length < 4) {
47355                 throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
47356               }
47357
47358               for (var j = 0; j < ring[ring.length - 1].length; j++) {
47359                 // Check if first point of Polygon contains two numbers
47360                 if (ring[ring.length - 1][j] !== ring[0][j]) {
47361                   throw new Error("First and last Position are not equivalent.");
47362                 }
47363               }
47364             }
47365
47366             var geom = {
47367               type: "Polygon",
47368               coordinates: coordinates
47369             };
47370             return feature(geom, properties, options);
47371           }
47372
47373           exports.polygon = polygon;
47374           /**
47375            * Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates.
47376            *
47377            * @name polygons
47378            * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates
47379            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47380            * @param {Object} [options={}] Optional Parameters
47381            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47382            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47383            * @returns {FeatureCollection<Polygon>} Polygon FeatureCollection
47384            * @example
47385            * var polygons = turf.polygons([
47386            *   [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]],
47387            *   [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]],
47388            * ]);
47389            *
47390            * //=polygons
47391            */
47392
47393           function polygons(coordinates, properties, options) {
47394             if (options === void 0) {
47395               options = {};
47396             }
47397
47398             return featureCollection(coordinates.map(function (coords) {
47399               return polygon(coords, properties);
47400             }), options);
47401           }
47402
47403           exports.polygons = polygons;
47404           /**
47405            * Creates a {@link LineString} {@link Feature} from an Array of Positions.
47406            *
47407            * @name lineString
47408            * @param {Array<Array<number>>} coordinates an array of Positions
47409            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47410            * @param {Object} [options={}] Optional Parameters
47411            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47412            * @param {string|number} [options.id] Identifier associated with the Feature
47413            * @returns {Feature<LineString>} LineString Feature
47414            * @example
47415            * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
47416            * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
47417            *
47418            * //=linestring1
47419            * //=linestring2
47420            */
47421
47422           function lineString(coordinates, properties, options) {
47423             if (options === void 0) {
47424               options = {};
47425             }
47426
47427             if (coordinates.length < 2) {
47428               throw new Error("coordinates must be an array of two or more positions");
47429             }
47430
47431             var geom = {
47432               type: "LineString",
47433               coordinates: coordinates
47434             };
47435             return feature(geom, properties, options);
47436           }
47437
47438           exports.lineString = lineString;
47439           /**
47440            * Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates.
47441            *
47442            * @name lineStrings
47443            * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
47444            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47445            * @param {Object} [options={}] Optional Parameters
47446            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
47447            * associated with the FeatureCollection
47448            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47449            * @returns {FeatureCollection<LineString>} LineString FeatureCollection
47450            * @example
47451            * var linestrings = turf.lineStrings([
47452            *   [[-24, 63], [-23, 60], [-25, 65], [-20, 69]],
47453            *   [[-14, 43], [-13, 40], [-15, 45], [-10, 49]]
47454            * ]);
47455            *
47456            * //=linestrings
47457            */
47458
47459           function lineStrings(coordinates, properties, options) {
47460             if (options === void 0) {
47461               options = {};
47462             }
47463
47464             return featureCollection(coordinates.map(function (coords) {
47465               return lineString(coords, properties);
47466             }), options);
47467           }
47468
47469           exports.lineStrings = lineStrings;
47470           /**
47471            * Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
47472            *
47473            * @name featureCollection
47474            * @param {Feature[]} features input features
47475            * @param {Object} [options={}] Optional Parameters
47476            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47477            * @param {string|number} [options.id] Identifier associated with the Feature
47478            * @returns {FeatureCollection} FeatureCollection of Features
47479            * @example
47480            * var locationA = turf.point([-75.343, 39.984], {name: 'Location A'});
47481            * var locationB = turf.point([-75.833, 39.284], {name: 'Location B'});
47482            * var locationC = turf.point([-75.534, 39.123], {name: 'Location C'});
47483            *
47484            * var collection = turf.featureCollection([
47485            *   locationA,
47486            *   locationB,
47487            *   locationC
47488            * ]);
47489            *
47490            * //=collection
47491            */
47492
47493           function featureCollection(features, options) {
47494             if (options === void 0) {
47495               options = {};
47496             }
47497
47498             var fc = {
47499               type: "FeatureCollection"
47500             };
47501
47502             if (options.id) {
47503               fc.id = options.id;
47504             }
47505
47506             if (options.bbox) {
47507               fc.bbox = options.bbox;
47508             }
47509
47510             fc.features = features;
47511             return fc;
47512           }
47513
47514           exports.featureCollection = featureCollection;
47515           /**
47516            * Creates a {@link Feature<MultiLineString>} based on a
47517            * coordinate array. Properties can be added optionally.
47518            *
47519            * @name multiLineString
47520            * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
47521            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47522            * @param {Object} [options={}] Optional Parameters
47523            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47524            * @param {string|number} [options.id] Identifier associated with the Feature
47525            * @returns {Feature<MultiLineString>} a MultiLineString feature
47526            * @throws {Error} if no coordinates are passed
47527            * @example
47528            * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
47529            *
47530            * //=multiLine
47531            */
47532
47533           function multiLineString(coordinates, properties, options) {
47534             if (options === void 0) {
47535               options = {};
47536             }
47537
47538             var geom = {
47539               type: "MultiLineString",
47540               coordinates: coordinates
47541             };
47542             return feature(geom, properties, options);
47543           }
47544
47545           exports.multiLineString = multiLineString;
47546           /**
47547            * Creates a {@link Feature<MultiPoint>} based on a
47548            * coordinate array. Properties can be added optionally.
47549            *
47550            * @name multiPoint
47551            * @param {Array<Array<number>>} coordinates an array of Positions
47552            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47553            * @param {Object} [options={}] Optional Parameters
47554            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47555            * @param {string|number} [options.id] Identifier associated with the Feature
47556            * @returns {Feature<MultiPoint>} a MultiPoint feature
47557            * @throws {Error} if no coordinates are passed
47558            * @example
47559            * var multiPt = turf.multiPoint([[0,0],[10,10]]);
47560            *
47561            * //=multiPt
47562            */
47563
47564           function multiPoint(coordinates, properties, options) {
47565             if (options === void 0) {
47566               options = {};
47567             }
47568
47569             var geom = {
47570               type: "MultiPoint",
47571               coordinates: coordinates
47572             };
47573             return feature(geom, properties, options);
47574           }
47575
47576           exports.multiPoint = multiPoint;
47577           /**
47578            * Creates a {@link Feature<MultiPolygon>} based on a
47579            * coordinate array. Properties can be added optionally.
47580            *
47581            * @name multiPolygon
47582            * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
47583            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47584            * @param {Object} [options={}] Optional Parameters
47585            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47586            * @param {string|number} [options.id] Identifier associated with the Feature
47587            * @returns {Feature<MultiPolygon>} a multipolygon feature
47588            * @throws {Error} if no coordinates are passed
47589            * @example
47590            * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
47591            *
47592            * //=multiPoly
47593            *
47594            */
47595
47596           function multiPolygon(coordinates, properties, options) {
47597             if (options === void 0) {
47598               options = {};
47599             }
47600
47601             var geom = {
47602               type: "MultiPolygon",
47603               coordinates: coordinates
47604             };
47605             return feature(geom, properties, options);
47606           }
47607
47608           exports.multiPolygon = multiPolygon;
47609           /**
47610            * Creates a {@link Feature<GeometryCollection>} based on a
47611            * coordinate array. Properties can be added optionally.
47612            *
47613            * @name geometryCollection
47614            * @param {Array<Geometry>} geometries an array of GeoJSON Geometries
47615            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47616            * @param {Object} [options={}] Optional Parameters
47617            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47618            * @param {string|number} [options.id] Identifier associated with the Feature
47619            * @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
47620            * @example
47621            * var pt = turf.geometry("Point", [100, 0]);
47622            * var line = turf.geometry("LineString", [[101, 0], [102, 1]]);
47623            * var collection = turf.geometryCollection([pt, line]);
47624            *
47625            * // => collection
47626            */
47627
47628           function geometryCollection(geometries, properties, options) {
47629             if (options === void 0) {
47630               options = {};
47631             }
47632
47633             var geom = {
47634               type: "GeometryCollection",
47635               geometries: geometries
47636             };
47637             return feature(geom, properties, options);
47638           }
47639
47640           exports.geometryCollection = geometryCollection;
47641           /**
47642            * Round number to precision
47643            *
47644            * @param {number} num Number
47645            * @param {number} [precision=0] Precision
47646            * @returns {number} rounded number
47647            * @example
47648            * turf.round(120.4321)
47649            * //=120
47650            *
47651            * turf.round(120.4321, 2)
47652            * //=120.43
47653            */
47654
47655           function round(num, precision) {
47656             if (precision === void 0) {
47657               precision = 0;
47658             }
47659
47660             if (precision && !(precision >= 0)) {
47661               throw new Error("precision must be a positive number");
47662             }
47663
47664             var multiplier = Math.pow(10, precision || 0);
47665             return Math.round(num * multiplier) / multiplier;
47666           }
47667
47668           exports.round = round;
47669           /**
47670            * Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
47671            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47672            *
47673            * @name radiansToLength
47674            * @param {number} radians in radians across the sphere
47675            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47676            * meters, kilometres, kilometers.
47677            * @returns {number} distance
47678            */
47679
47680           function radiansToLength(radians, units) {
47681             if (units === void 0) {
47682               units = "kilometers";
47683             }
47684
47685             var factor = exports.factors[units];
47686
47687             if (!factor) {
47688               throw new Error(units + " units is invalid");
47689             }
47690
47691             return radians * factor;
47692           }
47693
47694           exports.radiansToLength = radiansToLength;
47695           /**
47696            * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
47697            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47698            *
47699            * @name lengthToRadians
47700            * @param {number} distance in real units
47701            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47702            * meters, kilometres, kilometers.
47703            * @returns {number} radians
47704            */
47705
47706           function lengthToRadians(distance, units) {
47707             if (units === void 0) {
47708               units = "kilometers";
47709             }
47710
47711             var factor = exports.factors[units];
47712
47713             if (!factor) {
47714               throw new Error(units + " units is invalid");
47715             }
47716
47717             return distance / factor;
47718           }
47719
47720           exports.lengthToRadians = lengthToRadians;
47721           /**
47722            * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
47723            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
47724            *
47725            * @name lengthToDegrees
47726            * @param {number} distance in real units
47727            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47728            * meters, kilometres, kilometers.
47729            * @returns {number} degrees
47730            */
47731
47732           function lengthToDegrees(distance, units) {
47733             return radiansToDegrees(lengthToRadians(distance, units));
47734           }
47735
47736           exports.lengthToDegrees = lengthToDegrees;
47737           /**
47738            * Converts any bearing angle from the north line direction (positive clockwise)
47739            * and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
47740            *
47741            * @name bearingToAzimuth
47742            * @param {number} bearing angle, between -180 and +180 degrees
47743            * @returns {number} angle between 0 and 360 degrees
47744            */
47745
47746           function bearingToAzimuth(bearing) {
47747             var angle = bearing % 360;
47748
47749             if (angle < 0) {
47750               angle += 360;
47751             }
47752
47753             return angle;
47754           }
47755
47756           exports.bearingToAzimuth = bearingToAzimuth;
47757           /**
47758            * Converts an angle in radians to degrees
47759            *
47760            * @name radiansToDegrees
47761            * @param {number} radians angle in radians
47762            * @returns {number} degrees between 0 and 360 degrees
47763            */
47764
47765           function radiansToDegrees(radians) {
47766             var degrees = radians % (2 * Math.PI);
47767             return degrees * 180 / Math.PI;
47768           }
47769
47770           exports.radiansToDegrees = radiansToDegrees;
47771           /**
47772            * Converts an angle in degrees to radians
47773            *
47774            * @name degreesToRadians
47775            * @param {number} degrees angle between 0 and 360 degrees
47776            * @returns {number} angle in radians
47777            */
47778
47779           function degreesToRadians(degrees) {
47780             var radians = degrees % 360;
47781             return radians * Math.PI / 180;
47782           }
47783
47784           exports.degreesToRadians = degreesToRadians;
47785           /**
47786            * Converts a length to the requested unit.
47787            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47788            *
47789            * @param {number} length to be converted
47790            * @param {Units} [originalUnit="kilometers"] of the length
47791            * @param {Units} [finalUnit="kilometers"] returned unit
47792            * @returns {number} the converted length
47793            */
47794
47795           function convertLength(length, originalUnit, finalUnit) {
47796             if (originalUnit === void 0) {
47797               originalUnit = "kilometers";
47798             }
47799
47800             if (finalUnit === void 0) {
47801               finalUnit = "kilometers";
47802             }
47803
47804             if (!(length >= 0)) {
47805               throw new Error("length must be a positive number");
47806             }
47807
47808             return radiansToLength(lengthToRadians(length, originalUnit), finalUnit);
47809           }
47810
47811           exports.convertLength = convertLength;
47812           /**
47813            * Converts a area to the requested unit.
47814            * Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches
47815            * @param {number} area to be converted
47816            * @param {Units} [originalUnit="meters"] of the distance
47817            * @param {Units} [finalUnit="kilometers"] returned unit
47818            * @returns {number} the converted distance
47819            */
47820
47821           function convertArea(area, originalUnit, finalUnit) {
47822             if (originalUnit === void 0) {
47823               originalUnit = "meters";
47824             }
47825
47826             if (finalUnit === void 0) {
47827               finalUnit = "kilometers";
47828             }
47829
47830             if (!(area >= 0)) {
47831               throw new Error("area must be a positive number");
47832             }
47833
47834             var startFactor = exports.areaFactors[originalUnit];
47835
47836             if (!startFactor) {
47837               throw new Error("invalid original units");
47838             }
47839
47840             var finalFactor = exports.areaFactors[finalUnit];
47841
47842             if (!finalFactor) {
47843               throw new Error("invalid final units");
47844             }
47845
47846             return area / startFactor * finalFactor;
47847           }
47848
47849           exports.convertArea = convertArea;
47850           /**
47851            * isNumber
47852            *
47853            * @param {*} num Number to validate
47854            * @returns {boolean} true/false
47855            * @example
47856            * turf.isNumber(123)
47857            * //=true
47858            * turf.isNumber('foo')
47859            * //=false
47860            */
47861
47862           function isNumber(num) {
47863             return !isNaN(num) && num !== null && !Array.isArray(num) && !/^\s*$/.test(num);
47864           }
47865
47866           exports.isNumber = isNumber;
47867           /**
47868            * isObject
47869            *
47870            * @param {*} input variable to validate
47871            * @returns {boolean} true/false
47872            * @example
47873            * turf.isObject({elevation: 10})
47874            * //=true
47875            * turf.isObject('foo')
47876            * //=false
47877            */
47878
47879           function isObject(input) {
47880             return !!input && input.constructor === Object;
47881           }
47882
47883           exports.isObject = isObject;
47884           /**
47885            * Validate BBox
47886            *
47887            * @private
47888            * @param {Array<number>} bbox BBox to validate
47889            * @returns {void}
47890            * @throws Error if BBox is not valid
47891            * @example
47892            * validateBBox([-180, -40, 110, 50])
47893            * //=OK
47894            * validateBBox([-180, -40])
47895            * //=Error
47896            * validateBBox('Foo')
47897            * //=Error
47898            * validateBBox(5)
47899            * //=Error
47900            * validateBBox(null)
47901            * //=Error
47902            * validateBBox(undefined)
47903            * //=Error
47904            */
47905
47906           function validateBBox(bbox) {
47907             if (!bbox) {
47908               throw new Error("bbox is required");
47909             }
47910
47911             if (!Array.isArray(bbox)) {
47912               throw new Error("bbox must be an Array");
47913             }
47914
47915             if (bbox.length !== 4 && bbox.length !== 6) {
47916               throw new Error("bbox must be an Array of 4 or 6 numbers");
47917             }
47918
47919             bbox.forEach(function (num) {
47920               if (!isNumber(num)) {
47921                 throw new Error("bbox must only contain numbers");
47922               }
47923             });
47924           }
47925
47926           exports.validateBBox = validateBBox;
47927           /**
47928            * Validate Id
47929            *
47930            * @private
47931            * @param {string|number} id Id to validate
47932            * @returns {void}
47933            * @throws Error if Id is not valid
47934            * @example
47935            * validateId([-180, -40, 110, 50])
47936            * //=Error
47937            * validateId([-180, -40])
47938            * //=Error
47939            * validateId('Foo')
47940            * //=OK
47941            * validateId(5)
47942            * //=OK
47943            * validateId(null)
47944            * //=Error
47945            * validateId(undefined)
47946            * //=Error
47947            */
47948
47949           function validateId(id) {
47950             if (!id) {
47951               throw new Error("id is required");
47952             }
47953
47954             if (["string", "number"].indexOf(_typeof(id)) === -1) {
47955               throw new Error("id must be a number or a string");
47956             }
47957           }
47958
47959           exports.validateId = validateId; // Deprecated methods
47960
47961           function radians2degrees() {
47962             throw new Error("method has been renamed to `radiansToDegrees`");
47963           }
47964
47965           exports.radians2degrees = radians2degrees;
47966
47967           function degrees2radians() {
47968             throw new Error("method has been renamed to `degreesToRadians`");
47969           }
47970
47971           exports.degrees2radians = degrees2radians;
47972
47973           function distanceToDegrees() {
47974             throw new Error("method has been renamed to `lengthToDegrees`");
47975           }
47976
47977           exports.distanceToDegrees = distanceToDegrees;
47978
47979           function distanceToRadians() {
47980             throw new Error("method has been renamed to `lengthToRadians`");
47981           }
47982
47983           exports.distanceToRadians = distanceToRadians;
47984
47985           function radiansToDistance() {
47986             throw new Error("method has been renamed to `radiansToLength`");
47987           }
47988
47989           exports.radiansToDistance = radiansToDistance;
47990
47991           function bearingToAngle() {
47992             throw new Error("method has been renamed to `bearingToAzimuth`");
47993           }
47994
47995           exports.bearingToAngle = bearingToAngle;
47996
47997           function convertDistance() {
47998             throw new Error("method has been renamed to `convertLength`");
47999           }
48000
48001           exports.convertDistance = convertDistance;
48002         });
48003
48004         var invariant = createCommonjsModule(function (module, exports) {
48005
48006           Object.defineProperty(exports, "__esModule", {
48007             value: true
48008           });
48009           /**
48010            * Unwrap a coordinate from a Point Feature, Geometry or a single coordinate.
48011            *
48012            * @name getCoord
48013            * @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers
48014            * @returns {Array<number>} coordinates
48015            * @example
48016            * var pt = turf.point([10, 10]);
48017            *
48018            * var coord = turf.getCoord(pt);
48019            * //= [10, 10]
48020            */
48021
48022           function getCoord(coord) {
48023             if (!coord) {
48024               throw new Error("coord is required");
48025             }
48026
48027             if (!Array.isArray(coord)) {
48028               if (coord.type === "Feature" && coord.geometry !== null && coord.geometry.type === "Point") {
48029                 return coord.geometry.coordinates;
48030               }
48031
48032               if (coord.type === "Point") {
48033                 return coord.coordinates;
48034               }
48035             }
48036
48037             if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) {
48038               return coord;
48039             }
48040
48041             throw new Error("coord must be GeoJSON Point or an Array of numbers");
48042           }
48043
48044           exports.getCoord = getCoord;
48045           /**
48046            * Unwrap coordinates from a Feature, Geometry Object or an Array
48047            *
48048            * @name getCoords
48049            * @param {Array<any>|Geometry|Feature} coords Feature, Geometry Object or an Array
48050            * @returns {Array<any>} coordinates
48051            * @example
48052            * var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]);
48053            *
48054            * var coords = turf.getCoords(poly);
48055            * //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]
48056            */
48057
48058           function getCoords(coords) {
48059             if (Array.isArray(coords)) {
48060               return coords;
48061             } // Feature
48062
48063
48064             if (coords.type === "Feature") {
48065               if (coords.geometry !== null) {
48066                 return coords.geometry.coordinates;
48067               }
48068             } else {
48069               // Geometry
48070               if (coords.coordinates) {
48071                 return coords.coordinates;
48072               }
48073             }
48074
48075             throw new Error("coords must be GeoJSON Feature, Geometry Object or an Array");
48076           }
48077
48078           exports.getCoords = getCoords;
48079           /**
48080            * Checks if coordinates contains a number
48081            *
48082            * @name containsNumber
48083            * @param {Array<any>} coordinates GeoJSON Coordinates
48084            * @returns {boolean} true if Array contains a number
48085            */
48086
48087           function containsNumber(coordinates) {
48088             if (coordinates.length > 1 && helpers$1.isNumber(coordinates[0]) && helpers$1.isNumber(coordinates[1])) {
48089               return true;
48090             }
48091
48092             if (Array.isArray(coordinates[0]) && coordinates[0].length) {
48093               return containsNumber(coordinates[0]);
48094             }
48095
48096             throw new Error("coordinates must only contain numbers");
48097           }
48098
48099           exports.containsNumber = containsNumber;
48100           /**
48101            * Enforce expectations about types of GeoJSON objects for Turf.
48102            *
48103            * @name geojsonType
48104            * @param {GeoJSON} value any GeoJSON object
48105            * @param {string} type expected GeoJSON type
48106            * @param {string} name name of calling function
48107            * @throws {Error} if value is not the expected type.
48108            */
48109
48110           function geojsonType(value, type, name) {
48111             if (!type || !name) {
48112               throw new Error("type and name required");
48113             }
48114
48115             if (!value || value.type !== type) {
48116               throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + value.type);
48117             }
48118           }
48119
48120           exports.geojsonType = geojsonType;
48121           /**
48122            * Enforce expectations about types of {@link Feature} inputs for Turf.
48123            * Internally this uses {@link geojsonType} to judge geometry types.
48124            *
48125            * @name featureOf
48126            * @param {Feature} feature a feature with an expected geometry type
48127            * @param {string} type expected GeoJSON type
48128            * @param {string} name name of calling function
48129            * @throws {Error} error if value is not the expected type.
48130            */
48131
48132           function featureOf(feature, type, name) {
48133             if (!feature) {
48134               throw new Error("No feature passed");
48135             }
48136
48137             if (!name) {
48138               throw new Error(".featureOf() requires a name");
48139             }
48140
48141             if (!feature || feature.type !== "Feature" || !feature.geometry) {
48142               throw new Error("Invalid input to " + name + ", Feature with geometry required");
48143             }
48144
48145             if (!feature.geometry || feature.geometry.type !== type) {
48146               throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
48147             }
48148           }
48149
48150           exports.featureOf = featureOf;
48151           /**
48152            * Enforce expectations about types of {@link FeatureCollection} inputs for Turf.
48153            * Internally this uses {@link geojsonType} to judge geometry types.
48154            *
48155            * @name collectionOf
48156            * @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged
48157            * @param {string} type expected GeoJSON type
48158            * @param {string} name name of calling function
48159            * @throws {Error} if value is not the expected type.
48160            */
48161
48162           function collectionOf(featureCollection, type, name) {
48163             if (!featureCollection) {
48164               throw new Error("No featureCollection passed");
48165             }
48166
48167             if (!name) {
48168               throw new Error(".collectionOf() requires a name");
48169             }
48170
48171             if (!featureCollection || featureCollection.type !== "FeatureCollection") {
48172               throw new Error("Invalid input to " + name + ", FeatureCollection required");
48173             }
48174
48175             for (var _i = 0, _a = featureCollection.features; _i < _a.length; _i++) {
48176               var feature = _a[_i];
48177
48178               if (!feature || feature.type !== "Feature" || !feature.geometry) {
48179                 throw new Error("Invalid input to " + name + ", Feature with geometry required");
48180               }
48181
48182               if (!feature.geometry || feature.geometry.type !== type) {
48183                 throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
48184               }
48185             }
48186           }
48187
48188           exports.collectionOf = collectionOf;
48189           /**
48190            * Get Geometry from Feature or Geometry Object
48191            *
48192            * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
48193            * @returns {Geometry|null} GeoJSON Geometry Object
48194            * @throws {Error} if geojson is not a Feature or Geometry Object
48195            * @example
48196            * var point = {
48197            *   "type": "Feature",
48198            *   "properties": {},
48199            *   "geometry": {
48200            *     "type": "Point",
48201            *     "coordinates": [110, 40]
48202            *   }
48203            * }
48204            * var geom = turf.getGeom(point)
48205            * //={"type": "Point", "coordinates": [110, 40]}
48206            */
48207
48208           function getGeom(geojson) {
48209             if (geojson.type === "Feature") {
48210               return geojson.geometry;
48211             }
48212
48213             return geojson;
48214           }
48215
48216           exports.getGeom = getGeom;
48217           /**
48218            * Get GeoJSON object's type, Geometry type is prioritize.
48219            *
48220            * @param {GeoJSON} geojson GeoJSON object
48221            * @param {string} [name="geojson"] name of the variable to display in error message
48222            * @returns {string} GeoJSON type
48223            * @example
48224            * var point = {
48225            *   "type": "Feature",
48226            *   "properties": {},
48227            *   "geometry": {
48228            *     "type": "Point",
48229            *     "coordinates": [110, 40]
48230            *   }
48231            * }
48232            * var geom = turf.getType(point)
48233            * //="Point"
48234            */
48235
48236           function getType(geojson, name) {
48237             if (geojson.type === "FeatureCollection") {
48238               return "FeatureCollection";
48239             }
48240
48241             if (geojson.type === "GeometryCollection") {
48242               return "GeometryCollection";
48243             }
48244
48245             if (geojson.type === "Feature" && geojson.geometry !== null) {
48246               return geojson.geometry.type;
48247             }
48248
48249             return geojson.type;
48250           }
48251
48252           exports.getType = getType;
48253         });
48254
48255         var lineclip_1 = lineclip;
48256         var _default = lineclip;
48257         lineclip.polyline = lineclip;
48258         lineclip.polygon = polygonclip; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
48259         // handle polylines rather than just segments
48260
48261         function lineclip(points, bbox, result) {
48262           var len = points.length,
48263               codeA = bitCode(points[0], bbox),
48264               part = [],
48265               i,
48266               a,
48267               b,
48268               codeB,
48269               lastCode;
48270           if (!result) result = [];
48271
48272           for (i = 1; i < len; i++) {
48273             a = points[i - 1];
48274             b = points[i];
48275             codeB = lastCode = bitCode(b, bbox);
48276
48277             while (true) {
48278               if (!(codeA | codeB)) {
48279                 // accept
48280                 part.push(a);
48281
48282                 if (codeB !== lastCode) {
48283                   // segment went outside
48284                   part.push(b);
48285
48286                   if (i < len - 1) {
48287                     // start a new line
48288                     result.push(part);
48289                     part = [];
48290                   }
48291                 } else if (i === len - 1) {
48292                   part.push(b);
48293                 }
48294
48295                 break;
48296               } else if (codeA & codeB) {
48297                 // trivial reject
48298                 break;
48299               } else if (codeA) {
48300                 // a outside, intersect with clip edge
48301                 a = intersect(a, b, codeA, bbox);
48302                 codeA = bitCode(a, bbox);
48303               } else {
48304                 // b outside
48305                 b = intersect(a, b, codeB, bbox);
48306                 codeB = bitCode(b, bbox);
48307               }
48308             }
48309
48310             codeA = lastCode;
48311           }
48312
48313           if (part.length) result.push(part);
48314           return result;
48315         } // Sutherland-Hodgeman polygon clipping algorithm
48316
48317
48318         function polygonclip(points, bbox) {
48319           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
48320
48321           for (edge = 1; edge <= 8; edge *= 2) {
48322             result = [];
48323             prev = points[points.length - 1];
48324             prevInside = !(bitCode(prev, bbox) & edge);
48325
48326             for (i = 0; i < points.length; i++) {
48327               p = points[i];
48328               inside = !(bitCode(p, bbox) & edge); // if segment goes through the clip window, add an intersection
48329
48330               if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
48331               if (inside) result.push(p); // add a point if it's inside
48332
48333               prev = p;
48334               prevInside = inside;
48335             }
48336
48337             points = result;
48338             if (!points.length) break;
48339           }
48340
48341           return result;
48342         } // intersect a segment against one of the 4 lines that make up the bbox
48343
48344
48345         function intersect(a, b, edge, bbox) {
48346           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
48347           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
48348           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
48349           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
48350           null;
48351         } // bit code reflects the point position relative to the bbox:
48352         //         left  mid  right
48353         //    top  1001  1000  1010
48354         //    mid  0001  0000  0010
48355         // bottom  0101  0100  0110
48356
48357
48358         function bitCode(p, bbox) {
48359           var code = 0;
48360           if (p[0] < bbox[0]) code |= 1; // left
48361           else if (p[0] > bbox[2]) code |= 2; // right
48362
48363           if (p[1] < bbox[1]) code |= 4; // bottom
48364           else if (p[1] > bbox[3]) code |= 8; // top
48365
48366           return code;
48367         }
48368         lineclip_1["default"] = _default;
48369
48370         var bboxClip_1 = createCommonjsModule(function (module, exports) {
48371
48372           var __importStar = commonjsGlobal && commonjsGlobal.__importStar || function (mod) {
48373             if (mod && mod.__esModule) return mod;
48374             var result = {};
48375             if (mod != null) for (var k in mod) {
48376               if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
48377             }
48378             result["default"] = mod;
48379             return result;
48380           };
48381
48382           Object.defineProperty(exports, "__esModule", {
48383             value: true
48384           });
48385
48386           var lineclip = __importStar(lineclip_1);
48387           /**
48388            * Takes a {@link Feature} and a bbox and clips the feature to the bbox using
48389            * [lineclip](https://github.com/mapbox/lineclip).
48390            * May result in degenerate edges when clipping Polygons.
48391            *
48392            * @name bboxClip
48393            * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
48394            * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
48395            * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
48396            * @example
48397            * var bbox = [0, 0, 10, 10];
48398            * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
48399            *
48400            * var clipped = turf.bboxClip(poly, bbox);
48401            *
48402            * //addToMap
48403            * var addToMap = [bbox, poly, clipped]
48404            */
48405
48406
48407           function bboxClip(feature, bbox) {
48408             var geom = invariant.getGeom(feature);
48409             var type = geom.type;
48410             var properties = feature.type === "Feature" ? feature.properties : {};
48411             var coords = geom.coordinates;
48412
48413             switch (type) {
48414               case "LineString":
48415               case "MultiLineString":
48416                 var lines_1 = [];
48417
48418                 if (type === "LineString") {
48419                   coords = [coords];
48420                 }
48421
48422                 coords.forEach(function (line) {
48423                   lineclip.polyline(line, bbox, lines_1);
48424                 });
48425
48426                 if (lines_1.length === 1) {
48427                   return helpers$1.lineString(lines_1[0], properties);
48428                 }
48429
48430                 return helpers$1.multiLineString(lines_1, properties);
48431
48432               case "Polygon":
48433                 return helpers$1.polygon(clipPolygon(coords, bbox), properties);
48434
48435               case "MultiPolygon":
48436                 return helpers$1.multiPolygon(coords.map(function (poly) {
48437                   return clipPolygon(poly, bbox);
48438                 }), properties);
48439
48440               default:
48441                 throw new Error("geometry " + type + " not supported");
48442             }
48443           }
48444
48445           exports["default"] = bboxClip;
48446
48447           function clipPolygon(rings, bbox) {
48448             var outRings = [];
48449
48450             for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
48451               var ring = rings_1[_i];
48452               var clipped = lineclip.polygon(ring, bbox);
48453
48454               if (clipped.length > 0) {
48455                 if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
48456                   clipped.push(clipped[0]);
48457                 }
48458
48459                 if (clipped.length >= 4) {
48460                   outRings.push(clipped);
48461                 }
48462               }
48463             }
48464
48465             return outRings;
48466           }
48467         });
48468         var turf_bboxClip = /*@__PURE__*/getDefaultExportFromCjs(bboxClip_1);
48469
48470         var fastJsonStableStringify = function fastJsonStableStringify(data, opts) {
48471           if (!opts) opts = {};
48472           if (typeof opts === 'function') opts = {
48473             cmp: opts
48474           };
48475           var cycles = typeof opts.cycles === 'boolean' ? opts.cycles : false;
48476
48477           var cmp = opts.cmp && function (f) {
48478             return function (node) {
48479               return function (a, b) {
48480                 var aobj = {
48481                   key: a,
48482                   value: node[a]
48483                 };
48484                 var bobj = {
48485                   key: b,
48486                   value: node[b]
48487                 };
48488                 return f(aobj, bobj);
48489               };
48490             };
48491           }(opts.cmp);
48492
48493           var seen = [];
48494           return function stringify(node) {
48495             if (node && node.toJSON && typeof node.toJSON === 'function') {
48496               node = node.toJSON();
48497             }
48498
48499             if (node === undefined) return;
48500             if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
48501             if (_typeof(node) !== 'object') return JSON.stringify(node);
48502             var i, out;
48503
48504             if (Array.isArray(node)) {
48505               out = '[';
48506
48507               for (i = 0; i < node.length; i++) {
48508                 if (i) out += ',';
48509                 out += stringify(node[i]) || 'null';
48510               }
48511
48512               return out + ']';
48513             }
48514
48515             if (node === null) return 'null';
48516
48517             if (seen.indexOf(node) !== -1) {
48518               if (cycles) return JSON.stringify('__cycle__');
48519               throw new TypeError('Converting circular structure to JSON');
48520             }
48521
48522             var seenIndex = seen.push(node) - 1;
48523             var keys = Object.keys(node).sort(cmp && cmp(node));
48524             out = '';
48525
48526             for (i = 0; i < keys.length; i++) {
48527               var key = keys[i];
48528               var value = stringify(node[key]);
48529               if (!value) continue;
48530               if (out) out += ',';
48531               out += JSON.stringify(key) + ':' + value;
48532             }
48533
48534             seen.splice(seenIndex, 1);
48535             return '{' + out + '}';
48536           }(data);
48537         };
48538
48539         function DEFAULT_COMPARE(a, b) {
48540           return a > b ? 1 : a < b ? -1 : 0;
48541         }
48542
48543         var SplayTree = /*#__PURE__*/function () {
48544           function SplayTree() {
48545             var compare = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_COMPARE;
48546             var noDuplicates = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
48547
48548             _classCallCheck(this, SplayTree);
48549
48550             this._compare = compare;
48551             this._root = null;
48552             this._size = 0;
48553             this._noDuplicates = !!noDuplicates;
48554           }
48555
48556           _createClass(SplayTree, [{
48557             key: "rotateLeft",
48558             value: function rotateLeft(x) {
48559               var y = x.right;
48560
48561               if (y) {
48562                 x.right = y.left;
48563                 if (y.left) y.left.parent = x;
48564                 y.parent = x.parent;
48565               }
48566
48567               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
48568               if (y) y.left = x;
48569               x.parent = y;
48570             }
48571           }, {
48572             key: "rotateRight",
48573             value: function rotateRight(x) {
48574               var y = x.left;
48575
48576               if (y) {
48577                 x.left = y.right;
48578                 if (y.right) y.right.parent = x;
48579                 y.parent = x.parent;
48580               }
48581
48582               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
48583               if (y) y.right = x;
48584               x.parent = y;
48585             }
48586           }, {
48587             key: "_splay",
48588             value: function _splay(x) {
48589               while (x.parent) {
48590                 var p = x.parent;
48591
48592                 if (!p.parent) {
48593                   if (p.left === x) this.rotateRight(p);else this.rotateLeft(p);
48594                 } else if (p.left === x && p.parent.left === p) {
48595                   this.rotateRight(p.parent);
48596                   this.rotateRight(p);
48597                 } else if (p.right === x && p.parent.right === p) {
48598                   this.rotateLeft(p.parent);
48599                   this.rotateLeft(p);
48600                 } else if (p.left === x && p.parent.right === p) {
48601                   this.rotateRight(p);
48602                   this.rotateLeft(p);
48603                 } else {
48604                   this.rotateLeft(p);
48605                   this.rotateRight(p);
48606                 }
48607               }
48608             }
48609           }, {
48610             key: "splay",
48611             value: function splay(x) {
48612               var p, gp, ggp, l, r;
48613
48614               while (x.parent) {
48615                 p = x.parent;
48616                 gp = p.parent;
48617
48618                 if (gp && gp.parent) {
48619                   ggp = gp.parent;
48620                   if (ggp.left === gp) ggp.left = x;else ggp.right = x;
48621                   x.parent = ggp;
48622                 } else {
48623                   x.parent = null;
48624                   this._root = x;
48625                 }
48626
48627                 l = x.left;
48628                 r = x.right;
48629
48630                 if (x === p.left) {
48631                   // left
48632                   if (gp) {
48633                     if (gp.left === p) {
48634                       /* zig-zig */
48635                       if (p.right) {
48636                         gp.left = p.right;
48637                         gp.left.parent = gp;
48638                       } else gp.left = null;
48639
48640                       p.right = gp;
48641                       gp.parent = p;
48642                     } else {
48643                       /* zig-zag */
48644                       if (l) {
48645                         gp.right = l;
48646                         l.parent = gp;
48647                       } else gp.right = null;
48648
48649                       x.left = gp;
48650                       gp.parent = x;
48651                     }
48652                   }
48653
48654                   if (r) {
48655                     p.left = r;
48656                     r.parent = p;
48657                   } else p.left = null;
48658
48659                   x.right = p;
48660                   p.parent = x;
48661                 } else {
48662                   // right
48663                   if (gp) {
48664                     if (gp.right === p) {
48665                       /* zig-zig */
48666                       if (p.left) {
48667                         gp.right = p.left;
48668                         gp.right.parent = gp;
48669                       } else gp.right = null;
48670
48671                       p.left = gp;
48672                       gp.parent = p;
48673                     } else {
48674                       /* zig-zag */
48675                       if (r) {
48676                         gp.left = r;
48677                         r.parent = gp;
48678                       } else gp.left = null;
48679
48680                       x.right = gp;
48681                       gp.parent = x;
48682                     }
48683                   }
48684
48685                   if (l) {
48686                     p.right = l;
48687                     l.parent = p;
48688                   } else p.right = null;
48689
48690                   x.left = p;
48691                   p.parent = x;
48692                 }
48693               }
48694             }
48695           }, {
48696             key: "replace",
48697             value: function replace(u, v) {
48698               if (!u.parent) this._root = v;else if (u === u.parent.left) u.parent.left = v;else u.parent.right = v;
48699               if (v) v.parent = u.parent;
48700             }
48701           }, {
48702             key: "minNode",
48703             value: function minNode() {
48704               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
48705               if (u) while (u.left) {
48706                 u = u.left;
48707               }
48708               return u;
48709             }
48710           }, {
48711             key: "maxNode",
48712             value: function maxNode() {
48713               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
48714               if (u) while (u.right) {
48715                 u = u.right;
48716               }
48717               return u;
48718             }
48719           }, {
48720             key: "insert",
48721             value: function insert(key, data) {
48722               var z = this._root;
48723               var p = null;
48724               var comp = this._compare;
48725               var cmp;
48726
48727               if (this._noDuplicates) {
48728                 while (z) {
48729                   p = z;
48730                   cmp = comp(z.key, key);
48731                   if (cmp === 0) return;else if (comp(z.key, key) < 0) z = z.right;else z = z.left;
48732                 }
48733               } else {
48734                 while (z) {
48735                   p = z;
48736                   if (comp(z.key, key) < 0) z = z.right;else z = z.left;
48737                 }
48738               }
48739
48740               z = {
48741                 key: key,
48742                 data: data,
48743                 left: null,
48744                 right: null,
48745                 parent: p
48746               };
48747               if (!p) this._root = z;else if (comp(p.key, z.key) < 0) p.right = z;else p.left = z;
48748               this.splay(z);
48749               this._size++;
48750               return z;
48751             }
48752           }, {
48753             key: "find",
48754             value: function find(key) {
48755               var z = this._root;
48756               var comp = this._compare;
48757
48758               while (z) {
48759                 var cmp = comp(z.key, key);
48760                 if (cmp < 0) z = z.right;else if (cmp > 0) z = z.left;else return z;
48761               }
48762
48763               return null;
48764             }
48765             /**
48766              * Whether the tree contains a node with the given key
48767              * @param  {Key} key
48768              * @return {boolean} true/false
48769              */
48770
48771           }, {
48772             key: "contains",
48773             value: function contains(key) {
48774               var node = this._root;
48775               var comparator = this._compare;
48776
48777               while (node) {
48778                 var cmp = comparator(key, node.key);
48779                 if (cmp === 0) return true;else if (cmp < 0) node = node.left;else node = node.right;
48780               }
48781
48782               return false;
48783             }
48784           }, {
48785             key: "remove",
48786             value: function remove(key) {
48787               var z = this.find(key);
48788               if (!z) return false;
48789               this.splay(z);
48790               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
48791                 var y = this.minNode(z.right);
48792
48793                 if (y.parent !== z) {
48794                   this.replace(y, y.right);
48795                   y.right = z.right;
48796                   y.right.parent = y;
48797                 }
48798
48799                 this.replace(z, y);
48800                 y.left = z.left;
48801                 y.left.parent = y;
48802               }
48803               this._size--;
48804               return true;
48805             }
48806           }, {
48807             key: "removeNode",
48808             value: function removeNode(z) {
48809               if (!z) return false;
48810               this.splay(z);
48811               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
48812                 var y = this.minNode(z.right);
48813
48814                 if (y.parent !== z) {
48815                   this.replace(y, y.right);
48816                   y.right = z.right;
48817                   y.right.parent = y;
48818                 }
48819
48820                 this.replace(z, y);
48821                 y.left = z.left;
48822                 y.left.parent = y;
48823               }
48824               this._size--;
48825               return true;
48826             }
48827           }, {
48828             key: "erase",
48829             value: function erase(key) {
48830               var z = this.find(key);
48831               if (!z) return;
48832               this.splay(z);
48833               var s = z.left;
48834               var t = z.right;
48835               var sMax = null;
48836
48837               if (s) {
48838                 s.parent = null;
48839                 sMax = this.maxNode(s);
48840                 this.splay(sMax);
48841                 this._root = sMax;
48842               }
48843
48844               if (t) {
48845                 if (s) sMax.right = t;else this._root = t;
48846                 t.parent = sMax;
48847               }
48848
48849               this._size--;
48850             }
48851             /**
48852              * Removes and returns the node with smallest key
48853              * @return {?Node}
48854              */
48855
48856           }, {
48857             key: "pop",
48858             value: function pop() {
48859               var node = this._root,
48860                   returnValue = null;
48861
48862               if (node) {
48863                 while (node.left) {
48864                   node = node.left;
48865                 }
48866
48867                 returnValue = {
48868                   key: node.key,
48869                   data: node.data
48870                 };
48871                 this.remove(node.key);
48872               }
48873
48874               return returnValue;
48875             }
48876             /* eslint-disable class-methods-use-this */
48877
48878             /**
48879              * Successor node
48880              * @param  {Node} node
48881              * @return {?Node}
48882              */
48883
48884           }, {
48885             key: "next",
48886             value: function next(node) {
48887               var successor = node;
48888
48889               if (successor) {
48890                 if (successor.right) {
48891                   successor = successor.right;
48892
48893                   while (successor && successor.left) {
48894                     successor = successor.left;
48895                   }
48896                 } else {
48897                   successor = node.parent;
48898
48899                   while (successor && successor.right === node) {
48900                     node = successor;
48901                     successor = successor.parent;
48902                   }
48903                 }
48904               }
48905
48906               return successor;
48907             }
48908             /**
48909              * Predecessor node
48910              * @param  {Node} node
48911              * @return {?Node}
48912              */
48913
48914           }, {
48915             key: "prev",
48916             value: function prev(node) {
48917               var predecessor = node;
48918
48919               if (predecessor) {
48920                 if (predecessor.left) {
48921                   predecessor = predecessor.left;
48922
48923                   while (predecessor && predecessor.right) {
48924                     predecessor = predecessor.right;
48925                   }
48926                 } else {
48927                   predecessor = node.parent;
48928
48929                   while (predecessor && predecessor.left === node) {
48930                     node = predecessor;
48931                     predecessor = predecessor.parent;
48932                   }
48933                 }
48934               }
48935
48936               return predecessor;
48937             }
48938             /* eslint-enable class-methods-use-this */
48939
48940             /**
48941              * @param  {forEachCallback} callback
48942              * @return {SplayTree}
48943              */
48944
48945           }, {
48946             key: "forEach",
48947             value: function forEach(callback) {
48948               var current = this._root;
48949               var s = [],
48950                   done = false,
48951                   i = 0;
48952
48953               while (!done) {
48954                 // Reach the left most Node of the current Node
48955                 if (current) {
48956                   // Place pointer to a tree node on the stack
48957                   // before traversing the node's left subtree
48958                   s.push(current);
48959                   current = current.left;
48960                 } else {
48961                   // BackTrack from the empty subtree and visit the Node
48962                   // at the top of the stack; however, if the stack is
48963                   // empty you are done
48964                   if (s.length > 0) {
48965                     current = s.pop();
48966                     callback(current, i++); // We have visited the node and its left
48967                     // subtree. Now, it's right subtree's turn
48968
48969                     current = current.right;
48970                   } else done = true;
48971                 }
48972               }
48973
48974               return this;
48975             }
48976             /**
48977              * Walk key range from `low` to `high`. Stops if `fn` returns a value.
48978              * @param  {Key}      low
48979              * @param  {Key}      high
48980              * @param  {Function} fn
48981              * @param  {*?}       ctx
48982              * @return {SplayTree}
48983              */
48984
48985           }, {
48986             key: "range",
48987             value: function range(low, high, fn, ctx) {
48988               var Q = [];
48989               var compare = this._compare;
48990               var node = this._root,
48991                   cmp;
48992
48993               while (Q.length !== 0 || node) {
48994                 if (node) {
48995                   Q.push(node);
48996                   node = node.left;
48997                 } else {
48998                   node = Q.pop();
48999                   cmp = compare(node.key, high);
49000
49001                   if (cmp > 0) {
49002                     break;
49003                   } else if (compare(node.key, low) >= 0) {
49004                     if (fn.call(ctx, node)) return this; // stop if smth is returned
49005                   }
49006
49007                   node = node.right;
49008                 }
49009               }
49010
49011               return this;
49012             }
49013             /**
49014              * Returns all keys in order
49015              * @return {Array<Key>}
49016              */
49017
49018           }, {
49019             key: "keys",
49020             value: function keys() {
49021               var current = this._root;
49022               var s = [],
49023                   r = [],
49024                   done = false;
49025
49026               while (!done) {
49027                 if (current) {
49028                   s.push(current);
49029                   current = current.left;
49030                 } else {
49031                   if (s.length > 0) {
49032                     current = s.pop();
49033                     r.push(current.key);
49034                     current = current.right;
49035                   } else done = true;
49036                 }
49037               }
49038
49039               return r;
49040             }
49041             /**
49042              * Returns `data` fields of all nodes in order.
49043              * @return {Array<Value>}
49044              */
49045
49046           }, {
49047             key: "values",
49048             value: function values() {
49049               var current = this._root;
49050               var s = [],
49051                   r = [],
49052                   done = false;
49053
49054               while (!done) {
49055                 if (current) {
49056                   s.push(current);
49057                   current = current.left;
49058                 } else {
49059                   if (s.length > 0) {
49060                     current = s.pop();
49061                     r.push(current.data);
49062                     current = current.right;
49063                   } else done = true;
49064                 }
49065               }
49066
49067               return r;
49068             }
49069             /**
49070              * Returns node at given index
49071              * @param  {number} index
49072              * @return {?Node}
49073              */
49074
49075           }, {
49076             key: "at",
49077             value: function at(index) {
49078               // removed after a consideration, more misleading than useful
49079               // index = index % this.size;
49080               // if (index < 0) index = this.size - index;
49081               var current = this._root;
49082               var s = [],
49083                   done = false,
49084                   i = 0;
49085
49086               while (!done) {
49087                 if (current) {
49088                   s.push(current);
49089                   current = current.left;
49090                 } else {
49091                   if (s.length > 0) {
49092                     current = s.pop();
49093                     if (i === index) return current;
49094                     i++;
49095                     current = current.right;
49096                   } else done = true;
49097                 }
49098               }
49099
49100               return null;
49101             }
49102             /**
49103              * Bulk-load items. Both array have to be same size
49104              * @param  {Array<Key>}    keys
49105              * @param  {Array<Value>}  [values]
49106              * @param  {Boolean}       [presort=false] Pre-sort keys and values, using
49107              *                                         tree's comparator. Sorting is done
49108              *                                         in-place
49109              * @return {AVLTree}
49110              */
49111
49112           }, {
49113             key: "load",
49114             value: function load() {
49115               var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
49116               var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
49117               var presort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
49118               if (this._size !== 0) throw new Error('bulk-load: tree is not empty');
49119               var size = keys.length;
49120               if (presort) sort(keys, values, 0, size - 1, this._compare);
49121               this._root = loadRecursive(null, keys, values, 0, size);
49122               this._size = size;
49123               return this;
49124             }
49125           }, {
49126             key: "min",
49127             value: function min() {
49128               var node = this.minNode(this._root);
49129               if (node) return node.key;else return null;
49130             }
49131           }, {
49132             key: "max",
49133             value: function max() {
49134               var node = this.maxNode(this._root);
49135               if (node) return node.key;else return null;
49136             }
49137           }, {
49138             key: "isEmpty",
49139             value: function isEmpty() {
49140               return this._root === null;
49141             }
49142           }, {
49143             key: "size",
49144             get: function get() {
49145               return this._size;
49146             }
49147             /**
49148              * Create a tree and load it with items
49149              * @param  {Array<Key>}          keys
49150              * @param  {Array<Value>?}        [values]
49151               * @param  {Function?}            [comparator]
49152              * @param  {Boolean?}             [presort=false] Pre-sort keys and values, using
49153              *                                               tree's comparator. Sorting is done
49154              *                                               in-place
49155              * @param  {Boolean?}             [noDuplicates=false]   Allow duplicates
49156              * @return {SplayTree}
49157              */
49158
49159           }], [{
49160             key: "createTree",
49161             value: function createTree(keys, values, comparator, presort, noDuplicates) {
49162               return new SplayTree(comparator, noDuplicates).load(keys, values, presort);
49163             }
49164           }]);
49165
49166           return SplayTree;
49167         }();
49168
49169         function loadRecursive(parent, keys, values, start, end) {
49170           var size = end - start;
49171
49172           if (size > 0) {
49173             var middle = start + Math.floor(size / 2);
49174             var key = keys[middle];
49175             var data = values[middle];
49176             var node = {
49177               key: key,
49178               data: data,
49179               parent: parent
49180             };
49181             node.left = loadRecursive(node, keys, values, start, middle);
49182             node.right = loadRecursive(node, keys, values, middle + 1, end);
49183             return node;
49184           }
49185
49186           return null;
49187         }
49188
49189         function sort(keys, values, left, right, compare) {
49190           if (left >= right) return;
49191           var pivot = keys[left + right >> 1];
49192           var i = left - 1;
49193           var j = right + 1;
49194
49195           while (true) {
49196             do {
49197               i++;
49198             } while (compare(keys[i], pivot) < 0);
49199
49200             do {
49201               j--;
49202             } while (compare(keys[j], pivot) > 0);
49203
49204             if (i >= j) break;
49205             var tmp = keys[i];
49206             keys[i] = keys[j];
49207             keys[j] = tmp;
49208             tmp = values[i];
49209             values[i] = values[j];
49210             values[j] = tmp;
49211           }
49212
49213           sort(keys, values, left, j, compare);
49214           sort(keys, values, j + 1, right, compare);
49215         }
49216
49217         var NORMAL = 0;
49218         var NON_CONTRIBUTING = 1;
49219         var SAME_TRANSITION = 2;
49220         var DIFFERENT_TRANSITION = 3;
49221
49222         var INTERSECTION = 0;
49223         var UNION = 1;
49224         var DIFFERENCE = 2;
49225         var XOR = 3;
49226
49227         /**
49228          * @param  {SweepEvent} event
49229          * @param  {SweepEvent} prev
49230          * @param  {Operation} operation
49231          */
49232
49233         function computeFields(event, prev, operation) {
49234           // compute inOut and otherInOut fields
49235           if (prev === null) {
49236             event.inOut = false;
49237             event.otherInOut = true; // previous line segment in sweepline belongs to the same polygon
49238           } else {
49239             if (event.isSubject === prev.isSubject) {
49240               event.inOut = !prev.inOut;
49241               event.otherInOut = prev.otherInOut; // previous line segment in sweepline belongs to the clipping polygon
49242             } else {
49243               event.inOut = !prev.otherInOut;
49244               event.otherInOut = prev.isVertical() ? !prev.inOut : prev.inOut;
49245             } // compute prevInResult field
49246
49247
49248             if (prev) {
49249               event.prevInResult = !inResult(prev, operation) || prev.isVertical() ? prev.prevInResult : prev;
49250             }
49251           } // check if the line segment belongs to the Boolean operation
49252
49253
49254           var isInResult = inResult(event, operation);
49255
49256           if (isInResult) {
49257             event.resultTransition = determineResultTransition(event, operation);
49258           } else {
49259             event.resultTransition = 0;
49260           }
49261         }
49262         /* eslint-disable indent */
49263
49264         function inResult(event, operation) {
49265           switch (event.type) {
49266             case NORMAL:
49267               switch (operation) {
49268                 case INTERSECTION:
49269                   return !event.otherInOut;
49270
49271                 case UNION:
49272                   return event.otherInOut;
49273
49274                 case DIFFERENCE:
49275                   // return (event.isSubject && !event.otherInOut) ||
49276                   //         (!event.isSubject && event.otherInOut);
49277                   return event.isSubject && event.otherInOut || !event.isSubject && !event.otherInOut;
49278
49279                 case XOR:
49280                   return true;
49281               }
49282
49283               break;
49284
49285             case SAME_TRANSITION:
49286               return operation === INTERSECTION || operation === UNION;
49287
49288             case DIFFERENT_TRANSITION:
49289               return operation === DIFFERENCE;
49290
49291             case NON_CONTRIBUTING:
49292               return false;
49293           }
49294
49295           return false;
49296         }
49297         /* eslint-enable indent */
49298
49299
49300         function determineResultTransition(event, operation) {
49301           var thisIn = !event.inOut;
49302           var thatIn = !event.otherInOut;
49303           var isIn;
49304
49305           switch (operation) {
49306             case INTERSECTION:
49307               isIn = thisIn && thatIn;
49308               break;
49309
49310             case UNION:
49311               isIn = thisIn || thatIn;
49312               break;
49313
49314             case XOR:
49315               isIn = thisIn ^ thatIn;
49316               break;
49317
49318             case DIFFERENCE:
49319               if (event.isSubject) {
49320                 isIn = thisIn && !thatIn;
49321               } else {
49322                 isIn = thatIn && !thisIn;
49323               }
49324
49325               break;
49326           }
49327
49328           return isIn ? +1 : -1;
49329         }
49330
49331         var SweepEvent = /*#__PURE__*/function () {
49332           /**
49333            * Sweepline event
49334            *
49335            * @class {SweepEvent}
49336            * @param {Array.<Number>}  point
49337            * @param {Boolean}         left
49338            * @param {SweepEvent=}     otherEvent
49339            * @param {Boolean}         isSubject
49340            * @param {Number}          edgeType
49341            */
49342           function SweepEvent(point, left, otherEvent, isSubject, edgeType) {
49343             _classCallCheck(this, SweepEvent);
49344
49345             /**
49346              * Is left endpoint?
49347              * @type {Boolean}
49348              */
49349             this.left = left;
49350             /**
49351              * @type {Array.<Number>}
49352              */
49353
49354             this.point = point;
49355             /**
49356              * Other edge reference
49357              * @type {SweepEvent}
49358              */
49359
49360             this.otherEvent = otherEvent;
49361             /**
49362              * Belongs to source or clipping polygon
49363              * @type {Boolean}
49364              */
49365
49366             this.isSubject = isSubject;
49367             /**
49368              * Edge contribution type
49369              * @type {Number}
49370              */
49371
49372             this.type = edgeType || NORMAL;
49373             /**
49374              * In-out transition for the sweepline crossing polygon
49375              * @type {Boolean}
49376              */
49377
49378             this.inOut = false;
49379             /**
49380              * @type {Boolean}
49381              */
49382
49383             this.otherInOut = false;
49384             /**
49385              * Previous event in result?
49386              * @type {SweepEvent}
49387              */
49388
49389             this.prevInResult = null;
49390             /**
49391              * Type of result transition (0 = not in result, +1 = out-in, -1, in-out)
49392              * @type {Number}
49393              */
49394
49395             this.resultTransition = 0; // connection step
49396
49397             /**
49398              * @type {Number}
49399              */
49400
49401             this.otherPos = -1;
49402             /**
49403              * @type {Number}
49404              */
49405
49406             this.outputContourId = -1;
49407             this.isExteriorRing = true; // TODO: Looks unused, remove?
49408           }
49409           /**
49410            * @param  {Array.<Number>}  p
49411            * @return {Boolean}
49412            */
49413
49414
49415           _createClass(SweepEvent, [{
49416             key: "isBelow",
49417             value: function isBelow(p) {
49418               var p0 = this.point,
49419                   p1 = this.otherEvent.point;
49420               return this.left ? (p0[0] - p[0]) * (p1[1] - p[1]) - (p1[0] - p[0]) * (p0[1] - p[1]) > 0 // signedArea(this.point, this.otherEvent.point, p) > 0 :
49421               : (p1[0] - p[0]) * (p0[1] - p[1]) - (p0[0] - p[0]) * (p1[1] - p[1]) > 0; //signedArea(this.otherEvent.point, this.point, p) > 0;
49422             }
49423             /**
49424              * @param  {Array.<Number>}  p
49425              * @return {Boolean}
49426              */
49427
49428           }, {
49429             key: "isAbove",
49430             value: function isAbove(p) {
49431               return !this.isBelow(p);
49432             }
49433             /**
49434              * @return {Boolean}
49435              */
49436
49437           }, {
49438             key: "isVertical",
49439             value: function isVertical() {
49440               return this.point[0] === this.otherEvent.point[0];
49441             }
49442             /**
49443              * Does event belong to result?
49444              * @return {Boolean}
49445              */
49446
49447           }, {
49448             key: "clone",
49449             value: function clone() {
49450               var copy = new SweepEvent(this.point, this.left, this.otherEvent, this.isSubject, this.type);
49451               copy.contourId = this.contourId;
49452               copy.resultTransition = this.resultTransition;
49453               copy.prevInResult = this.prevInResult;
49454               copy.isExteriorRing = this.isExteriorRing;
49455               copy.inOut = this.inOut;
49456               copy.otherInOut = this.otherInOut;
49457               return copy;
49458             }
49459           }, {
49460             key: "inResult",
49461             get: function get() {
49462               return this.resultTransition !== 0;
49463             }
49464           }]);
49465
49466           return SweepEvent;
49467         }();
49468
49469         function equals(p1, p2) {
49470           if (p1[0] === p2[0]) {
49471             if (p1[1] === p2[1]) {
49472               return true;
49473             } else {
49474               return false;
49475             }
49476           }
49477
49478           return false;
49479         } // const EPSILON = 1e-9;
49480         // const abs = Math.abs;
49481         // TODO https://github.com/w8r/martinez/issues/6#issuecomment-262847164
49482         // Precision problem.
49483         //
49484         // module.exports = function equals(p1, p2) {
49485         //   return abs(p1[0] - p2[0]) <= EPSILON && abs(p1[1] - p2[1]) <= EPSILON;
49486         // };
49487
49488         var epsilon$1 = 1.1102230246251565e-16;
49489         var splitter = 134217729;
49490         var resulterrbound = (3 + 8 * epsilon$1) * epsilon$1; // fast_expansion_sum_zeroelim routine from oritinal code
49491
49492         function sum(elen, e, flen, f, h) {
49493           var Q, Qnew, hh, bvirt;
49494           var enow = e[0];
49495           var fnow = f[0];
49496           var eindex = 0;
49497           var findex = 0;
49498
49499           if (fnow > enow === fnow > -enow) {
49500             Q = enow;
49501             enow = e[++eindex];
49502           } else {
49503             Q = fnow;
49504             fnow = f[++findex];
49505           }
49506
49507           var hindex = 0;
49508
49509           if (eindex < elen && findex < flen) {
49510             if (fnow > enow === fnow > -enow) {
49511               Qnew = enow + Q;
49512               hh = Q - (Qnew - enow);
49513               enow = e[++eindex];
49514             } else {
49515               Qnew = fnow + Q;
49516               hh = Q - (Qnew - fnow);
49517               fnow = f[++findex];
49518             }
49519
49520             Q = Qnew;
49521
49522             if (hh !== 0) {
49523               h[hindex++] = hh;
49524             }
49525
49526             while (eindex < elen && findex < flen) {
49527               if (fnow > enow === fnow > -enow) {
49528                 Qnew = Q + enow;
49529                 bvirt = Qnew - Q;
49530                 hh = Q - (Qnew - bvirt) + (enow - bvirt);
49531                 enow = e[++eindex];
49532               } else {
49533                 Qnew = Q + fnow;
49534                 bvirt = Qnew - Q;
49535                 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
49536                 fnow = f[++findex];
49537               }
49538
49539               Q = Qnew;
49540
49541               if (hh !== 0) {
49542                 h[hindex++] = hh;
49543               }
49544             }
49545           }
49546
49547           while (eindex < elen) {
49548             Qnew = Q + enow;
49549             bvirt = Qnew - Q;
49550             hh = Q - (Qnew - bvirt) + (enow - bvirt);
49551             enow = e[++eindex];
49552             Q = Qnew;
49553
49554             if (hh !== 0) {
49555               h[hindex++] = hh;
49556             }
49557           }
49558
49559           while (findex < flen) {
49560             Qnew = Q + fnow;
49561             bvirt = Qnew - Q;
49562             hh = Q - (Qnew - bvirt) + (fnow - bvirt);
49563             fnow = f[++findex];
49564             Q = Qnew;
49565
49566             if (hh !== 0) {
49567               h[hindex++] = hh;
49568             }
49569           }
49570
49571           if (Q !== 0 || hindex === 0) {
49572             h[hindex++] = Q;
49573           }
49574
49575           return hindex;
49576         }
49577         function estimate(elen, e) {
49578           var Q = e[0];
49579
49580           for (var i = 1; i < elen; i++) {
49581             Q += e[i];
49582           }
49583
49584           return Q;
49585         }
49586         function vec(n) {
49587           return new Float64Array(n);
49588         }
49589
49590         var ccwerrboundA = (3 + 16 * epsilon$1) * epsilon$1;
49591         var ccwerrboundB = (2 + 12 * epsilon$1) * epsilon$1;
49592         var ccwerrboundC = (9 + 64 * epsilon$1) * epsilon$1 * epsilon$1;
49593         var B = vec(4);
49594         var C1 = vec(8);
49595         var C2 = vec(12);
49596         var D = vec(16);
49597         var u = vec(4);
49598
49599         function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
49600           var acxtail, acytail, bcxtail, bcytail;
49601
49602           var bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
49603
49604           var acx = ax - cx;
49605           var bcx = bx - cx;
49606           var acy = ay - cy;
49607           var bcy = by - cy;
49608           s1 = acx * bcy;
49609           c = splitter * acx;
49610           ahi = c - (c - acx);
49611           alo = acx - ahi;
49612           c = splitter * bcy;
49613           bhi = c - (c - bcy);
49614           blo = bcy - bhi;
49615           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49616           t1 = acy * bcx;
49617           c = splitter * acy;
49618           ahi = c - (c - acy);
49619           alo = acy - ahi;
49620           c = splitter * bcx;
49621           bhi = c - (c - bcx);
49622           blo = bcx - bhi;
49623           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49624           _i = s0 - t0;
49625           bvirt = s0 - _i;
49626           B[0] = s0 - (_i + bvirt) + (bvirt - t0);
49627           _j = s1 + _i;
49628           bvirt = _j - s1;
49629           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49630           _i = _0 - t1;
49631           bvirt = _0 - _i;
49632           B[1] = _0 - (_i + bvirt) + (bvirt - t1);
49633           u3 = _j + _i;
49634           bvirt = u3 - _j;
49635           B[2] = _j - (u3 - bvirt) + (_i - bvirt);
49636           B[3] = u3;
49637           var det = estimate(4, B);
49638           var errbound = ccwerrboundB * detsum;
49639
49640           if (det >= errbound || -det >= errbound) {
49641             return det;
49642           }
49643
49644           bvirt = ax - acx;
49645           acxtail = ax - (acx + bvirt) + (bvirt - cx);
49646           bvirt = bx - bcx;
49647           bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
49648           bvirt = ay - acy;
49649           acytail = ay - (acy + bvirt) + (bvirt - cy);
49650           bvirt = by - bcy;
49651           bcytail = by - (bcy + bvirt) + (bvirt - cy);
49652
49653           if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
49654             return det;
49655           }
49656
49657           errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
49658           det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
49659           if (det >= errbound || -det >= errbound) return det;
49660           s1 = acxtail * bcy;
49661           c = splitter * acxtail;
49662           ahi = c - (c - acxtail);
49663           alo = acxtail - ahi;
49664           c = splitter * bcy;
49665           bhi = c - (c - bcy);
49666           blo = bcy - bhi;
49667           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49668           t1 = acytail * bcx;
49669           c = splitter * acytail;
49670           ahi = c - (c - acytail);
49671           alo = acytail - ahi;
49672           c = splitter * bcx;
49673           bhi = c - (c - bcx);
49674           blo = bcx - bhi;
49675           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49676           _i = s0 - t0;
49677           bvirt = s0 - _i;
49678           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49679           _j = s1 + _i;
49680           bvirt = _j - s1;
49681           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49682           _i = _0 - t1;
49683           bvirt = _0 - _i;
49684           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49685           u3 = _j + _i;
49686           bvirt = u3 - _j;
49687           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49688           u[3] = u3;
49689           var C1len = sum(4, B, 4, u, C1);
49690           s1 = acx * bcytail;
49691           c = splitter * acx;
49692           ahi = c - (c - acx);
49693           alo = acx - ahi;
49694           c = splitter * bcytail;
49695           bhi = c - (c - bcytail);
49696           blo = bcytail - bhi;
49697           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49698           t1 = acy * bcxtail;
49699           c = splitter * acy;
49700           ahi = c - (c - acy);
49701           alo = acy - ahi;
49702           c = splitter * bcxtail;
49703           bhi = c - (c - bcxtail);
49704           blo = bcxtail - bhi;
49705           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49706           _i = s0 - t0;
49707           bvirt = s0 - _i;
49708           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49709           _j = s1 + _i;
49710           bvirt = _j - s1;
49711           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49712           _i = _0 - t1;
49713           bvirt = _0 - _i;
49714           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49715           u3 = _j + _i;
49716           bvirt = u3 - _j;
49717           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49718           u[3] = u3;
49719           var C2len = sum(C1len, C1, 4, u, C2);
49720           s1 = acxtail * bcytail;
49721           c = splitter * acxtail;
49722           ahi = c - (c - acxtail);
49723           alo = acxtail - ahi;
49724           c = splitter * bcytail;
49725           bhi = c - (c - bcytail);
49726           blo = bcytail - bhi;
49727           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49728           t1 = acytail * bcxtail;
49729           c = splitter * acytail;
49730           ahi = c - (c - acytail);
49731           alo = acytail - ahi;
49732           c = splitter * bcxtail;
49733           bhi = c - (c - bcxtail);
49734           blo = bcxtail - bhi;
49735           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49736           _i = s0 - t0;
49737           bvirt = s0 - _i;
49738           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49739           _j = s1 + _i;
49740           bvirt = _j - s1;
49741           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49742           _i = _0 - t1;
49743           bvirt = _0 - _i;
49744           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49745           u3 = _j + _i;
49746           bvirt = u3 - _j;
49747           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49748           u[3] = u3;
49749           var Dlen = sum(C2len, C2, 4, u, D);
49750           return D[Dlen - 1];
49751         }
49752
49753         function orient2d(ax, ay, bx, by, cx, cy) {
49754           var detleft = (ay - cy) * (bx - cx);
49755           var detright = (ax - cx) * (by - cy);
49756           var det = detleft - detright;
49757           if (detleft === 0 || detright === 0 || detleft > 0 !== detright > 0) return det;
49758           var detsum = Math.abs(detleft + detright);
49759           if (Math.abs(det) >= ccwerrboundA * detsum) return det;
49760           return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
49761         }
49762
49763         /**
49764          * Signed area of the triangle (p0, p1, p2)
49765          * @param  {Array.<Number>} p0
49766          * @param  {Array.<Number>} p1
49767          * @param  {Array.<Number>} p2
49768          * @return {Number}
49769          */
49770
49771         function signedArea(p0, p1, p2) {
49772           var res = orient2d(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]);
49773           if (res > 0) return -1;
49774           if (res < 0) return 1;
49775           return 0;
49776         }
49777
49778         /**
49779          * @param  {SweepEvent} e1
49780          * @param  {SweepEvent} e2
49781          * @return {Number}
49782          */
49783
49784         function compareEvents(e1, e2) {
49785           var p1 = e1.point;
49786           var p2 = e2.point; // Different x-coordinate
49787
49788           if (p1[0] > p2[0]) return 1;
49789           if (p1[0] < p2[0]) return -1; // Different points, but same x-coordinate
49790           // Event with lower y-coordinate is processed first
49791
49792           if (p1[1] !== p2[1]) return p1[1] > p2[1] ? 1 : -1;
49793           return specialCases(e1, e2, p1);
49794         }
49795         /* eslint-disable no-unused-vars */
49796
49797         function specialCases(e1, e2, p1, p2) {
49798           // Same coordinates, but one is a left endpoint and the other is
49799           // a right endpoint. The right endpoint is processed first
49800           if (e1.left !== e2.left) return e1.left ? 1 : -1; // const p2 = e1.otherEvent.point, p3 = e2.otherEvent.point;
49801           // const sa = (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
49802           // Same coordinates, both events
49803           // are left endpoints or right endpoints.
49804           // not collinear
49805
49806           if (signedArea(p1, e1.otherEvent.point, e2.otherEvent.point) !== 0) {
49807             // the event associate to the bottom segment is processed first
49808             return !e1.isBelow(e2.otherEvent.point) ? 1 : -1;
49809           }
49810
49811           return !e1.isSubject && e2.isSubject ? 1 : -1;
49812         }
49813         /* eslint-enable no-unused-vars */
49814
49815         /**
49816          * @param  {SweepEvent} se
49817          * @param  {Array.<Number>} p
49818          * @param  {Queue} queue
49819          * @return {Queue}
49820          */
49821
49822         function divideSegment(se, p, queue) {
49823           var r = new SweepEvent(p, false, se, se.isSubject);
49824           var l = new SweepEvent(p, true, se.otherEvent, se.isSubject);
49825           /* eslint-disable no-console */
49826
49827           if (equals(se.point, se.otherEvent.point)) {
49828             console.warn('what is that, a collapsed segment?', se);
49829           }
49830           /* eslint-enable no-console */
49831
49832
49833           r.contourId = l.contourId = se.contourId; // avoid a rounding error. The left event would be processed after the right event
49834
49835           if (compareEvents(l, se.otherEvent) > 0) {
49836             se.otherEvent.left = true;
49837             l.left = false;
49838           } // avoid a rounding error. The left event would be processed after the right event
49839           // if (compareEvents(se, r) > 0) {}
49840
49841
49842           se.otherEvent.otherEvent = l;
49843           se.otherEvent = r;
49844           queue.push(l);
49845           queue.push(r);
49846           return queue;
49847         }
49848
49849         //const EPS = 1e-9;
49850
49851         /**
49852          * Finds the magnitude of the cross product of two vectors (if we pretend
49853          * they're in three dimensions)
49854          *
49855          * @param {Object} a First vector
49856          * @param {Object} b Second vector
49857          * @private
49858          * @returns {Number} The magnitude of the cross product
49859          */
49860         function crossProduct(a, b) {
49861           return a[0] * b[1] - a[1] * b[0];
49862         }
49863         /**
49864          * Finds the dot product of two vectors.
49865          *
49866          * @param {Object} a First vector
49867          * @param {Object} b Second vector
49868          * @private
49869          * @returns {Number} The dot product
49870          */
49871
49872
49873         function dotProduct(a, b) {
49874           return a[0] * b[0] + a[1] * b[1];
49875         }
49876         /**
49877          * Finds the intersection (if any) between two line segments a and b, given the
49878          * line segments' end points a1, a2 and b1, b2.
49879          *
49880          * This algorithm is based on Schneider and Eberly.
49881          * http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf
49882          * Page 244.
49883          *
49884          * @param {Array.<Number>} a1 point of first line
49885          * @param {Array.<Number>} a2 point of first line
49886          * @param {Array.<Number>} b1 point of second line
49887          * @param {Array.<Number>} b2 point of second line
49888          * @param {Boolean=}       noEndpointTouch whether to skip single touchpoints
49889          *                                         (meaning connected segments) as
49890          *                                         intersections
49891          * @returns {Array.<Array.<Number>>|Null} If the lines intersect, the point of
49892          * intersection. If they overlap, the two end points of the overlapping segment.
49893          * Otherwise, null.
49894          */
49895
49896
49897         function intersection (a1, a2, b1, b2, noEndpointTouch) {
49898           // The algorithm expects our lines in the form P + sd, where P is a point,
49899           // s is on the interval [0, 1], and d is a vector.
49900           // We are passed two points. P can be the first point of each pair. The
49901           // vector, then, could be thought of as the distance (in x and y components)
49902           // from the first point to the second point.
49903           // So first, let's make our vectors:
49904           var va = [a2[0] - a1[0], a2[1] - a1[1]];
49905           var vb = [b2[0] - b1[0], b2[1] - b1[1]]; // We also define a function to convert back to regular point form:
49906
49907           /* eslint-disable arrow-body-style */
49908
49909           function toPoint(p, s, d) {
49910             return [p[0] + s * d[0], p[1] + s * d[1]];
49911           }
49912           /* eslint-enable arrow-body-style */
49913           // The rest is pretty much a straight port of the algorithm.
49914
49915
49916           var e = [b1[0] - a1[0], b1[1] - a1[1]];
49917           var kross = crossProduct(va, vb);
49918           var sqrKross = kross * kross;
49919           var sqrLenA = dotProduct(va, va); //const sqrLenB  = dotProduct(vb, vb);
49920           // Check for line intersection. This works because of the properties of the
49921           // cross product -- specifically, two vectors are parallel if and only if the
49922           // cross product is the 0 vector. The full calculation involves relative error
49923           // to account for possible very small line segments. See Schneider & Eberly
49924           // for details.
49925
49926           if (sqrKross > 0
49927           /* EPS * sqrLenB * sqLenA */
49928           ) {
49929               // If they're not parallel, then (because these are line segments) they
49930               // still might not actually intersect. This code checks that the
49931               // intersection point of the lines is actually on both line segments.
49932               var s = crossProduct(e, vb) / kross;
49933
49934               if (s < 0 || s > 1) {
49935                 // not on line segment a
49936                 return null;
49937               }
49938
49939               var t = crossProduct(e, va) / kross;
49940
49941               if (t < 0 || t > 1) {
49942                 // not on line segment b
49943                 return null;
49944               }
49945
49946               if (s === 0 || s === 1) {
49947                 // on an endpoint of line segment a
49948                 return noEndpointTouch ? null : [toPoint(a1, s, va)];
49949               }
49950
49951               if (t === 0 || t === 1) {
49952                 // on an endpoint of line segment b
49953                 return noEndpointTouch ? null : [toPoint(b1, t, vb)];
49954               }
49955
49956               return [toPoint(a1, s, va)];
49957             } // If we've reached this point, then the lines are either parallel or the
49958           // same, but the segments could overlap partially or fully, or not at all.
49959           // So we need to find the overlap, if any. To do that, we can use e, which is
49960           // the (vector) difference between the two initial points. If this is parallel
49961           // with the line itself, then the two lines are the same line, and there will
49962           // be overlap.
49963           //const sqrLenE = dotProduct(e, e);
49964
49965
49966           kross = crossProduct(e, va);
49967           sqrKross = kross * kross;
49968
49969           if (sqrKross > 0
49970           /* EPS * sqLenB * sqLenE */
49971           ) {
49972               // Lines are just parallel, not the same. No overlap.
49973               return null;
49974             }
49975
49976           var sa = dotProduct(va, e) / sqrLenA;
49977           var sb = sa + dotProduct(va, vb) / sqrLenA;
49978           var smin = Math.min(sa, sb);
49979           var smax = Math.max(sa, sb); // this is, essentially, the FindIntersection acting on floats from
49980           // Schneider & Eberly, just inlined into this function.
49981
49982           if (smin <= 1 && smax >= 0) {
49983             // overlap on an end point
49984             if (smin === 1) {
49985               return noEndpointTouch ? null : [toPoint(a1, smin > 0 ? smin : 0, va)];
49986             }
49987
49988             if (smax === 0) {
49989               return noEndpointTouch ? null : [toPoint(a1, smax < 1 ? smax : 1, va)];
49990             }
49991
49992             if (noEndpointTouch && smin === 0 && smax === 1) return null; // There's overlap on a segment -- two points of intersection. Return both.
49993
49994             return [toPoint(a1, smin > 0 ? smin : 0, va), toPoint(a1, smax < 1 ? smax : 1, va)];
49995           }
49996
49997           return null;
49998         }
49999
50000         /**
50001          * @param  {SweepEvent} se1
50002          * @param  {SweepEvent} se2
50003          * @param  {Queue}      queue
50004          * @return {Number}
50005          */
50006
50007         function possibleIntersection(se1, se2, queue) {
50008           // that disallows self-intersecting polygons,
50009           // did cost us half a day, so I'll leave it
50010           // out of respect
50011           // if (se1.isSubject === se2.isSubject) return;
50012           var inter = intersection(se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
50013           var nintersections = inter ? inter.length : 0;
50014           if (nintersections === 0) return 0; // no intersection
50015           // the line segments intersect at an endpoint of both line segments
50016
50017           if (nintersections === 1 && (equals(se1.point, se2.point) || equals(se1.otherEvent.point, se2.otherEvent.point))) {
50018             return 0;
50019           }
50020
50021           if (nintersections === 2 && se1.isSubject === se2.isSubject) {
50022             // if(se1.contourId === se2.contourId){
50023             // console.warn('Edges of the same polygon overlap',
50024             //   se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
50025             // }
50026             //throw new Error('Edges of the same polygon overlap');
50027             return 0;
50028           } // The line segments associated to se1 and se2 intersect
50029
50030
50031           if (nintersections === 1) {
50032             // if the intersection point is not an endpoint of se1
50033             if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) {
50034               divideSegment(se1, inter[0], queue);
50035             } // if the intersection point is not an endpoint of se2
50036
50037
50038             if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0])) {
50039               divideSegment(se2, inter[0], queue);
50040             }
50041
50042             return 1;
50043           } // The line segments associated to se1 and se2 overlap
50044
50045
50046           var events = [];
50047           var leftCoincide = false;
50048           var rightCoincide = false;
50049
50050           if (equals(se1.point, se2.point)) {
50051             leftCoincide = true; // linked
50052           } else if (compareEvents(se1, se2) === 1) {
50053             events.push(se2, se1);
50054           } else {
50055             events.push(se1, se2);
50056           }
50057
50058           if (equals(se1.otherEvent.point, se2.otherEvent.point)) {
50059             rightCoincide = true;
50060           } else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1) {
50061             events.push(se2.otherEvent, se1.otherEvent);
50062           } else {
50063             events.push(se1.otherEvent, se2.otherEvent);
50064           }
50065
50066           if (leftCoincide && rightCoincide || leftCoincide) {
50067             // both line segments are equal or share the left endpoint
50068             se2.type = NON_CONTRIBUTING;
50069             se1.type = se2.inOut === se1.inOut ? SAME_TRANSITION : DIFFERENT_TRANSITION;
50070
50071             if (leftCoincide && !rightCoincide) {
50072               // honestly no idea, but changing events selection from [2, 1]
50073               // to [0, 1] fixes the overlapping self-intersecting polygons issue
50074               divideSegment(events[1].otherEvent, events[0].point, queue);
50075             }
50076
50077             return 2;
50078           } // the line segments share the right endpoint
50079
50080
50081           if (rightCoincide) {
50082             divideSegment(events[0], events[1].point, queue);
50083             return 3;
50084           } // no line segment includes totally the other one
50085
50086
50087           if (events[0] !== events[3].otherEvent) {
50088             divideSegment(events[0], events[1].point, queue);
50089             divideSegment(events[1], events[2].point, queue);
50090             return 3;
50091           } // one line segment includes the other one
50092
50093
50094           divideSegment(events[0], events[1].point, queue);
50095           divideSegment(events[3].otherEvent, events[2].point, queue);
50096           return 3;
50097         }
50098
50099         /**
50100          * @param  {SweepEvent} le1
50101          * @param  {SweepEvent} le2
50102          * @return {Number}
50103          */
50104
50105         function compareSegments(le1, le2) {
50106           if (le1 === le2) return 0; // Segments are not collinear
50107
50108           if (signedArea(le1.point, le1.otherEvent.point, le2.point) !== 0 || signedArea(le1.point, le1.otherEvent.point, le2.otherEvent.point) !== 0) {
50109             // If they share their left endpoint use the right endpoint to sort
50110             if (equals(le1.point, le2.point)) return le1.isBelow(le2.otherEvent.point) ? -1 : 1; // Different left endpoint: use the left endpoint to sort
50111
50112             if (le1.point[0] === le2.point[0]) return le1.point[1] < le2.point[1] ? -1 : 1; // has the line segment associated to e1 been inserted
50113             // into S after the line segment associated to e2 ?
50114
50115             if (compareEvents(le1, le2) === 1) return le2.isAbove(le1.point) ? -1 : 1; // The line segment associated to e2 has been inserted
50116             // into S after the line segment associated to e1
50117
50118             return le1.isBelow(le2.point) ? -1 : 1;
50119           }
50120
50121           if (le1.isSubject === le2.isSubject) {
50122             // same polygon
50123             var p1 = le1.point,
50124                 p2 = le2.point;
50125
50126             if (p1[0] === p2[0] && p1[1] === p2[1]
50127             /*equals(le1.point, le2.point)*/
50128             ) {
50129                 p1 = le1.otherEvent.point;
50130                 p2 = le2.otherEvent.point;
50131                 if (p1[0] === p2[0] && p1[1] === p2[1]) return 0;else return le1.contourId > le2.contourId ? 1 : -1;
50132               }
50133           } else {
50134             // Segments are collinear, but belong to separate polygons
50135             return le1.isSubject ? -1 : 1;
50136           }
50137
50138           return compareEvents(le1, le2) === 1 ? 1 : -1;
50139         }
50140
50141         function subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation) {
50142           var sweepLine = new SplayTree(compareSegments);
50143           var sortedEvents = [];
50144           var rightbound = Math.min(sbbox[2], cbbox[2]);
50145           var prev, next, begin;
50146
50147           while (eventQueue.length !== 0) {
50148             var event = eventQueue.pop();
50149             sortedEvents.push(event); // optimization by bboxes for intersection and difference goes here
50150
50151             if (operation === INTERSECTION && event.point[0] > rightbound || operation === DIFFERENCE && event.point[0] > sbbox[2]) {
50152               break;
50153             }
50154
50155             if (event.left) {
50156               next = prev = sweepLine.insert(event);
50157               begin = sweepLine.minNode();
50158               if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
50159               next = sweepLine.next(next);
50160               var prevEvent = prev ? prev.key : null;
50161               var prevprevEvent = void 0;
50162               computeFields(event, prevEvent, operation);
50163
50164               if (next) {
50165                 if (possibleIntersection(event, next.key, eventQueue) === 2) {
50166                   computeFields(event, prevEvent, operation);
50167                   computeFields(event, next.key, operation);
50168                 }
50169               }
50170
50171               if (prev) {
50172                 if (possibleIntersection(prev.key, event, eventQueue) === 2) {
50173                   var prevprev = prev;
50174                   if (prevprev !== begin) prevprev = sweepLine.prev(prevprev);else prevprev = null;
50175                   prevprevEvent = prevprev ? prevprev.key : null;
50176                   computeFields(prevEvent, prevprevEvent, operation);
50177                   computeFields(event, prevEvent, operation);
50178                 }
50179               }
50180             } else {
50181               event = event.otherEvent;
50182               next = prev = sweepLine.find(event);
50183
50184               if (prev && next) {
50185                 if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
50186                 next = sweepLine.next(next);
50187                 sweepLine.remove(event);
50188
50189                 if (next && prev) {
50190                   possibleIntersection(prev.key, next.key, eventQueue);
50191                 }
50192               }
50193             }
50194           }
50195
50196           return sortedEvents;
50197         }
50198
50199         var Contour = /*#__PURE__*/function () {
50200           /**
50201            * Contour
50202            *
50203            * @class {Contour}
50204            */
50205           function Contour() {
50206             _classCallCheck(this, Contour);
50207
50208             this.points = [];
50209             this.holeIds = [];
50210             this.holeOf = null;
50211             this.depth = null;
50212           }
50213
50214           _createClass(Contour, [{
50215             key: "isExterior",
50216             value: function isExterior() {
50217               return this.holeOf == null;
50218             }
50219           }]);
50220
50221           return Contour;
50222         }();
50223
50224         /**
50225          * @param  {Array.<SweepEvent>} sortedEvents
50226          * @return {Array.<SweepEvent>}
50227          */
50228
50229         function orderEvents(sortedEvents) {
50230           var event, i, len, tmp;
50231           var resultEvents = [];
50232
50233           for (i = 0, len = sortedEvents.length; i < len; i++) {
50234             event = sortedEvents[i];
50235
50236             if (event.left && event.inResult || !event.left && event.otherEvent.inResult) {
50237               resultEvents.push(event);
50238             }
50239           } // Due to overlapping edges the resultEvents array can be not wholly sorted
50240
50241
50242           var sorted = false;
50243
50244           while (!sorted) {
50245             sorted = true;
50246
50247             for (i = 0, len = resultEvents.length; i < len; i++) {
50248               if (i + 1 < len && compareEvents(resultEvents[i], resultEvents[i + 1]) === 1) {
50249                 tmp = resultEvents[i];
50250                 resultEvents[i] = resultEvents[i + 1];
50251                 resultEvents[i + 1] = tmp;
50252                 sorted = false;
50253               }
50254             }
50255           }
50256
50257           for (i = 0, len = resultEvents.length; i < len; i++) {
50258             event = resultEvents[i];
50259             event.otherPos = i;
50260           } // imagine, the right event is found in the beginning of the queue,
50261           // when his left counterpart is not marked yet
50262
50263
50264           for (i = 0, len = resultEvents.length; i < len; i++) {
50265             event = resultEvents[i];
50266
50267             if (!event.left) {
50268               tmp = event.otherPos;
50269               event.otherPos = event.otherEvent.otherPos;
50270               event.otherEvent.otherPos = tmp;
50271             }
50272           }
50273
50274           return resultEvents;
50275         }
50276         /**
50277          * @param  {Number} pos
50278          * @param  {Array.<SweepEvent>} resultEvents
50279          * @param  {Object>}    processed
50280          * @return {Number}
50281          */
50282
50283
50284         function nextPos(pos, resultEvents, processed, origPos) {
50285           var newPos = pos + 1,
50286               p = resultEvents[pos].point,
50287               p1;
50288           var length = resultEvents.length;
50289           if (newPos < length) p1 = resultEvents[newPos].point;
50290
50291           while (newPos < length && p1[0] === p[0] && p1[1] === p[1]) {
50292             if (!processed[newPos]) {
50293               return newPos;
50294             } else {
50295               newPos++;
50296             }
50297
50298             p1 = resultEvents[newPos].point;
50299           }
50300
50301           newPos = pos - 1;
50302
50303           while (processed[newPos] && newPos > origPos) {
50304             newPos--;
50305           }
50306
50307           return newPos;
50308         }
50309
50310         function initializeContourFromContext(event, contours, contourId) {
50311           var contour = new Contour();
50312
50313           if (event.prevInResult != null) {
50314             var prevInResult = event.prevInResult; // Note that it is valid to query the "previous in result" for its output contour id,
50315             // because we must have already processed it (i.e., assigned an output contour id)
50316             // in an earlier iteration, otherwise it wouldn't be possible that it is "previous in
50317             // result".
50318
50319             var lowerContourId = prevInResult.outputContourId;
50320             var lowerResultTransition = prevInResult.resultTransition;
50321
50322             if (lowerResultTransition > 0) {
50323               // We are inside. Now we have to check if the thing below us is another hole or
50324               // an exterior contour.
50325               var lowerContour = contours[lowerContourId];
50326
50327               if (lowerContour.holeOf != null) {
50328                 // The lower contour is a hole => Connect the new contour as a hole to its parent,
50329                 // and use same depth.
50330                 var parentContourId = lowerContour.holeOf;
50331                 contours[parentContourId].holeIds.push(contourId);
50332                 contour.holeOf = parentContourId;
50333                 contour.depth = contours[lowerContourId].depth;
50334               } else {
50335                 // The lower contour is an exterior contour => Connect the new contour as a hole,
50336                 // and increment depth.
50337                 contours[lowerContourId].holeIds.push(contourId);
50338                 contour.holeOf = lowerContourId;
50339                 contour.depth = contours[lowerContourId].depth + 1;
50340               }
50341             } else {
50342               // We are outside => this contour is an exterior contour of same depth.
50343               contour.holeOf = null;
50344               contour.depth = contours[lowerContourId].depth;
50345             }
50346           } else {
50347             // There is no lower/previous contour => this contour is an exterior contour of depth 0.
50348             contour.holeOf = null;
50349             contour.depth = 0;
50350           }
50351
50352           return contour;
50353         }
50354         /**
50355          * @param  {Array.<SweepEvent>} sortedEvents
50356          * @return {Array.<*>} polygons
50357          */
50358
50359
50360         function connectEdges(sortedEvents) {
50361           var i, len;
50362           var resultEvents = orderEvents(sortedEvents); // "false"-filled array
50363
50364           var processed = {};
50365           var contours = [];
50366
50367           var _loop = function _loop() {
50368             if (processed[i]) {
50369               return "continue";
50370             }
50371
50372             var contourId = contours.length;
50373             var contour = initializeContourFromContext(resultEvents[i], contours, contourId); // Helper function that combines marking an event as processed with assigning its output contour ID
50374
50375             var markAsProcessed = function markAsProcessed(pos) {
50376               processed[pos] = true;
50377               resultEvents[pos].outputContourId = contourId;
50378             };
50379
50380             var pos = i;
50381             var origPos = i;
50382             var initial = resultEvents[i].point;
50383             contour.points.push(initial);
50384             /* eslint no-constant-condition: "off" */
50385
50386             while (true) {
50387               markAsProcessed(pos);
50388               pos = resultEvents[pos].otherPos;
50389               markAsProcessed(pos);
50390               contour.points.push(resultEvents[pos].point);
50391               pos = nextPos(pos, resultEvents, processed, origPos);
50392
50393               if (pos == origPos) {
50394                 break;
50395               }
50396             }
50397
50398             contours.push(contour);
50399           };
50400
50401           for (i = 0, len = resultEvents.length; i < len; i++) {
50402             var _ret = _loop();
50403
50404             if (_ret === "continue") continue;
50405           }
50406
50407           return contours;
50408         }
50409
50410         var tinyqueue = TinyQueue;
50411         var _default$1 = TinyQueue;
50412
50413         function TinyQueue(data, compare) {
50414           if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
50415           this.data = data || [];
50416           this.length = this.data.length;
50417           this.compare = compare || defaultCompare$1;
50418
50419           if (this.length > 0) {
50420             for (var i = (this.length >> 1) - 1; i >= 0; i--) {
50421               this._down(i);
50422             }
50423           }
50424         }
50425
50426         function defaultCompare$1(a, b) {
50427           return a < b ? -1 : a > b ? 1 : 0;
50428         }
50429
50430         TinyQueue.prototype = {
50431           push: function push(item) {
50432             this.data.push(item);
50433             this.length++;
50434
50435             this._up(this.length - 1);
50436           },
50437           pop: function pop() {
50438             if (this.length === 0) return undefined;
50439             var top = this.data[0];
50440             this.length--;
50441
50442             if (this.length > 0) {
50443               this.data[0] = this.data[this.length];
50444
50445               this._down(0);
50446             }
50447
50448             this.data.pop();
50449             return top;
50450           },
50451           peek: function peek() {
50452             return this.data[0];
50453           },
50454           _up: function _up(pos) {
50455             var data = this.data;
50456             var compare = this.compare;
50457             var item = data[pos];
50458
50459             while (pos > 0) {
50460               var parent = pos - 1 >> 1;
50461               var current = data[parent];
50462               if (compare(item, current) >= 0) break;
50463               data[pos] = current;
50464               pos = parent;
50465             }
50466
50467             data[pos] = item;
50468           },
50469           _down: function _down(pos) {
50470             var data = this.data;
50471             var compare = this.compare;
50472             var halfLength = this.length >> 1;
50473             var item = data[pos];
50474
50475             while (pos < halfLength) {
50476               var left = (pos << 1) + 1;
50477               var right = left + 1;
50478               var best = data[left];
50479
50480               if (right < this.length && compare(data[right], best) < 0) {
50481                 left = right;
50482                 best = data[right];
50483               }
50484
50485               if (compare(best, item) >= 0) break;
50486               data[pos] = best;
50487               pos = left;
50488             }
50489
50490             data[pos] = item;
50491           }
50492         };
50493         tinyqueue["default"] = _default$1;
50494
50495         var max$5 = Math.max;
50496         var min$a = Math.min;
50497         var contourId = 0;
50498
50499         function processPolygon(contourOrHole, isSubject, depth, Q, bbox, isExteriorRing) {
50500           var i, len, s1, s2, e1, e2;
50501
50502           for (i = 0, len = contourOrHole.length - 1; i < len; i++) {
50503             s1 = contourOrHole[i];
50504             s2 = contourOrHole[i + 1];
50505             e1 = new SweepEvent(s1, false, undefined, isSubject);
50506             e2 = new SweepEvent(s2, false, e1, isSubject);
50507             e1.otherEvent = e2;
50508
50509             if (s1[0] === s2[0] && s1[1] === s2[1]) {
50510               continue; // skip collapsed edges, or it breaks
50511             }
50512
50513             e1.contourId = e2.contourId = depth;
50514
50515             if (!isExteriorRing) {
50516               e1.isExteriorRing = false;
50517               e2.isExteriorRing = false;
50518             }
50519
50520             if (compareEvents(e1, e2) > 0) {
50521               e2.left = true;
50522             } else {
50523               e1.left = true;
50524             }
50525
50526             var x = s1[0],
50527                 y = s1[1];
50528             bbox[0] = min$a(bbox[0], x);
50529             bbox[1] = min$a(bbox[1], y);
50530             bbox[2] = max$5(bbox[2], x);
50531             bbox[3] = max$5(bbox[3], y); // Pushing it so the queue is sorted from left to right,
50532             // with object on the left having the highest priority.
50533
50534             Q.push(e1);
50535             Q.push(e2);
50536           }
50537         }
50538
50539         function fillQueue(subject, clipping, sbbox, cbbox, operation) {
50540           var eventQueue = new tinyqueue(null, compareEvents);
50541           var polygonSet, isExteriorRing, i, ii, j, jj; //, k, kk;
50542
50543           for (i = 0, ii = subject.length; i < ii; i++) {
50544             polygonSet = subject[i];
50545
50546             for (j = 0, jj = polygonSet.length; j < jj; j++) {
50547               isExteriorRing = j === 0;
50548               if (isExteriorRing) contourId++;
50549               processPolygon(polygonSet[j], true, contourId, eventQueue, sbbox, isExteriorRing);
50550             }
50551           }
50552
50553           for (i = 0, ii = clipping.length; i < ii; i++) {
50554             polygonSet = clipping[i];
50555
50556             for (j = 0, jj = polygonSet.length; j < jj; j++) {
50557               isExteriorRing = j === 0;
50558               if (operation === DIFFERENCE) isExteriorRing = false;
50559               if (isExteriorRing) contourId++;
50560               processPolygon(polygonSet[j], false, contourId, eventQueue, cbbox, isExteriorRing);
50561             }
50562           }
50563
50564           return eventQueue;
50565         }
50566
50567         var EMPTY = [];
50568
50569         function trivialOperation(subject, clipping, operation) {
50570           var result = null;
50571
50572           if (subject.length * clipping.length === 0) {
50573             if (operation === INTERSECTION) {
50574               result = EMPTY;
50575             } else if (operation === DIFFERENCE) {
50576               result = subject;
50577             } else if (operation === UNION || operation === XOR) {
50578               result = subject.length === 0 ? clipping : subject;
50579             }
50580           }
50581
50582           return result;
50583         }
50584
50585         function compareBBoxes(subject, clipping, sbbox, cbbox, operation) {
50586           var result = null;
50587
50588           if (sbbox[0] > cbbox[2] || cbbox[0] > sbbox[2] || sbbox[1] > cbbox[3] || cbbox[1] > sbbox[3]) {
50589             if (operation === INTERSECTION) {
50590               result = EMPTY;
50591             } else if (operation === DIFFERENCE) {
50592               result = subject;
50593             } else if (operation === UNION || operation === XOR) {
50594               result = subject.concat(clipping);
50595             }
50596           }
50597
50598           return result;
50599         }
50600
50601         function _boolean(subject, clipping, operation) {
50602           if (typeof subject[0][0][0] === 'number') {
50603             subject = [subject];
50604           }
50605
50606           if (typeof clipping[0][0][0] === 'number') {
50607             clipping = [clipping];
50608           }
50609
50610           var trivial = trivialOperation(subject, clipping, operation);
50611
50612           if (trivial) {
50613             return trivial === EMPTY ? null : trivial;
50614           }
50615
50616           var sbbox = [Infinity, Infinity, -Infinity, -Infinity];
50617           var cbbox = [Infinity, Infinity, -Infinity, -Infinity]; // console.time('fill queue');
50618
50619           var eventQueue = fillQueue(subject, clipping, sbbox, cbbox, operation); //console.timeEnd('fill queue');
50620
50621           trivial = compareBBoxes(subject, clipping, sbbox, cbbox, operation);
50622
50623           if (trivial) {
50624             return trivial === EMPTY ? null : trivial;
50625           } // console.time('subdivide edges');
50626
50627
50628           var sortedEvents = subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation); //console.timeEnd('subdivide edges');
50629           // console.time('connect vertices');
50630
50631           var contours = connectEdges(sortedEvents); //console.timeEnd('connect vertices');
50632           // Convert contours to polygons
50633
50634           var polygons = [];
50635
50636           for (var i = 0; i < contours.length; i++) {
50637             var contour = contours[i];
50638
50639             if (contour.isExterior()) {
50640               // The exterior ring goes first
50641               var rings = [contour.points]; // Followed by holes if any
50642
50643               for (var j = 0; j < contour.holeIds.length; j++) {
50644                 var holeId = contour.holeIds[j];
50645                 rings.push(contours[holeId].points);
50646               }
50647
50648               polygons.push(rings);
50649             }
50650           }
50651
50652           return polygons;
50653         }
50654
50655         function union(subject, clipping) {
50656           return _boolean(subject, clipping, UNION);
50657         }
50658
50659         var read$6 = function read(buffer, offset, isLE, mLen, nBytes) {
50660           var e, m;
50661           var eLen = nBytes * 8 - mLen - 1;
50662           var eMax = (1 << eLen) - 1;
50663           var eBias = eMax >> 1;
50664           var nBits = -7;
50665           var i = isLE ? nBytes - 1 : 0;
50666           var d = isLE ? -1 : 1;
50667           var s = buffer[offset + i];
50668           i += d;
50669           e = s & (1 << -nBits) - 1;
50670           s >>= -nBits;
50671           nBits += eLen;
50672
50673           for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50674
50675           m = e & (1 << -nBits) - 1;
50676           e >>= -nBits;
50677           nBits += mLen;
50678
50679           for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50680
50681           if (e === 0) {
50682             e = 1 - eBias;
50683           } else if (e === eMax) {
50684             return m ? NaN : (s ? -1 : 1) * Infinity;
50685           } else {
50686             m = m + Math.pow(2, mLen);
50687             e = e - eBias;
50688           }
50689
50690           return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
50691         };
50692
50693         var write$6 = function write(buffer, value, offset, isLE, mLen, nBytes) {
50694           var e, m, c;
50695           var eLen = nBytes * 8 - mLen - 1;
50696           var eMax = (1 << eLen) - 1;
50697           var eBias = eMax >> 1;
50698           var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
50699           var i = isLE ? 0 : nBytes - 1;
50700           var d = isLE ? 1 : -1;
50701           var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
50702           value = Math.abs(value);
50703
50704           if (isNaN(value) || value === Infinity) {
50705             m = isNaN(value) ? 1 : 0;
50706             e = eMax;
50707           } else {
50708             e = Math.floor(Math.log(value) / Math.LN2);
50709
50710             if (value * (c = Math.pow(2, -e)) < 1) {
50711               e--;
50712               c *= 2;
50713             }
50714
50715             if (e + eBias >= 1) {
50716               value += rt / c;
50717             } else {
50718               value += rt * Math.pow(2, 1 - eBias);
50719             }
50720
50721             if (value * c >= 2) {
50722               e++;
50723               c /= 2;
50724             }
50725
50726             if (e + eBias >= eMax) {
50727               m = 0;
50728               e = eMax;
50729             } else if (e + eBias >= 1) {
50730               m = (value * c - 1) * Math.pow(2, mLen);
50731               e = e + eBias;
50732             } else {
50733               m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
50734               e = 0;
50735             }
50736           }
50737
50738           for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
50739
50740           e = e << mLen | m;
50741           eLen += mLen;
50742
50743           for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
50744
50745           buffer[offset + i - d] |= s * 128;
50746         };
50747
50748         var ieee754$1 = {
50749           read: read$6,
50750           write: write$6
50751         };
50752
50753         var pbf = Pbf;
50754
50755         function Pbf(buf) {
50756           this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
50757           this.pos = 0;
50758           this.type = 0;
50759           this.length = this.buf.length;
50760         }
50761
50762         Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
50763
50764         Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
50765
50766         Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
50767
50768         Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
50769
50770         var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
50771             SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; // Threshold chosen based on both benchmarking and knowledge about browser string
50772         // data structures (which currently switch structure types at 12 bytes or more)
50773
50774         var TEXT_DECODER_MIN_LENGTH = 12;
50775         var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
50776         Pbf.prototype = {
50777           destroy: function destroy() {
50778             this.buf = null;
50779           },
50780           // === READING =================================================================
50781           readFields: function readFields(readField, result, end) {
50782             end = end || this.length;
50783
50784             while (this.pos < end) {
50785               var val = this.readVarint(),
50786                   tag = val >> 3,
50787                   startPos = this.pos;
50788               this.type = val & 0x7;
50789               readField(tag, result, this);
50790               if (this.pos === startPos) this.skip(val);
50791             }
50792
50793             return result;
50794           },
50795           readMessage: function readMessage(readField, result) {
50796             return this.readFields(readField, result, this.readVarint() + this.pos);
50797           },
50798           readFixed32: function readFixed32() {
50799             var val = readUInt32(this.buf, this.pos);
50800             this.pos += 4;
50801             return val;
50802           },
50803           readSFixed32: function readSFixed32() {
50804             var val = readInt32(this.buf, this.pos);
50805             this.pos += 4;
50806             return val;
50807           },
50808           // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
50809           readFixed64: function readFixed64() {
50810             var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50811             this.pos += 8;
50812             return val;
50813           },
50814           readSFixed64: function readSFixed64() {
50815             var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50816             this.pos += 8;
50817             return val;
50818           },
50819           readFloat: function readFloat() {
50820             var val = ieee754$1.read(this.buf, this.pos, true, 23, 4);
50821             this.pos += 4;
50822             return val;
50823           },
50824           readDouble: function readDouble() {
50825             var val = ieee754$1.read(this.buf, this.pos, true, 52, 8);
50826             this.pos += 8;
50827             return val;
50828           },
50829           readVarint: function readVarint(isSigned) {
50830             var buf = this.buf,
50831                 val,
50832                 b;
50833             b = buf[this.pos++];
50834             val = b & 0x7f;
50835             if (b < 0x80) return val;
50836             b = buf[this.pos++];
50837             val |= (b & 0x7f) << 7;
50838             if (b < 0x80) return val;
50839             b = buf[this.pos++];
50840             val |= (b & 0x7f) << 14;
50841             if (b < 0x80) return val;
50842             b = buf[this.pos++];
50843             val |= (b & 0x7f) << 21;
50844             if (b < 0x80) return val;
50845             b = buf[this.pos];
50846             val |= (b & 0x0f) << 28;
50847             return readVarintRemainder(val, isSigned, this);
50848           },
50849           readVarint64: function readVarint64() {
50850             // for compatibility with v2.0.1
50851             return this.readVarint(true);
50852           },
50853           readSVarint: function readSVarint() {
50854             var num = this.readVarint();
50855             return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
50856           },
50857           readBoolean: function readBoolean() {
50858             return Boolean(this.readVarint());
50859           },
50860           readString: function readString() {
50861             var end = this.readVarint() + this.pos;
50862             var pos = this.pos;
50863             this.pos = end;
50864
50865             if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
50866               // longer strings are fast with the built-in browser TextDecoder API
50867               return readUtf8TextDecoder(this.buf, pos, end);
50868             } // short strings are fast with our custom implementation
50869
50870
50871             return readUtf8(this.buf, pos, end);
50872           },
50873           readBytes: function readBytes() {
50874             var end = this.readVarint() + this.pos,
50875                 buffer = this.buf.subarray(this.pos, end);
50876             this.pos = end;
50877             return buffer;
50878           },
50879           // verbose for performance reasons; doesn't affect gzipped size
50880           readPackedVarint: function readPackedVarint(arr, isSigned) {
50881             if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
50882             var end = readPackedEnd(this);
50883             arr = arr || [];
50884
50885             while (this.pos < end) {
50886               arr.push(this.readVarint(isSigned));
50887             }
50888
50889             return arr;
50890           },
50891           readPackedSVarint: function readPackedSVarint(arr) {
50892             if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
50893             var end = readPackedEnd(this);
50894             arr = arr || [];
50895
50896             while (this.pos < end) {
50897               arr.push(this.readSVarint());
50898             }
50899
50900             return arr;
50901           },
50902           readPackedBoolean: function readPackedBoolean(arr) {
50903             if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
50904             var end = readPackedEnd(this);
50905             arr = arr || [];
50906
50907             while (this.pos < end) {
50908               arr.push(this.readBoolean());
50909             }
50910
50911             return arr;
50912           },
50913           readPackedFloat: function readPackedFloat(arr) {
50914             if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
50915             var end = readPackedEnd(this);
50916             arr = arr || [];
50917
50918             while (this.pos < end) {
50919               arr.push(this.readFloat());
50920             }
50921
50922             return arr;
50923           },
50924           readPackedDouble: function readPackedDouble(arr) {
50925             if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
50926             var end = readPackedEnd(this);
50927             arr = arr || [];
50928
50929             while (this.pos < end) {
50930               arr.push(this.readDouble());
50931             }
50932
50933             return arr;
50934           },
50935           readPackedFixed32: function readPackedFixed32(arr) {
50936             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
50937             var end = readPackedEnd(this);
50938             arr = arr || [];
50939
50940             while (this.pos < end) {
50941               arr.push(this.readFixed32());
50942             }
50943
50944             return arr;
50945           },
50946           readPackedSFixed32: function readPackedSFixed32(arr) {
50947             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
50948             var end = readPackedEnd(this);
50949             arr = arr || [];
50950
50951             while (this.pos < end) {
50952               arr.push(this.readSFixed32());
50953             }
50954
50955             return arr;
50956           },
50957           readPackedFixed64: function readPackedFixed64(arr) {
50958             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
50959             var end = readPackedEnd(this);
50960             arr = arr || [];
50961
50962             while (this.pos < end) {
50963               arr.push(this.readFixed64());
50964             }
50965
50966             return arr;
50967           },
50968           readPackedSFixed64: function readPackedSFixed64(arr) {
50969             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
50970             var end = readPackedEnd(this);
50971             arr = arr || [];
50972
50973             while (this.pos < end) {
50974               arr.push(this.readSFixed64());
50975             }
50976
50977             return arr;
50978           },
50979           skip: function skip(val) {
50980             var type = val & 0x7;
50981             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);
50982           },
50983           // === WRITING =================================================================
50984           writeTag: function writeTag(tag, type) {
50985             this.writeVarint(tag << 3 | type);
50986           },
50987           realloc: function realloc(min) {
50988             var length = this.length || 16;
50989
50990             while (length < this.pos + min) {
50991               length *= 2;
50992             }
50993
50994             if (length !== this.length) {
50995               var buf = new Uint8Array(length);
50996               buf.set(this.buf);
50997               this.buf = buf;
50998               this.length = length;
50999             }
51000           },
51001           finish: function finish() {
51002             this.length = this.pos;
51003             this.pos = 0;
51004             return this.buf.subarray(0, this.length);
51005           },
51006           writeFixed32: function writeFixed32(val) {
51007             this.realloc(4);
51008             writeInt32(this.buf, val, this.pos);
51009             this.pos += 4;
51010           },
51011           writeSFixed32: function writeSFixed32(val) {
51012             this.realloc(4);
51013             writeInt32(this.buf, val, this.pos);
51014             this.pos += 4;
51015           },
51016           writeFixed64: function writeFixed64(val) {
51017             this.realloc(8);
51018             writeInt32(this.buf, val & -1, this.pos);
51019             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51020             this.pos += 8;
51021           },
51022           writeSFixed64: function writeSFixed64(val) {
51023             this.realloc(8);
51024             writeInt32(this.buf, val & -1, this.pos);
51025             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51026             this.pos += 8;
51027           },
51028           writeVarint: function writeVarint(val) {
51029             val = +val || 0;
51030
51031             if (val > 0xfffffff || val < 0) {
51032               writeBigVarint(val, this);
51033               return;
51034             }
51035
51036             this.realloc(4);
51037             this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
51038             if (val <= 0x7f) return;
51039             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51040             if (val <= 0x7f) return;
51041             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51042             if (val <= 0x7f) return;
51043             this.buf[this.pos++] = val >>> 7 & 0x7f;
51044           },
51045           writeSVarint: function writeSVarint(val) {
51046             this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
51047           },
51048           writeBoolean: function writeBoolean(val) {
51049             this.writeVarint(Boolean(val));
51050           },
51051           writeString: function writeString(str) {
51052             str = String(str);
51053             this.realloc(str.length * 4);
51054             this.pos++; // reserve 1 byte for short string length
51055
51056             var startPos = this.pos; // write the string directly to the buffer and see how much was written
51057
51058             this.pos = writeUtf8(this.buf, str, this.pos);
51059             var len = this.pos - startPos;
51060             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51061
51062             this.pos = startPos - 1;
51063             this.writeVarint(len);
51064             this.pos += len;
51065           },
51066           writeFloat: function writeFloat(val) {
51067             this.realloc(4);
51068             ieee754$1.write(this.buf, val, this.pos, true, 23, 4);
51069             this.pos += 4;
51070           },
51071           writeDouble: function writeDouble(val) {
51072             this.realloc(8);
51073             ieee754$1.write(this.buf, val, this.pos, true, 52, 8);
51074             this.pos += 8;
51075           },
51076           writeBytes: function writeBytes(buffer) {
51077             var len = buffer.length;
51078             this.writeVarint(len);
51079             this.realloc(len);
51080
51081             for (var i = 0; i < len; i++) {
51082               this.buf[this.pos++] = buffer[i];
51083             }
51084           },
51085           writeRawMessage: function writeRawMessage(fn, obj) {
51086             this.pos++; // reserve 1 byte for short message length
51087             // write the message directly to the buffer and see how much was written
51088
51089             var startPos = this.pos;
51090             fn(obj, this);
51091             var len = this.pos - startPos;
51092             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51093
51094             this.pos = startPos - 1;
51095             this.writeVarint(len);
51096             this.pos += len;
51097           },
51098           writeMessage: function writeMessage(tag, fn, obj) {
51099             this.writeTag(tag, Pbf.Bytes);
51100             this.writeRawMessage(fn, obj);
51101           },
51102           writePackedVarint: function writePackedVarint(tag, arr) {
51103             if (arr.length) this.writeMessage(tag, _writePackedVarint, arr);
51104           },
51105           writePackedSVarint: function writePackedSVarint(tag, arr) {
51106             if (arr.length) this.writeMessage(tag, _writePackedSVarint, arr);
51107           },
51108           writePackedBoolean: function writePackedBoolean(tag, arr) {
51109             if (arr.length) this.writeMessage(tag, _writePackedBoolean, arr);
51110           },
51111           writePackedFloat: function writePackedFloat(tag, arr) {
51112             if (arr.length) this.writeMessage(tag, _writePackedFloat, arr);
51113           },
51114           writePackedDouble: function writePackedDouble(tag, arr) {
51115             if (arr.length) this.writeMessage(tag, _writePackedDouble, arr);
51116           },
51117           writePackedFixed32: function writePackedFixed32(tag, arr) {
51118             if (arr.length) this.writeMessage(tag, _writePackedFixed, arr);
51119           },
51120           writePackedSFixed32: function writePackedSFixed32(tag, arr) {
51121             if (arr.length) this.writeMessage(tag, _writePackedSFixed, arr);
51122           },
51123           writePackedFixed64: function writePackedFixed64(tag, arr) {
51124             if (arr.length) this.writeMessage(tag, _writePackedFixed2, arr);
51125           },
51126           writePackedSFixed64: function writePackedSFixed64(tag, arr) {
51127             if (arr.length) this.writeMessage(tag, _writePackedSFixed2, arr);
51128           },
51129           writeBytesField: function writeBytesField(tag, buffer) {
51130             this.writeTag(tag, Pbf.Bytes);
51131             this.writeBytes(buffer);
51132           },
51133           writeFixed32Field: function writeFixed32Field(tag, val) {
51134             this.writeTag(tag, Pbf.Fixed32);
51135             this.writeFixed32(val);
51136           },
51137           writeSFixed32Field: function writeSFixed32Field(tag, val) {
51138             this.writeTag(tag, Pbf.Fixed32);
51139             this.writeSFixed32(val);
51140           },
51141           writeFixed64Field: function writeFixed64Field(tag, val) {
51142             this.writeTag(tag, Pbf.Fixed64);
51143             this.writeFixed64(val);
51144           },
51145           writeSFixed64Field: function writeSFixed64Field(tag, val) {
51146             this.writeTag(tag, Pbf.Fixed64);
51147             this.writeSFixed64(val);
51148           },
51149           writeVarintField: function writeVarintField(tag, val) {
51150             this.writeTag(tag, Pbf.Varint);
51151             this.writeVarint(val);
51152           },
51153           writeSVarintField: function writeSVarintField(tag, val) {
51154             this.writeTag(tag, Pbf.Varint);
51155             this.writeSVarint(val);
51156           },
51157           writeStringField: function writeStringField(tag, str) {
51158             this.writeTag(tag, Pbf.Bytes);
51159             this.writeString(str);
51160           },
51161           writeFloatField: function writeFloatField(tag, val) {
51162             this.writeTag(tag, Pbf.Fixed32);
51163             this.writeFloat(val);
51164           },
51165           writeDoubleField: function writeDoubleField(tag, val) {
51166             this.writeTag(tag, Pbf.Fixed64);
51167             this.writeDouble(val);
51168           },
51169           writeBooleanField: function writeBooleanField(tag, val) {
51170             this.writeVarintField(tag, Boolean(val));
51171           }
51172         };
51173
51174         function readVarintRemainder(l, s, p) {
51175           var buf = p.buf,
51176               h,
51177               b;
51178           b = buf[p.pos++];
51179           h = (b & 0x70) >> 4;
51180           if (b < 0x80) return toNum(l, h, s);
51181           b = buf[p.pos++];
51182           h |= (b & 0x7f) << 3;
51183           if (b < 0x80) return toNum(l, h, s);
51184           b = buf[p.pos++];
51185           h |= (b & 0x7f) << 10;
51186           if (b < 0x80) return toNum(l, h, s);
51187           b = buf[p.pos++];
51188           h |= (b & 0x7f) << 17;
51189           if (b < 0x80) return toNum(l, h, s);
51190           b = buf[p.pos++];
51191           h |= (b & 0x7f) << 24;
51192           if (b < 0x80) return toNum(l, h, s);
51193           b = buf[p.pos++];
51194           h |= (b & 0x01) << 31;
51195           if (b < 0x80) return toNum(l, h, s);
51196           throw new Error('Expected varint not more than 10 bytes');
51197         }
51198
51199         function readPackedEnd(pbf) {
51200           return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
51201         }
51202
51203         function toNum(low, high, isSigned) {
51204           if (isSigned) {
51205             return high * 0x100000000 + (low >>> 0);
51206           }
51207
51208           return (high >>> 0) * 0x100000000 + (low >>> 0);
51209         }
51210
51211         function writeBigVarint(val, pbf) {
51212           var low, high;
51213
51214           if (val >= 0) {
51215             low = val % 0x100000000 | 0;
51216             high = val / 0x100000000 | 0;
51217           } else {
51218             low = ~(-val % 0x100000000);
51219             high = ~(-val / 0x100000000);
51220
51221             if (low ^ 0xffffffff) {
51222               low = low + 1 | 0;
51223             } else {
51224               low = 0;
51225               high = high + 1 | 0;
51226             }
51227           }
51228
51229           if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
51230             throw new Error('Given varint doesn\'t fit into 10 bytes');
51231           }
51232
51233           pbf.realloc(10);
51234           writeBigVarintLow(low, high, pbf);
51235           writeBigVarintHigh(high, pbf);
51236         }
51237
51238         function writeBigVarintLow(low, high, pbf) {
51239           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51240           low >>>= 7;
51241           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51242           low >>>= 7;
51243           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51244           low >>>= 7;
51245           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51246           low >>>= 7;
51247           pbf.buf[pbf.pos] = low & 0x7f;
51248         }
51249
51250         function writeBigVarintHigh(high, pbf) {
51251           var lsb = (high & 0x07) << 4;
51252           pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0);
51253           if (!high) return;
51254           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51255           if (!high) return;
51256           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51257           if (!high) return;
51258           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51259           if (!high) return;
51260           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51261           if (!high) return;
51262           pbf.buf[pbf.pos++] = high & 0x7f;
51263         }
51264
51265         function makeRoomForExtraLength(startPos, len, pbf) {
51266           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
51267
51268           pbf.realloc(extraLen);
51269
51270           for (var i = pbf.pos - 1; i >= startPos; i--) {
51271             pbf.buf[i + extraLen] = pbf.buf[i];
51272           }
51273         }
51274
51275         function _writePackedVarint(arr, pbf) {
51276           for (var i = 0; i < arr.length; i++) {
51277             pbf.writeVarint(arr[i]);
51278           }
51279         }
51280
51281         function _writePackedSVarint(arr, pbf) {
51282           for (var i = 0; i < arr.length; i++) {
51283             pbf.writeSVarint(arr[i]);
51284           }
51285         }
51286
51287         function _writePackedFloat(arr, pbf) {
51288           for (var i = 0; i < arr.length; i++) {
51289             pbf.writeFloat(arr[i]);
51290           }
51291         }
51292
51293         function _writePackedDouble(arr, pbf) {
51294           for (var i = 0; i < arr.length; i++) {
51295             pbf.writeDouble(arr[i]);
51296           }
51297         }
51298
51299         function _writePackedBoolean(arr, pbf) {
51300           for (var i = 0; i < arr.length; i++) {
51301             pbf.writeBoolean(arr[i]);
51302           }
51303         }
51304
51305         function _writePackedFixed(arr, pbf) {
51306           for (var i = 0; i < arr.length; i++) {
51307             pbf.writeFixed32(arr[i]);
51308           }
51309         }
51310
51311         function _writePackedSFixed(arr, pbf) {
51312           for (var i = 0; i < arr.length; i++) {
51313             pbf.writeSFixed32(arr[i]);
51314           }
51315         }
51316
51317         function _writePackedFixed2(arr, pbf) {
51318           for (var i = 0; i < arr.length; i++) {
51319             pbf.writeFixed64(arr[i]);
51320           }
51321         }
51322
51323         function _writePackedSFixed2(arr, pbf) {
51324           for (var i = 0; i < arr.length; i++) {
51325             pbf.writeSFixed64(arr[i]);
51326           }
51327         } // Buffer code below from https://github.com/feross/buffer, MIT-licensed
51328
51329
51330         function readUInt32(buf, pos) {
51331           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 0x1000000;
51332         }
51333
51334         function writeInt32(buf, val, pos) {
51335           buf[pos] = val;
51336           buf[pos + 1] = val >>> 8;
51337           buf[pos + 2] = val >>> 16;
51338           buf[pos + 3] = val >>> 24;
51339         }
51340
51341         function readInt32(buf, pos) {
51342           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
51343         }
51344
51345         function readUtf8(buf, pos, end) {
51346           var str = '';
51347           var i = pos;
51348
51349           while (i < end) {
51350             var b0 = buf[i];
51351             var c = null; // codepoint
51352
51353             var bytesPerSequence = b0 > 0xEF ? 4 : b0 > 0xDF ? 3 : b0 > 0xBF ? 2 : 1;
51354             if (i + bytesPerSequence > end) break;
51355             var b1, b2, b3;
51356
51357             if (bytesPerSequence === 1) {
51358               if (b0 < 0x80) {
51359                 c = b0;
51360               }
51361             } else if (bytesPerSequence === 2) {
51362               b1 = buf[i + 1];
51363
51364               if ((b1 & 0xC0) === 0x80) {
51365                 c = (b0 & 0x1F) << 0x6 | b1 & 0x3F;
51366
51367                 if (c <= 0x7F) {
51368                   c = null;
51369                 }
51370               }
51371             } else if (bytesPerSequence === 3) {
51372               b1 = buf[i + 1];
51373               b2 = buf[i + 2];
51374
51375               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
51376                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | b2 & 0x3F;
51377
51378                 if (c <= 0x7FF || c >= 0xD800 && c <= 0xDFFF) {
51379                   c = null;
51380                 }
51381               }
51382             } else if (bytesPerSequence === 4) {
51383               b1 = buf[i + 1];
51384               b2 = buf[i + 2];
51385               b3 = buf[i + 3];
51386
51387               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
51388                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | b3 & 0x3F;
51389
51390                 if (c <= 0xFFFF || c >= 0x110000) {
51391                   c = null;
51392                 }
51393               }
51394             }
51395
51396             if (c === null) {
51397               c = 0xFFFD;
51398               bytesPerSequence = 1;
51399             } else if (c > 0xFFFF) {
51400               c -= 0x10000;
51401               str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
51402               c = 0xDC00 | c & 0x3FF;
51403             }
51404
51405             str += String.fromCharCode(c);
51406             i += bytesPerSequence;
51407           }
51408
51409           return str;
51410         }
51411
51412         function readUtf8TextDecoder(buf, pos, end) {
51413           return utf8TextDecoder.decode(buf.subarray(pos, end));
51414         }
51415
51416         function writeUtf8(buf, str, pos) {
51417           for (var i = 0, c, lead; i < str.length; i++) {
51418             c = str.charCodeAt(i); // code point
51419
51420             if (c > 0xD7FF && c < 0xE000) {
51421               if (lead) {
51422                 if (c < 0xDC00) {
51423                   buf[pos++] = 0xEF;
51424                   buf[pos++] = 0xBF;
51425                   buf[pos++] = 0xBD;
51426                   lead = c;
51427                   continue;
51428                 } else {
51429                   c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
51430                   lead = null;
51431                 }
51432               } else {
51433                 if (c > 0xDBFF || i + 1 === str.length) {
51434                   buf[pos++] = 0xEF;
51435                   buf[pos++] = 0xBF;
51436                   buf[pos++] = 0xBD;
51437                 } else {
51438                   lead = c;
51439                 }
51440
51441                 continue;
51442               }
51443             } else if (lead) {
51444               buf[pos++] = 0xEF;
51445               buf[pos++] = 0xBF;
51446               buf[pos++] = 0xBD;
51447               lead = null;
51448             }
51449
51450             if (c < 0x80) {
51451               buf[pos++] = c;
51452             } else {
51453               if (c < 0x800) {
51454                 buf[pos++] = c >> 0x6 | 0xC0;
51455               } else {
51456                 if (c < 0x10000) {
51457                   buf[pos++] = c >> 0xC | 0xE0;
51458                 } else {
51459                   buf[pos++] = c >> 0x12 | 0xF0;
51460                   buf[pos++] = c >> 0xC & 0x3F | 0x80;
51461                 }
51462
51463                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
51464               }
51465
51466               buf[pos++] = c & 0x3F | 0x80;
51467             }
51468           }
51469
51470           return pos;
51471         }
51472
51473         var pointGeometry = Point;
51474         /**
51475          * A standalone point geometry with useful accessor, comparison, and
51476          * modification methods.
51477          *
51478          * @class Point
51479          * @param {Number} x the x-coordinate. this could be longitude or screen
51480          * pixels, or any other sort of unit.
51481          * @param {Number} y the y-coordinate. this could be latitude or screen
51482          * pixels, or any other sort of unit.
51483          * @example
51484          * var point = new Point(-77, 38);
51485          */
51486
51487         function Point(x, y) {
51488           this.x = x;
51489           this.y = y;
51490         }
51491
51492         Point.prototype = {
51493           /**
51494            * Clone this point, returning a new point that can be modified
51495            * without affecting the old one.
51496            * @return {Point} the clone
51497            */
51498           clone: function clone() {
51499             return new Point(this.x, this.y);
51500           },
51501
51502           /**
51503            * Add this point's x & y coordinates to another point,
51504            * yielding a new point.
51505            * @param {Point} p the other point
51506            * @return {Point} output point
51507            */
51508           add: function add(p) {
51509             return this.clone()._add(p);
51510           },
51511
51512           /**
51513            * Subtract this point's x & y coordinates to from point,
51514            * yielding a new point.
51515            * @param {Point} p the other point
51516            * @return {Point} output point
51517            */
51518           sub: function sub(p) {
51519             return this.clone()._sub(p);
51520           },
51521
51522           /**
51523            * Multiply this point's x & y coordinates by point,
51524            * yielding a new point.
51525            * @param {Point} p the other point
51526            * @return {Point} output point
51527            */
51528           multByPoint: function multByPoint(p) {
51529             return this.clone()._multByPoint(p);
51530           },
51531
51532           /**
51533            * Divide this point's x & y coordinates by point,
51534            * yielding a new point.
51535            * @param {Point} p the other point
51536            * @return {Point} output point
51537            */
51538           divByPoint: function divByPoint(p) {
51539             return this.clone()._divByPoint(p);
51540           },
51541
51542           /**
51543            * Multiply this point's x & y coordinates by a factor,
51544            * yielding a new point.
51545            * @param {Point} k factor
51546            * @return {Point} output point
51547            */
51548           mult: function mult(k) {
51549             return this.clone()._mult(k);
51550           },
51551
51552           /**
51553            * Divide this point's x & y coordinates by a factor,
51554            * yielding a new point.
51555            * @param {Point} k factor
51556            * @return {Point} output point
51557            */
51558           div: function div(k) {
51559             return this.clone()._div(k);
51560           },
51561
51562           /**
51563            * Rotate this point around the 0, 0 origin by an angle a,
51564            * given in radians
51565            * @param {Number} a angle to rotate around, in radians
51566            * @return {Point} output point
51567            */
51568           rotate: function rotate(a) {
51569             return this.clone()._rotate(a);
51570           },
51571
51572           /**
51573            * Rotate this point around p point by an angle a,
51574            * given in radians
51575            * @param {Number} a angle to rotate around, in radians
51576            * @param {Point} p Point to rotate around
51577            * @return {Point} output point
51578            */
51579           rotateAround: function rotateAround(a, p) {
51580             return this.clone()._rotateAround(a, p);
51581           },
51582
51583           /**
51584            * Multiply this point by a 4x1 transformation matrix
51585            * @param {Array<Number>} m transformation matrix
51586            * @return {Point} output point
51587            */
51588           matMult: function matMult(m) {
51589             return this.clone()._matMult(m);
51590           },
51591
51592           /**
51593            * Calculate this point but as a unit vector from 0, 0, meaning
51594            * that the distance from the resulting point to the 0, 0
51595            * coordinate will be equal to 1 and the angle from the resulting
51596            * point to the 0, 0 coordinate will be the same as before.
51597            * @return {Point} unit vector point
51598            */
51599           unit: function unit() {
51600             return this.clone()._unit();
51601           },
51602
51603           /**
51604            * Compute a perpendicular point, where the new y coordinate
51605            * is the old x coordinate and the new x coordinate is the old y
51606            * coordinate multiplied by -1
51607            * @return {Point} perpendicular point
51608            */
51609           perp: function perp() {
51610             return this.clone()._perp();
51611           },
51612
51613           /**
51614            * Return a version of this point with the x & y coordinates
51615            * rounded to integers.
51616            * @return {Point} rounded point
51617            */
51618           round: function round() {
51619             return this.clone()._round();
51620           },
51621
51622           /**
51623            * Return the magitude of this point: this is the Euclidean
51624            * distance from the 0, 0 coordinate to this point's x and y
51625            * coordinates.
51626            * @return {Number} magnitude
51627            */
51628           mag: function mag() {
51629             return Math.sqrt(this.x * this.x + this.y * this.y);
51630           },
51631
51632           /**
51633            * Judge whether this point is equal to another point, returning
51634            * true or false.
51635            * @param {Point} other the other point
51636            * @return {boolean} whether the points are equal
51637            */
51638           equals: function equals(other) {
51639             return this.x === other.x && this.y === other.y;
51640           },
51641
51642           /**
51643            * Calculate the distance from this point to another point
51644            * @param {Point} p the other point
51645            * @return {Number} distance
51646            */
51647           dist: function dist(p) {
51648             return Math.sqrt(this.distSqr(p));
51649           },
51650
51651           /**
51652            * Calculate the distance from this point to another point,
51653            * without the square root step. Useful if you're comparing
51654            * relative distances.
51655            * @param {Point} p the other point
51656            * @return {Number} distance
51657            */
51658           distSqr: function distSqr(p) {
51659             var dx = p.x - this.x,
51660                 dy = p.y - this.y;
51661             return dx * dx + dy * dy;
51662           },
51663
51664           /**
51665            * Get the angle from the 0, 0 coordinate to this point, in radians
51666            * coordinates.
51667            * @return {Number} angle
51668            */
51669           angle: function angle() {
51670             return Math.atan2(this.y, this.x);
51671           },
51672
51673           /**
51674            * Get the angle from this point to another point, in radians
51675            * @param {Point} b the other point
51676            * @return {Number} angle
51677            */
51678           angleTo: function angleTo(b) {
51679             return Math.atan2(this.y - b.y, this.x - b.x);
51680           },
51681
51682           /**
51683            * Get the angle between this point and another point, in radians
51684            * @param {Point} b the other point
51685            * @return {Number} angle
51686            */
51687           angleWith: function angleWith(b) {
51688             return this.angleWithSep(b.x, b.y);
51689           },
51690
51691           /*
51692            * Find the angle of the two vectors, solving the formula for
51693            * the cross product a x b = |a||b|sin(θ) for θ.
51694            * @param {Number} x the x-coordinate
51695            * @param {Number} y the y-coordinate
51696            * @return {Number} the angle in radians
51697            */
51698           angleWithSep: function angleWithSep(x, y) {
51699             return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
51700           },
51701           _matMult: function _matMult(m) {
51702             var x = m[0] * this.x + m[1] * this.y,
51703                 y = m[2] * this.x + m[3] * this.y;
51704             this.x = x;
51705             this.y = y;
51706             return this;
51707           },
51708           _add: function _add(p) {
51709             this.x += p.x;
51710             this.y += p.y;
51711             return this;
51712           },
51713           _sub: function _sub(p) {
51714             this.x -= p.x;
51715             this.y -= p.y;
51716             return this;
51717           },
51718           _mult: function _mult(k) {
51719             this.x *= k;
51720             this.y *= k;
51721             return this;
51722           },
51723           _div: function _div(k) {
51724             this.x /= k;
51725             this.y /= k;
51726             return this;
51727           },
51728           _multByPoint: function _multByPoint(p) {
51729             this.x *= p.x;
51730             this.y *= p.y;
51731             return this;
51732           },
51733           _divByPoint: function _divByPoint(p) {
51734             this.x /= p.x;
51735             this.y /= p.y;
51736             return this;
51737           },
51738           _unit: function _unit() {
51739             this._div(this.mag());
51740
51741             return this;
51742           },
51743           _perp: function _perp() {
51744             var y = this.y;
51745             this.y = this.x;
51746             this.x = -y;
51747             return this;
51748           },
51749           _rotate: function _rotate(angle) {
51750             var cos = Math.cos(angle),
51751                 sin = Math.sin(angle),
51752                 x = cos * this.x - sin * this.y,
51753                 y = sin * this.x + cos * this.y;
51754             this.x = x;
51755             this.y = y;
51756             return this;
51757           },
51758           _rotateAround: function _rotateAround(angle, p) {
51759             var cos = Math.cos(angle),
51760                 sin = Math.sin(angle),
51761                 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
51762                 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
51763             this.x = x;
51764             this.y = y;
51765             return this;
51766           },
51767           _round: function _round() {
51768             this.x = Math.round(this.x);
51769             this.y = Math.round(this.y);
51770             return this;
51771           }
51772         };
51773         /**
51774          * Construct a point from an array if necessary, otherwise if the input
51775          * is already a Point, or an unknown type, return it unchanged
51776          * @param {Array<Number>|Point|*} a any kind of input value
51777          * @return {Point} constructed point, or passed-through value.
51778          * @example
51779          * // this
51780          * var point = Point.convert([0, 1]);
51781          * // is equivalent to
51782          * var point = new Point(0, 1);
51783          */
51784
51785         Point.convert = function (a) {
51786           if (a instanceof Point) {
51787             return a;
51788           }
51789
51790           if (Array.isArray(a)) {
51791             return new Point(a[0], a[1]);
51792           }
51793
51794           return a;
51795         };
51796
51797         var vectortilefeature = VectorTileFeature;
51798
51799         function VectorTileFeature(pbf, end, extent, keys, values) {
51800           // Public
51801           this.properties = {};
51802           this.extent = extent;
51803           this.type = 0; // Private
51804
51805           this._pbf = pbf;
51806           this._geometry = -1;
51807           this._keys = keys;
51808           this._values = values;
51809           pbf.readFields(readFeature, this, end);
51810         }
51811
51812         function readFeature(tag, feature, pbf) {
51813           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;
51814         }
51815
51816         function readTag(pbf, feature) {
51817           var end = pbf.readVarint() + pbf.pos;
51818
51819           while (pbf.pos < end) {
51820             var key = feature._keys[pbf.readVarint()],
51821                 value = feature._values[pbf.readVarint()];
51822
51823             feature.properties[key] = value;
51824           }
51825         }
51826
51827         VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
51828
51829         VectorTileFeature.prototype.loadGeometry = function () {
51830           var pbf = this._pbf;
51831           pbf.pos = this._geometry;
51832           var end = pbf.readVarint() + pbf.pos,
51833               cmd = 1,
51834               length = 0,
51835               x = 0,
51836               y = 0,
51837               lines = [],
51838               line;
51839
51840           while (pbf.pos < end) {
51841             if (length <= 0) {
51842               var cmdLen = pbf.readVarint();
51843               cmd = cmdLen & 0x7;
51844               length = cmdLen >> 3;
51845             }
51846
51847             length--;
51848
51849             if (cmd === 1 || cmd === 2) {
51850               x += pbf.readSVarint();
51851               y += pbf.readSVarint();
51852
51853               if (cmd === 1) {
51854                 // moveTo
51855                 if (line) lines.push(line);
51856                 line = [];
51857               }
51858
51859               line.push(new pointGeometry(x, y));
51860             } else if (cmd === 7) {
51861               // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
51862               if (line) {
51863                 line.push(line[0].clone()); // closePolygon
51864               }
51865             } else {
51866               throw new Error('unknown command ' + cmd);
51867             }
51868           }
51869
51870           if (line) lines.push(line);
51871           return lines;
51872         };
51873
51874         VectorTileFeature.prototype.bbox = function () {
51875           var pbf = this._pbf;
51876           pbf.pos = this._geometry;
51877           var end = pbf.readVarint() + pbf.pos,
51878               cmd = 1,
51879               length = 0,
51880               x = 0,
51881               y = 0,
51882               x1 = Infinity,
51883               x2 = -Infinity,
51884               y1 = Infinity,
51885               y2 = -Infinity;
51886
51887           while (pbf.pos < end) {
51888             if (length <= 0) {
51889               var cmdLen = pbf.readVarint();
51890               cmd = cmdLen & 0x7;
51891               length = cmdLen >> 3;
51892             }
51893
51894             length--;
51895
51896             if (cmd === 1 || cmd === 2) {
51897               x += pbf.readSVarint();
51898               y += pbf.readSVarint();
51899               if (x < x1) x1 = x;
51900               if (x > x2) x2 = x;
51901               if (y < y1) y1 = y;
51902               if (y > y2) y2 = y;
51903             } else if (cmd !== 7) {
51904               throw new Error('unknown command ' + cmd);
51905             }
51906           }
51907
51908           return [x1, y1, x2, y2];
51909         };
51910
51911         VectorTileFeature.prototype.toGeoJSON = function (x, y, z) {
51912           var size = this.extent * Math.pow(2, z),
51913               x0 = this.extent * x,
51914               y0 = this.extent * y,
51915               coords = this.loadGeometry(),
51916               type = VectorTileFeature.types[this.type],
51917               i,
51918               j;
51919
51920           function project(line) {
51921             for (var j = 0; j < line.length; j++) {
51922               var p = line[j],
51923                   y2 = 180 - (p.y + y0) * 360 / size;
51924               line[j] = [(p.x + x0) * 360 / size - 180, 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90];
51925             }
51926           }
51927
51928           switch (this.type) {
51929             case 1:
51930               var points = [];
51931
51932               for (i = 0; i < coords.length; i++) {
51933                 points[i] = coords[i][0];
51934               }
51935
51936               coords = points;
51937               project(coords);
51938               break;
51939
51940             case 2:
51941               for (i = 0; i < coords.length; i++) {
51942                 project(coords[i]);
51943               }
51944
51945               break;
51946
51947             case 3:
51948               coords = classifyRings(coords);
51949
51950               for (i = 0; i < coords.length; i++) {
51951                 for (j = 0; j < coords[i].length; j++) {
51952                   project(coords[i][j]);
51953                 }
51954               }
51955
51956               break;
51957           }
51958
51959           if (coords.length === 1) {
51960             coords = coords[0];
51961           } else {
51962             type = 'Multi' + type;
51963           }
51964
51965           var result = {
51966             type: "Feature",
51967             geometry: {
51968               type: type,
51969               coordinates: coords
51970             },
51971             properties: this.properties
51972           };
51973
51974           if ('id' in this) {
51975             result.id = this.id;
51976           }
51977
51978           return result;
51979         }; // classifies an array of rings into polygons with outer rings and holes
51980
51981
51982         function classifyRings(rings) {
51983           var len = rings.length;
51984           if (len <= 1) return [rings];
51985           var polygons = [],
51986               polygon,
51987               ccw;
51988
51989           for (var i = 0; i < len; i++) {
51990             var area = signedArea$1(rings[i]);
51991             if (area === 0) continue;
51992             if (ccw === undefined) ccw = area < 0;
51993
51994             if (ccw === area < 0) {
51995               if (polygon) polygons.push(polygon);
51996               polygon = [rings[i]];
51997             } else {
51998               polygon.push(rings[i]);
51999             }
52000           }
52001
52002           if (polygon) polygons.push(polygon);
52003           return polygons;
52004         }
52005
52006         function signedArea$1(ring) {
52007           var sum = 0;
52008
52009           for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
52010             p1 = ring[i];
52011             p2 = ring[j];
52012             sum += (p2.x - p1.x) * (p1.y + p2.y);
52013           }
52014
52015           return sum;
52016         }
52017
52018         var vectortilelayer = VectorTileLayer;
52019
52020         function VectorTileLayer(pbf, end) {
52021           // Public
52022           this.version = 1;
52023           this.name = null;
52024           this.extent = 4096;
52025           this.length = 0; // Private
52026
52027           this._pbf = pbf;
52028           this._keys = [];
52029           this._values = [];
52030           this._features = [];
52031           pbf.readFields(readLayer, this, end);
52032           this.length = this._features.length;
52033         }
52034
52035         function readLayer(tag, layer, pbf) {
52036           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));
52037         }
52038
52039         function readValueMessage(pbf) {
52040           var value = null,
52041               end = pbf.readVarint() + pbf.pos;
52042
52043           while (pbf.pos < end) {
52044             var tag = pbf.readVarint() >> 3;
52045             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;
52046           }
52047
52048           return value;
52049         } // return feature `i` from this layer as a `VectorTileFeature`
52050
52051
52052         VectorTileLayer.prototype.feature = function (i) {
52053           if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
52054           this._pbf.pos = this._features[i];
52055
52056           var end = this._pbf.readVarint() + this._pbf.pos;
52057
52058           return new vectortilefeature(this._pbf, end, this.extent, this._keys, this._values);
52059         };
52060
52061         var vectortile = VectorTile;
52062
52063         function VectorTile(pbf, end) {
52064           this.layers = pbf.readFields(readTile, {}, end);
52065         }
52066
52067         function readTile(tag, layers, pbf) {
52068           if (tag === 3) {
52069             var layer = new vectortilelayer(pbf, pbf.readVarint() + pbf.pos);
52070             if (layer.length) layers[layer.name] = layer;
52071           }
52072         }
52073
52074         var VectorTile$1 = vectortile;
52075         var VectorTileFeature$1 = vectortilefeature;
52076         var VectorTileLayer$1 = vectortilelayer;
52077         var vectorTile = {
52078           VectorTile: VectorTile$1,
52079           VectorTileFeature: VectorTileFeature$1,
52080           VectorTileLayer: VectorTileLayer$1
52081         };
52082
52083         var tiler$7 = utilTiler().tileSize(512).margin(1);
52084         var dispatch$8 = dispatch('loadedData');
52085
52086         var _vtCache;
52087
52088         function abortRequest$7(controller) {
52089           controller.abort();
52090         }
52091
52092         function vtToGeoJSON(data, tile, mergeCache) {
52093           var vectorTile$1 = new vectorTile.VectorTile(new pbf(data));
52094           var layers = Object.keys(vectorTile$1.layers);
52095
52096           if (!Array.isArray(layers)) {
52097             layers = [layers];
52098           }
52099
52100           var features = [];
52101           layers.forEach(function (layerID) {
52102             var layer = vectorTile$1.layers[layerID];
52103
52104             if (layer) {
52105               for (var i = 0; i < layer.length; i++) {
52106                 var feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52107                 var geometry = feature.geometry; // Treat all Polygons as MultiPolygons
52108
52109                 if (geometry.type === 'Polygon') {
52110                   geometry.type = 'MultiPolygon';
52111                   geometry.coordinates = [geometry.coordinates];
52112                 }
52113
52114                 var isClipped = false; // Clip to tile bounds
52115
52116                 if (geometry.type === 'MultiPolygon') {
52117                   var featureClip = turf_bboxClip(feature, tile.extent.rectangle());
52118
52119                   if (!fastDeepEqual(feature.geometry, featureClip.geometry)) {
52120                     // feature = featureClip;
52121                     isClipped = true;
52122                   }
52123
52124                   if (!feature.geometry.coordinates.length) continue; // not actually on this tile
52125
52126                   if (!feature.geometry.coordinates[0].length) continue; // not actually on this tile
52127                 } // Generate some unique IDs and add some metadata
52128
52129
52130                 var featurehash = utilHashcode(fastJsonStableStringify(feature));
52131                 var propertyhash = utilHashcode(fastJsonStableStringify(feature.properties || {}));
52132                 feature.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, '_');
52133                 feature.__featurehash__ = featurehash;
52134                 feature.__propertyhash__ = propertyhash;
52135                 features.push(feature); // Clipped Polygons at same zoom with identical properties can get merged
52136
52137                 if (isClipped && geometry.type === 'MultiPolygon') {
52138                   var merged = mergeCache[propertyhash];
52139
52140                   if (merged && merged.length) {
52141                     var other = merged[0];
52142                     var coords = union(feature.geometry.coordinates, other.geometry.coordinates);
52143
52144                     if (!coords || !coords.length) {
52145                       continue; // something failed in martinez union
52146                     }
52147
52148                     merged.push(feature);
52149
52150                     for (var j = 0; j < merged.length; j++) {
52151                       // all these features get...
52152                       merged[j].geometry.coordinates = coords; // same coords
52153
52154                       merged[j].__featurehash__ = featurehash; // same hash, so deduplication works
52155                     }
52156                   } else {
52157                     mergeCache[propertyhash] = [feature];
52158                   }
52159                 }
52160               }
52161             }
52162           });
52163           return features;
52164         }
52165
52166         function loadTile(source, tile) {
52167           if (source.loaded[tile.id] || source.inflight[tile.id]) return;
52168           var url = source.template.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]) // TMS-flipped y coordinate
52169           .replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function (s, r) {
52170             var subdomains = r.split(',');
52171             return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
52172           });
52173           var controller = new AbortController();
52174           source.inflight[tile.id] = controller;
52175           fetch(url, {
52176             signal: controller.signal
52177           }).then(function (response) {
52178             if (!response.ok) {
52179               throw new Error(response.status + ' ' + response.statusText);
52180             }
52181
52182             source.loaded[tile.id] = [];
52183             delete source.inflight[tile.id];
52184             return response.arrayBuffer();
52185           }).then(function (data) {
52186             if (!data) {
52187               throw new Error('No Data');
52188             }
52189
52190             var z = tile.xyz[2];
52191
52192             if (!source.canMerge[z]) {
52193               source.canMerge[z] = {}; // initialize mergeCache
52194             }
52195
52196             source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
52197             dispatch$8.call('loadedData');
52198           })["catch"](function () {
52199             source.loaded[tile.id] = [];
52200             delete source.inflight[tile.id];
52201           });
52202         }
52203
52204         var serviceVectorTile = {
52205           init: function init() {
52206             if (!_vtCache) {
52207               this.reset();
52208             }
52209
52210             this.event = utilRebind(this, dispatch$8, 'on');
52211           },
52212           reset: function reset() {
52213             for (var sourceID in _vtCache) {
52214               var source = _vtCache[sourceID];
52215
52216               if (source && source.inflight) {
52217                 Object.values(source.inflight).forEach(abortRequest$7);
52218               }
52219             }
52220
52221             _vtCache = {};
52222           },
52223           addSource: function addSource(sourceID, template) {
52224             _vtCache[sourceID] = {
52225               template: template,
52226               inflight: {},
52227               loaded: {},
52228               canMerge: {}
52229             };
52230             return _vtCache[sourceID];
52231           },
52232           data: function data(sourceID, projection) {
52233             var source = _vtCache[sourceID];
52234             if (!source) return [];
52235             var tiles = tiler$7.getTiles(projection);
52236             var seen = {};
52237             var results = [];
52238
52239             for (var i = 0; i < tiles.length; i++) {
52240               var features = source.loaded[tiles[i].id];
52241               if (!features || !features.length) continue;
52242
52243               for (var j = 0; j < features.length; j++) {
52244                 var feature = features[j];
52245                 var hash = feature.__featurehash__;
52246                 if (seen[hash]) continue;
52247                 seen[hash] = true; // return a shallow copy, because the hash may change
52248                 // later if this feature gets merged with another
52249
52250                 results.push(Object.assign({}, feature)); // shallow copy
52251               }
52252             }
52253
52254             return results;
52255           },
52256           loadTiles: function loadTiles(sourceID, template, projection) {
52257             var source = _vtCache[sourceID];
52258
52259             if (!source) {
52260               source = this.addSource(sourceID, template);
52261             }
52262
52263             var tiles = tiler$7.getTiles(projection); // abort inflight requests that are no longer needed
52264
52265             Object.keys(source.inflight).forEach(function (k) {
52266               var wanted = tiles.find(function (tile) {
52267                 return k === tile.id;
52268               });
52269
52270               if (!wanted) {
52271                 abortRequest$7(source.inflight[k]);
52272                 delete source.inflight[k];
52273               }
52274             });
52275             tiles.forEach(function (tile) {
52276               loadTile(source, tile);
52277             });
52278           },
52279           cache: function cache() {
52280             return _vtCache;
52281           }
52282         };
52283
52284         var apibase$3 = 'https://www.wikidata.org/w/api.php?';
52285         var _wikidataCache = {};
52286         var serviceWikidata = {
52287           init: function init() {},
52288           reset: function reset() {
52289             _wikidataCache = {};
52290           },
52291           // Search for Wikidata items matching the query
52292           itemsForSearchQuery: function itemsForSearchQuery(query, callback) {
52293             if (!query) {
52294               if (callback) callback('No query', {});
52295               return;
52296             }
52297
52298             var lang = this.languagesToQuery()[0];
52299             var url = apibase$3 + utilQsString({
52300               action: 'wbsearchentities',
52301               format: 'json',
52302               formatversion: 2,
52303               search: query,
52304               type: 'item',
52305               // the language to search
52306               language: lang,
52307               // the language for the label and description in the result
52308               uselang: lang,
52309               limit: 10,
52310               origin: '*'
52311             });
52312             d3_json(url).then(function (result) {
52313               if (result && result.error) {
52314                 throw new Error(result.error);
52315               }
52316
52317               if (callback) callback(null, result.search || {});
52318             })["catch"](function (err) {
52319               if (callback) callback(err.message, {});
52320             });
52321           },
52322           // Given a Wikipedia language and article title,
52323           // return an array of corresponding Wikidata entities.
52324           itemsByTitle: function itemsByTitle(lang, title, callback) {
52325             if (!title) {
52326               if (callback) callback('No title', {});
52327               return;
52328             }
52329
52330             lang = lang || 'en';
52331             var url = apibase$3 + utilQsString({
52332               action: 'wbgetentities',
52333               format: 'json',
52334               formatversion: 2,
52335               sites: lang.replace(/-/g, '_') + 'wiki',
52336               titles: title,
52337               languages: 'en',
52338               // shrink response by filtering to one language
52339               origin: '*'
52340             });
52341             d3_json(url).then(function (result) {
52342               if (result && result.error) {
52343                 throw new Error(result.error);
52344               }
52345
52346               if (callback) callback(null, result.entities || {});
52347             })["catch"](function (err) {
52348               if (callback) callback(err.message, {});
52349             });
52350           },
52351           languagesToQuery: function languagesToQuery() {
52352             return _mainLocalizer.localeCodes().map(function (code) {
52353               return code.toLowerCase();
52354             }).filter(function (code) {
52355               // HACK: en-us isn't a wikidata language. We should really be filtering by
52356               // the languages known to be supported by wikidata.
52357               return code !== 'en-us';
52358             });
52359           },
52360           entityByQID: function entityByQID(qid, callback) {
52361             if (!qid) {
52362               callback('No qid', {});
52363               return;
52364             }
52365
52366             if (_wikidataCache[qid]) {
52367               if (callback) callback(null, _wikidataCache[qid]);
52368               return;
52369             }
52370
52371             var langs = this.languagesToQuery();
52372             var url = apibase$3 + utilQsString({
52373               action: 'wbgetentities',
52374               format: 'json',
52375               formatversion: 2,
52376               ids: qid,
52377               props: 'labels|descriptions|claims|sitelinks',
52378               sitefilter: langs.map(function (d) {
52379                 return d + 'wiki';
52380               }).join('|'),
52381               languages: langs.join('|'),
52382               languagefallback: 1,
52383               origin: '*'
52384             });
52385             d3_json(url).then(function (result) {
52386               if (result && result.error) {
52387                 throw new Error(result.error);
52388               }
52389
52390               if (callback) callback(null, result.entities[qid] || {});
52391             })["catch"](function (err) {
52392               if (callback) callback(err.message, {});
52393             });
52394           },
52395           // Pass `params` object of the form:
52396           // {
52397           //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
52398           // }
52399           //
52400           // Get an result object used to display tag documentation
52401           // {
52402           //   title:        'string',
52403           //   description:  'string',
52404           //   editURL:      'string',
52405           //   imageURL:     'string',
52406           //   wiki:         { title: 'string', text: 'string', url: 'string' }
52407           // }
52408           //
52409           getDocs: function getDocs(params, callback) {
52410             var langs = this.languagesToQuery();
52411             this.entityByQID(params.qid, function (err, entity) {
52412               if (err || !entity) {
52413                 callback(err || 'No entity');
52414                 return;
52415               }
52416
52417               var i;
52418               var description;
52419
52420               for (i in langs) {
52421                 var code = langs[i];
52422
52423                 if (entity.descriptions[code] && entity.descriptions[code].language === code) {
52424                   description = entity.descriptions[code];
52425                   break;
52426                 }
52427               }
52428
52429               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
52430
52431               var result = {
52432                 title: entity.id,
52433                 description: description ? description.value : '',
52434                 descriptionLocaleCode: description ? description.language : '',
52435                 editURL: 'https://www.wikidata.org/wiki/' + entity.id
52436               }; // add image
52437
52438               if (entity.claims) {
52439                 var imageroot = 'https://commons.wikimedia.org/w/index.php';
52440                 var props = ['P154', 'P18']; // logo image, image
52441
52442                 var prop, image;
52443
52444                 for (i = 0; i < props.length; i++) {
52445                   prop = entity.claims[props[i]];
52446
52447                   if (prop && Object.keys(prop).length > 0) {
52448                     image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
52449
52450                     if (image) {
52451                       result.imageURL = imageroot + '?' + utilQsString({
52452                         title: 'Special:Redirect/file/' + image,
52453                         width: 400
52454                       });
52455                       break;
52456                     }
52457                   }
52458                 }
52459               }
52460
52461               if (entity.sitelinks) {
52462                 var englishLocale = _mainLocalizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested..
52463
52464                 for (i = 0; i < langs.length; i++) {
52465                   // check each, in order of preference
52466                   var w = langs[i] + 'wiki';
52467
52468                   if (entity.sitelinks[w]) {
52469                     var title = entity.sitelinks[w].title;
52470                     var tKey = 'inspector.wiki_reference';
52471
52472                     if (!englishLocale && langs[i] === 'en') {
52473                       // user's locale isn't English but
52474                       tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
52475                     }
52476
52477                     result.wiki = {
52478                       title: title,
52479                       text: tKey,
52480                       url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
52481                     };
52482                     break;
52483                   }
52484                 }
52485               }
52486
52487               callback(null, result);
52488             });
52489           }
52490         };
52491
52492         var endpoint = 'https://en.wikipedia.org/w/api.php?';
52493         var serviceWikipedia = {
52494           init: function init() {},
52495           reset: function reset() {},
52496           search: function search(lang, query, callback) {
52497             if (!query) {
52498               if (callback) callback('No Query', []);
52499               return;
52500             }
52501
52502             lang = lang || 'en';
52503             var url = endpoint.replace('en', lang) + utilQsString({
52504               action: 'query',
52505               list: 'search',
52506               srlimit: '10',
52507               srinfo: 'suggestion',
52508               format: 'json',
52509               origin: '*',
52510               srsearch: query
52511             });
52512             d3_json(url).then(function (result) {
52513               if (result && result.error) {
52514                 throw new Error(result.error);
52515               } else if (!result || !result.query || !result.query.search) {
52516                 throw new Error('No Results');
52517               }
52518
52519               if (callback) {
52520                 var titles = result.query.search.map(function (d) {
52521                   return d.title;
52522                 });
52523                 callback(null, titles);
52524               }
52525             })["catch"](function (err) {
52526               if (callback) callback(err, []);
52527             });
52528           },
52529           suggestions: function suggestions(lang, query, callback) {
52530             if (!query) {
52531               if (callback) callback('', []);
52532               return;
52533             }
52534
52535             lang = lang || 'en';
52536             var url = endpoint.replace('en', lang) + utilQsString({
52537               action: 'opensearch',
52538               namespace: 0,
52539               suggest: '',
52540               format: 'json',
52541               origin: '*',
52542               search: query
52543             });
52544             d3_json(url).then(function (result) {
52545               if (result && result.error) {
52546                 throw new Error(result.error);
52547               } else if (!result || result.length < 2) {
52548                 throw new Error('No Results');
52549               }
52550
52551               if (callback) callback(null, result[1] || []);
52552             })["catch"](function (err) {
52553               if (callback) callback(err.message, []);
52554             });
52555           },
52556           translations: function translations(lang, title, callback) {
52557             if (!title) {
52558               if (callback) callback('No Title');
52559               return;
52560             }
52561
52562             var url = endpoint.replace('en', lang) + utilQsString({
52563               action: 'query',
52564               prop: 'langlinks',
52565               format: 'json',
52566               origin: '*',
52567               lllimit: 500,
52568               titles: title
52569             });
52570             d3_json(url).then(function (result) {
52571               if (result && result.error) {
52572                 throw new Error(result.error);
52573               } else if (!result || !result.query || !result.query.pages) {
52574                 throw new Error('No Results');
52575               }
52576
52577               if (callback) {
52578                 var list = result.query.pages[Object.keys(result.query.pages)[0]];
52579                 var translations = {};
52580
52581                 if (list && list.langlinks) {
52582                   list.langlinks.forEach(function (d) {
52583                     translations[d.lang] = d['*'];
52584                   });
52585                 }
52586
52587                 callback(null, translations);
52588               }
52589             })["catch"](function (err) {
52590               if (callback) callback(err.message);
52591             });
52592           }
52593         };
52594
52595         var services = {
52596           geocoder: serviceNominatim,
52597           keepRight: serviceKeepRight,
52598           improveOSM: serviceImproveOSM,
52599           osmose: serviceOsmose,
52600           mapillary: serviceMapillary,
52601           openstreetcam: serviceOpenstreetcam,
52602           osm: serviceOsm,
52603           osmWikibase: serviceOsmWikibase,
52604           maprules: serviceMapRules,
52605           streetside: serviceStreetside,
52606           taginfo: serviceTaginfo,
52607           vectorTile: serviceVectorTile,
52608           wikidata: serviceWikidata,
52609           wikipedia: serviceWikipedia
52610         };
52611
52612         function svgIcon(name, svgklass, useklass) {
52613           return function drawIcon(selection) {
52614             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);
52615           };
52616         }
52617
52618         function uiNoteComments() {
52619           var _note;
52620
52621           function noteComments(selection) {
52622             if (_note.isNew()) return; // don't draw .comments-container
52623
52624             var comments = selection.selectAll('.comments-container').data([0]);
52625             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments);
52626             var commentEnter = comments.selectAll('.comment').data(_note.comments).enter().append('div').attr('class', 'comment');
52627             commentEnter.append('div').attr('class', function (d) {
52628               return 'comment-avatar user-' + d.uid;
52629             }).call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
52630             var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
52631             var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
52632             metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
52633               var selection = select(this);
52634               var osm = services.osm;
52635
52636               if (osm && d.user) {
52637                 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.user)).attr('target', '_blank');
52638               }
52639
52640               selection.html(function (d) {
52641                 return d.user || _t.html('note.anonymous');
52642               });
52643             });
52644             metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
52645               return _t('note.status.' + d.action, {
52646                 when: localeDateString(d.date)
52647               });
52648             });
52649             mainEnter.append('div').attr('class', 'comment-text').html(function (d) {
52650               return d.html;
52651             }).selectAll('a').attr('rel', 'noopener nofollow').attr('target', '_blank');
52652             comments.call(replaceAvatars);
52653           }
52654
52655           function replaceAvatars(selection) {
52656             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
52657             var osm = services.osm;
52658             if (showThirdPartyIcons !== 'true' || !osm) return;
52659             var uids = {}; // gather uids in the comment thread
52660
52661             _note.comments.forEach(function (d) {
52662               if (d.uid) uids[d.uid] = true;
52663             });
52664
52665             Object.keys(uids).forEach(function (uid) {
52666               osm.loadUser(uid, function (err, user) {
52667                 if (!user || !user.image_url) return;
52668                 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);
52669               });
52670             });
52671           }
52672
52673           function localeDateString(s) {
52674             if (!s) return null;
52675             var options = {
52676               day: 'numeric',
52677               month: 'short',
52678               year: 'numeric'
52679             };
52680             s = s.replace(/-/g, '/'); // fix browser-specific Date() issues
52681
52682             var d = new Date(s);
52683             if (isNaN(d.getTime())) return null;
52684             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
52685           }
52686
52687           noteComments.note = function (val) {
52688             if (!arguments.length) return _note;
52689             _note = val;
52690             return noteComments;
52691           };
52692
52693           return noteComments;
52694         }
52695
52696         function uiNoteHeader() {
52697           var _note;
52698
52699           function noteHeader(selection) {
52700             var header = selection.selectAll('.note-header').data(_note ? [_note] : [], function (d) {
52701               return d.status + d.id;
52702             });
52703             header.exit().remove();
52704             var headerEnter = header.enter().append('div').attr('class', 'note-header');
52705             var iconEnter = headerEnter.append('div').attr('class', function (d) {
52706               return 'note-header-icon ' + d.status;
52707             }).classed('new', function (d) {
52708               return d.id < 0;
52709             });
52710             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-note', 'note-fill'));
52711             iconEnter.each(function (d) {
52712               var statusIcon = '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
52713               iconEnter.append('div').attr('class', 'note-icon-annotation').call(svgIcon(statusIcon, 'icon-annotation'));
52714             });
52715             headerEnter.append('div').attr('class', 'note-header-label').html(function (d) {
52716               if (_note.isNew()) {
52717                 return _t('note.new');
52718               }
52719
52720               return _t('note.note') + ' ' + d.id + ' ' + (d.status === 'closed' ? _t('note.closed') : '');
52721             });
52722           }
52723
52724           noteHeader.note = function (val) {
52725             if (!arguments.length) return _note;
52726             _note = val;
52727             return noteHeader;
52728           };
52729
52730           return noteHeader;
52731         }
52732
52733         function uiNoteReport() {
52734           var _note;
52735
52736           function noteReport(selection) {
52737             var url;
52738
52739             if (services.osm && _note instanceof osmNote && !_note.isNew()) {
52740               url = services.osm.noteReportURL(_note);
52741             }
52742
52743             var link = selection.selectAll('.note-report').data(url ? [url] : []); // exit
52744
52745             link.exit().remove(); // enter
52746
52747             var linkEnter = link.enter().append('a').attr('class', 'note-report').attr('target', '_blank').attr('href', function (d) {
52748               return d;
52749             }).call(svgIcon('#iD-icon-out-link', 'inline'));
52750             linkEnter.append('span').html(_t.html('note.report'));
52751           }
52752
52753           noteReport.note = function (val) {
52754             if (!arguments.length) return _note;
52755             _note = val;
52756             return noteReport;
52757           };
52758
52759           return noteReport;
52760         }
52761
52762         function uiViewOnOSM(context) {
52763           var _what; // an osmEntity or osmNote
52764
52765
52766           function viewOnOSM(selection) {
52767             var url;
52768
52769             if (_what instanceof osmEntity) {
52770               url = context.connection().entityURL(_what);
52771             } else if (_what instanceof osmNote) {
52772               url = context.connection().noteURL(_what);
52773             }
52774
52775             var data = !_what || _what.isNew() ? [] : [_what];
52776             var link = selection.selectAll('.view-on-osm').data(data, function (d) {
52777               return d.id;
52778             }); // exit
52779
52780             link.exit().remove(); // enter
52781
52782             var linkEnter = link.enter().append('a').attr('class', 'view-on-osm').attr('target', '_blank').attr('href', url).call(svgIcon('#iD-icon-out-link', 'inline'));
52783             linkEnter.append('span').html(_t.html('inspector.view_on_osm'));
52784           }
52785
52786           viewOnOSM.what = function (_) {
52787             if (!arguments.length) return _what;
52788             _what = _;
52789             return viewOnOSM;
52790           };
52791
52792           return viewOnOSM;
52793         }
52794
52795         function uiNoteEditor(context) {
52796           var dispatch$1 = dispatch('change');
52797           var noteComments = uiNoteComments();
52798           var noteHeader = uiNoteHeader(); // var formFields = uiFormFields(context);
52799
52800           var _note;
52801
52802           var _newNote; // var _fieldsArr;
52803
52804
52805           function noteEditor(selection) {
52806             var header = selection.selectAll('.header').data([0]);
52807             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
52808             headerEnter.append('button').attr('class', 'close').on('click', function () {
52809               context.enter(modeBrowse(context));
52810             }).call(svgIcon('#iD-icon-close'));
52811             headerEnter.append('h3').html(_t.html('note.title'));
52812             var body = selection.selectAll('.body').data([0]);
52813             body = body.enter().append('div').attr('class', 'body').merge(body);
52814             var editor = body.selectAll('.note-editor').data([0]);
52815             editor.enter().append('div').attr('class', 'modal-section note-editor').merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
52816             var footer = selection.selectAll('.footer').data([0]);
52817             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
52818
52819             var osm = services.osm;
52820
52821             if (osm) {
52822               osm.on('change.note-save', function () {
52823                 selection.call(noteEditor);
52824               });
52825             }
52826           }
52827
52828           function noteSaveSection(selection) {
52829             var isSelected = _note && _note.id === context.selectedNoteID();
52830
52831             var noteSave = selection.selectAll('.note-save').data(isSelected ? [_note] : [], function (d) {
52832               return d.status + d.id;
52833             }); // exit
52834
52835             noteSave.exit().remove(); // enter
52836
52837             var noteSaveEnter = noteSave.enter().append('div').attr('class', 'note-save save-section cf'); // // if new note, show categories to pick from
52838             // if (_note.isNew()) {
52839             //     var presets = presetManager;
52840             //     // NOTE: this key isn't a age and therefore there is no documentation (yet)
52841             //     _fieldsArr = [
52842             //         uiField(context, presets.field('category'), null, { show: true, revert: false }),
52843             //     ];
52844             //     _fieldsArr.forEach(function(field) {
52845             //         field
52846             //             .on('change', changeCategory);
52847             //     });
52848             //     noteSaveEnter
52849             //         .append('div')
52850             //         .attr('class', 'note-category')
52851             //         .call(formFields.fieldsArr(_fieldsArr));
52852             // }
52853             // function changeCategory() {
52854             //     // NOTE: perhaps there is a better way to get value
52855             //     var val = context.container().select('input[name=\'category\']:checked').property('__data__') || undefined;
52856             //     // store the unsaved category with the note itself
52857             //     _note = _note.update({ newCategory: val });
52858             //     var osm = services.osm;
52859             //     if (osm) {
52860             //         osm.replaceNote(_note);  // update note cache
52861             //     }
52862             //     noteSave
52863             //         .call(noteSaveButtons);
52864             // }
52865
52866             noteSaveEnter.append('h4').attr('class', '.note-save-header').html(function () {
52867               return _note.isNew() ? _t('note.newDescription') : _t('note.newComment');
52868             });
52869             var commentTextarea = noteSaveEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('note.inputPlaceholder')).attr('maxlength', 1000).property('value', function (d) {
52870               return d.newComment;
52871             }).call(utilNoAuto).on('keydown.note-input', keydown).on('input.note-input', changeInput).on('blur.note-input', changeInput);
52872
52873             if (!commentTextarea.empty() && _newNote) {
52874               // autofocus the comment field for new notes
52875               commentTextarea.node().focus();
52876             } // update
52877
52878
52879             noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons); // fast submit if user presses cmd+enter
52880
52881             function keydown(d3_event) {
52882               if (!(d3_event.keyCode === 13 && // ↩ Return
52883               d3_event.metaKey)) return;
52884               var osm = services.osm;
52885               if (!osm) return;
52886               var hasAuth = osm.authenticated();
52887               if (!hasAuth) return;
52888               if (!_note.newComment) return;
52889               d3_event.preventDefault();
52890               select(this).on('keydown.note-input', null); // focus on button and submit
52891
52892               window.setTimeout(function () {
52893                 if (_note.isNew()) {
52894                   noteSave.selectAll('.save-button').node().focus();
52895                   clickSave();
52896                 } else {
52897                   noteSave.selectAll('.comment-button').node().focus();
52898                   clickComment();
52899                 }
52900               }, 10);
52901             }
52902
52903             function changeInput() {
52904               var input = select(this);
52905               var val = input.property('value').trim() || undefined; // store the unsaved comment with the note itself
52906
52907               _note = _note.update({
52908                 newComment: val
52909               });
52910               var osm = services.osm;
52911
52912               if (osm) {
52913                 osm.replaceNote(_note); // update note cache
52914               }
52915
52916               noteSave.call(noteSaveButtons);
52917             }
52918           }
52919
52920           function userDetails(selection) {
52921             var detailSection = selection.selectAll('.detail-section').data([0]);
52922             detailSection = detailSection.enter().append('div').attr('class', 'detail-section').merge(detailSection);
52923             var osm = services.osm;
52924             if (!osm) return; // Add warning if user is not logged in
52925
52926             var hasAuth = osm.authenticated();
52927             var authWarning = detailSection.selectAll('.auth-warning').data(hasAuth ? [] : [0]);
52928             authWarning.exit().transition().duration(200).style('opacity', 0).remove();
52929             var authEnter = authWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning auth-warning').style('opacity', 0);
52930             authEnter.call(svgIcon('#iD-icon-alert', 'inline'));
52931             authEnter.append('span').html(_t.html('note.login'));
52932             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) {
52933               d3_event.preventDefault();
52934               osm.authenticate();
52935             });
52936             authEnter.transition().duration(200).style('opacity', 1);
52937             var prose = detailSection.selectAll('.note-save-prose').data(hasAuth ? [0] : []);
52938             prose.exit().remove();
52939             prose = prose.enter().append('p').attr('class', 'note-save-prose').html(_t.html('note.upload_explanation')).merge(prose);
52940             osm.userDetails(function (err, user) {
52941               if (err) return;
52942               var userLink = select(document.createElement('div'));
52943
52944               if (user.image_url) {
52945                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
52946               }
52947
52948               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
52949               prose.html(_t.html('note.upload_explanation_with_user', {
52950                 user: userLink.html()
52951               }));
52952             });
52953           }
52954
52955           function noteSaveButtons(selection) {
52956             var osm = services.osm;
52957             var hasAuth = osm && osm.authenticated();
52958
52959             var isSelected = _note && _note.id === context.selectedNoteID();
52960
52961             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_note] : [], function (d) {
52962               return d.status + d.id;
52963             }); // exit
52964
52965             buttonSection.exit().remove(); // enter
52966
52967             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
52968
52969             if (_note.isNew()) {
52970               buttonEnter.append('button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
52971               buttonEnter.append('button').attr('class', 'button save-button action').html(_t.html('note.save'));
52972             } else {
52973               buttonEnter.append('button').attr('class', 'button status-button action');
52974               buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('note.comment'));
52975             } // update
52976
52977
52978             buttonSection = buttonSection.merge(buttonEnter);
52979             buttonSection.select('.cancel-button') // select and propagate data
52980             .on('click.cancel', clickCancel);
52981             buttonSection.select('.save-button') // select and propagate data
52982             .attr('disabled', isSaveDisabled).on('click.save', clickSave);
52983             buttonSection.select('.status-button') // select and propagate data
52984             .attr('disabled', hasAuth ? null : true).html(function (d) {
52985               var action = d.status === 'open' ? 'close' : 'open';
52986               var andComment = d.newComment ? '_comment' : '';
52987               return _t('note.' + action + andComment);
52988             }).on('click.status', clickStatus);
52989             buttonSection.select('.comment-button') // select and propagate data
52990             .attr('disabled', isSaveDisabled).on('click.comment', clickComment);
52991
52992             function isSaveDisabled(d) {
52993               return hasAuth && d.status === 'open' && d.newComment ? null : true;
52994             }
52995           }
52996
52997           function clickCancel(d3_event, d) {
52998             this.blur(); // avoid keeping focus on the button - #4641
52999
53000             var osm = services.osm;
53001
53002             if (osm) {
53003               osm.removeNote(d);
53004             }
53005
53006             context.enter(modeBrowse(context));
53007             dispatch$1.call('change');
53008           }
53009
53010           function clickSave(d3_event, d) {
53011             this.blur(); // avoid keeping focus on the button - #4641
53012
53013             var osm = services.osm;
53014
53015             if (osm) {
53016               osm.postNoteCreate(d, function (err, note) {
53017                 dispatch$1.call('change', note);
53018               });
53019             }
53020           }
53021
53022           function clickStatus(d3_event, d) {
53023             this.blur(); // avoid keeping focus on the button - #4641
53024
53025             var osm = services.osm;
53026
53027             if (osm) {
53028               var setStatus = d.status === 'open' ? 'closed' : 'open';
53029               osm.postNoteUpdate(d, setStatus, function (err, note) {
53030                 dispatch$1.call('change', note);
53031               });
53032             }
53033           }
53034
53035           function clickComment(d3_event, d) {
53036             this.blur(); // avoid keeping focus on the button - #4641
53037
53038             var osm = services.osm;
53039
53040             if (osm) {
53041               osm.postNoteUpdate(d, d.status, function (err, note) {
53042                 dispatch$1.call('change', note);
53043               });
53044             }
53045           }
53046
53047           noteEditor.note = function (val) {
53048             if (!arguments.length) return _note;
53049             _note = val;
53050             return noteEditor;
53051           };
53052
53053           noteEditor.newNote = function (val) {
53054             if (!arguments.length) return _newNote;
53055             _newNote = val;
53056             return noteEditor;
53057           };
53058
53059           return utilRebind(noteEditor, dispatch$1, 'on');
53060         }
53061
53062         function modeSelectNote(context, selectedNoteID) {
53063           var mode = {
53064             id: 'select-note',
53065             button: 'browse'
53066           };
53067
53068           var _keybinding = utilKeybinding('select-note');
53069
53070           var _noteEditor = uiNoteEditor(context).on('change', function () {
53071             context.map().pan([0, 0]); // trigger a redraw
53072
53073             var note = checkSelectedID();
53074             if (!note) return;
53075             context.ui().sidebar.show(_noteEditor.note(note));
53076           });
53077
53078           var _behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
53079           var _newFeature = false;
53080
53081           function checkSelectedID() {
53082             if (!services.osm) return;
53083             var note = services.osm.getNote(selectedNoteID);
53084
53085             if (!note) {
53086               context.enter(modeBrowse(context));
53087             }
53088
53089             return note;
53090           } // class the note as selected, or return to browse mode if the note is gone
53091
53092
53093           function selectNote(d3_event, drawn) {
53094             if (!checkSelectedID()) return;
53095             var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID);
53096
53097             if (selection.empty()) {
53098               // Return to browse mode if selected DOM elements have
53099               // disappeared because the user moved them out of view..
53100               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
53101
53102               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
53103                 context.enter(modeBrowse(context));
53104               }
53105             } else {
53106               selection.classed('selected', true);
53107               context.selectedNoteID(selectedNoteID);
53108             }
53109           }
53110
53111           function esc() {
53112             if (context.container().select('.combobox').size()) return;
53113             context.enter(modeBrowse(context));
53114           }
53115
53116           mode.zoomToSelected = function () {
53117             if (!services.osm) return;
53118             var note = services.osm.getNote(selectedNoteID);
53119
53120             if (note) {
53121               context.map().centerZoomEase(note.loc, 20);
53122             }
53123           };
53124
53125           mode.newFeature = function (val) {
53126             if (!arguments.length) return _newFeature;
53127             _newFeature = val;
53128             return mode;
53129           };
53130
53131           mode.enter = function () {
53132             var note = checkSelectedID();
53133             if (!note) return;
53134
53135             _behaviors.forEach(context.install);
53136
53137             _keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
53138
53139             select(document).call(_keybinding);
53140             selectNote();
53141             var sidebar = context.ui().sidebar;
53142             sidebar.show(_noteEditor.note(note).newNote(_newFeature)); // expand the sidebar, avoid obscuring the note if needed
53143
53144             sidebar.expand(sidebar.intersects(note.extent()));
53145             context.map().on('drawn.select', selectNote);
53146           };
53147
53148           mode.exit = function () {
53149             _behaviors.forEach(context.uninstall);
53150
53151             select(document).call(_keybinding.unbind);
53152             context.surface().selectAll('.layer-notes .selected').classed('selected hover', false);
53153             context.map().on('drawn.select', null);
53154             context.ui().sidebar.hide();
53155             context.selectedNoteID(null);
53156           };
53157
53158           return mode;
53159         }
53160
53161         function modeDragNote(context) {
53162           var mode = {
53163             id: 'drag-note',
53164             button: 'browse'
53165           };
53166           var edit = behaviorEdit(context);
53167
53168           var _nudgeInterval;
53169
53170           var _lastLoc;
53171
53172           var _note; // most current note.. dragged note may have stale datum.
53173
53174
53175           function startNudge(d3_event, nudge) {
53176             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
53177             _nudgeInterval = window.setInterval(function () {
53178               context.map().pan(nudge);
53179               doMove(d3_event, nudge);
53180             }, 50);
53181           }
53182
53183           function stopNudge() {
53184             if (_nudgeInterval) {
53185               window.clearInterval(_nudgeInterval);
53186               _nudgeInterval = null;
53187             }
53188           }
53189
53190           function origin(note) {
53191             return context.projection(note.loc);
53192           }
53193
53194           function start(d3_event, note) {
53195             _note = note;
53196             var osm = services.osm;
53197
53198             if (osm) {
53199               // Get latest note from cache.. The marker may have a stale datum bound to it
53200               // and dragging it around can sometimes delete the users note comment.
53201               _note = osm.getNote(_note.id);
53202             }
53203
53204             context.surface().selectAll('.note-' + _note.id).classed('active', true);
53205             context.perform(actionNoop());
53206             context.enter(mode);
53207             context.selectedNoteID(_note.id);
53208           }
53209
53210           function move(d3_event, entity, point) {
53211             d3_event.stopPropagation();
53212             _lastLoc = context.projection.invert(point);
53213             doMove(d3_event);
53214             var nudge = geoViewportEdge(point, context.map().dimensions());
53215
53216             if (nudge) {
53217               startNudge(d3_event, nudge);
53218             } else {
53219               stopNudge();
53220             }
53221           }
53222
53223           function doMove(d3_event, nudge) {
53224             nudge = nudge || [0, 0];
53225             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
53226             var currMouse = geoVecSubtract(currPoint, nudge);
53227             var loc = context.projection.invert(currMouse);
53228             _note = _note.move(loc);
53229             var osm = services.osm;
53230
53231             if (osm) {
53232               osm.replaceNote(_note); // update note cache
53233             }
53234
53235             context.replace(actionNoop()); // trigger redraw
53236           }
53237
53238           function end() {
53239             context.replace(actionNoop()); // trigger redraw
53240
53241             context.selectedNoteID(_note.id).enter(modeSelectNote(context, _note.id));
53242           }
53243
53244           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);
53245
53246           mode.enter = function () {
53247             context.install(edit);
53248           };
53249
53250           mode.exit = function () {
53251             context.ui().sidebar.hover.cancel();
53252             context.uninstall(edit);
53253             context.surface().selectAll('.active').classed('active', false);
53254             stopNudge();
53255           };
53256
53257           mode.behavior = drag;
53258           return mode;
53259         }
53260
53261         function uiDataHeader() {
53262           var _datum;
53263
53264           function dataHeader(selection) {
53265             var header = selection.selectAll('.data-header').data(_datum ? [_datum] : [], function (d) {
53266               return d.__featurehash__;
53267             });
53268             header.exit().remove();
53269             var headerEnter = header.enter().append('div').attr('class', 'data-header');
53270             var iconEnter = headerEnter.append('div').attr('class', 'data-header-icon');
53271             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-data', 'note-fill'));
53272             headerEnter.append('div').attr('class', 'data-header-label').html(_t.html('map_data.layers.custom.title'));
53273           }
53274
53275           dataHeader.datum = function (val) {
53276             if (!arguments.length) return _datum;
53277             _datum = val;
53278             return this;
53279           };
53280
53281           return dataHeader;
53282         }
53283
53284         // It is keyed on the `value` of the entry. Data should be an array of objects like:
53285         //   [{
53286         //       value:   'string value',  // required
53287         //       display: 'label html'     // optional
53288         //       title:   'hover text'     // optional
53289         //       terms:   ['search terms'] // optional
53290         //   }, ...]
53291
53292         var _comboHideTimerID;
53293
53294         function uiCombobox(context, klass) {
53295           var dispatch$1 = dispatch('accept', 'cancel');
53296           var container = context.container();
53297           var _suggestions = [];
53298           var _data = [];
53299           var _fetched = {};
53300           var _selected = null;
53301           var _canAutocomplete = true;
53302           var _caseSensitive = false;
53303           var _cancelFetch = false;
53304           var _minItems = 2;
53305           var _tDown = 0;
53306
53307           var _mouseEnterHandler, _mouseLeaveHandler;
53308
53309           var _fetcher = function _fetcher(val, cb) {
53310             cb(_data.filter(function (d) {
53311               var terms = d.terms || [];
53312               terms.push(d.value);
53313               return terms.some(function (term) {
53314                 return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
53315               });
53316             }));
53317           };
53318
53319           var combobox = function combobox(input, attachTo) {
53320             if (!input || input.empty()) return;
53321             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 () {
53322               var parent = this.parentNode;
53323               var sibling = this.nextSibling;
53324               select(parent).selectAll('.combobox-caret').filter(function (d) {
53325                 return d === input.node();
53326               }).data([input.node()]).enter().insert('div', function () {
53327                 return sibling;
53328               }).attr('class', 'combobox-caret').on('mousedown.combo-caret', function (d3_event) {
53329                 d3_event.preventDefault(); // don't steal focus from input
53330
53331                 input.node().focus(); // focus the input as if it was clicked
53332
53333                 mousedown(d3_event);
53334               }).on('mouseup.combo-caret', function (d3_event) {
53335                 d3_event.preventDefault(); // don't steal focus from input
53336
53337                 mouseup(d3_event);
53338               });
53339             });
53340
53341             function mousedown(d3_event) {
53342               if (d3_event.button !== 0) return; // left click only
53343
53344               _tDown = +new Date(); // clear selection
53345
53346               var start = input.property('selectionStart');
53347               var end = input.property('selectionEnd');
53348
53349               if (start !== end) {
53350                 var val = utilGetSetValue(input);
53351                 input.node().setSelectionRange(val.length, val.length);
53352                 return;
53353               }
53354
53355               input.on('mouseup.combo-input', mouseup);
53356             }
53357
53358             function mouseup(d3_event) {
53359               input.on('mouseup.combo-input', null);
53360               if (d3_event.button !== 0) return; // left click only
53361
53362               if (input.node() !== document.activeElement) return; // exit if this input is not focused
53363
53364               var start = input.property('selectionStart');
53365               var end = input.property('selectionEnd');
53366               if (start !== end) return; // exit if user is selecting
53367               // not showing or showing for a different field - try to show it.
53368
53369               var combo = container.selectAll('.combobox');
53370
53371               if (combo.empty() || combo.datum() !== input.node()) {
53372                 var tOrig = _tDown;
53373                 window.setTimeout(function () {
53374                   if (tOrig !== _tDown) return; // exit if user double clicked
53375
53376                   fetchComboData('', function () {
53377                     show();
53378                     render();
53379                   });
53380                 }, 250);
53381               } else {
53382                 hide();
53383               }
53384             }
53385
53386             function focus() {
53387               fetchComboData(''); // prefetch values (may warm taginfo cache)
53388             }
53389
53390             function blur() {
53391               _comboHideTimerID = window.setTimeout(hide, 75);
53392             }
53393
53394             function show() {
53395               hide(); // remove any existing
53396
53397               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) {
53398                 // prevent moving focus out of the input field
53399                 d3_event.preventDefault();
53400               });
53401               container.on('scroll.combo-scroll', render, true);
53402             }
53403
53404             function hide() {
53405               if (_comboHideTimerID) {
53406                 window.clearTimeout(_comboHideTimerID);
53407                 _comboHideTimerID = undefined;
53408               }
53409
53410               container.selectAll('.combobox').remove();
53411               container.on('scroll.combo-scroll', null);
53412             }
53413
53414             function keydown(d3_event) {
53415               var shown = !container.selectAll('.combobox').empty();
53416               var tagName = input.node() ? input.node().tagName.toLowerCase() : '';
53417
53418               switch (d3_event.keyCode) {
53419                 case 8: // ⌫ Backspace
53420
53421                 case 46:
53422                   // ⌦ Delete
53423                   d3_event.stopPropagation();
53424                   _selected = null;
53425                   render();
53426                   input.on('input.combo-input', function () {
53427                     var start = input.property('selectionStart');
53428                     input.node().setSelectionRange(start, start);
53429                     input.on('input.combo-input', change);
53430                   });
53431                   break;
53432
53433                 case 9:
53434                   // ⇥ Tab
53435                   accept();
53436                   break;
53437
53438                 case 13:
53439                   // ↩ Return
53440                   d3_event.preventDefault();
53441                   d3_event.stopPropagation();
53442                   break;
53443
53444                 case 38:
53445                   // ↑ Up arrow
53446                   if (tagName === 'textarea' && !shown) return;
53447                   d3_event.preventDefault();
53448
53449                   if (tagName === 'input' && !shown) {
53450                     show();
53451                   }
53452
53453                   nav(-1);
53454                   break;
53455
53456                 case 40:
53457                   // ↓ Down arrow
53458                   if (tagName === 'textarea' && !shown) return;
53459                   d3_event.preventDefault();
53460
53461                   if (tagName === 'input' && !shown) {
53462                     show();
53463                   }
53464
53465                   nav(+1);
53466                   break;
53467               }
53468             }
53469
53470             function keyup(d3_event) {
53471               switch (d3_event.keyCode) {
53472                 case 27:
53473                   // ⎋ Escape
53474                   cancel();
53475                   break;
53476
53477                 case 13:
53478                   // ↩ Return
53479                   accept();
53480                   break;
53481               }
53482             } // Called whenever the input value is changed (e.g. on typing)
53483
53484
53485             function change() {
53486               fetchComboData(value(), function () {
53487                 _selected = null;
53488                 var val = input.property('value');
53489
53490                 if (_suggestions.length) {
53491                   if (input.property('selectionEnd') === val.length) {
53492                     _selected = tryAutocomplete();
53493                   }
53494
53495                   if (!_selected) {
53496                     _selected = val;
53497                   }
53498                 }
53499
53500                 if (val.length) {
53501                   var combo = container.selectAll('.combobox');
53502
53503                   if (combo.empty()) {
53504                     show();
53505                   }
53506                 } else {
53507                   hide();
53508                 }
53509
53510                 render();
53511               });
53512             } // Called when the user presses up/down arrows to navigate the list
53513
53514
53515             function nav(dir) {
53516               if (_suggestions.length) {
53517                 // try to determine previously selected index..
53518                 var index = -1;
53519
53520                 for (var i = 0; i < _suggestions.length; i++) {
53521                   if (_selected && _suggestions[i].value === _selected) {
53522                     index = i;
53523                     break;
53524                   }
53525                 } // pick new _selected
53526
53527
53528                 index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
53529                 _selected = _suggestions[index].value;
53530                 input.property('value', _selected);
53531               }
53532
53533               render();
53534               ensureVisible();
53535             }
53536
53537             function ensureVisible() {
53538               var combo = container.selectAll('.combobox');
53539               if (combo.empty()) return;
53540               var containerRect = container.node().getBoundingClientRect();
53541               var comboRect = combo.node().getBoundingClientRect();
53542
53543               if (comboRect.bottom > containerRect.bottom) {
53544                 var node = attachTo ? attachTo.node() : input.node();
53545                 node.scrollIntoView({
53546                   behavior: 'instant',
53547                   block: 'center'
53548                 });
53549                 render();
53550               } // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
53551
53552
53553               var selected = combo.selectAll('.combobox-option.selected').node();
53554
53555               if (selected) {
53556                 selected.scrollIntoView({
53557                   behavior: 'smooth',
53558                   block: 'nearest'
53559                 });
53560               }
53561             }
53562
53563             function value() {
53564               var value = input.property('value');
53565               var start = input.property('selectionStart');
53566               var end = input.property('selectionEnd');
53567
53568               if (start && end) {
53569                 value = value.substring(0, start);
53570               }
53571
53572               return value;
53573             }
53574
53575             function fetchComboData(v, cb) {
53576               _cancelFetch = false;
53577
53578               _fetcher.call(input, v, function (results) {
53579                 // already chose a value, don't overwrite or autocomplete it
53580                 if (_cancelFetch) return;
53581                 _suggestions = results;
53582                 results.forEach(function (d) {
53583                   _fetched[d.value] = d;
53584                 });
53585
53586                 if (cb) {
53587                   cb();
53588                 }
53589               });
53590             }
53591
53592             function tryAutocomplete() {
53593               if (!_canAutocomplete) return;
53594               var val = _caseSensitive ? value() : value().toLowerCase();
53595               if (!val) return; // Don't autocomplete if user is typing a number - #4935
53596
53597               if (!isNaN(parseFloat(val)) && isFinite(val)) return;
53598               var bestIndex = -1;
53599
53600               for (var i = 0; i < _suggestions.length; i++) {
53601                 var suggestion = _suggestions[i].value;
53602                 var compare = _caseSensitive ? suggestion : suggestion.toLowerCase(); // if search string matches suggestion exactly, pick it..
53603
53604                 if (compare === val) {
53605                   bestIndex = i;
53606                   break; // otherwise lock in the first result that starts with the search string..
53607                 } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
53608                   bestIndex = i;
53609                 }
53610               }
53611
53612               if (bestIndex !== -1) {
53613                 var bestVal = _suggestions[bestIndex].value;
53614                 input.property('value', bestVal);
53615                 input.node().setSelectionRange(val.length, bestVal.length);
53616                 return bestVal;
53617               }
53618             }
53619
53620             function render() {
53621               if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
53622                 hide();
53623                 return;
53624               }
53625
53626               var shown = !container.selectAll('.combobox').empty();
53627               if (!shown) return;
53628               var combo = container.selectAll('.combobox');
53629               var options = combo.selectAll('.combobox-option').data(_suggestions, function (d) {
53630                 return d.value;
53631               });
53632               options.exit().remove(); // enter/update
53633
53634               options.enter().append('a').attr('class', 'combobox-option').attr('title', function (d) {
53635                 return d.title;
53636               }).html(function (d) {
53637                 return d.display || d.value;
53638               }).on('mouseenter', _mouseEnterHandler).on('mouseleave', _mouseLeaveHandler).merge(options).classed('selected', function (d) {
53639                 return d.value === _selected;
53640               }).on('click.combo-option', accept).order();
53641               var node = attachTo ? attachTo.node() : input.node();
53642               var containerRect = container.node().getBoundingClientRect();
53643               var rect = node.getBoundingClientRect();
53644               combo.style('left', rect.left + 5 - containerRect.left + 'px').style('width', rect.width - 10 + 'px').style('top', rect.height + rect.top - containerRect.top + 'px');
53645             } // Dispatches an 'accept' event
53646             // Then hides the combobox.
53647
53648
53649             function accept(d3_event, d) {
53650               _cancelFetch = true;
53651               var thiz = input.node();
53652
53653               if (d) {
53654                 // user clicked on a suggestion
53655                 utilGetSetValue(input, d.value); // replace field contents
53656
53657                 utilTriggerEvent(input, 'change');
53658               } // clear (and keep) selection
53659
53660
53661               var val = utilGetSetValue(input);
53662               thiz.setSelectionRange(val.length, val.length);
53663               d = _fetched[val];
53664               dispatch$1.call('accept', thiz, d, val);
53665               hide();
53666             } // Dispatches an 'cancel' event
53667             // Then hides the combobox.
53668
53669
53670             function cancel() {
53671               _cancelFetch = true;
53672               var thiz = input.node(); // clear (and remove) selection, and replace field contents
53673
53674               var val = utilGetSetValue(input);
53675               var start = input.property('selectionStart');
53676               var end = input.property('selectionEnd');
53677               val = val.slice(0, start) + val.slice(end);
53678               utilGetSetValue(input, val);
53679               thiz.setSelectionRange(val.length, val.length);
53680               dispatch$1.call('cancel', thiz);
53681               hide();
53682             }
53683           };
53684
53685           combobox.canAutocomplete = function (val) {
53686             if (!arguments.length) return _canAutocomplete;
53687             _canAutocomplete = val;
53688             return combobox;
53689           };
53690
53691           combobox.caseSensitive = function (val) {
53692             if (!arguments.length) return _caseSensitive;
53693             _caseSensitive = val;
53694             return combobox;
53695           };
53696
53697           combobox.data = function (val) {
53698             if (!arguments.length) return _data;
53699             _data = val;
53700             return combobox;
53701           };
53702
53703           combobox.fetcher = function (val) {
53704             if (!arguments.length) return _fetcher;
53705             _fetcher = val;
53706             return combobox;
53707           };
53708
53709           combobox.minItems = function (val) {
53710             if (!arguments.length) return _minItems;
53711             _minItems = val;
53712             return combobox;
53713           };
53714
53715           combobox.itemsMouseEnter = function (val) {
53716             if (!arguments.length) return _mouseEnterHandler;
53717             _mouseEnterHandler = val;
53718             return combobox;
53719           };
53720
53721           combobox.itemsMouseLeave = function (val) {
53722             if (!arguments.length) return _mouseLeaveHandler;
53723             _mouseLeaveHandler = val;
53724             return combobox;
53725           };
53726
53727           return utilRebind(combobox, dispatch$1, 'on');
53728         }
53729
53730         uiCombobox.off = function (input, context) {
53731           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);
53732           context.container().on('scroll.combo-scroll', null);
53733         };
53734
53735         // hide class, which sets display=none, and a d3 transition for opacity.
53736         // this will cause blinking when called repeatedly, so check that the
53737         // value actually changes between calls.
53738
53739         function uiToggle(show, callback) {
53740           return function (selection) {
53741             selection.style('opacity', show ? 0 : 1).classed('hide', false).transition().style('opacity', show ? 1 : 0).on('end', function () {
53742               select(this).classed('hide', !show).style('opacity', null);
53743               if (callback) callback.apply(this);
53744             });
53745           };
53746         }
53747
53748         function uiDisclosure(context, key, expandedDefault) {
53749           var dispatch$1 = dispatch('toggled');
53750
53751           var _expanded;
53752
53753           var _label = utilFunctor('');
53754
53755           var _updatePreference = true;
53756
53757           var _content = function _content() {};
53758
53759           var disclosure = function disclosure(selection) {
53760             if (_expanded === undefined || _expanded === null) {
53761               // loading _expanded here allows it to be reset by calling `disclosure.expanded(null)`
53762               var preference = corePreferences('disclosure.' + key + '.expanded');
53763               _expanded = preference === null ? !!expandedDefault : preference === 'true';
53764             }
53765
53766             var hideToggle = selection.selectAll('.hide-toggle-' + key).data([0]); // enter
53767
53768             var hideToggleEnter = hideToggle.enter().append('a').attr('href', '#').attr('class', 'hide-toggle hide-toggle-' + key).call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
53769             hideToggleEnter.append('span').attr('class', 'hide-toggle-text'); // update
53770
53771             hideToggle = hideToggleEnter.merge(hideToggle);
53772             hideToggle.on('click', toggle).classed('expanded', _expanded);
53773             hideToggle.selectAll('.hide-toggle-text').html(_label());
53774             hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
53775             var wrap = selection.selectAll('.disclosure-wrap').data([0]); // enter/update
53776
53777             wrap = wrap.enter().append('div').attr('class', 'disclosure-wrap disclosure-wrap-' + key).merge(wrap).classed('hide', !_expanded);
53778
53779             if (_expanded) {
53780               wrap.call(_content);
53781             }
53782
53783             function toggle(d3_event) {
53784               d3_event.preventDefault();
53785               _expanded = !_expanded;
53786
53787               if (_updatePreference) {
53788                 corePreferences('disclosure.' + key + '.expanded', _expanded);
53789               }
53790
53791               hideToggle.classed('expanded', _expanded);
53792               hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
53793               wrap.call(uiToggle(_expanded));
53794
53795               if (_expanded) {
53796                 wrap.call(_content);
53797               }
53798
53799               dispatch$1.call('toggled', this, _expanded);
53800             }
53801           };
53802
53803           disclosure.label = function (val) {
53804             if (!arguments.length) return _label;
53805             _label = utilFunctor(val);
53806             return disclosure;
53807           };
53808
53809           disclosure.expanded = function (val) {
53810             if (!arguments.length) return _expanded;
53811             _expanded = val;
53812             return disclosure;
53813           };
53814
53815           disclosure.updatePreference = function (val) {
53816             if (!arguments.length) return _updatePreference;
53817             _updatePreference = val;
53818             return disclosure;
53819           };
53820
53821           disclosure.content = function (val) {
53822             if (!arguments.length) return _content;
53823             _content = val;
53824             return disclosure;
53825           };
53826
53827           return utilRebind(disclosure, dispatch$1, 'on');
53828         }
53829
53830         // Can be labeled and collapsible.
53831
53832         function uiSection(id, context) {
53833           var _classes = utilFunctor('');
53834
53835           var _shouldDisplay;
53836
53837           var _content;
53838
53839           var _disclosure;
53840
53841           var _label;
53842
53843           var _expandedByDefault = utilFunctor(true);
53844
53845           var _disclosureContent;
53846
53847           var _disclosureExpanded;
53848
53849           var _containerSelection = select(null);
53850
53851           var section = {
53852             id: id
53853           };
53854
53855           section.classes = function (val) {
53856             if (!arguments.length) return _classes;
53857             _classes = utilFunctor(val);
53858             return section;
53859           };
53860
53861           section.label = function (val) {
53862             if (!arguments.length) return _label;
53863             _label = utilFunctor(val);
53864             return section;
53865           };
53866
53867           section.expandedByDefault = function (val) {
53868             if (!arguments.length) return _expandedByDefault;
53869             _expandedByDefault = utilFunctor(val);
53870             return section;
53871           };
53872
53873           section.shouldDisplay = function (val) {
53874             if (!arguments.length) return _shouldDisplay;
53875             _shouldDisplay = utilFunctor(val);
53876             return section;
53877           };
53878
53879           section.content = function (val) {
53880             if (!arguments.length) return _content;
53881             _content = val;
53882             return section;
53883           };
53884
53885           section.disclosureContent = function (val) {
53886             if (!arguments.length) return _disclosureContent;
53887             _disclosureContent = val;
53888             return section;
53889           };
53890
53891           section.disclosureExpanded = function (val) {
53892             if (!arguments.length) return _disclosureExpanded;
53893             _disclosureExpanded = val;
53894             return section;
53895           }; // may be called multiple times
53896
53897
53898           section.render = function (selection) {
53899             _containerSelection = selection.selectAll('.section-' + id).data([0]);
53900
53901             var sectionEnter = _containerSelection.enter().append('div').attr('class', 'section section-' + id + ' ' + (_classes && _classes() || ''));
53902
53903             _containerSelection = sectionEnter.merge(_containerSelection);
53904
53905             _containerSelection.call(renderContent);
53906           };
53907
53908           section.reRender = function () {
53909             _containerSelection.call(renderContent);
53910           };
53911
53912           section.selection = function () {
53913             return _containerSelection;
53914           };
53915
53916           section.disclosure = function () {
53917             return _disclosure;
53918           }; // may be called multiple times
53919
53920
53921           function renderContent(selection) {
53922             if (_shouldDisplay) {
53923               var shouldDisplay = _shouldDisplay();
53924
53925               selection.classed('hide', !shouldDisplay);
53926
53927               if (!shouldDisplay) {
53928                 selection.html('');
53929                 return;
53930               }
53931             }
53932
53933             if (_disclosureContent) {
53934               if (!_disclosure) {
53935                 _disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault()).label(_label || '')
53936                 /*.on('toggled', function(expanded) {
53937                     if (expanded) { selection.node().parentNode.scrollTop += 200; }
53938                 })*/
53939                 .content(_disclosureContent);
53940               }
53941
53942               if (_disclosureExpanded !== undefined) {
53943                 _disclosure.expanded(_disclosureExpanded);
53944
53945                 _disclosureExpanded = undefined;
53946               }
53947
53948               selection.call(_disclosure);
53949               return;
53950             }
53951
53952             if (_content) {
53953               selection.call(_content);
53954             }
53955           }
53956
53957           return section;
53958         }
53959
53960         // {
53961         //   key: 'string',     // required
53962         //   value: 'string'    // optional
53963         // }
53964         //   -or-
53965         // {
53966         //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
53967         // }
53968         //
53969
53970         function uiTagReference(what) {
53971           var wikibase = what.qid ? services.wikidata : services.osmWikibase;
53972           var tagReference = {};
53973
53974           var _button = select(null);
53975
53976           var _body = select(null);
53977
53978           var _loaded;
53979
53980           var _showing;
53981
53982           function load() {
53983             if (!wikibase) return;
53984
53985             _button.classed('tag-reference-loading', true);
53986
53987             wikibase.getDocs(what, gotDocs);
53988           }
53989
53990           function gotDocs(err, docs) {
53991             _body.html('');
53992
53993             if (!docs || !docs.title) {
53994               _body.append('p').attr('class', 'tag-reference-description').html(_t.html('inspector.no_documentation_key'));
53995
53996               done();
53997               return;
53998             }
53999
54000             if (docs.imageURL) {
54001               _body.append('img').attr('class', 'tag-reference-wiki-image').attr('src', docs.imageURL).on('load', function () {
54002                 done();
54003               }).on('error', function () {
54004                 select(this).remove();
54005                 done();
54006               });
54007             } else {
54008               done();
54009             }
54010
54011             _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'));
54012
54013             if (docs.wiki) {
54014               _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));
54015             } // Add link to info about "good changeset comments" - #2923
54016
54017
54018             if (what.key === 'comment') {
54019               _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'));
54020             }
54021           }
54022
54023           function done() {
54024             _loaded = true;
54025
54026             _button.classed('tag-reference-loading', false);
54027
54028             _body.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1');
54029
54030             _showing = true;
54031
54032             _button.selectAll('svg.icon use').each(function () {
54033               var iconUse = select(this);
54034
54035               if (iconUse.attr('href') === '#iD-icon-info') {
54036                 iconUse.attr('href', '#iD-icon-info-filled');
54037               }
54038             });
54039           }
54040
54041           function hide() {
54042             _body.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
54043               _body.classed('expanded', false);
54044             });
54045
54046             _showing = false;
54047
54048             _button.selectAll('svg.icon use').each(function () {
54049               var iconUse = select(this);
54050
54051               if (iconUse.attr('href') === '#iD-icon-info-filled') {
54052                 iconUse.attr('href', '#iD-icon-info');
54053               }
54054             });
54055           }
54056
54057           tagReference.button = function (selection, klass, iconName) {
54058             _button = selection.selectAll('.tag-reference-button').data([0]);
54059             _button = _button.enter().append('button').attr('class', 'tag-reference-button ' + (klass || '')).attr('title', _t('icons.information')).call(svgIcon('#iD-icon-' + (iconName || 'inspect'))).merge(_button);
54060
54061             _button.on('click', function (d3_event) {
54062               d3_event.stopPropagation();
54063               d3_event.preventDefault();
54064               this.blur(); // avoid keeping focus on the button - #4641
54065
54066               if (_showing) {
54067                 hide();
54068               } else if (_loaded) {
54069                 done();
54070               } else {
54071                 load();
54072               }
54073             });
54074           };
54075
54076           tagReference.body = function (selection) {
54077             var itemID = what.qid || what.key + '-' + (what.value || '');
54078             _body = selection.selectAll('.tag-reference-body').data([itemID], function (d) {
54079               return d;
54080             });
54081
54082             _body.exit().remove();
54083
54084             _body = _body.enter().append('div').attr('class', 'tag-reference-body').style('max-height', '0').style('opacity', '0').merge(_body);
54085
54086             if (_showing === false) {
54087               hide();
54088             }
54089           };
54090
54091           tagReference.showing = function (val) {
54092             if (!arguments.length) return _showing;
54093             _showing = val;
54094             return tagReference;
54095           };
54096
54097           return tagReference;
54098         }
54099
54100         function uiSectionRawTagEditor(id, context) {
54101           var section = uiSection(id, context).classes('raw-tag-editor').label(function () {
54102             var count = Object.keys(_tags).filter(function (d) {
54103               return d;
54104             }).length;
54105             return _t('inspector.title_count', {
54106               title: _t.html('inspector.tags'),
54107               count: count
54108             });
54109           }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
54110           var taginfo = services.taginfo;
54111           var dispatch$1 = dispatch('change');
54112           var availableViews = [{
54113             id: 'list',
54114             icon: '#fas-th-list'
54115           }, {
54116             id: 'text',
54117             icon: '#fas-i-cursor'
54118           }];
54119
54120           var _tagView = corePreferences('raw-tag-editor-view') || 'list'; // 'list, 'text'
54121
54122
54123           var _readOnlyTags = []; // the keys in the order we want them to display
54124
54125           var _orderedKeys = [];
54126           var _showBlank = false;
54127           var _pendingChange = null;
54128
54129           var _state;
54130
54131           var _presets;
54132
54133           var _tags;
54134
54135           var _entityIDs;
54136
54137           var _didInteract = false;
54138
54139           function interacted() {
54140             _didInteract = true;
54141           }
54142
54143           function renderDisclosureContent(wrap) {
54144             // remove deleted keys
54145             _orderedKeys = _orderedKeys.filter(function (key) {
54146               return _tags[key] !== undefined;
54147             }); // When switching to a different entity or changing the state (hover/select)
54148             // reorder the keys alphabetically.
54149             // We trigger this by emptying the `_orderedKeys` array, then it will be rebuilt here.
54150             // Otherwise leave their order alone - #5857, #5927
54151
54152             var all = Object.keys(_tags).sort();
54153             var missingKeys = utilArrayDifference(all, _orderedKeys);
54154
54155             for (var i in missingKeys) {
54156               _orderedKeys.push(missingKeys[i]);
54157             } // assemble row data
54158
54159
54160             var rowData = _orderedKeys.map(function (key, i) {
54161               return {
54162                 index: i,
54163                 key: key,
54164                 value: _tags[key]
54165               };
54166             }); // append blank row last, if necessary
54167
54168
54169             if (!rowData.length || _showBlank) {
54170               _showBlank = false;
54171               rowData.push({
54172                 index: rowData.length,
54173                 key: '',
54174                 value: ''
54175               });
54176             } // View Options
54177
54178
54179             var options = wrap.selectAll('.raw-tag-options').data([0]);
54180             options.exit().remove();
54181             var optionsEnter = options.enter().insert('div', ':first-child').attr('class', 'raw-tag-options');
54182             var optionEnter = optionsEnter.selectAll('.raw-tag-option').data(availableViews, function (d) {
54183               return d.id;
54184             }).enter();
54185             optionEnter.append('button').attr('class', function (d) {
54186               return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
54187             }).attr('title', function (d) {
54188               return _t('icons.' + d.id);
54189             }).on('click', function (d3_event, d) {
54190               _tagView = d.id;
54191               corePreferences('raw-tag-editor-view', d.id);
54192               wrap.selectAll('.raw-tag-option').classed('selected', function (datum) {
54193                 return datum === d;
54194               });
54195               wrap.selectAll('.tag-text').classed('hide', d.id !== 'text').each(setTextareaHeight);
54196               wrap.selectAll('.tag-list, .add-row').classed('hide', d.id !== 'list');
54197             }).each(function (d) {
54198               select(this).call(svgIcon(d.icon));
54199             }); // View as Text
54200
54201             var textData = rowsToText(rowData);
54202             var textarea = wrap.selectAll('.tag-text').data([0]);
54203             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);
54204             textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on('input', setTextareaHeight).on('focus', interacted).on('blur', textChanged).on('change', textChanged); // View as List
54205
54206             var list = wrap.selectAll('.tag-list').data([0]);
54207             list = list.enter().append('ul').attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : '')).merge(list); // Container for the Add button
54208
54209             var addRowEnter = wrap.selectAll('.add-row').data([0]).enter().append('div').attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
54210             addRowEnter.append('button').attr('class', 'add-tag').call(svgIcon('#iD-icon-plus', 'light')).on('click', addTag);
54211             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
54212
54213             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
54214             // Tag list items
54215
54216             var items = list.selectAll('.tag-row').data(rowData, function (d) {
54217               return d.key;
54218             });
54219             items.exit().each(unbind).remove(); // Enter
54220
54221             var itemsEnter = items.enter().append('li').attr('class', 'tag-row').classed('readonly', isReadOnly);
54222             var innerWrap = itemsEnter.append('div').attr('class', 'inner-wrap');
54223             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);
54224             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);
54225             innerWrap.append('button').attr('class', 'form-field-button remove').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete')); // Update
54226
54227             items = items.merge(itemsEnter).sort(function (a, b) {
54228               return a.index - b.index;
54229             });
54230             items.each(function (d) {
54231               var row = select(this);
54232               var key = row.select('input.key'); // propagate bound data
54233
54234               var value = row.select('input.value'); // propagate bound data
54235
54236               if (_entityIDs && taginfo && _state !== 'hover') {
54237                 bindTypeahead(key, value);
54238               }
54239
54240               var referenceOptions = {
54241                 key: d.key
54242               };
54243
54244               if (typeof d.value === 'string') {
54245                 referenceOptions.value = d.value;
54246               }
54247
54248               var reference = uiTagReference(referenceOptions);
54249
54250               if (_state === 'hover') {
54251                 reference.showing(false);
54252               }
54253
54254               row.select('.inner-wrap') // propagate bound data
54255               .call(reference.button);
54256               row.call(reference.body);
54257               row.select('button.remove'); // propagate bound data
54258             });
54259             items.selectAll('input.key').attr('title', function (d) {
54260               return d.key;
54261             }).call(utilGetSetValue, function (d) {
54262               return d.key;
54263             }).attr('readonly', function (d) {
54264               return isReadOnly(d) || typeof d.value !== 'string' || null;
54265             });
54266             items.selectAll('input.value').attr('title', function (d) {
54267               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : d.value;
54268             }).classed('mixed', function (d) {
54269               return Array.isArray(d.value);
54270             }).attr('placeholder', function (d) {
54271               return typeof d.value === 'string' ? null : _t('inspector.multiple_values');
54272             }).call(utilGetSetValue, function (d) {
54273               return typeof d.value === 'string' ? d.value : '';
54274             }).attr('readonly', function (d) {
54275               return isReadOnly(d) || null;
54276             });
54277             items.selectAll('button.remove').on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'down', removeTag); // 'click' fires too late - #5878
54278           }
54279
54280           function isReadOnly(d) {
54281             for (var i = 0; i < _readOnlyTags.length; i++) {
54282               if (d.key.match(_readOnlyTags[i]) !== null) {
54283                 return true;
54284               }
54285             }
54286
54287             return false;
54288           }
54289
54290           function setTextareaHeight() {
54291             if (_tagView !== 'text') return;
54292             var selection = select(this);
54293             var matches = selection.node().value.match(/\n/g);
54294             var lineCount = 2 + Number(matches && matches.length);
54295             var lineHeight = 20;
54296             selection.style('height', lineCount * lineHeight + 'px');
54297           }
54298
54299           function stringify(s) {
54300             return JSON.stringify(s).slice(1, -1); // without leading/trailing "
54301           }
54302
54303           function unstringify(s) {
54304             var leading = '';
54305             var trailing = '';
54306
54307             if (s.length < 1 || s.charAt(0) !== '"') {
54308               leading = '"';
54309             }
54310
54311             if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\') {
54312               trailing = '"';
54313             }
54314
54315             return JSON.parse(leading + s + trailing);
54316           }
54317
54318           function rowsToText(rows) {
54319             var str = rows.filter(function (row) {
54320               return row.key && row.key.trim() !== '';
54321             }).map(function (row) {
54322               var rawVal = row.value;
54323               if (typeof rawVal !== 'string') rawVal = '*';
54324               var val = rawVal ? stringify(rawVal) : '';
54325               return stringify(row.key) + '=' + val;
54326             }).join('\n');
54327
54328             if (_state !== 'hover' && str.length) {
54329               return str + '\n';
54330             }
54331
54332             return str;
54333           }
54334
54335           function textChanged() {
54336             var newText = this.value.trim();
54337             var newTags = {};
54338             newText.split('\n').forEach(function (row) {
54339               var m = row.match(/^\s*([^=]+)=(.*)$/);
54340
54341               if (m !== null) {
54342                 var k = context.cleanTagKey(unstringify(m[1].trim()));
54343                 var v = context.cleanTagValue(unstringify(m[2].trim()));
54344                 newTags[k] = v;
54345               }
54346             });
54347             var tagDiff = utilTagDiff(_tags, newTags);
54348             if (!tagDiff.length) return;
54349             _pendingChange = _pendingChange || {};
54350             tagDiff.forEach(function (change) {
54351               if (isReadOnly({
54352                 key: change.key
54353               })) return; // skip unchanged multiselection placeholders
54354
54355               if (change.newVal === '*' && typeof change.oldVal !== 'string') return;
54356
54357               if (change.type === '-') {
54358                 _pendingChange[change.key] = undefined;
54359               } else if (change.type === '+') {
54360                 _pendingChange[change.key] = change.newVal || '';
54361               }
54362             });
54363
54364             if (Object.keys(_pendingChange).length === 0) {
54365               _pendingChange = null;
54366               return;
54367             }
54368
54369             scheduleChange();
54370           }
54371
54372           function pushMore(d3_event) {
54373             // if pressing Tab on the last value field with content, add a blank row
54374             if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll('.tag-list li:last-child input.value').node() === this && utilGetSetValue(select(this))) {
54375               addTag();
54376             }
54377           }
54378
54379           function bindTypeahead(key, value) {
54380             if (isReadOnly(key.datum())) return;
54381
54382             if (Array.isArray(value.datum().value)) {
54383               value.call(uiCombobox(context, 'tag-value').minItems(1).fetcher(function (value, callback) {
54384                 var keyString = utilGetSetValue(key);
54385                 if (!_tags[keyString]) return;
54386
54387                 var data = _tags[keyString].filter(Boolean).map(function (tagValue) {
54388                   return {
54389                     value: tagValue,
54390                     title: tagValue
54391                   };
54392                 });
54393
54394                 callback(data);
54395               }));
54396               return;
54397             }
54398
54399             var geometry = context.graph().geometry(_entityIDs[0]);
54400             key.call(uiCombobox(context, 'tag-key').fetcher(function (value, callback) {
54401               taginfo.keys({
54402                 debounce: true,
54403                 geometry: geometry,
54404                 query: value
54405               }, function (err, data) {
54406                 if (!err) {
54407                   var filtered = data.filter(function (d) {
54408                     return _tags[d.value] === undefined;
54409                   });
54410                   callback(sort(value, filtered));
54411                 }
54412               });
54413             }));
54414             value.call(uiCombobox(context, 'tag-value').fetcher(function (value, callback) {
54415               taginfo.values({
54416                 debounce: true,
54417                 key: utilGetSetValue(key),
54418                 geometry: geometry,
54419                 query: value
54420               }, function (err, data) {
54421                 if (!err) callback(sort(value, data));
54422               });
54423             }));
54424
54425             function sort(value, data) {
54426               var sameletter = [];
54427               var other = [];
54428
54429               for (var i = 0; i < data.length; i++) {
54430                 if (data[i].value.substring(0, value.length) === value) {
54431                   sameletter.push(data[i]);
54432                 } else {
54433                   other.push(data[i]);
54434                 }
54435               }
54436
54437               return sameletter.concat(other);
54438             }
54439           }
54440
54441           function unbind() {
54442             var row = select(this);
54443             row.selectAll('input.key').call(uiCombobox.off, context);
54444             row.selectAll('input.value').call(uiCombobox.off, context);
54445           }
54446
54447           function keyChange(d3_event, d) {
54448             if (select(this).attr('readonly')) return;
54449             var kOld = d.key; // exit if we are currently about to delete this row anyway - #6366
54450
54451             if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
54452             var kNew = context.cleanTagKey(this.value.trim()); // allow no change if the key should be readonly
54453
54454             if (isReadOnly({
54455               key: kNew
54456             })) {
54457               this.value = kOld;
54458               return;
54459             }
54460
54461             if (kNew && kNew !== kOld && _tags[kNew] !== undefined) {
54462               // new key is already in use, switch focus to the existing row
54463               this.value = kOld; // reset the key
54464
54465               section.selection().selectAll('.tag-list input.value').each(function (d) {
54466                 if (d.key === kNew) {
54467                   // send focus to that other value combo instead
54468                   var input = select(this).node();
54469                   input.focus();
54470                   input.select();
54471                 }
54472               });
54473               return;
54474             }
54475
54476             var row = this.parentNode.parentNode;
54477             var inputVal = select(row).selectAll('input.value');
54478             var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
54479             _pendingChange = _pendingChange || {};
54480
54481             if (kOld) {
54482               _pendingChange[kOld] = undefined;
54483             }
54484
54485             _pendingChange[kNew] = vNew; // update the ordered key index so this row doesn't change position
54486
54487             var existingKeyIndex = _orderedKeys.indexOf(kOld);
54488
54489             if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
54490             d.key = kNew; // update datum to avoid exit/enter on tag update
54491
54492             d.value = vNew;
54493             this.value = kNew;
54494             utilGetSetValue(inputVal, vNew);
54495             scheduleChange();
54496           }
54497
54498           function valueChange(d3_event, d) {
54499             if (isReadOnly(d)) return; // exit if this is a multiselection and no value was entered
54500
54501             if (typeof d.value !== 'string' && !this.value) return; // exit if we are currently about to delete this row anyway - #6366
54502
54503             if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
54504             _pendingChange = _pendingChange || {};
54505             _pendingChange[d.key] = context.cleanTagValue(this.value);
54506             scheduleChange();
54507           }
54508
54509           function removeTag(d3_event, d) {
54510             if (isReadOnly(d)) return;
54511
54512             if (d.key === '') {
54513               // removing the blank row
54514               _showBlank = false;
54515               section.reRender();
54516             } else {
54517               // remove the key from the ordered key index
54518               _orderedKeys = _orderedKeys.filter(function (key) {
54519                 return key !== d.key;
54520               });
54521               _pendingChange = _pendingChange || {};
54522               _pendingChange[d.key] = undefined;
54523               scheduleChange();
54524             }
54525           }
54526
54527           function addTag() {
54528             // Delay render in case this click is blurring an edited combo.
54529             // Without the setTimeout, the `content` render would wipe out the pending tag change.
54530             window.setTimeout(function () {
54531               _showBlank = true;
54532               section.reRender();
54533               section.selection().selectAll('.tag-list li:last-child input.key').node().focus();
54534             }, 20);
54535           }
54536
54537           function scheduleChange() {
54538             // Cache IDs in case the editor is reloaded before the change event is called. - #6028
54539             var entityIDs = _entityIDs; // Delay change in case this change is blurring an edited combo. - #5878
54540
54541             window.setTimeout(function () {
54542               if (!_pendingChange) return;
54543               dispatch$1.call('change', this, entityIDs, _pendingChange);
54544               _pendingChange = null;
54545             }, 10);
54546           }
54547
54548           section.state = function (val) {
54549             if (!arguments.length) return _state;
54550
54551             if (_state !== val) {
54552               _orderedKeys = [];
54553               _state = val;
54554             }
54555
54556             return section;
54557           };
54558
54559           section.presets = function (val) {
54560             if (!arguments.length) return _presets;
54561             _presets = val;
54562
54563             if (_presets && _presets.length && _presets[0].isFallback()) {
54564               section.disclosureExpanded(true); // don't collapse the disclosure if the mapper used the raw tag editor - #1881
54565             } else if (!_didInteract) {
54566               section.disclosureExpanded(null);
54567             }
54568
54569             return section;
54570           };
54571
54572           section.tags = function (val) {
54573             if (!arguments.length) return _tags;
54574             _tags = val;
54575             return section;
54576           };
54577
54578           section.entityIDs = function (val) {
54579             if (!arguments.length) return _entityIDs;
54580
54581             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
54582               _entityIDs = val;
54583               _orderedKeys = [];
54584             }
54585
54586             return section;
54587           }; // pass an array of regular expressions to test against the tag key
54588
54589
54590           section.readOnlyTags = function (val) {
54591             if (!arguments.length) return _readOnlyTags;
54592             _readOnlyTags = val;
54593             return section;
54594           };
54595
54596           return utilRebind(section, dispatch$1, 'on');
54597         }
54598
54599         function uiDataEditor(context) {
54600           var dataHeader = uiDataHeader();
54601           var rawTagEditor = uiSectionRawTagEditor('custom-data-tag-editor', context).expandedByDefault(true).readOnlyTags([/./]);
54602
54603           var _datum;
54604
54605           function dataEditor(selection) {
54606             var header = selection.selectAll('.header').data([0]);
54607             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
54608             headerEnter.append('button').attr('class', 'close').on('click', function () {
54609               context.enter(modeBrowse(context));
54610             }).call(svgIcon('#iD-icon-close'));
54611             headerEnter.append('h3').html(_t.html('map_data.title'));
54612             var body = selection.selectAll('.body').data([0]);
54613             body = body.enter().append('div').attr('class', 'body').merge(body);
54614             var editor = body.selectAll('.data-editor').data([0]); // enter/update
54615
54616             editor.enter().append('div').attr('class', 'modal-section data-editor').merge(editor).call(dataHeader.datum(_datum));
54617             var rte = body.selectAll('.raw-tag-editor').data([0]); // enter/update
54618
54619             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);
54620           }
54621
54622           dataEditor.datum = function (val) {
54623             if (!arguments.length) return _datum;
54624             _datum = val;
54625             return this;
54626           };
54627
54628           return dataEditor;
54629         }
54630
54631         function modeSelectData(context, selectedDatum) {
54632           var mode = {
54633             id: 'select-data',
54634             button: 'browse'
54635           };
54636           var keybinding = utilKeybinding('select-data');
54637           var dataEditor = uiDataEditor(context);
54638           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
54639
54640           function selectData(d3_event, drawn) {
54641             var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__);
54642
54643             if (selection.empty()) {
54644               // Return to browse mode if selected DOM elements have
54645               // disappeared because the user moved them out of view..
54646               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
54647
54648               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
54649                 context.enter(modeBrowse(context));
54650               }
54651             } else {
54652               selection.classed('selected', true);
54653             }
54654           }
54655
54656           function esc() {
54657             if (context.container().select('.combobox').size()) return;
54658             context.enter(modeBrowse(context));
54659           }
54660
54661           mode.zoomToSelected = function () {
54662             var extent = geoExtent(d3_geoBounds(selectedDatum));
54663             context.map().centerZoomEase(extent.center(), context.map().trimmedExtentZoom(extent));
54664           };
54665
54666           mode.enter = function () {
54667             behaviors.forEach(context.install);
54668             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
54669             select(document).call(keybinding);
54670             selectData();
54671             var sidebar = context.ui().sidebar;
54672             sidebar.show(dataEditor.datum(selectedDatum)); // expand the sidebar, avoid obscuring the data if needed
54673
54674             var extent = geoExtent(d3_geoBounds(selectedDatum));
54675             sidebar.expand(sidebar.intersects(extent));
54676             context.map().on('drawn.select-data', selectData);
54677           };
54678
54679           mode.exit = function () {
54680             behaviors.forEach(context.uninstall);
54681             select(document).call(keybinding.unbind);
54682             context.surface().selectAll('.layer-mapdata .selected').classed('selected hover', false);
54683             context.map().on('drawn.select-data', null);
54684             context.ui().sidebar.hide();
54685           };
54686
54687           return mode;
54688         }
54689
54690         function uiImproveOsmComments() {
54691           var _qaItem;
54692
54693           function issueComments(selection) {
54694             // make the div immediately so it appears above the buttons
54695             var comments = selection.selectAll('.comments-container').data([0]);
54696             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments); // must retrieve comments from API before they can be displayed
54697
54698             services.improveOSM.getComments(_qaItem).then(function (d) {
54699               if (!d.comments) return; // nothing to do here
54700
54701               var commentEnter = comments.selectAll('.comment').data(d.comments).enter().append('div').attr('class', 'comment');
54702               commentEnter.append('div').attr('class', 'comment-avatar').call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
54703               var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
54704               var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
54705               metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
54706                 var osm = services.osm;
54707                 var selection = select(this);
54708
54709                 if (osm && d.username) {
54710                   selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.username)).attr('target', '_blank');
54711                 }
54712
54713                 selection.html(function (d) {
54714                   return d.username;
54715                 });
54716               });
54717               metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
54718                 return _t.html('note.status.commented', {
54719                   when: localeDateString(d.timestamp)
54720                 });
54721               });
54722               mainEnter.append('div').attr('class', 'comment-text').append('p').html(function (d) {
54723                 return d.text;
54724               });
54725             })["catch"](function (err) {
54726               console.log(err); // eslint-disable-line no-console
54727             });
54728           }
54729
54730           function localeDateString(s) {
54731             if (!s) return null;
54732             var options = {
54733               day: 'numeric',
54734               month: 'short',
54735               year: 'numeric'
54736             };
54737             var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
54738
54739             if (isNaN(d.getTime())) return null;
54740             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
54741           }
54742
54743           issueComments.issue = function (val) {
54744             if (!arguments.length) return _qaItem;
54745             _qaItem = val;
54746             return issueComments;
54747           };
54748
54749           return issueComments;
54750         }
54751
54752         function uiImproveOsmDetails(context) {
54753           var _qaItem;
54754
54755           function issueDetail(d) {
54756             if (d.desc) return d.desc;
54757             var issueKey = d.issueKey;
54758             d.replacements = d.replacements || {};
54759             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
54760
54761             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d.replacements);
54762           }
54763
54764           function improveOsmDetails(selection) {
54765             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
54766               return "".concat(d.id, "-").concat(d.status || 0);
54767             });
54768             details.exit().remove();
54769             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
54770
54771             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54772             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
54773             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
54774
54775             var relatedEntities = [];
54776             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
54777               var link = select(this);
54778               var isObjectLink = link.classed('error_object_link');
54779               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
54780               var entity = context.hasEntity(entityID);
54781               relatedEntities.push(entityID); // Add click handler
54782
54783               link.on('mouseenter', function () {
54784                 utilHighlightEntities([entityID], true, context);
54785               }).on('mouseleave', function () {
54786                 utilHighlightEntities([entityID], false, context);
54787               }).on('click', function (d3_event) {
54788                 d3_event.preventDefault();
54789                 utilHighlightEntities([entityID], false, context);
54790                 var osmlayer = context.layers().layer('osm');
54791
54792                 if (!osmlayer.enabled()) {
54793                   osmlayer.enabled(true);
54794                 }
54795
54796                 context.map().centerZoom(_qaItem.loc, 20);
54797
54798                 if (entity) {
54799                   context.enter(modeSelect(context, [entityID]));
54800                 } else {
54801                   context.loadEntity(entityID, function () {
54802                     context.enter(modeSelect(context, [entityID]));
54803                   });
54804                 }
54805               }); // Replace with friendly name if possible
54806               // (The entity may not yet be loaded into the graph)
54807
54808               if (entity) {
54809                 var name = utilDisplayName(entity); // try to use common name
54810
54811                 if (!name && !isObjectLink) {
54812                   var preset = _mainPresetIndex.match(entity, context.graph());
54813                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
54814                 }
54815
54816                 if (name) {
54817                   this.innerText = name;
54818                 }
54819               }
54820             }); // Don't hide entities related to this error - #5880
54821
54822             context.features().forceVisible(relatedEntities);
54823             context.map().pan([0, 0]); // trigger a redraw
54824           }
54825
54826           improveOsmDetails.issue = function (val) {
54827             if (!arguments.length) return _qaItem;
54828             _qaItem = val;
54829             return improveOsmDetails;
54830           };
54831
54832           return improveOsmDetails;
54833         }
54834
54835         function uiImproveOsmHeader() {
54836           var _qaItem;
54837
54838           function issueTitle(d) {
54839             var issueKey = d.issueKey;
54840             d.replacements = d.replacements || {};
54841             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
54842
54843             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d.replacements);
54844           }
54845
54846           function improveOsmHeader(selection) {
54847             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
54848               return "".concat(d.id, "-").concat(d.status || 0);
54849             });
54850             header.exit().remove();
54851             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
54852             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
54853               return d.id < 0;
54854             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
54855               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
54856             });
54857             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');
54858             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
54859               var picon = d.icon;
54860
54861               if (!picon) {
54862                 return '';
54863               } else {
54864                 var isMaki = /^maki-/.test(picon);
54865                 return "#".concat(picon).concat(isMaki ? '-11' : '');
54866               }
54867             });
54868             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
54869           }
54870
54871           improveOsmHeader.issue = function (val) {
54872             if (!arguments.length) return _qaItem;
54873             _qaItem = val;
54874             return improveOsmHeader;
54875           };
54876
54877           return improveOsmHeader;
54878         }
54879
54880         function uiImproveOsmEditor(context) {
54881           var dispatch$1 = dispatch('change');
54882           var qaDetails = uiImproveOsmDetails(context);
54883           var qaComments = uiImproveOsmComments();
54884           var qaHeader = uiImproveOsmHeader();
54885
54886           var _qaItem;
54887
54888           function improveOsmEditor(selection) {
54889             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
54890             headerEnter.append('button').attr('class', 'close').on('click', function () {
54891               return context.enter(modeBrowse(context));
54892             }).call(svgIcon('#iD-icon-close'));
54893             headerEnter.append('h3').html(_t.html('QA.improveOSM.title'));
54894             var body = selection.selectAll('.body').data([0]);
54895             body = body.enter().append('div').attr('class', 'body').merge(body);
54896             var editor = body.selectAll('.qa-editor').data([0]);
54897             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);
54898           }
54899
54900           function improveOsmSaveSection(selection) {
54901             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54902
54903             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
54904             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
54905               return "".concat(d.id, "-").concat(d.status || 0);
54906             }); // exit
54907
54908             saveSection.exit().remove(); // enter
54909
54910             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
54911             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('note.newComment'));
54912             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
54913               return d.newComment;
54914             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
54915
54916             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
54917
54918             function changeInput() {
54919               var input = select(this);
54920               var val = input.property('value').trim();
54921
54922               if (val === '') {
54923                 val = undefined;
54924               } // store the unsaved comment with the issue itself
54925
54926
54927               _qaItem = _qaItem.update({
54928                 newComment: val
54929               });
54930               var qaService = services.improveOSM;
54931
54932               if (qaService) {
54933                 qaService.replaceItem(_qaItem);
54934               }
54935
54936               saveSection.call(qaSaveButtons);
54937             }
54938           }
54939
54940           function qaSaveButtons(selection) {
54941             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54942
54943             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
54944               return d.status + d.id;
54945             }); // exit
54946
54947             buttonSection.exit().remove(); // enter
54948
54949             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
54950             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
54951             buttonEnter.append('button').attr('class', 'button close-button action');
54952             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
54953
54954             buttonSection = buttonSection.merge(buttonEnter);
54955             buttonSection.select('.comment-button').attr('disabled', function (d) {
54956               return d.newComment ? null : true;
54957             }).on('click.comment', function (d3_event, d) {
54958               this.blur(); // avoid keeping focus on the button - #4641
54959
54960               var qaService = services.improveOSM;
54961
54962               if (qaService) {
54963                 qaService.postUpdate(d, function (err, item) {
54964                   return dispatch$1.call('change', item);
54965                 });
54966               }
54967             });
54968             buttonSection.select('.close-button').html(function (d) {
54969               var andComment = d.newComment ? '_comment' : '';
54970               return _t.html("QA.keepRight.close".concat(andComment));
54971             }).on('click.close', function (d3_event, d) {
54972               this.blur(); // avoid keeping focus on the button - #4641
54973
54974               var qaService = services.improveOSM;
54975
54976               if (qaService) {
54977                 d.newStatus = 'SOLVED';
54978                 qaService.postUpdate(d, function (err, item) {
54979                   return dispatch$1.call('change', item);
54980                 });
54981               }
54982             });
54983             buttonSection.select('.ignore-button').html(function (d) {
54984               var andComment = d.newComment ? '_comment' : '';
54985               return _t.html("QA.keepRight.ignore".concat(andComment));
54986             }).on('click.ignore', function (d3_event, d) {
54987               this.blur(); // avoid keeping focus on the button - #4641
54988
54989               var qaService = services.improveOSM;
54990
54991               if (qaService) {
54992                 d.newStatus = 'INVALID';
54993                 qaService.postUpdate(d, function (err, item) {
54994                   return dispatch$1.call('change', item);
54995                 });
54996               }
54997             });
54998           } // NOTE: Don't change method name until UI v3 is merged
54999
55000
55001           improveOsmEditor.error = function (val) {
55002             if (!arguments.length) return _qaItem;
55003             _qaItem = val;
55004             return improveOsmEditor;
55005           };
55006
55007           return utilRebind(improveOsmEditor, dispatch$1, 'on');
55008         }
55009
55010         function uiKeepRightDetails(context) {
55011           var _qaItem;
55012
55013           function issueDetail(d) {
55014             var itemType = d.itemType,
55015                 parentIssueType = d.parentIssueType;
55016             var unknown = _t.html('inspector.unknown');
55017             var replacements = d.replacements || {};
55018             replacements["default"] = unknown; // special key `default` works as a fallback string
55019
55020             var detail = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
55021
55022             if (detail === unknown) {
55023               detail = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
55024             }
55025
55026             return detail;
55027           }
55028
55029           function keepRightDetails(selection) {
55030             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
55031               return "".concat(d.id, "-").concat(d.status || 0);
55032             });
55033             details.exit().remove();
55034             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
55035
55036             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55037             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
55038             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
55039
55040             var relatedEntities = [];
55041             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
55042               var link = select(this);
55043               var isObjectLink = link.classed('error_object_link');
55044               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
55045               var entity = context.hasEntity(entityID);
55046               relatedEntities.push(entityID); // Add click handler
55047
55048               link.on('mouseenter', function () {
55049                 utilHighlightEntities([entityID], true, context);
55050               }).on('mouseleave', function () {
55051                 utilHighlightEntities([entityID], false, context);
55052               }).on('click', function (d3_event) {
55053                 d3_event.preventDefault();
55054                 utilHighlightEntities([entityID], false, context);
55055                 var osmlayer = context.layers().layer('osm');
55056
55057                 if (!osmlayer.enabled()) {
55058                   osmlayer.enabled(true);
55059                 }
55060
55061                 context.map().centerZoomEase(_qaItem.loc, 20);
55062
55063                 if (entity) {
55064                   context.enter(modeSelect(context, [entityID]));
55065                 } else {
55066                   context.loadEntity(entityID, function () {
55067                     context.enter(modeSelect(context, [entityID]));
55068                   });
55069                 }
55070               }); // Replace with friendly name if possible
55071               // (The entity may not yet be loaded into the graph)
55072
55073               if (entity) {
55074                 var name = utilDisplayName(entity); // try to use common name
55075
55076                 if (!name && !isObjectLink) {
55077                   var preset = _mainPresetIndex.match(entity, context.graph());
55078                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
55079                 }
55080
55081                 if (name) {
55082                   this.innerText = name;
55083                 }
55084               }
55085             }); // Don't hide entities related to this issue - #5880
55086
55087             context.features().forceVisible(relatedEntities);
55088             context.map().pan([0, 0]); // trigger a redraw
55089           }
55090
55091           keepRightDetails.issue = function (val) {
55092             if (!arguments.length) return _qaItem;
55093             _qaItem = val;
55094             return keepRightDetails;
55095           };
55096
55097           return keepRightDetails;
55098         }
55099
55100         function uiKeepRightHeader() {
55101           var _qaItem;
55102
55103           function issueTitle(d) {
55104             var itemType = d.itemType,
55105                 parentIssueType = d.parentIssueType;
55106             var unknown = _t.html('inspector.unknown');
55107             var replacements = d.replacements || {};
55108             replacements["default"] = unknown; // special key `default` works as a fallback string
55109
55110             var title = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
55111
55112             if (title === unknown) {
55113               title = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
55114             }
55115
55116             return title;
55117           }
55118
55119           function keepRightHeader(selection) {
55120             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
55121               return "".concat(d.id, "-").concat(d.status || 0);
55122             });
55123             header.exit().remove();
55124             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
55125             var iconEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
55126               return d.id < 0;
55127             });
55128             iconEnter.append('div').attr('class', function (d) {
55129               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
55130             }).call(svgIcon('#iD-icon-bolt', 'qaItem-fill'));
55131             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
55132           }
55133
55134           keepRightHeader.issue = function (val) {
55135             if (!arguments.length) return _qaItem;
55136             _qaItem = val;
55137             return keepRightHeader;
55138           };
55139
55140           return keepRightHeader;
55141         }
55142
55143         function uiViewOnKeepRight() {
55144           var _qaItem;
55145
55146           function viewOnKeepRight(selection) {
55147             var url;
55148
55149             if (services.keepRight && _qaItem instanceof QAItem) {
55150               url = services.keepRight.issueURL(_qaItem);
55151             }
55152
55153             var link = selection.selectAll('.view-on-keepRight').data(url ? [url] : []); // exit
55154
55155             link.exit().remove(); // enter
55156
55157             var linkEnter = link.enter().append('a').attr('class', 'view-on-keepRight').attr('target', '_blank').attr('rel', 'noopener') // security measure
55158             .attr('href', function (d) {
55159               return d;
55160             }).call(svgIcon('#iD-icon-out-link', 'inline'));
55161             linkEnter.append('span').html(_t.html('inspector.view_on_keepRight'));
55162           }
55163
55164           viewOnKeepRight.what = function (val) {
55165             if (!arguments.length) return _qaItem;
55166             _qaItem = val;
55167             return viewOnKeepRight;
55168           };
55169
55170           return viewOnKeepRight;
55171         }
55172
55173         function uiKeepRightEditor(context) {
55174           var dispatch$1 = dispatch('change');
55175           var qaDetails = uiKeepRightDetails(context);
55176           var qaHeader = uiKeepRightHeader();
55177
55178           var _qaItem;
55179
55180           function keepRightEditor(selection) {
55181             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
55182             headerEnter.append('button').attr('class', 'close').on('click', function () {
55183               return context.enter(modeBrowse(context));
55184             }).call(svgIcon('#iD-icon-close'));
55185             headerEnter.append('h3').html(_t.html('QA.keepRight.title'));
55186             var body = selection.selectAll('.body').data([0]);
55187             body = body.enter().append('div').attr('class', 'body').merge(body);
55188             var editor = body.selectAll('.qa-editor').data([0]);
55189             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
55190             var footer = selection.selectAll('.footer').data([0]);
55191             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnKeepRight().what(_qaItem));
55192           }
55193
55194           function keepRightSaveSection(selection) {
55195             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55196
55197             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
55198             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
55199               return "".concat(d.id, "-").concat(d.status || 0);
55200             }); // exit
55201
55202             saveSection.exit().remove(); // enter
55203
55204             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
55205             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('QA.keepRight.comment'));
55206             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
55207               return d.newComment || d.comment;
55208             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
55209
55210             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
55211
55212             function changeInput() {
55213               var input = select(this);
55214               var val = input.property('value').trim();
55215
55216               if (val === _qaItem.comment) {
55217                 val = undefined;
55218               } // store the unsaved comment with the issue itself
55219
55220
55221               _qaItem = _qaItem.update({
55222                 newComment: val
55223               });
55224               var qaService = services.keepRight;
55225
55226               if (qaService) {
55227                 qaService.replaceItem(_qaItem); // update keepright cache
55228               }
55229
55230               saveSection.call(qaSaveButtons);
55231             }
55232           }
55233
55234           function qaSaveButtons(selection) {
55235             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55236
55237             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
55238               return d.status + d.id;
55239             }); // exit
55240
55241             buttonSection.exit().remove(); // enter
55242
55243             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55244             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
55245             buttonEnter.append('button').attr('class', 'button close-button action');
55246             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55247
55248             buttonSection = buttonSection.merge(buttonEnter);
55249             buttonSection.select('.comment-button') // select and propagate data
55250             .attr('disabled', function (d) {
55251               return d.newComment ? null : true;
55252             }).on('click.comment', function (d3_event, d) {
55253               this.blur(); // avoid keeping focus on the button - #4641
55254
55255               var qaService = services.keepRight;
55256
55257               if (qaService) {
55258                 qaService.postUpdate(d, function (err, item) {
55259                   return dispatch$1.call('change', item);
55260                 });
55261               }
55262             });
55263             buttonSection.select('.close-button') // select and propagate data
55264             .html(function (d) {
55265               var andComment = d.newComment ? '_comment' : '';
55266               return _t.html("QA.keepRight.close".concat(andComment));
55267             }).on('click.close', function (d3_event, d) {
55268               this.blur(); // avoid keeping focus on the button - #4641
55269
55270               var qaService = services.keepRight;
55271
55272               if (qaService) {
55273                 d.newStatus = 'ignore_t'; // ignore temporarily (item fixed)
55274
55275                 qaService.postUpdate(d, function (err, item) {
55276                   return dispatch$1.call('change', item);
55277                 });
55278               }
55279             });
55280             buttonSection.select('.ignore-button') // select and propagate data
55281             .html(function (d) {
55282               var andComment = d.newComment ? '_comment' : '';
55283               return _t.html("QA.keepRight.ignore".concat(andComment));
55284             }).on('click.ignore', function (d3_event, d) {
55285               this.blur(); // avoid keeping focus on the button - #4641
55286
55287               var qaService = services.keepRight;
55288
55289               if (qaService) {
55290                 d.newStatus = 'ignore'; // ignore permanently (false positive)
55291
55292                 qaService.postUpdate(d, function (err, item) {
55293                   return dispatch$1.call('change', item);
55294                 });
55295               }
55296             });
55297           } // NOTE: Don't change method name until UI v3 is merged
55298
55299
55300           keepRightEditor.error = function (val) {
55301             if (!arguments.length) return _qaItem;
55302             _qaItem = val;
55303             return keepRightEditor;
55304           };
55305
55306           return utilRebind(keepRightEditor, dispatch$1, 'on');
55307         }
55308
55309         function uiOsmoseDetails(context) {
55310           var _qaItem;
55311
55312           function issueString(d, type) {
55313             if (!d) return ''; // Issue strings are cached from Osmose API
55314
55315             var s = services.osmose.getStrings(d.itemType);
55316             return type in s ? s[type] : '';
55317           }
55318
55319           function osmoseDetails(selection) {
55320             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
55321               return "".concat(d.id, "-").concat(d.status || 0);
55322             });
55323             details.exit().remove();
55324             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // Description
55325
55326             if (issueString(_qaItem, 'detail')) {
55327               var div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55328               div.append('h4').html(_t.html('QA.keepRight.detail_description'));
55329               div.append('p').attr('class', 'qa-details-description-text').html(function (d) {
55330                 return issueString(d, 'detail');
55331               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55332             } // Elements (populated later as data is requested)
55333
55334
55335             var detailsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55336             var elemsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection'); // Suggested Fix (mustn't exist for every issue type)
55337
55338             if (issueString(_qaItem, 'fix')) {
55339               var _div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55340
55341               _div.append('h4').html(_t.html('QA.osmose.fix_title'));
55342
55343               _div.append('p').html(function (d) {
55344                 return issueString(d, 'fix');
55345               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55346             } // Common Pitfalls (mustn't exist for every issue type)
55347
55348
55349             if (issueString(_qaItem, 'trap')) {
55350               var _div2 = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55351
55352               _div2.append('h4').html(_t.html('QA.osmose.trap_title'));
55353
55354               _div2.append('p').html(function (d) {
55355                 return issueString(d, 'trap');
55356               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55357             } // Save current item to check if UI changed by time request resolves
55358
55359
55360             var thisItem = _qaItem;
55361             services.osmose.loadIssueDetail(_qaItem).then(function (d) {
55362               // No details to add if there are no associated issue elements
55363               if (!d.elems || d.elems.length === 0) return; // Do nothing if UI has moved on by the time this resolves
55364
55365               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
55366
55367               if (d.detail) {
55368                 detailsDiv.append('h4').html(_t.html('QA.osmose.detail_title'));
55369                 detailsDiv.append('p').html(function (d) {
55370                   return d.detail;
55371                 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55372               } // Create list of linked issue elements
55373
55374
55375               elemsDiv.append('h4').html(_t.html('QA.osmose.elems_title'));
55376               elemsDiv.append('ul').selectAll('li').data(d.elems).enter().append('li').append('a').attr('href', '#').attr('class', 'error_entity_link').html(function (d) {
55377                 return d;
55378               }).each(function () {
55379                 var link = select(this);
55380                 var entityID = this.textContent;
55381                 var entity = context.hasEntity(entityID); // Add click handler
55382
55383                 link.on('mouseenter', function () {
55384                   utilHighlightEntities([entityID], true, context);
55385                 }).on('mouseleave', function () {
55386                   utilHighlightEntities([entityID], false, context);
55387                 }).on('click', function (d3_event) {
55388                   d3_event.preventDefault();
55389                   utilHighlightEntities([entityID], false, context);
55390                   var osmlayer = context.layers().layer('osm');
55391
55392                   if (!osmlayer.enabled()) {
55393                     osmlayer.enabled(true);
55394                   }
55395
55396                   context.map().centerZoom(d.loc, 20);
55397
55398                   if (entity) {
55399                     context.enter(modeSelect(context, [entityID]));
55400                   } else {
55401                     context.loadEntity(entityID, function () {
55402                       context.enter(modeSelect(context, [entityID]));
55403                     });
55404                   }
55405                 }); // Replace with friendly name if possible
55406                 // (The entity may not yet be loaded into the graph)
55407
55408                 if (entity) {
55409                   var name = utilDisplayName(entity); // try to use common name
55410
55411                   if (!name) {
55412                     var preset = _mainPresetIndex.match(entity, context.graph());
55413                     name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
55414                   }
55415
55416                   if (name) {
55417                     this.innerText = name;
55418                   }
55419                 }
55420               }); // Don't hide entities related to this issue - #5880
55421
55422               context.features().forceVisible(d.elems);
55423               context.map().pan([0, 0]); // trigger a redraw
55424             })["catch"](function (err) {
55425               console.log(err); // eslint-disable-line no-console
55426             });
55427           }
55428
55429           osmoseDetails.issue = function (val) {
55430             if (!arguments.length) return _qaItem;
55431             _qaItem = val;
55432             return osmoseDetails;
55433           };
55434
55435           return osmoseDetails;
55436         }
55437
55438         function uiOsmoseHeader() {
55439           var _qaItem;
55440
55441           function issueTitle(d) {
55442             var unknown = _t('inspector.unknown');
55443             if (!d) return unknown; // Issue titles supplied by Osmose
55444
55445             var s = services.osmose.getStrings(d.itemType);
55446             return 'title' in s ? s.title : unknown;
55447           }
55448
55449           function osmoseHeader(selection) {
55450             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
55451               return "".concat(d.id, "-").concat(d.status || 0);
55452             });
55453             header.exit().remove();
55454             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
55455             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
55456               return d.id < 0;
55457             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
55458               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
55459             });
55460             svgEnter.append('polygon').attr('fill', function (d) {
55461               return services.osmose.getColor(d.item);
55462             }).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');
55463             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
55464               var picon = d.icon;
55465
55466               if (!picon) {
55467                 return '';
55468               } else {
55469                 var isMaki = /^maki-/.test(picon);
55470                 return "#".concat(picon).concat(isMaki ? '-11' : '');
55471               }
55472             });
55473             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
55474           }
55475
55476           osmoseHeader.issue = function (val) {
55477             if (!arguments.length) return _qaItem;
55478             _qaItem = val;
55479             return osmoseHeader;
55480           };
55481
55482           return osmoseHeader;
55483         }
55484
55485         function uiViewOnOsmose() {
55486           var _qaItem;
55487
55488           function viewOnOsmose(selection) {
55489             var url;
55490
55491             if (services.osmose && _qaItem instanceof QAItem) {
55492               url = services.osmose.itemURL(_qaItem);
55493             }
55494
55495             var link = selection.selectAll('.view-on-osmose').data(url ? [url] : []); // exit
55496
55497             link.exit().remove(); // enter
55498
55499             var linkEnter = link.enter().append('a').attr('class', 'view-on-osmose').attr('target', '_blank').attr('rel', 'noopener') // security measure
55500             .attr('href', function (d) {
55501               return d;
55502             }).call(svgIcon('#iD-icon-out-link', 'inline'));
55503             linkEnter.append('span').html(_t.html('inspector.view_on_osmose'));
55504           }
55505
55506           viewOnOsmose.what = function (val) {
55507             if (!arguments.length) return _qaItem;
55508             _qaItem = val;
55509             return viewOnOsmose;
55510           };
55511
55512           return viewOnOsmose;
55513         }
55514
55515         function uiOsmoseEditor(context) {
55516           var dispatch$1 = dispatch('change');
55517           var qaDetails = uiOsmoseDetails(context);
55518           var qaHeader = uiOsmoseHeader();
55519
55520           var _qaItem;
55521
55522           function osmoseEditor(selection) {
55523             var header = selection.selectAll('.header').data([0]);
55524             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
55525             headerEnter.append('button').attr('class', 'close').on('click', function () {
55526               return context.enter(modeBrowse(context));
55527             }).call(svgIcon('#iD-icon-close'));
55528             headerEnter.append('h3').html(_t.html('QA.osmose.title'));
55529             var body = selection.selectAll('.body').data([0]);
55530             body = body.enter().append('div').attr('class', 'body').merge(body);
55531             var editor = body.selectAll('.qa-editor').data([0]);
55532             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
55533             var footer = selection.selectAll('.footer').data([0]);
55534             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOsmose().what(_qaItem));
55535           }
55536
55537           function osmoseSaveSection(selection) {
55538             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55539
55540             var isShown = _qaItem && isSelected;
55541             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
55542               return "".concat(d.id, "-").concat(d.status || 0);
55543             }); // exit
55544
55545             saveSection.exit().remove(); // enter
55546
55547             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf'); // update
55548
55549             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
55550           }
55551
55552           function qaSaveButtons(selection) {
55553             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55554
55555             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
55556               return d.status + d.id;
55557             }); // exit
55558
55559             buttonSection.exit().remove(); // enter
55560
55561             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55562             buttonEnter.append('button').attr('class', 'button close-button action');
55563             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55564
55565             buttonSection = buttonSection.merge(buttonEnter);
55566             buttonSection.select('.close-button').html(_t.html('QA.keepRight.close')).on('click.close', function (d3_event, d) {
55567               this.blur(); // avoid keeping focus on the button - #4641
55568
55569               var qaService = services.osmose;
55570
55571               if (qaService) {
55572                 d.newStatus = 'done';
55573                 qaService.postUpdate(d, function (err, item) {
55574                   return dispatch$1.call('change', item);
55575                 });
55576               }
55577             });
55578             buttonSection.select('.ignore-button').html(_t.html('QA.keepRight.ignore')).on('click.ignore', function (d3_event, d) {
55579               this.blur(); // avoid keeping focus on the button - #4641
55580
55581               var qaService = services.osmose;
55582
55583               if (qaService) {
55584                 d.newStatus = 'false';
55585                 qaService.postUpdate(d, function (err, item) {
55586                   return dispatch$1.call('change', item);
55587                 });
55588               }
55589             });
55590           } // NOTE: Don't change method name until UI v3 is merged
55591
55592
55593           osmoseEditor.error = function (val) {
55594             if (!arguments.length) return _qaItem;
55595             _qaItem = val;
55596             return osmoseEditor;
55597           };
55598
55599           return utilRebind(osmoseEditor, dispatch$1, 'on');
55600         }
55601
55602         function modeSelectError(context, selectedErrorID, selectedErrorService) {
55603           var mode = {
55604             id: 'select-error',
55605             button: 'browse'
55606           };
55607           var keybinding = utilKeybinding('select-error');
55608           var errorService = services[selectedErrorService];
55609           var errorEditor;
55610
55611           switch (selectedErrorService) {
55612             case 'improveOSM':
55613               errorEditor = uiImproveOsmEditor(context).on('change', function () {
55614                 context.map().pan([0, 0]); // trigger a redraw
55615
55616                 var error = checkSelectedID();
55617                 if (!error) return;
55618                 context.ui().sidebar.show(errorEditor.error(error));
55619               });
55620               break;
55621
55622             case 'keepRight':
55623               errorEditor = uiKeepRightEditor(context).on('change', function () {
55624                 context.map().pan([0, 0]); // trigger a redraw
55625
55626                 var error = checkSelectedID();
55627                 if (!error) return;
55628                 context.ui().sidebar.show(errorEditor.error(error));
55629               });
55630               break;
55631
55632             case 'osmose':
55633               errorEditor = uiOsmoseEditor(context).on('change', function () {
55634                 context.map().pan([0, 0]); // trigger a redraw
55635
55636                 var error = checkSelectedID();
55637                 if (!error) return;
55638                 context.ui().sidebar.show(errorEditor.error(error));
55639               });
55640               break;
55641           }
55642
55643           var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
55644
55645           function checkSelectedID() {
55646             if (!errorService) return;
55647             var error = errorService.getError(selectedErrorID);
55648
55649             if (!error) {
55650               context.enter(modeBrowse(context));
55651             }
55652
55653             return error;
55654           }
55655
55656           mode.zoomToSelected = function () {
55657             if (!errorService) return;
55658             var error = errorService.getError(selectedErrorID);
55659
55660             if (error) {
55661               context.map().centerZoomEase(error.loc, 20);
55662             }
55663           };
55664
55665           mode.enter = function () {
55666             var error = checkSelectedID();
55667             if (!error) return;
55668             behaviors.forEach(context.install);
55669             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
55670             select(document).call(keybinding);
55671             selectError();
55672             var sidebar = context.ui().sidebar;
55673             sidebar.show(errorEditor.error(error));
55674             context.map().on('drawn.select-error', selectError); // class the error as selected, or return to browse mode if the error is gone
55675
55676             function selectError(d3_event, drawn) {
55677               if (!checkSelectedID()) return;
55678               var selection = context.surface().selectAll('.itemId-' + selectedErrorID + '.' + selectedErrorService);
55679
55680               if (selection.empty()) {
55681                 // Return to browse mode if selected DOM elements have
55682                 // disappeared because the user moved them out of view..
55683                 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
55684
55685                 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
55686                   context.enter(modeBrowse(context));
55687                 }
55688               } else {
55689                 selection.classed('selected', true);
55690                 context.selectedErrorID(selectedErrorID);
55691               }
55692             }
55693
55694             function esc() {
55695               if (context.container().select('.combobox').size()) return;
55696               context.enter(modeBrowse(context));
55697             }
55698           };
55699
55700           mode.exit = function () {
55701             behaviors.forEach(context.uninstall);
55702             select(document).call(keybinding.unbind);
55703             context.surface().selectAll('.qaItem.selected').classed('selected hover', false);
55704             context.map().on('drawn.select-error', null);
55705             context.ui().sidebar.hide();
55706             context.selectedErrorID(null);
55707             context.features().forceVisible([]);
55708           };
55709
55710           return mode;
55711         }
55712
55713         function behaviorSelect(context) {
55714           var _tolerancePx = 4; // see also behaviorDrag
55715
55716           var _lastMouseEvent = null;
55717           var _showMenu = false;
55718           var _downPointers = {};
55719           var _longPressTimeout = null;
55720           var _lastInteractionType = null; // the id of the down pointer that's enabling multiselection while down
55721
55722           var _multiselectionPointerId = null; // use pointer events on supported platforms; fallback to mouse events
55723
55724           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
55725
55726           function keydown(d3_event) {
55727             if (d3_event.keyCode === 32) {
55728               // don't react to spacebar events during text input
55729               var activeNode = document.activeElement;
55730               if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
55731             }
55732
55733             if (d3_event.keyCode === 93 || // context menu key
55734             d3_event.keyCode === 32) {
55735               // spacebar
55736               d3_event.preventDefault();
55737             }
55738
55739             if (d3_event.repeat) return; // ignore repeated events for held keys
55740             // if any key is pressed the user is probably doing something other than long-pressing
55741
55742             cancelLongPress();
55743
55744             if (d3_event.shiftKey) {
55745               context.surface().classed('behavior-multiselect', true);
55746             }
55747
55748             if (d3_event.keyCode === 32) {
55749               // spacebar
55750               if (!_downPointers.spacebar && _lastMouseEvent) {
55751                 cancelLongPress();
55752                 _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar', 'spacebar');
55753                 _downPointers.spacebar = {
55754                   firstEvent: _lastMouseEvent,
55755                   lastEvent: _lastMouseEvent
55756                 };
55757               }
55758             }
55759           }
55760
55761           function keyup(d3_event) {
55762             cancelLongPress();
55763
55764             if (!d3_event.shiftKey) {
55765               context.surface().classed('behavior-multiselect', false);
55766             }
55767
55768             if (d3_event.keyCode === 93) {
55769               // context menu key
55770               d3_event.preventDefault();
55771               _lastInteractionType = 'menukey';
55772               contextmenu(d3_event);
55773             } else if (d3_event.keyCode === 32) {
55774               // spacebar
55775               var pointer = _downPointers.spacebar;
55776
55777               if (pointer) {
55778                 delete _downPointers.spacebar;
55779                 if (pointer.done) return;
55780                 d3_event.preventDefault();
55781                 _lastInteractionType = 'spacebar';
55782                 click(pointer.firstEvent, pointer.lastEvent, 'spacebar');
55783               }
55784             }
55785           }
55786
55787           function pointerdown(d3_event) {
55788             var id = (d3_event.pointerId || 'mouse').toString();
55789             cancelLongPress();
55790             if (d3_event.buttons && d3_event.buttons !== 1) return;
55791             context.ui().closeEditMenu();
55792             _longPressTimeout = window.setTimeout(didLongPress, 500, id, 'longdown-' + (d3_event.pointerType || 'mouse'));
55793             _downPointers[id] = {
55794               firstEvent: d3_event,
55795               lastEvent: d3_event
55796             };
55797           }
55798
55799           function didLongPress(id, interactionType) {
55800             var pointer = _downPointers[id];
55801             if (!pointer) return;
55802
55803             for (var i in _downPointers) {
55804               // don't allow this or any currently down pointer to trigger another click
55805               _downPointers[i].done = true;
55806             } // treat long presses like right-clicks
55807
55808
55809             _longPressTimeout = null;
55810             _lastInteractionType = interactionType;
55811             _showMenu = true;
55812             click(pointer.firstEvent, pointer.lastEvent, id);
55813           }
55814
55815           function pointermove(d3_event) {
55816             var id = (d3_event.pointerId || 'mouse').toString();
55817
55818             if (_downPointers[id]) {
55819               _downPointers[id].lastEvent = d3_event;
55820             }
55821
55822             if (!d3_event.pointerType || d3_event.pointerType === 'mouse') {
55823               _lastMouseEvent = d3_event;
55824
55825               if (_downPointers.spacebar) {
55826                 _downPointers.spacebar.lastEvent = d3_event;
55827               }
55828             }
55829           }
55830
55831           function pointerup(d3_event) {
55832             var id = (d3_event.pointerId || 'mouse').toString();
55833             var pointer = _downPointers[id];
55834             if (!pointer) return;
55835             delete _downPointers[id];
55836
55837             if (_multiselectionPointerId === id) {
55838               _multiselectionPointerId = null;
55839             }
55840
55841             if (pointer.done) return;
55842             click(pointer.firstEvent, d3_event, id);
55843           }
55844
55845           function pointercancel(d3_event) {
55846             var id = (d3_event.pointerId || 'mouse').toString();
55847             if (!_downPointers[id]) return;
55848             delete _downPointers[id];
55849
55850             if (_multiselectionPointerId === id) {
55851               _multiselectionPointerId = null;
55852             }
55853           }
55854
55855           function contextmenu(d3_event) {
55856             d3_event.preventDefault();
55857
55858             if (!+d3_event.clientX && !+d3_event.clientY) {
55859               if (_lastMouseEvent) {
55860                 d3_event.sourceEvent = _lastMouseEvent;
55861               } else {
55862                 return;
55863               }
55864             } else {
55865               _lastMouseEvent = d3_event;
55866               _lastInteractionType = 'rightclick';
55867             }
55868
55869             _showMenu = true;
55870             click(d3_event, d3_event);
55871           }
55872
55873           function click(firstEvent, lastEvent, pointerId) {
55874             cancelLongPress();
55875             var mapNode = context.container().select('.main-map').node(); // Use the `main-map` coordinate system since the surface and supersurface
55876             // are transformed when drag-panning.
55877
55878             var pointGetter = utilFastMouse(mapNode);
55879             var p1 = pointGetter(firstEvent);
55880             var p2 = pointGetter(lastEvent);
55881             var dist = geoVecLength(p1, p2);
55882
55883             if (dist > _tolerancePx || !mapContains(lastEvent)) {
55884               resetProperties();
55885               return;
55886             }
55887
55888             var targetDatum = lastEvent.target.__data__;
55889             var multiselectEntityId;
55890
55891             if (!_multiselectionPointerId) {
55892               // If a different pointer than the one triggering this click is down on a
55893               // feature, treat this and all future clicks as multiselection until that
55894               // pointer is raised.
55895               var selectPointerInfo = pointerDownOnSelection(pointerId);
55896
55897               if (selectPointerInfo) {
55898                 _multiselectionPointerId = selectPointerInfo.pointerId; // if the other feature isn't selected yet, make sure we select it
55899
55900                 multiselectEntityId = !selectPointerInfo.selected && selectPointerInfo.entityId;
55901                 _downPointers[selectPointerInfo.pointerId].done = true;
55902               }
55903             } // support multiselect if data is already selected
55904
55905
55906             var isMultiselect = context.mode().id === 'select' && ( // and shift key is down
55907             lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
55908             context.surface().select('.lasso').node() || // or a pointer is down over a selected feature
55909             _multiselectionPointerId && !multiselectEntityId);
55910
55911             processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
55912
55913             function mapContains(event) {
55914               var rect = mapNode.getBoundingClientRect();
55915               return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
55916             }
55917
55918             function pointerDownOnSelection(skipPointerId) {
55919               var mode = context.mode();
55920               var selectedIDs = mode.id === 'select' ? mode.selectedIDs() : [];
55921
55922               for (var pointerId in _downPointers) {
55923                 if (pointerId === 'spacebar' || pointerId === skipPointerId) continue;
55924                 var pointerInfo = _downPointers[pointerId];
55925                 var p1 = pointGetter(pointerInfo.firstEvent);
55926                 var p2 = pointGetter(pointerInfo.lastEvent);
55927                 if (geoVecLength(p1, p2) > _tolerancePx) continue;
55928                 var datum = pointerInfo.firstEvent.target.__data__;
55929                 var entity = datum && datum.properties && datum.properties.entity || datum;
55930                 if (context.graph().hasEntity(entity.id)) return {
55931                   pointerId: pointerId,
55932                   entityId: entity.id,
55933                   selected: selectedIDs.indexOf(entity.id) !== -1
55934                 };
55935               }
55936
55937               return null;
55938             }
55939           }
55940
55941           function processClick(datum, isMultiselect, point, alsoSelectId) {
55942             var mode = context.mode();
55943             var showMenu = _showMenu;
55944             var interactionType = _lastInteractionType;
55945             var entity = datum && datum.properties && datum.properties.entity;
55946             if (entity) datum = entity;
55947
55948             if (datum && datum.type === 'midpoint') {
55949               // treat targeting midpoints as if targeting the parent way
55950               datum = datum.parents[0];
55951             }
55952
55953             var newMode;
55954
55955             if (datum instanceof osmEntity) {
55956               // targeting an entity
55957               var selectedIDs = context.selectedIDs();
55958               context.selectedNoteID(null);
55959               context.selectedErrorID(null);
55960
55961               if (!isMultiselect) {
55962                 // don't change the selection if we're toggling the menu atop a multiselection
55963                 if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum.id) === -1) {
55964                   if (alsoSelectId === datum.id) alsoSelectId = null;
55965                   selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum.id]); // always enter modeSelect even if the entity is already
55966                   // selected since listeners may expect `context.enter` events,
55967                   // e.g. in the walkthrough
55968
55969                   newMode = mode.id === 'select' ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
55970                   context.enter(newMode);
55971                 }
55972               } else {
55973                 if (selectedIDs.indexOf(datum.id) !== -1) {
55974                   // clicked entity is already in the selectedIDs list..
55975                   if (!showMenu) {
55976                     // deselect clicked entity, then reenter select mode or return to browse mode..
55977                     selectedIDs = selectedIDs.filter(function (id) {
55978                       return id !== datum.id;
55979                     });
55980                     newMode = selectedIDs.length ? mode.selectedIDs(selectedIDs) : modeBrowse(context).selectBehavior(behavior);
55981                     context.enter(newMode);
55982                   }
55983                 } else {
55984                   // clicked entity is not in the selected list, add it..
55985                   selectedIDs = selectedIDs.concat([datum.id]);
55986                   newMode = mode.selectedIDs(selectedIDs);
55987                   context.enter(newMode);
55988                 }
55989               }
55990             } else if (datum && datum.__featurehash__ && !isMultiselect) {
55991               // targeting custom data
55992               context.selectedNoteID(null).enter(modeSelectData(context, datum));
55993             } else if (datum instanceof osmNote && !isMultiselect) {
55994               // targeting a note
55995               context.selectedNoteID(datum.id).enter(modeSelectNote(context, datum.id));
55996             } else if (datum instanceof QAItem & !isMultiselect) {
55997               // targeting an external QA issue
55998               context.selectedErrorID(datum.id).enter(modeSelectError(context, datum.id, datum.service));
55999             } else {
56000               // targeting nothing
56001               context.selectedNoteID(null);
56002               context.selectedErrorID(null);
56003
56004               if (!isMultiselect && mode.id !== 'browse') {
56005                 context.enter(modeBrowse(context));
56006               }
56007             }
56008
56009             context.ui().closeEditMenu(); // always request to show the edit menu in case the mode needs it
56010
56011             if (showMenu) context.ui().showEditMenu(point, interactionType);
56012             resetProperties();
56013           }
56014
56015           function cancelLongPress() {
56016             if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
56017             _longPressTimeout = null;
56018           }
56019
56020           function resetProperties() {
56021             cancelLongPress();
56022             _showMenu = false;
56023             _lastInteractionType = null; // don't reset _lastMouseEvent since it might still be useful
56024           }
56025
56026           function behavior(selection) {
56027             resetProperties();
56028             _lastMouseEvent = context.map().lastPointerEvent();
56029             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) {
56030               // Edge and IE really like to show the contextmenu on the
56031               // menubar when user presses a keyboard menu button
56032               // even after we've already preventdefaulted the key event.
56033               var e = d3_event;
56034
56035               if (+e.clientX === 0 && +e.clientY === 0) {
56036                 d3_event.preventDefault();
56037               }
56038             });
56039             selection.on(_pointerPrefix + 'down.select', pointerdown).on('contextmenu.select', contextmenu);
56040             /*if (d3_event && d3_event.shiftKey) {
56041                 context.surface()
56042                     .classed('behavior-multiselect', true);
56043             }*/
56044           }
56045
56046           behavior.off = function (selection) {
56047             cancelLongPress();
56048             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);
56049             selection.on(_pointerPrefix + 'down.select', null).on('contextmenu.select', null);
56050             context.surface().classed('behavior-multiselect', false);
56051           };
56052
56053           return behavior;
56054         }
56055
56056         function behaviorDrawWay(context, wayID, mode, startGraph) {
56057           var dispatch$1 = dispatch('rejectedSelfIntersection');
56058           var behavior = behaviorDraw(context); // Must be set by `drawWay.nodeIndex` before each install of this behavior.
56059
56060           var _nodeIndex;
56061
56062           var _origWay;
56063
56064           var _wayGeometry;
56065
56066           var _headNodeID;
56067
56068           var _annotation;
56069
56070           var _pointerHasMoved = false; // The osmNode to be placed.
56071           // This is temporary and just follows the mouse cursor until an "add" event occurs.
56072
56073           var _drawNode;
56074
56075           var _didResolveTempEdit = false;
56076
56077           function createDrawNode(loc) {
56078             // don't make the draw node until we actually need it
56079             _drawNode = osmNode({
56080               loc: loc
56081             });
56082             context.pauseChangeDispatch();
56083             context.replace(function actionAddDrawNode(graph) {
56084               // add the draw node to the graph and insert it into the way
56085               var way = graph.entity(wayID);
56086               return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
56087             }, _annotation);
56088             context.resumeChangeDispatch();
56089             setActiveElements();
56090           }
56091
56092           function removeDrawNode() {
56093             context.pauseChangeDispatch();
56094             context.replace(function actionDeleteDrawNode(graph) {
56095               var way = graph.entity(wayID);
56096               return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
56097             }, _annotation);
56098             _drawNode = undefined;
56099             context.resumeChangeDispatch();
56100           }
56101
56102           function keydown(d3_event) {
56103             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56104               if (context.surface().classed('nope')) {
56105                 context.surface().classed('nope-suppressed', true);
56106               }
56107
56108               context.surface().classed('nope', false).classed('nope-disabled', true);
56109             }
56110           }
56111
56112           function keyup(d3_event) {
56113             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56114               if (context.surface().classed('nope-suppressed')) {
56115                 context.surface().classed('nope', true);
56116               }
56117
56118               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
56119             }
56120           }
56121
56122           function allowsVertex(d) {
56123             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
56124           } // related code
56125           // - `mode/drag_node.js`     `doMove()`
56126           // - `behavior/draw.js`      `click()`
56127           // - `behavior/draw_way.js`  `move()`
56128
56129
56130           function move(d3_event, datum) {
56131             var loc = context.map().mouseCoordinates();
56132             if (!_drawNode) createDrawNode(loc);
56133             context.surface().classed('nope-disabled', d3_event.altKey);
56134             var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
56135             var targetNodes = datum && datum.properties && datum.properties.nodes;
56136
56137             if (targetLoc) {
56138               // snap to node/vertex - a point target with `.loc`
56139               loc = targetLoc;
56140             } else if (targetNodes) {
56141               // snap to way - a line target with `.nodes`
56142               var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
56143
56144               if (choice) {
56145                 loc = choice.loc;
56146               }
56147             }
56148
56149             context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56150             _drawNode = context.entity(_drawNode.id);
56151             checkGeometry(true
56152             /* includeDrawNode */
56153             );
56154           } // Check whether this edit causes the geometry to break.
56155           // If so, class the surface with a nope cursor.
56156           // `includeDrawNode` - Only check the relevant line segments if finishing drawing
56157
56158
56159           function checkGeometry(includeDrawNode) {
56160             var nopeDisabled = context.surface().classed('nope-disabled');
56161             var isInvalid = isInvalidGeometry(includeDrawNode);
56162
56163             if (nopeDisabled) {
56164               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
56165             } else {
56166               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
56167             }
56168           }
56169
56170           function isInvalidGeometry(includeDrawNode) {
56171             var testNode = _drawNode; // we only need to test the single way we're drawing
56172
56173             var parentWay = context.graph().entity(wayID);
56174             var nodes = context.graph().childNodes(parentWay).slice(); // shallow copy
56175
56176             if (includeDrawNode) {
56177               if (parentWay.isClosed()) {
56178                 // don't test the last segment for closed ways - #4655
56179                 // (still test the first segment)
56180                 nodes.pop();
56181               }
56182             } else {
56183               // discount the draw node
56184               if (parentWay.isClosed()) {
56185                 if (nodes.length < 3) return false;
56186                 if (_drawNode) nodes.splice(-2, 1);
56187                 testNode = nodes[nodes.length - 2];
56188               } else {
56189                 // there's nothing we need to test if we ignore the draw node on open ways
56190                 return false;
56191               }
56192             }
56193
56194             return testNode && geoHasSelfIntersections(nodes, testNode.id);
56195           }
56196
56197           function undone() {
56198             // undoing removed the temp edit
56199             _didResolveTempEdit = true;
56200             context.pauseChangeDispatch();
56201             var nextMode;
56202
56203             if (context.graph() === startGraph) {
56204               // We've undone back to the initial state before we started drawing.
56205               // Just exit the draw mode without undoing whatever we did before
56206               // we entered the draw mode.
56207               nextMode = modeSelect(context, [wayID]);
56208             } else {
56209               // The `undo` only removed the temporary edit, so here we have to
56210               // manually undo to actually remove the last node we added. We can't
56211               // use the `undo` function since the initial "add" graph doesn't have
56212               // an annotation and so cannot be undone to.
56213               context.pop(1); // continue drawing
56214
56215               nextMode = mode;
56216             } // clear the redo stack by adding and removing a blank edit
56217
56218
56219             context.perform(actionNoop());
56220             context.pop(1);
56221             context.resumeChangeDispatch();
56222             context.enter(nextMode);
56223           }
56224
56225           function setActiveElements() {
56226             if (!_drawNode) return;
56227             context.surface().selectAll('.' + _drawNode.id).classed('active', true);
56228           }
56229
56230           function resetToStartGraph() {
56231             while (context.graph() !== startGraph) {
56232               context.pop();
56233             }
56234           }
56235
56236           var drawWay = function drawWay(surface) {
56237             _drawNode = undefined;
56238             _didResolveTempEdit = false;
56239             _origWay = context.entity(wayID);
56240             _headNodeID = typeof _nodeIndex === 'number' ? _origWay.nodes[_nodeIndex] : _origWay.isClosed() ? _origWay.nodes[_origWay.nodes.length - 2] : _origWay.nodes[_origWay.nodes.length - 1];
56241             _wayGeometry = _origWay.geometry(context.graph());
56242             _annotation = _t((_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? 'operations.start.annotation.' : 'operations.continue.annotation.') + _wayGeometry);
56243             _pointerHasMoved = false; // Push an annotated state for undo to return back to.
56244             // We must make sure to replace or remove it later.
56245
56246             context.pauseChangeDispatch();
56247             context.perform(actionNoop(), _annotation);
56248             context.resumeChangeDispatch();
56249             behavior.hover().initialNodeID(_headNodeID);
56250             behavior.on('move', function () {
56251               _pointerHasMoved = true;
56252               move.apply(this, arguments);
56253             }).on('down', function () {
56254               move.apply(this, arguments);
56255             }).on('downcancel', function () {
56256               if (_drawNode) removeDrawNode();
56257             }).on('click', drawWay.add).on('clickWay', drawWay.addWay).on('clickNode', drawWay.addNode).on('undo', context.undo).on('cancel', drawWay.cancel).on('finish', drawWay.finish);
56258             select(window).on('keydown.drawWay', keydown).on('keyup.drawWay', keyup);
56259             context.map().dblclickZoomEnable(false).on('drawn.draw', setActiveElements);
56260             setActiveElements();
56261             surface.call(behavior);
56262             context.history().on('undone.draw', undone);
56263           };
56264
56265           drawWay.off = function (surface) {
56266             if (!_didResolveTempEdit) {
56267               // Drawing was interrupted unexpectedly.
56268               // This can happen if the user changes modes,
56269               // clicks geolocate button, a hashchange event occurs, etc.
56270               context.pauseChangeDispatch();
56271               resetToStartGraph();
56272               context.resumeChangeDispatch();
56273             }
56274
56275             _drawNode = undefined;
56276             _nodeIndex = undefined;
56277             context.map().on('drawn.draw', null);
56278             surface.call(behavior.off).selectAll('.active').classed('active', false);
56279             surface.classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false);
56280             select(window).on('keydown.drawWay', null).on('keyup.drawWay', null);
56281             context.history().on('undone.draw', null);
56282           };
56283
56284           function attemptAdd(d, loc, doAdd) {
56285             if (_drawNode) {
56286               // move the node to the final loc in case move wasn't called
56287               // consistently (e.g. on touch devices)
56288               context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56289               _drawNode = context.entity(_drawNode.id);
56290             } else {
56291               createDrawNode(loc);
56292             }
56293
56294             checkGeometry(true
56295             /* includeDrawNode */
56296             );
56297
56298             if (d && d.properties && d.properties.nope || context.surface().classed('nope')) {
56299               if (!_pointerHasMoved) {
56300                 // prevent the temporary draw node from appearing on touch devices
56301                 removeDrawNode();
56302               }
56303
56304               dispatch$1.call('rejectedSelfIntersection', this);
56305               return; // can't click here
56306             }
56307
56308             context.pauseChangeDispatch();
56309             doAdd(); // we just replaced the temporary edit with the real one
56310
56311             _didResolveTempEdit = true;
56312             context.resumeChangeDispatch();
56313             context.enter(mode);
56314           } // Accept the current position of the drawing node
56315
56316
56317           drawWay.add = function (loc, d) {
56318             attemptAdd(d, loc, function () {// don't need to do anything extra
56319             });
56320           }; // Connect the way to an existing way
56321
56322
56323           drawWay.addWay = function (loc, edge, d) {
56324             attemptAdd(d, loc, function () {
56325               context.replace(actionAddMidpoint({
56326                 loc: loc,
56327                 edge: edge
56328               }, _drawNode), _annotation);
56329             });
56330           }; // Connect the way to an existing node
56331
56332
56333           drawWay.addNode = function (node, d) {
56334             // finish drawing if the mapper targets the prior node
56335             if (node.id === _headNodeID || // or the first node when drawing an area
56336             _origWay.isClosed() && node.id === _origWay.first()) {
56337               drawWay.finish();
56338               return;
56339             }
56340
56341             attemptAdd(d, node.loc, function () {
56342               context.replace(function actionReplaceDrawNode(graph) {
56343                 // remove the temporary draw node and insert the existing node
56344                 // at the same index
56345                 graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
56346                 return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
56347               }, _annotation);
56348             });
56349           }; // Finish the draw operation, removing the temporary edit.
56350           // If the way has enough nodes to be valid, it's selected.
56351           // Otherwise, delete everything and return to browse mode.
56352
56353
56354           drawWay.finish = function () {
56355             checkGeometry(false
56356             /* includeDrawNode */
56357             );
56358
56359             if (context.surface().classed('nope')) {
56360               dispatch$1.call('rejectedSelfIntersection', this);
56361               return; // can't click here
56362             }
56363
56364             context.pauseChangeDispatch(); // remove the temporary edit
56365
56366             context.pop(1);
56367             _didResolveTempEdit = true;
56368             context.resumeChangeDispatch();
56369             var way = context.hasEntity(wayID);
56370
56371             if (!way || way.isDegenerate()) {
56372               drawWay.cancel();
56373               return;
56374             }
56375
56376             window.setTimeout(function () {
56377               context.map().dblclickZoomEnable(true);
56378             }, 1000);
56379             var isNewFeature = !mode.isContinuing;
56380             context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
56381           }; // Cancel the draw operation, delete everything, and return to browse mode.
56382
56383
56384           drawWay.cancel = function () {
56385             context.pauseChangeDispatch();
56386             resetToStartGraph();
56387             context.resumeChangeDispatch();
56388             window.setTimeout(function () {
56389               context.map().dblclickZoomEnable(true);
56390             }, 1000);
56391             context.surface().classed('nope', false).classed('nope-disabled', false).classed('nope-suppressed', false);
56392             context.enter(modeBrowse(context));
56393           };
56394
56395           drawWay.nodeIndex = function (val) {
56396             if (!arguments.length) return _nodeIndex;
56397             _nodeIndex = val;
56398             return drawWay;
56399           };
56400
56401           drawWay.activeID = function () {
56402             if (!arguments.length) return _drawNode && _drawNode.id; // no assign
56403
56404             return drawWay;
56405           };
56406
56407           return utilRebind(drawWay, dispatch$1, 'on');
56408         }
56409
56410         function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
56411           var mode = {
56412             button: button,
56413             id: 'draw-line'
56414           };
56415           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawLine', function () {
56416             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.lines'))();
56417           });
56418           mode.wayID = wayID;
56419           mode.isContinuing = continuing;
56420
56421           mode.enter = function () {
56422             behavior.nodeIndex(affix === 'prefix' ? 0 : undefined);
56423             context.install(behavior);
56424           };
56425
56426           mode.exit = function () {
56427             context.uninstall(behavior);
56428           };
56429
56430           mode.selectedIDs = function () {
56431             return [wayID];
56432           };
56433
56434           mode.activeID = function () {
56435             return behavior && behavior.activeID() || [];
56436           };
56437
56438           return mode;
56439         }
56440
56441         function operationContinue(context, selectedIDs) {
56442           var _entities = selectedIDs.map(function (id) {
56443             return context.graph().entity(id);
56444           });
56445
56446           var _geometries = Object.assign({
56447             line: [],
56448             vertex: []
56449           }, utilArrayGroupBy(_entities, function (entity) {
56450             return entity.geometry(context.graph());
56451           }));
56452
56453           var _vertex = _geometries.vertex.length && _geometries.vertex[0];
56454
56455           function candidateWays() {
56456             return _vertex ? context.graph().parentWays(_vertex).filter(function (parent) {
56457               return parent.geometry(context.graph()) === 'line' && !parent.isClosed() && parent.affix(_vertex.id) && (_geometries.line.length === 0 || _geometries.line[0] === parent);
56458             }) : [];
56459           }
56460
56461           var _candidates = candidateWays();
56462
56463           var operation = function operation() {
56464             var candidate = _candidates[0];
56465             context.enter(modeDrawLine(context, candidate.id, context.graph(), 'line', candidate.affix(_vertex.id), true));
56466           };
56467
56468           operation.relatedEntityIds = function () {
56469             return _candidates.length ? [_candidates[0].id] : [];
56470           };
56471
56472           operation.available = function () {
56473             return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
56474           };
56475
56476           operation.disabled = function () {
56477             if (_candidates.length === 0) {
56478               return 'not_eligible';
56479             } else if (_candidates.length > 1) {
56480               return 'multiple';
56481             }
56482
56483             return false;
56484           };
56485
56486           operation.tooltip = function () {
56487             var disable = operation.disabled();
56488             return disable ? _t('operations.continue.' + disable) : _t('operations.continue.description');
56489           };
56490
56491           operation.annotation = function () {
56492             return _t('operations.continue.annotation.line');
56493           };
56494
56495           operation.id = 'continue';
56496           operation.keys = [_t('operations.continue.key')];
56497           operation.title = _t('operations.continue.title');
56498           operation.behavior = behaviorOperation(context).which(operation);
56499           return operation;
56500         }
56501
56502         function operationCopy(context, selectedIDs) {
56503           function getFilteredIdsToCopy() {
56504             return selectedIDs.filter(function (selectedID) {
56505               var entity = context.graph().hasEntity(selectedID); // don't copy untagged vertices separately from ways
56506
56507               return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
56508             });
56509           }
56510
56511           var operation = function operation() {
56512             var graph = context.graph();
56513             var selected = groupEntities(getFilteredIdsToCopy(), graph);
56514             var canCopy = [];
56515             var skip = {};
56516             var entity;
56517             var i;
56518
56519             for (i = 0; i < selected.relation.length; i++) {
56520               entity = selected.relation[i];
56521
56522               if (!skip[entity.id] && entity.isComplete(graph)) {
56523                 canCopy.push(entity.id);
56524                 skip = getDescendants(entity.id, graph, skip);
56525               }
56526             }
56527
56528             for (i = 0; i < selected.way.length; i++) {
56529               entity = selected.way[i];
56530
56531               if (!skip[entity.id]) {
56532                 canCopy.push(entity.id);
56533                 skip = getDescendants(entity.id, graph, skip);
56534               }
56535             }
56536
56537             for (i = 0; i < selected.node.length; i++) {
56538               entity = selected.node[i];
56539
56540               if (!skip[entity.id]) {
56541                 canCopy.push(entity.id);
56542               }
56543             }
56544
56545             context.copyIDs(canCopy);
56546
56547             if (_point && (canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
56548               // store the anchor coordinates if copying more than a single node
56549               context.copyLonLat(context.projection.invert(_point));
56550             } else {
56551               context.copyLonLat(null);
56552             }
56553           };
56554
56555           function groupEntities(ids, graph) {
56556             var entities = ids.map(function (id) {
56557               return graph.entity(id);
56558             });
56559             return Object.assign({
56560               relation: [],
56561               way: [],
56562               node: []
56563             }, utilArrayGroupBy(entities, 'type'));
56564           }
56565
56566           function getDescendants(id, graph, descendants) {
56567             var entity = graph.entity(id);
56568             var children;
56569             descendants = descendants || {};
56570
56571             if (entity.type === 'relation') {
56572               children = entity.members.map(function (m) {
56573                 return m.id;
56574               });
56575             } else if (entity.type === 'way') {
56576               children = entity.nodes;
56577             } else {
56578               children = [];
56579             }
56580
56581             for (var i = 0; i < children.length; i++) {
56582               if (!descendants[children[i]]) {
56583                 descendants[children[i]] = true;
56584                 descendants = getDescendants(children[i], graph, descendants);
56585               }
56586             }
56587
56588             return descendants;
56589           }
56590
56591           operation.available = function () {
56592             return getFilteredIdsToCopy().length > 0;
56593           };
56594
56595           operation.disabled = function () {
56596             var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
56597
56598             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
56599               return 'too_large';
56600             }
56601
56602             return false;
56603           };
56604
56605           operation.availableForKeypress = function () {
56606             var selection = window.getSelection && window.getSelection(); // if the user has text selected then let them copy that, not the selected feature
56607
56608             return !selection || !selection.toString();
56609           };
56610
56611           operation.tooltip = function () {
56612             var disable = operation.disabled();
56613             return disable ? _t('operations.copy.' + disable, {
56614               n: selectedIDs.length
56615             }) : _t('operations.copy.description', {
56616               n: selectedIDs.length
56617             });
56618           };
56619
56620           operation.annotation = function () {
56621             return _t('operations.copy.annotation', {
56622               n: selectedIDs.length
56623             });
56624           };
56625
56626           var _point;
56627
56628           operation.point = function (val) {
56629             _point = val;
56630             return operation;
56631           };
56632
56633           operation.id = 'copy';
56634           operation.keys = [uiCmd('⌘C')];
56635           operation.title = _t('operations.copy.title');
56636           operation.behavior = behaviorOperation(context).which(operation);
56637           return operation;
56638         }
56639
56640         function operationDisconnect(context, selectedIDs) {
56641           var _vertexIDs = [];
56642           var _wayIDs = [];
56643           var _otherIDs = [];
56644           var _actions = [];
56645           selectedIDs.forEach(function (id) {
56646             var entity = context.entity(id);
56647
56648             if (entity.type === 'way') {
56649               _wayIDs.push(id);
56650             } else if (entity.geometry(context.graph()) === 'vertex') {
56651               _vertexIDs.push(id);
56652             } else {
56653               _otherIDs.push(id);
56654             }
56655           });
56656
56657           var _coords,
56658               _descriptionID = '',
56659               _annotationID = 'features';
56660
56661           var _disconnectingVertexIds = [];
56662           var _disconnectingWayIds = [];
56663
56664           if (_vertexIDs.length > 0) {
56665             // At the selected vertices, disconnect the selected ways, if any, else
56666             // disconnect all connected ways
56667             _disconnectingVertexIds = _vertexIDs;
56668
56669             _vertexIDs.forEach(function (vertexID) {
56670               var action = actionDisconnect(vertexID);
56671
56672               if (_wayIDs.length > 0) {
56673                 var waysIDsForVertex = _wayIDs.filter(function (wayID) {
56674                   var way = context.entity(wayID);
56675                   return way.nodes.indexOf(vertexID) !== -1;
56676                 });
56677
56678                 action.limitWays(waysIDsForVertex);
56679               }
56680
56681               _actions.push(action);
56682
56683               _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map(function (d) {
56684                 return d.id;
56685               }));
56686             });
56687
56688             _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function (id) {
56689               return _wayIDs.indexOf(id) === -1;
56690             });
56691             _descriptionID += _actions.length === 1 ? 'single_point.' : 'multiple_points.';
56692
56693             if (_wayIDs.length === 1) {
56694               _descriptionID += 'single_way.' + context.graph().geometry(_wayIDs[0]);
56695             } else {
56696               _descriptionID += _wayIDs.length === 0 ? 'no_ways' : 'multiple_ways';
56697             }
56698           } else if (_wayIDs.length > 0) {
56699             // Disconnect the selected ways from each other, if they're connected,
56700             // else disconnect them from all connected ways
56701             var ways = _wayIDs.map(function (id) {
56702               return context.entity(id);
56703             });
56704
56705             var nodes = utilGetAllNodes(_wayIDs, context.graph());
56706             _coords = nodes.map(function (n) {
56707               return n.loc;
56708             }); // actions for connected nodes shared by at least two selected ways
56709
56710             var sharedActions = [];
56711             var sharedNodes = []; // actions for connected nodes
56712
56713             var unsharedActions = [];
56714             var unsharedNodes = [];
56715             nodes.forEach(function (node) {
56716               var action = actionDisconnect(node.id).limitWays(_wayIDs);
56717
56718               if (action.disabled(context.graph()) !== 'not_connected') {
56719                 var count = 0;
56720
56721                 for (var i in ways) {
56722                   var way = ways[i];
56723
56724                   if (way.nodes.indexOf(node.id) !== -1) {
56725                     count += 1;
56726                   }
56727
56728                   if (count > 1) break;
56729                 }
56730
56731                 if (count > 1) {
56732                   sharedActions.push(action);
56733                   sharedNodes.push(node);
56734                 } else {
56735                   unsharedActions.push(action);
56736                   unsharedNodes.push(node);
56737                 }
56738               }
56739             });
56740             _descriptionID += 'no_points.';
56741             _descriptionID += _wayIDs.length === 1 ? 'single_way.' : 'multiple_ways.';
56742
56743             if (sharedActions.length) {
56744               // if any nodes are shared, only disconnect the selected ways from each other
56745               _actions = sharedActions;
56746               _disconnectingVertexIds = sharedNodes.map(function (node) {
56747                 return node.id;
56748               });
56749               _descriptionID += 'conjoined';
56750               _annotationID = 'from_each_other';
56751             } else {
56752               // if no nodes are shared, disconnect the selected ways from all connected ways
56753               _actions = unsharedActions;
56754               _disconnectingVertexIds = unsharedNodes.map(function (node) {
56755                 return node.id;
56756               });
56757
56758               if (_wayIDs.length === 1) {
56759                 _descriptionID += context.graph().geometry(_wayIDs[0]);
56760               } else {
56761                 _descriptionID += 'separate';
56762               }
56763             }
56764           }
56765
56766           var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
56767
56768           var operation = function operation() {
56769             context.perform(function (graph) {
56770               return _actions.reduce(function (graph, action) {
56771                 return action(graph);
56772               }, graph);
56773             }, operation.annotation());
56774             context.validator().validate();
56775           };
56776
56777           operation.relatedEntityIds = function () {
56778             if (_vertexIDs.length) {
56779               return _disconnectingWayIds;
56780             }
56781
56782             return _disconnectingVertexIds;
56783           };
56784
56785           operation.available = function () {
56786             if (_actions.length === 0) return false;
56787             if (_otherIDs.length !== 0) return false;
56788             if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function (wayID) {
56789               return _vertexIDs.some(function (vertexID) {
56790                 var way = context.entity(wayID);
56791                 return way.nodes.indexOf(vertexID) !== -1;
56792               });
56793             })) return false;
56794             return true;
56795           };
56796
56797           operation.disabled = function () {
56798             var reason;
56799
56800             for (var actionIndex in _actions) {
56801               reason = _actions[actionIndex].disabled(context.graph());
56802               if (reason) return reason;
56803             }
56804
56805             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
56806               return 'too_large.' + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? 'single' : 'multiple');
56807             } else if (_coords && someMissing()) {
56808               return 'not_downloaded';
56809             } else if (selectedIDs.some(context.hasHiddenConnections)) {
56810               return 'connected_to_hidden';
56811             }
56812
56813             return false;
56814
56815             function someMissing() {
56816               if (context.inIntro()) return false;
56817               var osm = context.connection();
56818
56819               if (osm) {
56820                 var missing = _coords.filter(function (loc) {
56821                   return !osm.isDataLoaded(loc);
56822                 });
56823
56824                 if (missing.length) {
56825                   missing.forEach(function (loc) {
56826                     context.loadTileAtLoc(loc);
56827                   });
56828                   return true;
56829                 }
56830               }
56831
56832               return false;
56833             }
56834           };
56835
56836           operation.tooltip = function () {
56837             var disable = operation.disabled();
56838
56839             if (disable) {
56840               return _t('operations.disconnect.' + disable);
56841             }
56842
56843             return _t('operations.disconnect.description.' + _descriptionID);
56844           };
56845
56846           operation.annotation = function () {
56847             return _t('operations.disconnect.annotation.' + _annotationID);
56848           };
56849
56850           operation.id = 'disconnect';
56851           operation.keys = [_t('operations.disconnect.key')];
56852           operation.title = _t('operations.disconnect.title');
56853           operation.behavior = behaviorOperation(context).which(operation);
56854           return operation;
56855         }
56856
56857         function operationDowngrade(context, selectedIDs) {
56858           var _affectedFeatureCount = 0;
56859
56860           var _downgradeType = downgradeTypeForEntityIDs(selectedIDs);
56861
56862           var _multi = _affectedFeatureCount === 1 ? 'single' : 'multiple';
56863
56864           function downgradeTypeForEntityIDs(entityIds) {
56865             var downgradeType;
56866             _affectedFeatureCount = 0;
56867
56868             for (var i in entityIds) {
56869               var entityID = entityIds[i];
56870               var type = downgradeTypeForEntityID(entityID);
56871
56872               if (type) {
56873                 _affectedFeatureCount += 1;
56874
56875                 if (downgradeType && type !== downgradeType) {
56876                   if (downgradeType !== 'generic' && type !== 'generic') {
56877                     downgradeType = 'building_address';
56878                   } else {
56879                     downgradeType = 'generic';
56880                   }
56881                 } else {
56882                   downgradeType = type;
56883                 }
56884               }
56885             }
56886
56887             return downgradeType;
56888           }
56889
56890           function downgradeTypeForEntityID(entityID) {
56891             var graph = context.graph();
56892             var entity = graph.entity(entityID);
56893             var preset = _mainPresetIndex.match(entity, graph);
56894             if (!preset || preset.isFallback()) return null;
56895
56896             if (entity.type === 'node' && preset.id !== 'address' && Object.keys(entity.tags).some(function (key) {
56897               return key.match(/^addr:.{1,}/);
56898             })) {
56899               return 'address';
56900             }
56901
56902             var geometry = entity.geometry(graph);
56903
56904             if (geometry === 'area' && entity.tags.building && !preset.tags.building) {
56905               return 'building';
56906             }
56907
56908             if (geometry === 'vertex' && Object.keys(entity.tags).length) {
56909               return 'generic';
56910             }
56911
56912             return null;
56913           }
56914
56915           var buildingKeysToKeep = ['architect', 'building', 'height', 'layer', 'source', 'type', 'wheelchair'];
56916           var addressKeysToKeep = ['source'];
56917
56918           var operation = function operation() {
56919             context.perform(function (graph) {
56920               for (var i in selectedIDs) {
56921                 var entityID = selectedIDs[i];
56922                 var type = downgradeTypeForEntityID(entityID);
56923                 if (!type) continue;
56924                 var tags = Object.assign({}, graph.entity(entityID).tags); // shallow copy
56925
56926                 for (var key in tags) {
56927                   if (type === 'address' && addressKeysToKeep.indexOf(key) !== -1) continue;
56928
56929                   if (type === 'building') {
56930                     if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
56931                   }
56932
56933                   if (type !== 'generic' && key.match(/^addr:.{1,}/)) continue;
56934                   delete tags[key];
56935                 }
56936
56937                 graph = actionChangeTags(entityID, tags)(graph);
56938               }
56939
56940               return graph;
56941             }, operation.annotation());
56942             context.validator().validate(); // refresh the select mode to enable the delete operation
56943
56944             context.enter(modeSelect(context, selectedIDs));
56945           };
56946
56947           operation.available = function () {
56948             return _downgradeType;
56949           };
56950
56951           operation.disabled = function () {
56952             if (selectedIDs.some(hasWikidataTag)) {
56953               return 'has_wikidata_tag';
56954             }
56955
56956             return false;
56957
56958             function hasWikidataTag(id) {
56959               var entity = context.entity(id);
56960               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
56961             }
56962           };
56963
56964           operation.tooltip = function () {
56965             var disable = operation.disabled();
56966             return disable ? _t('operations.downgrade.' + disable + '.' + _multi) : _t('operations.downgrade.description.' + _downgradeType);
56967           };
56968
56969           operation.annotation = function () {
56970             var suffix;
56971
56972             if (_downgradeType === 'building_address') {
56973               suffix = 'generic';
56974             } else {
56975               suffix = _downgradeType;
56976             }
56977
56978             return _t('operations.downgrade.annotation.' + suffix, {
56979               n: _affectedFeatureCount
56980             });
56981           };
56982
56983           operation.id = 'downgrade';
56984           operation.keys = [uiCmd('⌫')];
56985           operation.title = _t('operations.downgrade.title');
56986           operation.behavior = behaviorOperation(context).which(operation);
56987           return operation;
56988         }
56989
56990         function operationExtract(context, selectedIDs) {
56991           var _amount = selectedIDs.length === 1 ? 'single' : 'multiple';
56992
56993           var _geometries = utilArrayUniq(selectedIDs.map(function (entityID) {
56994             return context.graph().hasEntity(entityID) && context.graph().geometry(entityID);
56995           }).filter(Boolean));
56996
56997           var _geometryID = _geometries.length === 1 ? _geometries[0] : 'feature';
56998
56999           var _extent;
57000
57001           var _actions = selectedIDs.map(function (entityID) {
57002             var graph = context.graph();
57003             var entity = graph.hasEntity(entityID);
57004             if (!entity || !entity.hasInterestingTags()) return null;
57005             if (entity.type === 'node' && graph.parentWays(entity).length === 0) return null;
57006
57007             if (entity.type !== 'node') {
57008               var preset = _mainPresetIndex.match(entity, graph); // only allow extraction from ways/relations if the preset supports points
57009
57010               if (preset.geometry.indexOf('point') === -1) return null;
57011             }
57012
57013             _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
57014             return actionExtract(entityID);
57015           }).filter(Boolean);
57016
57017           var operation = function operation() {
57018             var combinedAction = function combinedAction(graph) {
57019               _actions.forEach(function (action) {
57020                 graph = action(graph);
57021               });
57022
57023               return graph;
57024             };
57025
57026             context.perform(combinedAction, operation.annotation()); // do the extract
57027
57028             var extractedNodeIDs = _actions.map(function (action) {
57029               return action.getExtractedNodeID();
57030             });
57031
57032             context.enter(modeSelect(context, extractedNodeIDs));
57033           };
57034
57035           operation.available = function () {
57036             return _actions.length && selectedIDs.length === _actions.length;
57037           };
57038
57039           operation.disabled = function () {
57040             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
57041               return 'too_large';
57042             } else if (selectedIDs.some(function (entityID) {
57043               return context.graph().geometry(entityID) === 'vertex' && context.hasHiddenConnections(entityID);
57044             })) {
57045               return 'connected_to_hidden';
57046             }
57047
57048             return false;
57049           };
57050
57051           operation.tooltip = function () {
57052             var disableReason = operation.disabled();
57053
57054             if (disableReason) {
57055               return _t('operations.extract.' + disableReason + '.' + _amount);
57056             } else {
57057               return _t('operations.extract.description.' + _geometryID + '.' + _amount);
57058             }
57059           };
57060
57061           operation.annotation = function () {
57062             return _t('operations.extract.annotation', {
57063               n: selectedIDs.length
57064             });
57065           };
57066
57067           operation.id = 'extract';
57068           operation.keys = [_t('operations.extract.key')];
57069           operation.title = _t('operations.extract.title');
57070           operation.behavior = behaviorOperation(context).which(operation);
57071           return operation;
57072         }
57073
57074         function operationMerge(context, selectedIDs) {
57075           var _action = getAction();
57076
57077           function getAction() {
57078             // prefer a non-disabled action first
57079             var join = actionJoin(selectedIDs);
57080             if (!join.disabled(context.graph())) return join;
57081             var merge = actionMerge(selectedIDs);
57082             if (!merge.disabled(context.graph())) return merge;
57083             var mergePolygon = actionMergePolygon(selectedIDs);
57084             if (!mergePolygon.disabled(context.graph())) return mergePolygon;
57085             var mergeNodes = actionMergeNodes(selectedIDs);
57086             if (!mergeNodes.disabled(context.graph())) return mergeNodes; // otherwise prefer an action with an interesting disabled reason
57087
57088             if (join.disabled(context.graph()) !== 'not_eligible') return join;
57089             if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
57090             if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
57091             return mergeNodes;
57092           }
57093
57094           var operation = function operation() {
57095             if (operation.disabled()) return;
57096             context.perform(_action, operation.annotation());
57097             context.validator().validate();
57098             var resultIDs = selectedIDs.filter(context.hasEntity);
57099
57100             if (resultIDs.length > 1) {
57101               var interestingIDs = resultIDs.filter(function (id) {
57102                 return context.entity(id).hasInterestingTags();
57103               });
57104               if (interestingIDs.length) resultIDs = interestingIDs;
57105             }
57106
57107             context.enter(modeSelect(context, resultIDs));
57108           };
57109
57110           operation.available = function () {
57111             return selectedIDs.length >= 2;
57112           };
57113
57114           operation.disabled = function () {
57115             var actionDisabled = _action.disabled(context.graph());
57116
57117             if (actionDisabled) return actionDisabled;
57118             var osm = context.connection();
57119
57120             if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
57121               return 'too_many_vertices';
57122             }
57123
57124             return false;
57125           };
57126
57127           operation.tooltip = function () {
57128             var disabled = operation.disabled();
57129
57130             if (disabled) {
57131               if (disabled === 'restriction') {
57132                 return _t('operations.merge.restriction', {
57133                   relation: _mainPresetIndex.item('type/restriction').name()
57134                 });
57135               }
57136
57137               return _t('operations.merge.' + disabled);
57138             }
57139
57140             return _t('operations.merge.description');
57141           };
57142
57143           operation.annotation = function () {
57144             return _t('operations.merge.annotation', {
57145               n: selectedIDs.length
57146             });
57147           };
57148
57149           operation.id = 'merge';
57150           operation.keys = [_t('operations.merge.key')];
57151           operation.title = _t('operations.merge.title');
57152           operation.behavior = behaviorOperation(context).which(operation);
57153           return operation;
57154         }
57155
57156         function operationPaste(context) {
57157           var _pastePoint;
57158
57159           var operation = function operation() {
57160             if (!_pastePoint) return;
57161             var oldIDs = context.copyIDs();
57162             if (!oldIDs.length) return;
57163             var projection = context.projection;
57164             var extent = geoExtent();
57165             var oldGraph = context.copyGraph();
57166             var newIDs = [];
57167             var action = actionCopyEntities(oldIDs, oldGraph);
57168             context.perform(action);
57169             var copies = action.copies();
57170             var originals = new Set();
57171             Object.values(copies).forEach(function (entity) {
57172               originals.add(entity.id);
57173             });
57174
57175             for (var id in copies) {
57176               var oldEntity = oldGraph.entity(id);
57177               var newEntity = copies[id];
57178
57179               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
57180
57181
57182               var parents = context.graph().parentWays(newEntity);
57183               var parentCopied = parents.some(function (parent) {
57184                 return originals.has(parent.id);
57185               });
57186
57187               if (!parentCopied) {
57188                 newIDs.push(newEntity.id);
57189               }
57190             } // Use the location of the copy operation to offset the paste location,
57191             // or else use the center of the pasted extent
57192
57193
57194             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
57195             var delta = geoVecSubtract(_pastePoint, copyPoint); // Move the pasted objects to be anchored at the paste location
57196
57197             context.replace(actionMove(newIDs, delta, projection), operation.annotation());
57198             context.enter(modeSelect(context, newIDs));
57199           };
57200
57201           operation.point = function (val) {
57202             _pastePoint = val;
57203             return operation;
57204           };
57205
57206           operation.available = function () {
57207             return context.mode().id === 'browse';
57208           };
57209
57210           operation.disabled = function () {
57211             return !context.copyIDs().length;
57212           };
57213
57214           operation.tooltip = function () {
57215             var oldGraph = context.copyGraph();
57216             var ids = context.copyIDs();
57217
57218             if (!ids.length) {
57219               return _t('operations.paste.nothing_copied');
57220             }
57221
57222             return _t('operations.paste.description', {
57223               feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph),
57224               n: ids.length
57225             });
57226           };
57227
57228           operation.annotation = function () {
57229             var ids = context.copyIDs();
57230             return _t('operations.paste.annotation', {
57231               n: ids.length
57232             });
57233           };
57234
57235           operation.id = 'paste';
57236           operation.keys = [uiCmd('⌘V')];
57237           operation.title = _t('operations.paste.title');
57238           return operation;
57239         }
57240
57241         function operationReverse(context, selectedIDs) {
57242           var operation = function operation() {
57243             context.perform(function combinedReverseAction(graph) {
57244               actions().forEach(function (action) {
57245                 graph = action(graph);
57246               });
57247               return graph;
57248             }, operation.annotation());
57249             context.validator().validate();
57250           };
57251
57252           function actions(situation) {
57253             return selectedIDs.map(function (entityID) {
57254               var entity = context.hasEntity(entityID);
57255               if (!entity) return null;
57256
57257               if (situation === 'toolbar') {
57258                 if (entity.type === 'way' && !entity.isOneWay() && !entity.isSided()) return null;
57259               }
57260
57261               var geometry = entity.geometry(context.graph());
57262               if (entity.type !== 'node' && geometry !== 'line') return null;
57263               var action = actionReverse(entityID);
57264               if (action.disabled(context.graph())) return null;
57265               return action;
57266             }).filter(Boolean);
57267           }
57268
57269           function reverseTypeID() {
57270             var acts = actions();
57271             var nodeActionCount = acts.filter(function (act) {
57272               var entity = context.hasEntity(act.entityID());
57273               return entity && entity.type === 'node';
57274             }).length;
57275             if (nodeActionCount === 0) return 'line';
57276             if (nodeActionCount === acts.length) return 'point';
57277             return 'feature';
57278           }
57279
57280           operation.available = function (situation) {
57281             return actions(situation).length > 0;
57282           };
57283
57284           operation.disabled = function () {
57285             return false;
57286           };
57287
57288           operation.tooltip = function () {
57289             return _t('operations.reverse.description.' + reverseTypeID());
57290           };
57291
57292           operation.annotation = function () {
57293             var acts = actions();
57294             return _t('operations.reverse.annotation.' + reverseTypeID(), {
57295               n: acts.length
57296             });
57297           };
57298
57299           operation.id = 'reverse';
57300           operation.keys = [_t('operations.reverse.key')];
57301           operation.title = _t('operations.reverse.title');
57302           operation.behavior = behaviorOperation(context).which(operation);
57303           return operation;
57304         }
57305
57306         function operationSplit(context, selectedIDs) {
57307           var _vertexIds = selectedIDs.filter(function (id) {
57308             return context.graph().geometry(id) === 'vertex';
57309           });
57310
57311           var _selectedWayIds = selectedIDs.filter(function (id) {
57312             var entity = context.graph().hasEntity(id);
57313             return entity && entity.type === 'way';
57314           });
57315
57316           var _isAvailable = _vertexIds.length > 0 && _vertexIds.length + _selectedWayIds.length === selectedIDs.length;
57317
57318           var _action = actionSplit(_vertexIds);
57319
57320           var _ways = [];
57321           var _geometry = 'feature';
57322           var _waysAmount = 'single';
57323
57324           var _nodesAmount = _vertexIds.length === 1 ? 'single' : 'multiple';
57325
57326           if (_isAvailable) {
57327             if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
57328             _ways = _action.ways(context.graph());
57329             var geometries = {};
57330
57331             _ways.forEach(function (way) {
57332               geometries[way.geometry(context.graph())] = true;
57333             });
57334
57335             if (Object.keys(geometries).length === 1) {
57336               _geometry = Object.keys(geometries)[0];
57337             }
57338
57339             _waysAmount = _ways.length === 1 ? 'single' : 'multiple';
57340           }
57341
57342           var operation = function operation() {
57343             var difference = context.perform(_action, operation.annotation()); // select both the nodes and the ways so the mapper can immediately disconnect them if desired
57344
57345             var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function (id) {
57346               // filter out relations that may have had member additions
57347               return context.entity(id).type === 'way';
57348             }));
57349
57350             context.enter(modeSelect(context, idsToSelect));
57351           };
57352
57353           operation.relatedEntityIds = function () {
57354             return _selectedWayIds.length ? [] : _ways.map(function (way) {
57355               return way.id;
57356             });
57357           };
57358
57359           operation.available = function () {
57360             return _isAvailable;
57361           };
57362
57363           operation.disabled = function () {
57364             var reason = _action.disabled(context.graph());
57365
57366             if (reason) {
57367               return reason;
57368             } else if (selectedIDs.some(context.hasHiddenConnections)) {
57369               return 'connected_to_hidden';
57370             }
57371
57372             return false;
57373           };
57374
57375           operation.tooltip = function () {
57376             var disable = operation.disabled();
57377             if (disable) return _t('operations.split.' + disable);
57378             return _t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node');
57379           };
57380
57381           operation.annotation = function () {
57382             return _t('operations.split.annotation.' + _geometry, {
57383               n: _ways.length
57384             });
57385           };
57386
57387           operation.id = 'split';
57388           operation.keys = [_t('operations.split.key')];
57389           operation.title = _t('operations.split.title');
57390           operation.behavior = behaviorOperation(context).which(operation);
57391           return operation;
57392         }
57393
57394         function operationStraighten(context, selectedIDs) {
57395           var _wayIDs = selectedIDs.filter(function (id) {
57396             return id.charAt(0) === 'w';
57397           });
57398
57399           var _nodeIDs = selectedIDs.filter(function (id) {
57400             return id.charAt(0) === 'n';
57401           });
57402
57403           var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? 'single' : 'multiple';
57404
57405           var _nodes = utilGetAllNodes(selectedIDs, context.graph());
57406
57407           var _coords = _nodes.map(function (n) {
57408             return n.loc;
57409           });
57410
57411           var _extent = utilTotalExtent(selectedIDs, context.graph());
57412
57413           var _action = chooseAction();
57414
57415           var _geometry;
57416
57417           function chooseAction() {
57418             // straighten selected nodes
57419             if (_wayIDs.length === 0 && _nodeIDs.length > 2) {
57420               _geometry = 'point';
57421               return actionStraightenNodes(_nodeIDs, context.projection); // straighten selected ways (possibly between range of 2 selected nodes)
57422             } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
57423               var startNodeIDs = [];
57424               var endNodeIDs = [];
57425
57426               for (var i = 0; i < selectedIDs.length; i++) {
57427                 var entity = context.entity(selectedIDs[i]);
57428
57429                 if (entity.type === 'node') {
57430                   continue;
57431                 } else if (entity.type !== 'way' || entity.isClosed()) {
57432                   return null; // exit early, can't straighten these
57433                 }
57434
57435                 startNodeIDs.push(entity.first());
57436                 endNodeIDs.push(entity.last());
57437               } // Remove duplicate end/startNodeIDs (duplicate nodes cannot be at the line end)
57438
57439
57440               startNodeIDs = startNodeIDs.filter(function (n) {
57441                 return startNodeIDs.indexOf(n) === startNodeIDs.lastIndexOf(n);
57442               });
57443               endNodeIDs = endNodeIDs.filter(function (n) {
57444                 return endNodeIDs.indexOf(n) === endNodeIDs.lastIndexOf(n);
57445               }); // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints)
57446
57447               if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null; // Ensure path contains at least 3 unique nodes
57448
57449               var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function (node) {
57450                 return node.id;
57451               });
57452               if (wayNodeIDs.length <= 2) return null; // If range of 2 selected nodes is supplied, ensure nodes lie on the selected path
57453
57454               if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
57455
57456               if (_nodeIDs.length) {
57457                 // If we're only straightenting between two points, we only need that extent visible
57458                 _extent = utilTotalExtent(_nodeIDs, context.graph());
57459               }
57460
57461               _geometry = 'line';
57462               return actionStraightenWay(selectedIDs, context.projection);
57463             }
57464
57465             return null;
57466           }
57467
57468           function operation() {
57469             if (!_action) return;
57470             context.perform(_action, operation.annotation());
57471             window.setTimeout(function () {
57472               context.validator().validate();
57473             }, 300); // after any transition
57474           }
57475
57476           operation.available = function () {
57477             return Boolean(_action);
57478           };
57479
57480           operation.disabled = function () {
57481             var reason = _action.disabled(context.graph());
57482
57483             if (reason) {
57484               return reason;
57485             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
57486               return 'too_large';
57487             } else if (someMissing()) {
57488               return 'not_downloaded';
57489             } else if (selectedIDs.some(context.hasHiddenConnections)) {
57490               return 'connected_to_hidden';
57491             }
57492
57493             return false;
57494
57495             function someMissing() {
57496               if (context.inIntro()) return false;
57497               var osm = context.connection();
57498
57499               if (osm) {
57500                 var missing = _coords.filter(function (loc) {
57501                   return !osm.isDataLoaded(loc);
57502                 });
57503
57504                 if (missing.length) {
57505                   missing.forEach(function (loc) {
57506                     context.loadTileAtLoc(loc);
57507                   });
57508                   return true;
57509                 }
57510               }
57511
57512               return false;
57513             }
57514           };
57515
57516           operation.tooltip = function () {
57517             var disable = operation.disabled();
57518             return disable ? _t('operations.straighten.' + disable + '.' + _amount) : _t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's'));
57519           };
57520
57521           operation.annotation = function () {
57522             return _t('operations.straighten.annotation.' + _geometry, {
57523               n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length
57524             });
57525           };
57526
57527           operation.id = 'straighten';
57528           operation.keys = [_t('operations.straighten.key')];
57529           operation.title = _t('operations.straighten.title');
57530           operation.behavior = behaviorOperation(context).which(operation);
57531           return operation;
57532         }
57533
57534         var Operations = /*#__PURE__*/Object.freeze({
57535                 __proto__: null,
57536                 operationCircularize: operationCircularize,
57537                 operationContinue: operationContinue,
57538                 operationCopy: operationCopy,
57539                 operationDelete: operationDelete,
57540                 operationDisconnect: operationDisconnect,
57541                 operationDowngrade: operationDowngrade,
57542                 operationExtract: operationExtract,
57543                 operationMerge: operationMerge,
57544                 operationMove: operationMove,
57545                 operationOrthogonalize: operationOrthogonalize,
57546                 operationPaste: operationPaste,
57547                 operationReflectShort: operationReflectShort,
57548                 operationReflectLong: operationReflectLong,
57549                 operationReverse: operationReverse,
57550                 operationRotate: operationRotate,
57551                 operationSplit: operationSplit,
57552                 operationStraighten: operationStraighten
57553         });
57554
57555         var _relatedParent;
57556
57557         function modeSelect(context, selectedIDs) {
57558           var mode = {
57559             id: 'select',
57560             button: 'browse'
57561           };
57562           var keybinding = utilKeybinding('select');
57563
57564           var _breatheBehavior = behaviorBreathe();
57565
57566           var _modeDragNode = modeDragNode(context);
57567
57568           var _selectBehavior;
57569
57570           var _behaviors = [];
57571           var _operations = [];
57572           var _newFeature = false;
57573           var _follow = false;
57574
57575           function singular() {
57576             if (selectedIDs && selectedIDs.length === 1) {
57577               return context.hasEntity(selectedIDs[0]);
57578             }
57579           }
57580
57581           function selectedEntities() {
57582             return selectedIDs.map(function (id) {
57583               return context.hasEntity(id);
57584             }).filter(Boolean);
57585           }
57586
57587           function checkSelectedIDs() {
57588             var ids = [];
57589
57590             if (Array.isArray(selectedIDs)) {
57591               ids = selectedIDs.filter(function (id) {
57592                 return context.hasEntity(id);
57593               });
57594             }
57595
57596             if (!ids.length) {
57597               context.enter(modeBrowse(context));
57598               return false;
57599             } else if (selectedIDs.length > 1 && ids.length === 1 || selectedIDs.length === 1 && ids.length > 1) {
57600               // switch between single- and multi-select UI
57601               context.enter(modeSelect(context, ids));
57602               return false;
57603             }
57604
57605             selectedIDs = ids;
57606             return true;
57607           } // find the common parent ways for nextVertex, previousVertex
57608
57609
57610           function commonParents() {
57611             var graph = context.graph();
57612             var commonParents = [];
57613
57614             for (var i = 0; i < selectedIDs.length; i++) {
57615               var entity = context.hasEntity(selectedIDs[i]);
57616
57617               if (!entity || entity.geometry(graph) !== 'vertex') {
57618                 return []; // selection includes some not vertices
57619               }
57620
57621               var currParents = graph.parentWays(entity).map(function (w) {
57622                 return w.id;
57623               });
57624
57625               if (!commonParents.length) {
57626                 commonParents = currParents;
57627                 continue;
57628               }
57629
57630               commonParents = utilArrayIntersection(commonParents, currParents);
57631
57632               if (!commonParents.length) {
57633                 return [];
57634               }
57635             }
57636
57637             return commonParents;
57638           }
57639
57640           function singularParent() {
57641             var parents = commonParents();
57642
57643             if (!parents || parents.length === 0) {
57644               _relatedParent = null;
57645               return null;
57646             } // relatedParent is used when we visit a vertex with multiple
57647             // parents, and we want to remember which parent line we started on.
57648
57649
57650             if (parents.length === 1) {
57651               _relatedParent = parents[0]; // remember this parent for later
57652
57653               return _relatedParent;
57654             }
57655
57656             if (parents.indexOf(_relatedParent) !== -1) {
57657               return _relatedParent; // prefer the previously seen parent
57658             }
57659
57660             return parents[0];
57661           }
57662
57663           mode.selectedIDs = function (val) {
57664             if (!arguments.length) return selectedIDs;
57665             selectedIDs = val;
57666             return mode;
57667           };
57668
57669           mode.zoomToSelected = function () {
57670             context.map().zoomToEase(selectedEntities());
57671           };
57672
57673           mode.newFeature = function (val) {
57674             if (!arguments.length) return _newFeature;
57675             _newFeature = val;
57676             return mode;
57677           };
57678
57679           mode.selectBehavior = function (val) {
57680             if (!arguments.length) return _selectBehavior;
57681             _selectBehavior = val;
57682             return mode;
57683           };
57684
57685           mode.follow = function (val) {
57686             if (!arguments.length) return _follow;
57687             _follow = val;
57688             return mode;
57689           };
57690
57691           function loadOperations() {
57692             _operations.forEach(function (operation) {
57693               if (operation.behavior) {
57694                 context.uninstall(operation.behavior);
57695               }
57696             });
57697
57698             _operations = Object.values(Operations).map(function (o) {
57699               return o(context, selectedIDs);
57700             }).filter(function (o) {
57701               return o.id !== 'delete' && o.id !== 'downgrade' && o.id !== 'copy';
57702             }).concat([// group copy/downgrade/delete operation together at the end of the list
57703             operationCopy(context, selectedIDs), operationDowngrade(context, selectedIDs), operationDelete(context, selectedIDs)]).filter(function (operation) {
57704               return operation.available();
57705             });
57706
57707             _operations.forEach(function (operation) {
57708               if (operation.behavior) {
57709                 context.install(operation.behavior);
57710               }
57711             }); // remove any displayed menu
57712
57713
57714             context.ui().closeEditMenu();
57715           }
57716
57717           mode.operations = function () {
57718             return _operations;
57719           };
57720
57721           mode.enter = function () {
57722             if (!checkSelectedIDs()) return;
57723             context.features().forceVisible(selectedIDs);
57724
57725             _modeDragNode.restoreSelectedIDs(selectedIDs);
57726
57727             loadOperations();
57728
57729             if (!_behaviors.length) {
57730               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
57731               _behaviors = [behaviorPaste(context), _breatheBehavior, behaviorHover(context).on('hover', context.ui().sidebar.hoverModeSelect), _selectBehavior, behaviorLasso(context), _modeDragNode.behavior, modeDragNote(context).behavior];
57732             }
57733
57734             _behaviors.forEach(context.install);
57735
57736             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) {
57737               return uiCmd('⇧' + key);
57738             }), scaleSelection(1.05)).on(utilKeybinding.plusKeys.map(function (key) {
57739               return uiCmd('⇧⌥' + key);
57740             }), scaleSelection(Math.pow(1.05, 5))).on(utilKeybinding.minusKeys.map(function (key) {
57741               return uiCmd('⇧' + key);
57742             }), scaleSelection(1 / 1.05)).on(utilKeybinding.minusKeys.map(function (key) {
57743               return uiCmd('⇧⌥' + key);
57744             }), scaleSelection(1 / Math.pow(1.05, 5))).on(['\\', 'pause'], nextParent).on('⎋', esc, true);
57745             select(document).call(keybinding);
57746             context.ui().sidebar.select(selectedIDs, _newFeature);
57747             context.history().on('change.select', function () {
57748               loadOperations(); // reselect after change in case relation members were removed or added
57749
57750               selectElements();
57751             }).on('undone.select', checkSelectedIDs).on('redone.select', checkSelectedIDs);
57752             context.map().on('drawn.select', selectElements).on('crossEditableZoom.select', function () {
57753               selectElements();
57754
57755               _breatheBehavior.restartIfNeeded(context.surface());
57756             });
57757             context.map().doubleUpHandler().on('doubleUp.modeSelect', didDoubleUp);
57758             selectElements();
57759
57760             if (_follow) {
57761               var extent = geoExtent();
57762               var graph = context.graph();
57763               selectedIDs.forEach(function (id) {
57764                 var entity = context.entity(id);
57765
57766                 extent._extend(entity.extent(graph));
57767               });
57768               var loc = extent.center();
57769               context.map().centerEase(loc); // we could enter the mode multiple times, so reset follow for next time
57770
57771               _follow = false;
57772             }
57773
57774             function nudgeSelection(delta) {
57775               return function () {
57776                 // prevent nudging during low zoom selection
57777                 if (!context.map().withinEditableZoom()) return;
57778                 var moveOp = operationMove(context, selectedIDs);
57779
57780                 if (moveOp.disabled()) {
57781                   context.ui().flash.duration(4000).iconName('#iD-operation-' + moveOp.id).iconClass('operation disabled').label(moveOp.tooltip)();
57782                 } else {
57783                   context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation());
57784                   context.validator().validate();
57785                 }
57786               };
57787             }
57788
57789             function scaleSelection(factor) {
57790               return function () {
57791                 // prevent scaling during low zoom selection
57792                 if (!context.map().withinEditableZoom()) return;
57793                 var nodes = utilGetAllNodes(selectedIDs, context.graph());
57794                 var isUp = factor > 1; // can only scale if multiple nodes are selected
57795
57796                 if (nodes.length <= 1) return;
57797                 var extent = utilTotalExtent(selectedIDs, context.graph()); // These disabled checks would normally be handled by an operation
57798                 // object, but we don't want an actual scale operation at this point.
57799
57800                 function scalingDisabled() {
57801                   if (tooSmall()) {
57802                     return 'too_small';
57803                   } else if (extent.percentContainedIn(context.map().extent()) < 0.8) {
57804                     return 'too_large';
57805                   } else if (someMissing() || selectedIDs.some(incompleteRelation)) {
57806                     return 'not_downloaded';
57807                   } else if (selectedIDs.some(context.hasHiddenConnections)) {
57808                     return 'connected_to_hidden';
57809                   }
57810
57811                   return false;
57812
57813                   function tooSmall() {
57814                     if (isUp) return false;
57815                     var dLon = Math.abs(extent[1][0] - extent[0][0]);
57816                     var dLat = Math.abs(extent[1][1] - extent[0][1]);
57817                     return dLon < geoMetersToLon(1, extent[1][1]) && dLat < geoMetersToLat(1);
57818                   }
57819
57820                   function someMissing() {
57821                     if (context.inIntro()) return false;
57822                     var osm = context.connection();
57823
57824                     if (osm) {
57825                       var missing = nodes.filter(function (n) {
57826                         return !osm.isDataLoaded(n.loc);
57827                       });
57828
57829                       if (missing.length) {
57830                         missing.forEach(function (loc) {
57831                           context.loadTileAtLoc(loc);
57832                         });
57833                         return true;
57834                       }
57835                     }
57836
57837                     return false;
57838                   }
57839
57840                   function incompleteRelation(id) {
57841                     var entity = context.entity(id);
57842                     return entity.type === 'relation' && !entity.isComplete(context.graph());
57843                   }
57844                 }
57845
57846                 var disabled = scalingDisabled();
57847
57848                 if (disabled) {
57849                   var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
57850                   context.ui().flash.duration(4000).iconName('#iD-icon-no').iconClass('operation disabled').label(_t('operations.scale.' + disabled + '.' + multi))();
57851                 } else {
57852                   var pivot = context.projection(extent.center());
57853                   var annotation = _t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', {
57854                     n: selectedIDs.length
57855                   });
57856                   context.perform(actionScale(selectedIDs, pivot, factor, context.projection), annotation);
57857                   context.validator().validate();
57858                 }
57859               };
57860             }
57861
57862             function didDoubleUp(d3_event, loc) {
57863               if (!context.map().withinEditableZoom()) return;
57864               var target = select(d3_event.target);
57865               var datum = target.datum();
57866               var entity = datum && datum.properties && datum.properties.entity;
57867               if (!entity) return;
57868
57869               if (entity instanceof osmWay && target.classed('target')) {
57870                 var choice = geoChooseEdge(context.graph().childNodes(entity), loc, context.projection);
57871                 var prev = entity.nodes[choice.index - 1];
57872                 var next = entity.nodes[choice.index];
57873                 context.perform(actionAddMidpoint({
57874                   loc: choice.loc,
57875                   edge: [prev, next]
57876                 }, osmNode()), _t('operations.add.annotation.vertex'));
57877               } else if (entity.type === 'midpoint') {
57878                 context.perform(actionAddMidpoint({
57879                   loc: entity.loc,
57880                   edge: entity.edge
57881                 }, osmNode()), _t('operations.add.annotation.vertex'));
57882               }
57883             }
57884
57885             function selectElements() {
57886               if (!checkSelectedIDs()) return;
57887               var surface = context.surface();
57888               surface.selectAll('.selected-member').classed('selected-member', false);
57889               surface.selectAll('.selected').classed('selected', false);
57890               surface.selectAll('.related').classed('related', false);
57891               singularParent();
57892
57893               if (_relatedParent) {
57894                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
57895               }
57896
57897               if (context.map().withinEditableZoom()) {
57898                 // Apply selection styling if not in wide selection
57899                 surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true
57900                 /* skipMultipolgonMembers */
57901                 )).classed('selected-member', true);
57902                 surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed('selected', true);
57903               }
57904             }
57905
57906             function esc() {
57907               if (context.container().select('.combobox').size()) return;
57908               context.enter(modeBrowse(context));
57909             }
57910
57911             function firstVertex(d3_event) {
57912               d3_event.preventDefault();
57913               var entity = singular();
57914               var parent = singularParent();
57915               var way;
57916
57917               if (entity && entity.type === 'way') {
57918                 way = entity;
57919               } else if (parent) {
57920                 way = context.entity(parent);
57921               }
57922
57923               if (way) {
57924                 context.enter(modeSelect(context, [way.first()]).follow(true));
57925               }
57926             }
57927
57928             function lastVertex(d3_event) {
57929               d3_event.preventDefault();
57930               var entity = singular();
57931               var parent = singularParent();
57932               var way;
57933
57934               if (entity && entity.type === 'way') {
57935                 way = entity;
57936               } else if (parent) {
57937                 way = context.entity(parent);
57938               }
57939
57940               if (way) {
57941                 context.enter(modeSelect(context, [way.last()]).follow(true));
57942               }
57943             }
57944
57945             function previousVertex(d3_event) {
57946               d3_event.preventDefault();
57947               var parent = singularParent();
57948               if (!parent) return;
57949               var way = context.entity(parent);
57950               var length = way.nodes.length;
57951               var curr = way.nodes.indexOf(selectedIDs[0]);
57952               var index = -1;
57953
57954               if (curr > 0) {
57955                 index = curr - 1;
57956               } else if (way.isClosed()) {
57957                 index = length - 2;
57958               }
57959
57960               if (index !== -1) {
57961                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
57962               }
57963             }
57964
57965             function nextVertex(d3_event) {
57966               d3_event.preventDefault();
57967               var parent = singularParent();
57968               if (!parent) return;
57969               var way = context.entity(parent);
57970               var length = way.nodes.length;
57971               var curr = way.nodes.indexOf(selectedIDs[0]);
57972               var index = -1;
57973
57974               if (curr < length - 1) {
57975                 index = curr + 1;
57976               } else if (way.isClosed()) {
57977                 index = 0;
57978               }
57979
57980               if (index !== -1) {
57981                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
57982               }
57983             }
57984
57985             function nextParent(d3_event) {
57986               d3_event.preventDefault();
57987               var parents = commonParents();
57988               if (!parents || parents.length < 2) return;
57989               var index = parents.indexOf(_relatedParent);
57990
57991               if (index < 0 || index > parents.length - 2) {
57992                 _relatedParent = parents[0];
57993               } else {
57994                 _relatedParent = parents[index + 1];
57995               }
57996
57997               var surface = context.surface();
57998               surface.selectAll('.related').classed('related', false);
57999
58000               if (_relatedParent) {
58001                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
58002               }
58003             }
58004           };
58005
58006           mode.exit = function () {
58007             _newFeature = false;
58008
58009             _operations.forEach(function (operation) {
58010               if (operation.behavior) {
58011                 context.uninstall(operation.behavior);
58012               }
58013             });
58014
58015             _operations = [];
58016
58017             _behaviors.forEach(context.uninstall);
58018
58019             select(document).call(keybinding.unbind);
58020             context.ui().closeEditMenu();
58021             context.history().on('change.select', null).on('undone.select', null).on('redone.select', null);
58022             var surface = context.surface();
58023             surface.selectAll('.selected-member').classed('selected-member', false);
58024             surface.selectAll('.selected').classed('selected', false);
58025             surface.selectAll('.highlighted').classed('highlighted', false);
58026             surface.selectAll('.related').classed('related', false);
58027             context.map().on('drawn.select', null);
58028             context.ui().sidebar.hide();
58029             context.features().forceVisible([]);
58030             var entity = singular();
58031
58032             if (_newFeature && entity && entity.type === 'relation' && // no tags
58033             Object.keys(entity.tags).length === 0 && // no parent relations
58034             context.graph().parentRelations(entity).length === 0 && ( // no members or one member with no role
58035             entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
58036               // the user added this relation but didn't edit it at all, so just delete it
58037               var deleteAction = actionDeleteRelation(entity.id, true
58038               /* don't delete untagged members */
58039               );
58040               context.perform(deleteAction, _t('operations.delete.annotation.relation'));
58041             }
58042           };
58043
58044           return mode;
58045         }
58046
58047         function uiLasso(context) {
58048           var group, polygon;
58049           lasso.coordinates = [];
58050
58051           function lasso(selection) {
58052             context.container().classed('lasso', true);
58053             group = selection.append('g').attr('class', 'lasso hide');
58054             polygon = group.append('path').attr('class', 'lasso-path');
58055             group.call(uiToggle(true));
58056           }
58057
58058           function draw() {
58059             if (polygon) {
58060               polygon.data([lasso.coordinates]).attr('d', function (d) {
58061                 return 'M' + d.join(' L') + ' Z';
58062               });
58063             }
58064           }
58065
58066           lasso.extent = function () {
58067             return lasso.coordinates.reduce(function (extent, point) {
58068               return extent.extend(geoExtent(point));
58069             }, geoExtent());
58070           };
58071
58072           lasso.p = function (_) {
58073             if (!arguments.length) return lasso;
58074             lasso.coordinates.push(_);
58075             draw();
58076             return lasso;
58077           };
58078
58079           lasso.close = function () {
58080             if (group) {
58081               group.call(uiToggle(false, function () {
58082                 select(this).remove();
58083               }));
58084             }
58085
58086             context.container().classed('lasso', false);
58087           };
58088
58089           return lasso;
58090         }
58091
58092         function behaviorLasso(context) {
58093           // use pointer events on supported platforms; fallback to mouse events
58094           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
58095
58096           var behavior = function behavior(selection) {
58097             var lasso;
58098
58099             function pointerdown(d3_event) {
58100               var button = 0; // left
58101
58102               if (d3_event.button === button && d3_event.shiftKey === true) {
58103                 lasso = null;
58104                 select(window).on(_pointerPrefix + 'move.lasso', pointermove).on(_pointerPrefix + 'up.lasso', pointerup);
58105                 d3_event.stopPropagation();
58106               }
58107             }
58108
58109             function pointermove() {
58110               if (!lasso) {
58111                 lasso = uiLasso(context);
58112                 context.surface().call(lasso);
58113               }
58114
58115               lasso.p(context.map().mouse());
58116             }
58117
58118             function normalize(a, b) {
58119               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])]];
58120             }
58121
58122             function lassoed() {
58123               if (!lasso) return [];
58124               var graph = context.graph();
58125               var limitToNodes;
58126
58127               if (context.map().editableDataEnabled(true
58128               /* skipZoomCheck */
58129               ) && context.map().isInWideSelection()) {
58130                 // only select from the visible nodes
58131                 limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
58132               } else if (!context.map().editableDataEnabled()) {
58133                 return [];
58134               }
58135
58136               var bounds = lasso.extent().map(context.projection.invert);
58137               var extent = geoExtent(normalize(bounds[0], bounds[1]));
58138               var intersects = context.history().intersects(extent).filter(function (entity) {
58139                 return entity.type === 'node' && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
58140               }); // sort the lassoed nodes as best we can
58141
58142               intersects.sort(function (node1, node2) {
58143                 var parents1 = graph.parentWays(node1);
58144                 var parents2 = graph.parentWays(node2);
58145
58146                 if (parents1.length && parents2.length) {
58147                   // both nodes are vertices
58148                   var sharedParents = utilArrayIntersection(parents1, parents2);
58149
58150                   if (sharedParents.length) {
58151                     var sharedParentNodes = sharedParents[0].nodes; // vertices are members of the same way; sort them in their listed order
58152
58153                     return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
58154                   } else {
58155                     // vertices do not share a way; group them by their respective parent ways
58156                     return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
58157                   }
58158                 } else if (parents1.length || parents2.length) {
58159                   // only one node is a vertex; sort standalone points before vertices
58160                   return parents1.length - parents2.length;
58161                 } // both nodes are standalone points; sort left to right
58162
58163
58164                 return node1.loc[0] - node2.loc[0];
58165               });
58166               return intersects.map(function (entity) {
58167                 return entity.id;
58168               });
58169             }
58170
58171             function pointerup() {
58172               select(window).on(_pointerPrefix + 'move.lasso', null).on(_pointerPrefix + 'up.lasso', null);
58173               if (!lasso) return;
58174               var ids = lassoed();
58175               lasso.close();
58176
58177               if (ids.length) {
58178                 context.enter(modeSelect(context, ids));
58179               }
58180             }
58181
58182             selection.on(_pointerPrefix + 'down.lasso', pointerdown);
58183           };
58184
58185           behavior.off = function (selection) {
58186             selection.on(_pointerPrefix + 'down.lasso', null);
58187           };
58188
58189           return behavior;
58190         }
58191
58192         function modeBrowse(context) {
58193           var mode = {
58194             button: 'browse',
58195             id: 'browse',
58196             title: _t('modes.browse.title'),
58197             description: _t('modes.browse.description')
58198           };
58199           var sidebar;
58200
58201           var _selectBehavior;
58202
58203           var _behaviors = [];
58204
58205           mode.selectBehavior = function (val) {
58206             if (!arguments.length) return _selectBehavior;
58207             _selectBehavior = val;
58208             return mode;
58209           };
58210
58211           mode.enter = function () {
58212             if (!_behaviors.length) {
58213               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
58214               _behaviors = [behaviorPaste(context), behaviorHover(context).on('hover', context.ui().sidebar.hover), _selectBehavior, behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
58215             }
58216
58217             _behaviors.forEach(context.install); // Get focus on the body.
58218
58219
58220             if (document.activeElement && document.activeElement.blur) {
58221               document.activeElement.blur();
58222             }
58223
58224             if (sidebar) {
58225               context.ui().sidebar.show(sidebar);
58226             } else {
58227               context.ui().sidebar.select(null);
58228             }
58229           };
58230
58231           mode.exit = function () {
58232             context.ui().sidebar.hover.cancel();
58233
58234             _behaviors.forEach(context.uninstall);
58235
58236             if (sidebar) {
58237               context.ui().sidebar.hide();
58238             }
58239           };
58240
58241           mode.sidebar = function (_) {
58242             if (!arguments.length) return sidebar;
58243             sidebar = _;
58244             return mode;
58245           };
58246
58247           mode.operations = function () {
58248             return [operationPaste(context)];
58249           };
58250
58251           return mode;
58252         }
58253
58254         function behaviorAddWay(context) {
58255           var dispatch$1 = dispatch('start', 'startFromWay', 'startFromNode');
58256           var draw = behaviorDraw(context);
58257
58258           function behavior(surface) {
58259             draw.on('click', function () {
58260               dispatch$1.apply('start', this, arguments);
58261             }).on('clickWay', function () {
58262               dispatch$1.apply('startFromWay', this, arguments);
58263             }).on('clickNode', function () {
58264               dispatch$1.apply('startFromNode', this, arguments);
58265             }).on('cancel', behavior.cancel).on('finish', behavior.cancel);
58266             context.map().dblclickZoomEnable(false);
58267             surface.call(draw);
58268           }
58269
58270           behavior.off = function (surface) {
58271             surface.call(draw.off);
58272           };
58273
58274           behavior.cancel = function () {
58275             window.setTimeout(function () {
58276               context.map().dblclickZoomEnable(true);
58277             }, 1000);
58278             context.enter(modeBrowse(context));
58279           };
58280
58281           return utilRebind(behavior, dispatch$1, 'on');
58282         }
58283
58284         function behaviorHash(context) {
58285           // cached window.location.hash
58286           var _cachedHash = null; // allowable latitude range
58287
58288           var _latitudeLimit = 90 - 1e-8;
58289
58290           function computedHashParameters() {
58291             var map = context.map();
58292             var center = map.center();
58293             var zoom = map.zoom();
58294             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
58295             var oldParams = utilObjectOmit(utilStringQs(window.location.hash), ['comment', 'source', 'hashtags', 'walkthrough']);
58296             var newParams = {};
58297             delete oldParams.id;
58298             var selected = context.selectedIDs().filter(function (id) {
58299               return context.hasEntity(id);
58300             });
58301
58302             if (selected.length) {
58303               newParams.id = selected.join(',');
58304             }
58305
58306             newParams.map = zoom.toFixed(2) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
58307             return Object.assign(oldParams, newParams);
58308           }
58309
58310           function computedHash() {
58311             return '#' + utilQsString(computedHashParameters(), true);
58312           }
58313
58314           function computedTitle(includeChangeCount) {
58315             var baseTitle = context.documentTitleBase() || 'iD';
58316             var contextual;
58317             var changeCount;
58318             var titleID;
58319             var selected = context.selectedIDs().filter(function (id) {
58320               return context.hasEntity(id);
58321             });
58322
58323             if (selected.length) {
58324               var firstLabel = utilDisplayLabel(context.entity(selected[0]), context.graph());
58325
58326               if (selected.length > 1) {
58327                 contextual = _t('title.labeled_and_more', {
58328                   labeled: firstLabel,
58329                   count: selected.length - 1
58330                 });
58331               } else {
58332                 contextual = firstLabel;
58333               }
58334
58335               titleID = 'context';
58336             }
58337
58338             if (includeChangeCount) {
58339               changeCount = context.history().difference().summary().length;
58340
58341               if (changeCount > 0) {
58342                 titleID = contextual ? 'changes_context' : 'changes';
58343               }
58344             }
58345
58346             if (titleID) {
58347               return _t('title.format.' + titleID, {
58348                 changes: changeCount,
58349                 base: baseTitle,
58350                 context: contextual
58351               });
58352             }
58353
58354             return baseTitle;
58355           }
58356
58357           function updateTitle(includeChangeCount) {
58358             if (!context.setsDocumentTitle()) return;
58359             var newTitle = computedTitle(includeChangeCount);
58360
58361             if (document.title !== newTitle) {
58362               document.title = newTitle;
58363             }
58364           }
58365
58366           function updateHashIfNeeded() {
58367             if (context.inIntro()) return;
58368             var latestHash = computedHash();
58369
58370             if (_cachedHash !== latestHash) {
58371               _cachedHash = latestHash; // Update the URL hash without affecting the browser navigation stack,
58372               // though unavoidably creating a browser history entry
58373
58374               window.history.replaceState(null, computedTitle(false
58375               /* includeChangeCount */
58376               ), latestHash); // set the title we want displayed for the browser tab/window
58377
58378               updateTitle(true
58379               /* includeChangeCount */
58380               );
58381             }
58382           }
58383
58384           var _throttledUpdate = throttle(updateHashIfNeeded, 500);
58385
58386           var _throttledUpdateTitle = throttle(function () {
58387             updateTitle(true
58388             /* includeChangeCount */
58389             );
58390           }, 500);
58391
58392           function hashchange() {
58393             // ignore spurious hashchange events
58394             if (window.location.hash === _cachedHash) return;
58395             _cachedHash = window.location.hash;
58396             var q = utilStringQs(_cachedHash);
58397             var mapArgs = (q.map || '').split('/').map(Number);
58398
58399             if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
58400               // replace bogus hash
58401               updateHashIfNeeded();
58402             } else {
58403               // don't update if the new hash already reflects the state of iD
58404               if (_cachedHash === computedHash()) return;
58405               var mode = context.mode();
58406               context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
58407
58408               if (q.id && mode) {
58409                 var ids = q.id.split(',').filter(function (id) {
58410                   return context.hasEntity(id);
58411                 });
58412
58413                 if (ids.length && (mode.id === 'browse' || mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids))) {
58414                   context.enter(modeSelect(context, ids));
58415                   return;
58416                 }
58417               }
58418
58419               var center = context.map().center();
58420               var dist = geoSphericalDistance(center, [mapArgs[2], mapArgs[1]]);
58421               var maxdist = 500; // Don't allow the hash location to change too much while drawing
58422               // This can happen if the user accidentally hit the back button.  #3996
58423
58424               if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
58425                 context.enter(modeBrowse(context));
58426                 return;
58427               }
58428             }
58429           }
58430
58431           function behavior() {
58432             context.map().on('move.behaviorHash', _throttledUpdate);
58433             context.history().on('change.behaviorHash', _throttledUpdateTitle);
58434             context.on('enter.behaviorHash', _throttledUpdate);
58435             select(window).on('hashchange.behaviorHash', hashchange);
58436
58437             if (window.location.hash) {
58438               var q = utilStringQs(window.location.hash);
58439
58440               if (q.id) {
58441                 //if (!context.history().hasRestorableChanges()) {
58442                 // targeting specific features: download, select, and zoom to them
58443                 context.zoomToEntity(q.id.split(',')[0], !q.map); //}
58444               }
58445
58446               if (q.walkthrough === 'true') {
58447                 behavior.startWalkthrough = true;
58448               }
58449
58450               if (q.map) {
58451                 behavior.hadHash = true;
58452               }
58453
58454               hashchange();
58455               updateTitle(false);
58456             }
58457           }
58458
58459           behavior.off = function () {
58460             _throttledUpdate.cancel();
58461
58462             _throttledUpdateTitle.cancel();
58463
58464             context.map().on('move.behaviorHash', null);
58465             context.on('enter.behaviorHash', null);
58466             select(window).on('hashchange.behaviorHash', null);
58467             window.location.hash = '';
58468           };
58469
58470           return behavior;
58471         }
58472
58473         /*
58474             iD.coreDifference represents the difference between two graphs.
58475             It knows how to calculate the set of entities that were
58476             created, modified, or deleted, and also contains the logic
58477             for recursively extending a difference to the complete set
58478             of entities that will require a redraw, taking into account
58479             child and parent relationships.
58480          */
58481
58482         function coreDifference(base, head) {
58483           var _changes = {};
58484           var _didChange = {}; // 'addition', 'deletion', 'geometry', 'properties'
58485
58486           var _diff = {};
58487
58488           function checkEntityID(id) {
58489             var h = head.entities[id];
58490             var b = base.entities[id];
58491             if (h === b) return;
58492             if (_changes[id]) return;
58493
58494             if (!h && b) {
58495               _changes[id] = {
58496                 base: b,
58497                 head: h
58498               };
58499               _didChange.deletion = true;
58500               return;
58501             }
58502
58503             if (h && !b) {
58504               _changes[id] = {
58505                 base: b,
58506                 head: h
58507               };
58508               _didChange.addition = true;
58509               return;
58510             }
58511
58512             if (h && b) {
58513               if (h.members && b.members && !fastDeepEqual(h.members, b.members)) {
58514                 _changes[id] = {
58515                   base: b,
58516                   head: h
58517                 };
58518                 _didChange.geometry = true;
58519                 _didChange.properties = true;
58520                 return;
58521               }
58522
58523               if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
58524                 _changes[id] = {
58525                   base: b,
58526                   head: h
58527                 };
58528                 _didChange.geometry = true;
58529               }
58530
58531               if (h.nodes && b.nodes && !fastDeepEqual(h.nodes, b.nodes)) {
58532                 _changes[id] = {
58533                   base: b,
58534                   head: h
58535                 };
58536                 _didChange.geometry = true;
58537               }
58538
58539               if (h.tags && b.tags && !fastDeepEqual(h.tags, b.tags)) {
58540                 _changes[id] = {
58541                   base: b,
58542                   head: h
58543                 };
58544                 _didChange.properties = true;
58545               }
58546             }
58547           }
58548
58549           function load() {
58550             // HOT CODE: there can be many thousands of downloaded entities, so looping
58551             // through them all can become a performance bottleneck. Optimize by
58552             // resolving duplicates and using a basic `for` loop
58553             var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
58554
58555             for (var i = 0; i < ids.length; i++) {
58556               checkEntityID(ids[i]);
58557             }
58558           }
58559
58560           load();
58561
58562           _diff.length = function length() {
58563             return Object.keys(_changes).length;
58564           };
58565
58566           _diff.changes = function changes() {
58567             return _changes;
58568           };
58569
58570           _diff.didChange = _didChange; // pass true to include affected relation members
58571
58572           _diff.extantIDs = function extantIDs(includeRelMembers) {
58573             var result = new Set();
58574             Object.keys(_changes).forEach(function (id) {
58575               if (_changes[id].head) {
58576                 result.add(id);
58577               }
58578
58579               var h = _changes[id].head;
58580               var b = _changes[id].base;
58581               var entity = h || b;
58582
58583               if (includeRelMembers && entity.type === 'relation') {
58584                 var mh = h ? h.members.map(function (m) {
58585                   return m.id;
58586                 }) : [];
58587                 var mb = b ? b.members.map(function (m) {
58588                   return m.id;
58589                 }) : [];
58590                 utilArrayUnion(mh, mb).forEach(function (memberID) {
58591                   if (head.hasEntity(memberID)) {
58592                     result.add(memberID);
58593                   }
58594                 });
58595               }
58596             });
58597             return Array.from(result);
58598           };
58599
58600           _diff.modified = function modified() {
58601             var result = [];
58602             Object.values(_changes).forEach(function (change) {
58603               if (change.base && change.head) {
58604                 result.push(change.head);
58605               }
58606             });
58607             return result;
58608           };
58609
58610           _diff.created = function created() {
58611             var result = [];
58612             Object.values(_changes).forEach(function (change) {
58613               if (!change.base && change.head) {
58614                 result.push(change.head);
58615               }
58616             });
58617             return result;
58618           };
58619
58620           _diff.deleted = function deleted() {
58621             var result = [];
58622             Object.values(_changes).forEach(function (change) {
58623               if (change.base && !change.head) {
58624                 result.push(change.base);
58625               }
58626             });
58627             return result;
58628           };
58629
58630           _diff.summary = function summary() {
58631             var relevant = {};
58632             var keys = Object.keys(_changes);
58633
58634             for (var i = 0; i < keys.length; i++) {
58635               var change = _changes[keys[i]];
58636
58637               if (change.head && change.head.geometry(head) !== 'vertex') {
58638                 addEntity(change.head, head, change.base ? 'modified' : 'created');
58639               } else if (change.base && change.base.geometry(base) !== 'vertex') {
58640                 addEntity(change.base, base, 'deleted');
58641               } else if (change.base && change.head) {
58642                 // modified vertex
58643                 var moved = !fastDeepEqual(change.base.loc, change.head.loc);
58644                 var retagged = !fastDeepEqual(change.base.tags, change.head.tags);
58645
58646                 if (moved) {
58647                   addParents(change.head);
58648                 }
58649
58650                 if (retagged || moved && change.head.hasInterestingTags()) {
58651                   addEntity(change.head, head, 'modified');
58652                 }
58653               } else if (change.head && change.head.hasInterestingTags()) {
58654                 // created vertex
58655                 addEntity(change.head, head, 'created');
58656               } else if (change.base && change.base.hasInterestingTags()) {
58657                 // deleted vertex
58658                 addEntity(change.base, base, 'deleted');
58659               }
58660             }
58661
58662             return Object.values(relevant);
58663
58664             function addEntity(entity, graph, changeType) {
58665               relevant[entity.id] = {
58666                 entity: entity,
58667                 graph: graph,
58668                 changeType: changeType
58669               };
58670             }
58671
58672             function addParents(entity) {
58673               var parents = head.parentWays(entity);
58674
58675               for (var j = parents.length - 1; j >= 0; j--) {
58676                 var parent = parents[j];
58677
58678                 if (!(parent.id in relevant)) {
58679                   addEntity(parent, head, 'modified');
58680                 }
58681               }
58682             }
58683           }; // returns complete set of entities that require a redraw
58684           //  (optionally within given `extent`)
58685
58686
58687           _diff.complete = function complete(extent) {
58688             var result = {};
58689             var id, change;
58690
58691             for (id in _changes) {
58692               change = _changes[id];
58693               var h = change.head;
58694               var b = change.base;
58695               var entity = h || b;
58696               var i;
58697               if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) continue;
58698               result[id] = h;
58699
58700               if (entity.type === 'way') {
58701                 var nh = h ? h.nodes : [];
58702                 var nb = b ? b.nodes : [];
58703                 var diff;
58704                 diff = utilArrayDifference(nh, nb);
58705
58706                 for (i = 0; i < diff.length; i++) {
58707                   result[diff[i]] = head.hasEntity(diff[i]);
58708                 }
58709
58710                 diff = utilArrayDifference(nb, nh);
58711
58712                 for (i = 0; i < diff.length; i++) {
58713                   result[diff[i]] = head.hasEntity(diff[i]);
58714                 }
58715               }
58716
58717               if (entity.type === 'relation' && entity.isMultipolygon()) {
58718                 var mh = h ? h.members.map(function (m) {
58719                   return m.id;
58720                 }) : [];
58721                 var mb = b ? b.members.map(function (m) {
58722                   return m.id;
58723                 }) : [];
58724                 var ids = utilArrayUnion(mh, mb);
58725
58726                 for (i = 0; i < ids.length; i++) {
58727                   var member = head.hasEntity(ids[i]);
58728                   if (!member) continue; // not downloaded
58729
58730                   if (extent && !member.intersects(extent, head)) continue; // not visible
58731
58732                   result[ids[i]] = member;
58733                 }
58734               }
58735
58736               addParents(head.parentWays(entity), result);
58737               addParents(head.parentRelations(entity), result);
58738             }
58739
58740             return result;
58741
58742             function addParents(parents, result) {
58743               for (var i = 0; i < parents.length; i++) {
58744                 var parent = parents[i];
58745                 if (parent.id in result) continue;
58746                 result[parent.id] = parent;
58747                 addParents(head.parentRelations(parent), result);
58748               }
58749             }
58750           };
58751
58752           return _diff;
58753         }
58754
58755         function coreTree(head) {
58756           // tree for entities
58757           var _rtree = new RBush();
58758
58759           var _bboxes = {}; // maintain a separate tree for granular way segments
58760
58761           var _segmentsRTree = new RBush();
58762
58763           var _segmentsBBoxes = {};
58764           var _segmentsByWayId = {};
58765           var tree = {};
58766
58767           function entityBBox(entity) {
58768             var bbox = entity.extent(head).bbox();
58769             bbox.id = entity.id;
58770             _bboxes[entity.id] = bbox;
58771             return bbox;
58772           }
58773
58774           function segmentBBox(segment) {
58775             var extent = segment.extent(head); // extent can be null if the node entities aren't in the graph for some reason
58776
58777             if (!extent) return null;
58778             var bbox = extent.bbox();
58779             bbox.segment = segment;
58780             _segmentsBBoxes[segment.id] = bbox;
58781             return bbox;
58782           }
58783
58784           function removeEntity(entity) {
58785             _rtree.remove(_bboxes[entity.id]);
58786
58787             delete _bboxes[entity.id];
58788
58789             if (_segmentsByWayId[entity.id]) {
58790               _segmentsByWayId[entity.id].forEach(function (segment) {
58791                 _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
58792
58793                 delete _segmentsBBoxes[segment.id];
58794               });
58795
58796               delete _segmentsByWayId[entity.id];
58797             }
58798           }
58799
58800           function loadEntities(entities) {
58801             _rtree.load(entities.map(entityBBox));
58802
58803             var segments = [];
58804             entities.forEach(function (entity) {
58805               if (entity.segments) {
58806                 var entitySegments = entity.segments(head); // cache these to make them easy to remove later
58807
58808                 _segmentsByWayId[entity.id] = entitySegments;
58809                 segments = segments.concat(entitySegments);
58810               }
58811             });
58812             if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
58813           }
58814
58815           function updateParents(entity, insertions, memo) {
58816             head.parentWays(entity).forEach(function (way) {
58817               if (_bboxes[way.id]) {
58818                 removeEntity(way);
58819                 insertions[way.id] = way;
58820               }
58821
58822               updateParents(way, insertions, memo);
58823             });
58824             head.parentRelations(entity).forEach(function (relation) {
58825               if (memo[entity.id]) return;
58826               memo[entity.id] = true;
58827
58828               if (_bboxes[relation.id]) {
58829                 removeEntity(relation);
58830                 insertions[relation.id] = relation;
58831               }
58832
58833               updateParents(relation, insertions, memo);
58834             });
58835           }
58836
58837           tree.rebase = function (entities, force) {
58838             var insertions = {};
58839
58840             for (var i = 0; i < entities.length; i++) {
58841               var entity = entities[i];
58842               if (!entity.visible) continue;
58843
58844               if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
58845                 if (!force) {
58846                   continue;
58847                 } else if (_bboxes[entity.id]) {
58848                   removeEntity(entity);
58849                 }
58850               }
58851
58852               insertions[entity.id] = entity;
58853               updateParents(entity, insertions, {});
58854             }
58855
58856             loadEntities(Object.values(insertions));
58857             return tree;
58858           };
58859
58860           function updateToGraph(graph) {
58861             if (graph === head) return;
58862             var diff = coreDifference(head, graph);
58863             head = graph;
58864             var changed = diff.didChange;
58865             if (!changed.addition && !changed.deletion && !changed.geometry) return;
58866             var insertions = {};
58867
58868             if (changed.deletion) {
58869               diff.deleted().forEach(function (entity) {
58870                 removeEntity(entity);
58871               });
58872             }
58873
58874             if (changed.geometry) {
58875               diff.modified().forEach(function (entity) {
58876                 removeEntity(entity);
58877                 insertions[entity.id] = entity;
58878                 updateParents(entity, insertions, {});
58879               });
58880             }
58881
58882             if (changed.addition) {
58883               diff.created().forEach(function (entity) {
58884                 insertions[entity.id] = entity;
58885               });
58886             }
58887
58888             loadEntities(Object.values(insertions));
58889           } // returns an array of entities with bounding boxes overlapping `extent` for the given `graph`
58890
58891
58892           tree.intersects = function (extent, graph) {
58893             updateToGraph(graph);
58894             return _rtree.search(extent.bbox()).map(function (bbox) {
58895               return graph.entity(bbox.id);
58896             });
58897           }; // returns an array of segment objects with bounding boxes overlapping `extent` for the given `graph`
58898
58899
58900           tree.waySegments = function (extent, graph) {
58901             updateToGraph(graph);
58902             return _segmentsRTree.search(extent.bbox()).map(function (bbox) {
58903               return bbox.segment;
58904             });
58905           };
58906
58907           return tree;
58908         }
58909
58910         function uiModal(selection, blocking) {
58911           var _this = this;
58912
58913           var keybinding = utilKeybinding('modal');
58914           var previous = selection.select('div.modal');
58915           var animate = previous.empty();
58916           previous.transition().duration(200).style('opacity', 0).remove();
58917           var shaded = selection.append('div').attr('class', 'shaded').style('opacity', 0);
58918
58919           shaded.close = function () {
58920             shaded.transition().duration(200).style('opacity', 0).remove();
58921             modal.transition().duration(200).style('top', '0px');
58922             select(document).call(keybinding.unbind);
58923           };
58924
58925           var modal = shaded.append('div').attr('class', 'modal fillL');
58926           modal.append('input').attr('class', 'keytrap keytrap-first').on('focus.keytrap', moveFocusToLast);
58927
58928           if (!blocking) {
58929             shaded.on('click.remove-modal', function (d3_event) {
58930               if (d3_event.target === _this) {
58931                 shaded.close();
58932               }
58933             });
58934             modal.append('button').attr('class', 'close').on('click', shaded.close).call(svgIcon('#iD-icon-close'));
58935             keybinding.on('⌫', shaded.close).on('⎋', shaded.close);
58936             select(document).call(keybinding);
58937           }
58938
58939           modal.append('div').attr('class', 'content');
58940           modal.append('input').attr('class', 'keytrap keytrap-last').on('focus.keytrap', moveFocusToFirst);
58941
58942           if (animate) {
58943             shaded.transition().style('opacity', 1);
58944           } else {
58945             shaded.style('opacity', 1);
58946           }
58947
58948           return shaded;
58949
58950           function moveFocusToFirst() {
58951             var node = modal // there are additional rules about what's focusable, but this suits our purposes
58952             .select('a, button, input:not(.keytrap), select, textarea').node();
58953
58954             if (node) {
58955               node.focus();
58956             } else {
58957               select(this).node().blur();
58958             }
58959           }
58960
58961           function moveFocusToLast() {
58962             var nodes = modal.selectAll('a, button, input:not(.keytrap), select, textarea').nodes();
58963
58964             if (nodes.length) {
58965               nodes[nodes.length - 1].focus();
58966             } else {
58967               select(this).node().blur();
58968             }
58969           }
58970         }
58971
58972         function uiLoading(context) {
58973           var _modalSelection = select(null);
58974
58975           var _message = '';
58976           var _blocking = false;
58977
58978           var loading = function loading(selection) {
58979             _modalSelection = uiModal(selection, _blocking);
58980
58981             var loadertext = _modalSelection.select('.content').classed('loading-modal', true).append('div').attr('class', 'modal-section fillL');
58982
58983             loadertext.append('img').attr('class', 'loader').attr('src', context.imagePath('loader-white.gif'));
58984             loadertext.append('h3').html(_message);
58985
58986             _modalSelection.select('button.close').attr('class', 'hide');
58987
58988             return loading;
58989           };
58990
58991           loading.message = function (val) {
58992             if (!arguments.length) return _message;
58993             _message = val;
58994             return loading;
58995           };
58996
58997           loading.blocking = function (val) {
58998             if (!arguments.length) return _blocking;
58999             _blocking = val;
59000             return loading;
59001           };
59002
59003           loading.close = function () {
59004             _modalSelection.remove();
59005           };
59006
59007           loading.isShown = function () {
59008             return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
59009           };
59010
59011           return loading;
59012         }
59013
59014         function coreHistory(context) {
59015           var dispatch$1 = dispatch('reset', 'change', 'merge', 'restore', 'undone', 'redone');
59016
59017           var _lock = utilSessionMutex('lock'); // restorable if iD not open in another window/tab and a saved history exists in localStorage
59018
59019
59020           var _hasUnresolvedRestorableChanges = _lock.lock() && !!corePreferences(getKey('saved_history'));
59021
59022           var duration = 150;
59023           var _imageryUsed = [];
59024           var _photoOverlaysUsed = [];
59025           var _checkpoints = {};
59026
59027           var _pausedGraph;
59028
59029           var _stack;
59030
59031           var _index;
59032
59033           var _tree; // internal _act, accepts list of actions and eased time
59034
59035
59036           function _act(actions, t) {
59037             actions = Array.prototype.slice.call(actions);
59038             var annotation;
59039
59040             if (typeof actions[actions.length - 1] !== 'function') {
59041               annotation = actions.pop();
59042             }
59043
59044             var graph = _stack[_index].graph;
59045
59046             for (var i = 0; i < actions.length; i++) {
59047               graph = actions[i](graph, t);
59048             }
59049
59050             return {
59051               graph: graph,
59052               annotation: annotation,
59053               imageryUsed: _imageryUsed,
59054               photoOverlaysUsed: _photoOverlaysUsed,
59055               transform: context.projection.transform(),
59056               selectedIDs: context.selectedIDs()
59057             };
59058           } // internal _perform with eased time
59059
59060
59061           function _perform(args, t) {
59062             var previous = _stack[_index].graph;
59063             _stack = _stack.slice(0, _index + 1);
59064
59065             var actionResult = _act(args, t);
59066
59067             _stack.push(actionResult);
59068
59069             _index++;
59070             return change(previous);
59071           } // internal _replace with eased time
59072
59073
59074           function _replace(args, t) {
59075             var previous = _stack[_index].graph; // assert(_index == _stack.length - 1)
59076
59077             var actionResult = _act(args, t);
59078
59079             _stack[_index] = actionResult;
59080             return change(previous);
59081           } // internal _overwrite with eased time
59082
59083
59084           function _overwrite(args, t) {
59085             var previous = _stack[_index].graph;
59086
59087             if (_index > 0) {
59088               _index--;
59089
59090               _stack.pop();
59091             }
59092
59093             _stack = _stack.slice(0, _index + 1);
59094
59095             var actionResult = _act(args, t);
59096
59097             _stack.push(actionResult);
59098
59099             _index++;
59100             return change(previous);
59101           } // determine difference and dispatch a change event
59102
59103
59104           function change(previous) {
59105             var difference = coreDifference(previous, history.graph());
59106
59107             if (!_pausedGraph) {
59108               dispatch$1.call('change', this, difference);
59109             }
59110
59111             return difference;
59112           } // iD uses namespaced keys so multiple installations do not conflict
59113
59114
59115           function getKey(n) {
59116             return 'iD_' + window.location.origin + '_' + n;
59117           }
59118
59119           var history = {
59120             graph: function graph() {
59121               return _stack[_index].graph;
59122             },
59123             tree: function tree() {
59124               return _tree;
59125             },
59126             base: function base() {
59127               return _stack[0].graph;
59128             },
59129             merge: function merge(entities
59130             /*, extent*/
59131             ) {
59132               var stack = _stack.map(function (state) {
59133                 return state.graph;
59134               });
59135
59136               _stack[0].graph.rebase(entities, stack, false);
59137
59138               _tree.rebase(entities, false);
59139
59140               dispatch$1.call('merge', this, entities);
59141             },
59142             perform: function perform() {
59143               // complete any transition already in progress
59144               select(document).interrupt('history.perform');
59145               var transitionable = false;
59146               var action0 = arguments[0];
59147
59148               if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== 'function') {
59149                 transitionable = !!action0.transitionable;
59150               }
59151
59152               if (transitionable) {
59153                 var origArguments = arguments;
59154                 select(document).transition('history.perform').duration(duration).ease(linear$1).tween('history.tween', function () {
59155                   return function (t) {
59156                     if (t < 1) _overwrite([action0], t);
59157                   };
59158                 }).on('start', function () {
59159                   _perform([action0], 0);
59160                 }).on('end interrupt', function () {
59161                   _overwrite(origArguments, 1);
59162                 });
59163               } else {
59164                 return _perform(arguments);
59165               }
59166             },
59167             replace: function replace() {
59168               select(document).interrupt('history.perform');
59169               return _replace(arguments, 1);
59170             },
59171             // Same as calling pop and then perform
59172             overwrite: function overwrite() {
59173               select(document).interrupt('history.perform');
59174               return _overwrite(arguments, 1);
59175             },
59176             pop: function pop(n) {
59177               select(document).interrupt('history.perform');
59178               var previous = _stack[_index].graph;
59179
59180               if (isNaN(+n) || +n < 0) {
59181                 n = 1;
59182               }
59183
59184               while (n-- > 0 && _index > 0) {
59185                 _index--;
59186
59187                 _stack.pop();
59188               }
59189
59190               return change(previous);
59191             },
59192             // Back to the previous annotated state or _index = 0.
59193             undo: function undo() {
59194               select(document).interrupt('history.perform');
59195               var previousStack = _stack[_index];
59196               var previous = previousStack.graph;
59197
59198               while (_index > 0) {
59199                 _index--;
59200                 if (_stack[_index].annotation) break;
59201               }
59202
59203               dispatch$1.call('undone', this, _stack[_index], previousStack);
59204               return change(previous);
59205             },
59206             // Forward to the next annotated state.
59207             redo: function redo() {
59208               select(document).interrupt('history.perform');
59209               var previousStack = _stack[_index];
59210               var previous = previousStack.graph;
59211               var tryIndex = _index;
59212
59213               while (tryIndex < _stack.length - 1) {
59214                 tryIndex++;
59215
59216                 if (_stack[tryIndex].annotation) {
59217                   _index = tryIndex;
59218                   dispatch$1.call('redone', this, _stack[_index], previousStack);
59219                   break;
59220                 }
59221               }
59222
59223               return change(previous);
59224             },
59225             pauseChangeDispatch: function pauseChangeDispatch() {
59226               if (!_pausedGraph) {
59227                 _pausedGraph = _stack[_index].graph;
59228               }
59229             },
59230             resumeChangeDispatch: function resumeChangeDispatch() {
59231               if (_pausedGraph) {
59232                 var previous = _pausedGraph;
59233                 _pausedGraph = null;
59234                 return change(previous);
59235               }
59236             },
59237             undoAnnotation: function undoAnnotation() {
59238               var i = _index;
59239
59240               while (i >= 0) {
59241                 if (_stack[i].annotation) return _stack[i].annotation;
59242                 i--;
59243               }
59244             },
59245             redoAnnotation: function redoAnnotation() {
59246               var i = _index + 1;
59247
59248               while (i <= _stack.length - 1) {
59249                 if (_stack[i].annotation) return _stack[i].annotation;
59250                 i++;
59251               }
59252             },
59253             // Returns the entities from the active graph with bounding boxes
59254             // overlapping the given `extent`.
59255             intersects: function intersects(extent) {
59256               return _tree.intersects(extent, _stack[_index].graph);
59257             },
59258             difference: function difference() {
59259               var base = _stack[0].graph;
59260               var head = _stack[_index].graph;
59261               return coreDifference(base, head);
59262             },
59263             changes: function changes(action) {
59264               var base = _stack[0].graph;
59265               var head = _stack[_index].graph;
59266
59267               if (action) {
59268                 head = action(head);
59269               }
59270
59271               var difference = coreDifference(base, head);
59272               return {
59273                 modified: difference.modified(),
59274                 created: difference.created(),
59275                 deleted: difference.deleted()
59276               };
59277             },
59278             hasChanges: function hasChanges() {
59279               return this.difference().length() > 0;
59280             },
59281             imageryUsed: function imageryUsed(sources) {
59282               if (sources) {
59283                 _imageryUsed = sources;
59284                 return history;
59285               } else {
59286                 var s = new Set();
59287
59288                 _stack.slice(1, _index + 1).forEach(function (state) {
59289                   state.imageryUsed.forEach(function (source) {
59290                     if (source !== 'Custom') {
59291                       s.add(source);
59292                     }
59293                   });
59294                 });
59295
59296                 return Array.from(s);
59297               }
59298             },
59299             photoOverlaysUsed: function photoOverlaysUsed(sources) {
59300               if (sources) {
59301                 _photoOverlaysUsed = sources;
59302                 return history;
59303               } else {
59304                 var s = new Set();
59305
59306                 _stack.slice(1, _index + 1).forEach(function (state) {
59307                   if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
59308                     state.photoOverlaysUsed.forEach(function (photoOverlay) {
59309                       s.add(photoOverlay);
59310                     });
59311                   }
59312                 });
59313
59314                 return Array.from(s);
59315               }
59316             },
59317             // save the current history state
59318             checkpoint: function checkpoint(key) {
59319               _checkpoints[key] = {
59320                 stack: _stack,
59321                 index: _index
59322               };
59323               return history;
59324             },
59325             // restore history state to a given checkpoint or reset completely
59326             reset: function reset(key) {
59327               if (key !== undefined && _checkpoints.hasOwnProperty(key)) {
59328                 _stack = _checkpoints[key].stack;
59329                 _index = _checkpoints[key].index;
59330               } else {
59331                 _stack = [{
59332                   graph: coreGraph()
59333                 }];
59334                 _index = 0;
59335                 _tree = coreTree(_stack[0].graph);
59336                 _checkpoints = {};
59337               }
59338
59339               dispatch$1.call('reset');
59340               dispatch$1.call('change');
59341               return history;
59342             },
59343             // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
59344             //
59345             // To use it:
59346             //  1. Start the walkthrough.
59347             //  2. Get to a "free editing" tutorial step
59348             //  3. Make your edits to the walkthrough map
59349             //  4. In your browser dev console run:
59350             //        `id.history().toIntroGraph()`
59351             //  5. This outputs stringified JSON to the browser console
59352             //  6. Copy it to `data/intro_graph.json` and prettify it in your code editor
59353             toIntroGraph: function toIntroGraph() {
59354               var nextID = {
59355                 n: 0,
59356                 r: 0,
59357                 w: 0
59358               };
59359               var permIDs = {};
59360               var graph = this.graph();
59361               var baseEntities = {}; // clone base entities..
59362
59363               Object.values(graph.base().entities).forEach(function (entity) {
59364                 var copy = copyIntroEntity(entity);
59365                 baseEntities[copy.id] = copy;
59366               }); // replace base entities with head entities..
59367
59368               Object.keys(graph.entities).forEach(function (id) {
59369                 var entity = graph.entities[id];
59370
59371                 if (entity) {
59372                   var copy = copyIntroEntity(entity);
59373                   baseEntities[copy.id] = copy;
59374                 } else {
59375                   delete baseEntities[id];
59376                 }
59377               }); // swap temporary for permanent ids..
59378
59379               Object.values(baseEntities).forEach(function (entity) {
59380                 if (Array.isArray(entity.nodes)) {
59381                   entity.nodes = entity.nodes.map(function (node) {
59382                     return permIDs[node] || node;
59383                   });
59384                 }
59385
59386                 if (Array.isArray(entity.members)) {
59387                   entity.members = entity.members.map(function (member) {
59388                     member.id = permIDs[member.id] || member.id;
59389                     return member;
59390                   });
59391                 }
59392               });
59393               return JSON.stringify({
59394                 dataIntroGraph: baseEntities
59395               });
59396
59397               function copyIntroEntity(source) {
59398                 var copy = utilObjectOmit(source, ['type', 'user', 'v', 'version', 'visible']); // Note: the copy is no longer an osmEntity, so it might not have `tags`
59399
59400                 if (copy.tags && !Object.keys(copy.tags)) {
59401                   delete copy.tags;
59402                 }
59403
59404                 if (Array.isArray(copy.loc)) {
59405                   copy.loc[0] = +copy.loc[0].toFixed(6);
59406                   copy.loc[1] = +copy.loc[1].toFixed(6);
59407                 }
59408
59409                 var match = source.id.match(/([nrw])-\d*/); // temporary id
59410
59411                 if (match !== null) {
59412                   var nrw = match[1];
59413                   var permID;
59414
59415                   do {
59416                     permID = nrw + ++nextID[nrw];
59417                   } while (baseEntities.hasOwnProperty(permID));
59418
59419                   copy.id = permIDs[source.id] = permID;
59420                 }
59421
59422                 return copy;
59423               }
59424             },
59425             toJSON: function toJSON() {
59426               if (!this.hasChanges()) return;
59427               var allEntities = {};
59428               var baseEntities = {};
59429               var base = _stack[0];
59430
59431               var s = _stack.map(function (i) {
59432                 var modified = [];
59433                 var deleted = [];
59434                 Object.keys(i.graph.entities).forEach(function (id) {
59435                   var entity = i.graph.entities[id];
59436
59437                   if (entity) {
59438                     var key = osmEntity.key(entity);
59439                     allEntities[key] = entity;
59440                     modified.push(key);
59441                   } else {
59442                     deleted.push(id);
59443                   } // make sure that the originals of changed or deleted entities get merged
59444                   // into the base of the _stack after restoring the data from JSON.
59445
59446
59447                   if (id in base.graph.entities) {
59448                     baseEntities[id] = base.graph.entities[id];
59449                   }
59450
59451                   if (entity && entity.nodes) {
59452                     // get originals of pre-existing child nodes
59453                     entity.nodes.forEach(function (nodeID) {
59454                       if (nodeID in base.graph.entities) {
59455                         baseEntities[nodeID] = base.graph.entities[nodeID];
59456                       }
59457                     });
59458                   } // get originals of parent entities too
59459
59460
59461                   var baseParents = base.graph._parentWays[id];
59462
59463                   if (baseParents) {
59464                     baseParents.forEach(function (parentID) {
59465                       if (parentID in base.graph.entities) {
59466                         baseEntities[parentID] = base.graph.entities[parentID];
59467                       }
59468                     });
59469                   }
59470                 });
59471                 var x = {};
59472                 if (modified.length) x.modified = modified;
59473                 if (deleted.length) x.deleted = deleted;
59474                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
59475                 if (i.photoOverlaysUsed) x.photoOverlaysUsed = i.photoOverlaysUsed;
59476                 if (i.annotation) x.annotation = i.annotation;
59477                 if (i.transform) x.transform = i.transform;
59478                 if (i.selectedIDs) x.selectedIDs = i.selectedIDs;
59479                 return x;
59480               });
59481
59482               return JSON.stringify({
59483                 version: 3,
59484                 entities: Object.values(allEntities),
59485                 baseEntities: Object.values(baseEntities),
59486                 stack: s,
59487                 nextIDs: osmEntity.id.next,
59488                 index: _index,
59489                 // note the time the changes were saved
59490                 timestamp: new Date().getTime()
59491               });
59492             },
59493             fromJSON: function fromJSON(json, loadChildNodes) {
59494               var h = JSON.parse(json);
59495               var loadComplete = true;
59496               osmEntity.id.next = h.nextIDs;
59497               _index = h.index;
59498
59499               if (h.version === 2 || h.version === 3) {
59500                 var allEntities = {};
59501                 h.entities.forEach(function (entity) {
59502                   allEntities[osmEntity.key(entity)] = osmEntity(entity);
59503                 });
59504
59505                 if (h.version === 3) {
59506                   // This merges originals for changed entities into the base of
59507                   // the _stack even if the current _stack doesn't have them (for
59508                   // example when iD has been restarted in a different region)
59509                   var baseEntities = h.baseEntities.map(function (d) {
59510                     return osmEntity(d);
59511                   });
59512
59513                   var stack = _stack.map(function (state) {
59514                     return state.graph;
59515                   });
59516
59517                   _stack[0].graph.rebase(baseEntities, stack, true);
59518
59519                   _tree.rebase(baseEntities, true); // When we restore a modified way, we also need to fetch any missing
59520                   // childnodes that would normally have been downloaded with it.. #2142
59521
59522
59523                   if (loadChildNodes) {
59524                     var osm = context.connection();
59525                     var baseWays = baseEntities.filter(function (e) {
59526                       return e.type === 'way';
59527                     });
59528                     var nodeIDs = baseWays.reduce(function (acc, way) {
59529                       return utilArrayUnion(acc, way.nodes);
59530                     }, []);
59531                     var missing = nodeIDs.filter(function (n) {
59532                       return !_stack[0].graph.hasEntity(n);
59533                     });
59534
59535                     if (missing.length && osm) {
59536                       loadComplete = false;
59537                       context.map().redrawEnable(false);
59538                       var loading = uiLoading(context).blocking(true);
59539                       context.container().call(loading);
59540
59541                       var childNodesLoaded = function childNodesLoaded(err, result) {
59542                         if (!err) {
59543                           var visibleGroups = utilArrayGroupBy(result.data, 'visible');
59544                           var visibles = visibleGroups["true"] || []; // alive nodes
59545
59546                           var invisibles = visibleGroups["false"] || []; // deleted nodes
59547
59548                           if (visibles.length) {
59549                             var visibleIDs = visibles.map(function (entity) {
59550                               return entity.id;
59551                             });
59552
59553                             var stack = _stack.map(function (state) {
59554                               return state.graph;
59555                             });
59556
59557                             missing = utilArrayDifference(missing, visibleIDs);
59558
59559                             _stack[0].graph.rebase(visibles, stack, true);
59560
59561                             _tree.rebase(visibles, true);
59562                           } // fetch older versions of nodes that were deleted..
59563
59564
59565                           invisibles.forEach(function (entity) {
59566                             osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
59567                           });
59568                         }
59569
59570                         if (err || !missing.length) {
59571                           loading.close();
59572                           context.map().redrawEnable(true);
59573                           dispatch$1.call('change');
59574                           dispatch$1.call('restore', this);
59575                         }
59576                       };
59577
59578                       osm.loadMultiple(missing, childNodesLoaded);
59579                     }
59580                   }
59581                 }
59582
59583                 _stack = h.stack.map(function (d) {
59584                   var entities = {},
59585                       entity;
59586
59587                   if (d.modified) {
59588                     d.modified.forEach(function (key) {
59589                       entity = allEntities[key];
59590                       entities[entity.id] = entity;
59591                     });
59592                   }
59593
59594                   if (d.deleted) {
59595                     d.deleted.forEach(function (id) {
59596                       entities[id] = undefined;
59597                     });
59598                   }
59599
59600                   return {
59601                     graph: coreGraph(_stack[0].graph).load(entities),
59602                     annotation: d.annotation,
59603                     imageryUsed: d.imageryUsed,
59604                     photoOverlaysUsed: d.photoOverlaysUsed,
59605                     transform: d.transform,
59606                     selectedIDs: d.selectedIDs
59607                   };
59608                 });
59609               } else {
59610                 // original version
59611                 _stack = h.stack.map(function (d) {
59612                   var entities = {};
59613
59614                   for (var i in d.entities) {
59615                     var entity = d.entities[i];
59616                     entities[i] = entity === 'undefined' ? undefined : osmEntity(entity);
59617                   }
59618
59619                   d.graph = coreGraph(_stack[0].graph).load(entities);
59620                   return d;
59621                 });
59622               }
59623
59624               var transform = _stack[_index].transform;
59625
59626               if (transform) {
59627                 context.map().transformEase(transform, 0); // 0 = immediate, no easing
59628               }
59629
59630               if (loadComplete) {
59631                 dispatch$1.call('change');
59632                 dispatch$1.call('restore', this);
59633               }
59634
59635               return history;
59636             },
59637             lock: function lock() {
59638               return _lock.lock();
59639             },
59640             unlock: function unlock() {
59641               _lock.unlock();
59642             },
59643             save: function save() {
59644               if (_lock.locked() && // don't overwrite existing, unresolved changes
59645               !_hasUnresolvedRestorableChanges) {
59646                 corePreferences(getKey('saved_history'), history.toJSON() || null);
59647               }
59648
59649               return history;
59650             },
59651             // delete the history version saved in localStorage
59652             clearSaved: function clearSaved() {
59653               context.debouncedSave.cancel();
59654
59655               if (_lock.locked()) {
59656                 _hasUnresolvedRestorableChanges = false;
59657                 corePreferences(getKey('saved_history'), null); // clear the changeset metadata associated with the saved history
59658
59659                 corePreferences('comment', null);
59660                 corePreferences('hashtags', null);
59661                 corePreferences('source', null);
59662               }
59663
59664               return history;
59665             },
59666             savedHistoryJSON: function savedHistoryJSON() {
59667               return corePreferences(getKey('saved_history'));
59668             },
59669             hasRestorableChanges: function hasRestorableChanges() {
59670               return _hasUnresolvedRestorableChanges;
59671             },
59672             // load history from a version stored in localStorage
59673             restore: function restore() {
59674               if (_lock.locked()) {
59675                 _hasUnresolvedRestorableChanges = false;
59676                 var json = this.savedHistoryJSON();
59677                 if (json) history.fromJSON(json, true);
59678               }
59679             },
59680             _getKey: getKey
59681           };
59682           history.reset();
59683           return utilRebind(history, dispatch$1, 'on');
59684         }
59685
59686         /**
59687          * Look for roads that can be connected to other roads with a short extension
59688          */
59689
59690         function validationAlmostJunction(context) {
59691           var type = 'almost_junction';
59692           var EXTEND_TH_METERS = 5;
59693           var WELD_TH_METERS = 0.75; // Comes from considering bounding case of parallel ways
59694
59695           var CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS; // Comes from considering bounding case of perpendicular ways
59696
59697           var SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
59698
59699           function isHighway(entity) {
59700             return entity.type === 'way' && osmRoutableHighwayTagValues[entity.tags.highway];
59701           }
59702
59703           function isTaggedAsNotContinuing(node) {
59704             return node.tags.noexit === 'yes' || node.tags.amenity === 'parking_entrance' || node.tags.entrance && node.tags.entrance !== 'no';
59705           }
59706
59707           var validation = function checkAlmostJunction(entity, graph) {
59708             if (!isHighway(entity)) return [];
59709             if (entity.isDegenerate()) return [];
59710             var tree = context.history().tree();
59711             var extendableNodeInfos = findConnectableEndNodesByExtension(entity);
59712             var issues = [];
59713             extendableNodeInfos.forEach(function (extendableNodeInfo) {
59714               issues.push(new validationIssue({
59715                 type: type,
59716                 subtype: 'highway-highway',
59717                 severity: 'warning',
59718                 message: function message(context) {
59719                   var entity1 = context.hasEntity(this.entityIds[0]);
59720
59721                   if (this.entityIds[0] === this.entityIds[2]) {
59722                     return entity1 ? _t.html('issues.almost_junction.self.message', {
59723                       feature: utilDisplayLabel(entity1, context.graph())
59724                     }) : '';
59725                   } else {
59726                     var entity2 = context.hasEntity(this.entityIds[2]);
59727                     return entity1 && entity2 ? _t.html('issues.almost_junction.message', {
59728                       feature: utilDisplayLabel(entity1, context.graph()),
59729                       feature2: utilDisplayLabel(entity2, context.graph())
59730                     }) : '';
59731                   }
59732                 },
59733                 reference: showReference,
59734                 entityIds: [entity.id, extendableNodeInfo.node.id, extendableNodeInfo.wid],
59735                 loc: extendableNodeInfo.node.loc,
59736                 hash: JSON.stringify(extendableNodeInfo.node.loc),
59737                 data: {
59738                   midId: extendableNodeInfo.mid.id,
59739                   edge: extendableNodeInfo.edge,
59740                   cross_loc: extendableNodeInfo.cross_loc
59741                 },
59742                 dynamicFixes: makeFixes
59743               }));
59744             });
59745             return issues;
59746
59747             function makeFixes(context) {
59748               var fixes = [new validationIssueFix({
59749                 icon: 'iD-icon-abutment',
59750                 title: _t.html('issues.fix.connect_features.title'),
59751                 onClick: function onClick(context) {
59752                   var annotation = _t('issues.fix.connect_almost_junction.annotation');
59753
59754                   var _this$issue$entityIds = _slicedToArray(this.issue.entityIds, 3),
59755                       endNodeId = _this$issue$entityIds[1],
59756                       crossWayId = _this$issue$entityIds[2];
59757
59758                   var midNode = context.entity(this.issue.data.midId);
59759                   var endNode = context.entity(endNodeId);
59760                   var crossWay = context.entity(crossWayId); // When endpoints are close, just join if resulting small change in angle (#7201)
59761
59762                   var nearEndNodes = findNearbyEndNodes(endNode, crossWay);
59763
59764                   if (nearEndNodes.length > 0) {
59765                     var collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
59766
59767                     if (collinear) {
59768                       context.perform(actionMergeNodes([collinear.id, endNode.id], collinear.loc), annotation);
59769                       return;
59770                     }
59771                   }
59772
59773                   var targetEdge = this.issue.data.edge;
59774                   var crossLoc = this.issue.data.cross_loc;
59775                   var edgeNodes = [context.entity(targetEdge[0]), context.entity(targetEdge[1])];
59776                   var closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc); // already a point nearby, just connect to that
59777
59778                   if (closestNodeInfo.distance < WELD_TH_METERS) {
59779                     context.perform(actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc), annotation); // else add the end node to the edge way
59780                   } else {
59781                     context.perform(actionAddMidpoint({
59782                       loc: crossLoc,
59783                       edge: targetEdge
59784                     }, endNode), annotation);
59785                   }
59786                 }
59787               })];
59788               var node = context.hasEntity(this.entityIds[1]);
59789
59790               if (node && !node.hasInterestingTags()) {
59791                 // node has no descriptive tags, suggest noexit fix
59792                 fixes.push(new validationIssueFix({
59793                   icon: 'maki-barrier',
59794                   title: _t.html('issues.fix.tag_as_disconnected.title'),
59795                   onClick: function onClick(context) {
59796                     var nodeID = this.issue.entityIds[1];
59797                     var tags = Object.assign({}, context.entity(nodeID).tags);
59798                     tags.noexit = 'yes';
59799                     context.perform(actionChangeTags(nodeID, tags), _t('issues.fix.tag_as_disconnected.annotation'));
59800                   }
59801                 }));
59802               }
59803
59804               return fixes;
59805             }
59806
59807             function showReference(selection) {
59808               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.almost_junction.highway-highway.reference'));
59809             }
59810
59811             function isExtendableCandidate(node, way) {
59812               // can not accurately test vertices on tiles not downloaded from osm - #5938
59813               var osm = services.osm;
59814
59815               if (osm && !osm.isDataLoaded(node.loc)) {
59816                 return false;
59817               }
59818
59819               if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
59820                 return false;
59821               }
59822
59823               var occurrences = 0;
59824
59825               for (var index in way.nodes) {
59826                 if (way.nodes[index] === node.id) {
59827                   occurrences += 1;
59828
59829                   if (occurrences > 1) {
59830                     return false;
59831                   }
59832                 }
59833               }
59834
59835               return true;
59836             }
59837
59838             function findConnectableEndNodesByExtension(way) {
59839               var results = [];
59840               if (way.isClosed()) return results;
59841               var testNodes;
59842               var indices = [0, way.nodes.length - 1];
59843               indices.forEach(function (nodeIndex) {
59844                 var nodeID = way.nodes[nodeIndex];
59845                 var node = graph.entity(nodeID);
59846                 if (!isExtendableCandidate(node, way)) return;
59847                 var connectionInfo = canConnectByExtend(way, nodeIndex);
59848                 if (!connectionInfo) return;
59849                 testNodes = graph.childNodes(way).slice(); // shallow copy
59850
59851                 testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc); // don't flag issue if connecting the ways would cause self-intersection
59852
59853                 if (geoHasSelfIntersections(testNodes, nodeID)) return;
59854                 results.push(connectionInfo);
59855               });
59856               return results;
59857             }
59858
59859             function findNearbyEndNodes(node, way) {
59860               return [way.nodes[0], way.nodes[way.nodes.length - 1]].map(function (d) {
59861                 return graph.entity(d);
59862               }).filter(function (d) {
59863                 // Node cannot be near to itself, but other endnode of same way could be
59864                 return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
59865               });
59866             }
59867
59868             function findSmallJoinAngle(midNode, tipNode, endNodes) {
59869               // Both nodes could be close, so want to join whichever is closest to collinear
59870               var joinTo;
59871               var minAngle = Infinity; // Checks midNode -> tipNode -> endNode for collinearity
59872
59873               endNodes.forEach(function (endNode) {
59874                 var a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
59875                 var a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
59876                 var diff = Math.max(a1, a2) - Math.min(a1, a2);
59877
59878                 if (diff < minAngle) {
59879                   joinTo = endNode;
59880                   minAngle = diff;
59881                 }
59882               });
59883               /* Threshold set by considering right angle triangle
59884               based on node joining threshold and extension distance */
59885
59886               if (minAngle <= SIG_ANGLE_TH) return joinTo;
59887               return null;
59888             }
59889
59890             function hasTag(tags, key) {
59891               return tags[key] !== undefined && tags[key] !== 'no';
59892             }
59893
59894             function canConnectWays(way, way2) {
59895               // allow self-connections
59896               if (way.id === way2.id) return true; // if one is bridge or tunnel, both must be bridge or tunnel
59897
59898               if ((hasTag(way.tags, 'bridge') || hasTag(way2.tags, 'bridge')) && !(hasTag(way.tags, 'bridge') && hasTag(way2.tags, 'bridge'))) return false;
59899               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
59900
59901               var layer1 = way.tags.layer || '0',
59902                   layer2 = way2.tags.layer || '0';
59903               if (layer1 !== layer2) return false;
59904               var level1 = way.tags.level || '0',
59905                   level2 = way2.tags.level || '0';
59906               if (level1 !== level2) return false;
59907               return true;
59908             }
59909
59910             function canConnectByExtend(way, endNodeIdx) {
59911               var tipNid = way.nodes[endNodeIdx]; // the 'tip' node for extension point
59912
59913               var midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2]; // the other node of the edge
59914
59915               var tipNode = graph.entity(tipNid);
59916               var midNode = graph.entity(midNid);
59917               var lon = tipNode.loc[0];
59918               var lat = tipNode.loc[1];
59919               var lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
59920               var lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
59921               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
59922
59923               var edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
59924               var t = EXTEND_TH_METERS / edgeLen + 1.0;
59925               var extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t); // then, check if the extension part [tipNode.loc -> extTipLoc] intersects any other ways
59926
59927               var segmentInfos = tree.waySegments(queryExtent, graph);
59928
59929               for (var i = 0; i < segmentInfos.length; i++) {
59930                 var segmentInfo = segmentInfos[i];
59931                 var way2 = graph.entity(segmentInfo.wayId);
59932                 if (!isHighway(way2)) continue;
59933                 if (!canConnectWays(way, way2)) continue;
59934                 var nAid = segmentInfo.nodes[0],
59935                     nBid = segmentInfo.nodes[1];
59936                 if (nAid === tipNid || nBid === tipNid) continue;
59937                 var nA = graph.entity(nAid),
59938                     nB = graph.entity(nBid);
59939                 var crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
59940
59941                 if (crossLoc) {
59942                   return {
59943                     mid: midNode,
59944                     node: tipNode,
59945                     wid: way2.id,
59946                     edge: [nA.id, nB.id],
59947                     cross_loc: crossLoc
59948                   };
59949                 }
59950               }
59951
59952               return null;
59953             }
59954           };
59955
59956           validation.type = type;
59957           return validation;
59958         }
59959
59960         function validationCloseNodes(context) {
59961           var type = 'close_nodes';
59962           var pointThresholdMeters = 0.2;
59963
59964           var validation = function validation(entity, graph) {
59965             if (entity.type === 'node') {
59966               return getIssuesForNode(entity);
59967             } else if (entity.type === 'way') {
59968               return getIssuesForWay(entity);
59969             }
59970
59971             return [];
59972
59973             function getIssuesForNode(node) {
59974               var parentWays = graph.parentWays(node);
59975
59976               if (parentWays.length) {
59977                 return getIssuesForVertex(node, parentWays);
59978               } else {
59979                 return getIssuesForDetachedPoint(node);
59980               }
59981             }
59982
59983             function wayTypeFor(way) {
59984               if (way.tags.boundary && way.tags.boundary !== 'no') return 'boundary';
59985               if (way.tags.indoor && way.tags.indoor !== 'no') return 'indoor';
59986               if (way.tags.building && way.tags.building !== 'no' || way.tags['building:part'] && way.tags['building:part'] !== 'no') return 'building';
59987               if (osmPathHighwayTagValues[way.tags.highway]) return 'path';
59988               var parentRelations = graph.parentRelations(way);
59989
59990               for (var i in parentRelations) {
59991                 var relation = parentRelations[i];
59992                 if (relation.tags.type === 'boundary') return 'boundary';
59993
59994                 if (relation.isMultipolygon()) {
59995                   if (relation.tags.indoor && relation.tags.indoor !== 'no') return 'indoor';
59996                   if (relation.tags.building && relation.tags.building !== 'no' || relation.tags['building:part'] && relation.tags['building:part'] !== 'no') return 'building';
59997                 }
59998               }
59999
60000               return 'other';
60001             }
60002
60003             function shouldCheckWay(way) {
60004               // don't flag issues where merging would create degenerate ways
60005               if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
60006               var bbox = way.extent(graph).bbox();
60007               var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]); // don't flag close nodes in very small ways
60008
60009               if (hypotenuseMeters < 1.5) return false;
60010               return true;
60011             }
60012
60013             function getIssuesForWay(way) {
60014               if (!shouldCheckWay(way)) return [];
60015               var issues = [],
60016                   nodes = graph.childNodes(way);
60017
60018               for (var i = 0; i < nodes.length - 1; i++) {
60019                 var node1 = nodes[i];
60020                 var node2 = nodes[i + 1];
60021                 var issue = getWayIssueIfAny(node1, node2, way);
60022                 if (issue) issues.push(issue);
60023               }
60024
60025               return issues;
60026             }
60027
60028             function getIssuesForVertex(node, parentWays) {
60029               var issues = [];
60030
60031               function checkForCloseness(node1, node2, way) {
60032                 var issue = getWayIssueIfAny(node1, node2, way);
60033                 if (issue) issues.push(issue);
60034               }
60035
60036               for (var i = 0; i < parentWays.length; i++) {
60037                 var parentWay = parentWays[i];
60038                 if (!shouldCheckWay(parentWay)) continue;
60039                 var lastIndex = parentWay.nodes.length - 1;
60040
60041                 for (var j = 0; j < parentWay.nodes.length; j++) {
60042                   if (j !== 0) {
60043                     if (parentWay.nodes[j - 1] === node.id) {
60044                       checkForCloseness(node, graph.entity(parentWay.nodes[j]), parentWay);
60045                     }
60046                   }
60047
60048                   if (j !== lastIndex) {
60049                     if (parentWay.nodes[j + 1] === node.id) {
60050                       checkForCloseness(graph.entity(parentWay.nodes[j]), node, parentWay);
60051                     }
60052                   }
60053                 }
60054               }
60055
60056               return issues;
60057             }
60058
60059             function thresholdMetersForWay(way) {
60060               if (!shouldCheckWay(way)) return 0;
60061               var wayType = wayTypeFor(way); // don't flag boundaries since they might be highly detailed and can't be easily verified
60062
60063               if (wayType === 'boundary') return 0; // expect some features to be mapped with higher levels of detail
60064
60065               if (wayType === 'indoor') return 0.01;
60066               if (wayType === 'building') return 0.05;
60067               if (wayType === 'path') return 0.1;
60068               return 0.2;
60069             }
60070
60071             function getIssuesForDetachedPoint(node) {
60072               var issues = [];
60073               var lon = node.loc[0];
60074               var lat = node.loc[1];
60075               var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
60076               var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
60077               var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]);
60078               var intersected = context.history().tree().intersects(queryExtent, graph);
60079
60080               for (var j = 0; j < intersected.length; j++) {
60081                 var nearby = intersected[j];
60082                 if (nearby.id === node.id) continue;
60083                 if (nearby.type !== 'node' || nearby.geometry(graph) !== 'point') continue;
60084
60085                 if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
60086                   // allow very close points if tags indicate the z-axis might vary
60087                   var zAxisKeys = {
60088                     layer: true,
60089                     level: true,
60090                     'addr:housenumber': true,
60091                     'addr:unit': true
60092                   };
60093                   var zAxisDifferentiates = false;
60094
60095                   for (var key in zAxisKeys) {
60096                     var nodeValue = node.tags[key] || '0';
60097                     var nearbyValue = nearby.tags[key] || '0';
60098
60099                     if (nodeValue !== nearbyValue) {
60100                       zAxisDifferentiates = true;
60101                       break;
60102                     }
60103                   }
60104
60105                   if (zAxisDifferentiates) continue;
60106                   issues.push(new validationIssue({
60107                     type: type,
60108                     subtype: 'detached',
60109                     severity: 'warning',
60110                     message: function message(context) {
60111                       var entity = context.hasEntity(this.entityIds[0]),
60112                           entity2 = context.hasEntity(this.entityIds[1]);
60113                       return entity && entity2 ? _t.html('issues.close_nodes.detached.message', {
60114                         feature: utilDisplayLabel(entity, context.graph()),
60115                         feature2: utilDisplayLabel(entity2, context.graph())
60116                       }) : '';
60117                     },
60118                     reference: showReference,
60119                     entityIds: [node.id, nearby.id],
60120                     dynamicFixes: function dynamicFixes() {
60121                       return [new validationIssueFix({
60122                         icon: 'iD-operation-disconnect',
60123                         title: _t.html('issues.fix.move_points_apart.title')
60124                       }), new validationIssueFix({
60125                         icon: 'iD-icon-layers',
60126                         title: _t.html('issues.fix.use_different_layers_or_levels.title')
60127                       })];
60128                     }
60129                   }));
60130                 }
60131               }
60132
60133               return issues;
60134
60135               function showReference(selection) {
60136                 var referenceText = _t('issues.close_nodes.detached.reference');
60137                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
60138               }
60139             }
60140
60141             function getWayIssueIfAny(node1, node2, way) {
60142               if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
60143                 return null;
60144               }
60145
60146               if (node1.loc !== node2.loc) {
60147                 var parentWays1 = graph.parentWays(node1);
60148                 var parentWays2 = new Set(graph.parentWays(node2));
60149                 var sharedWays = parentWays1.filter(function (parentWay) {
60150                   return parentWays2.has(parentWay);
60151                 });
60152                 var thresholds = sharedWays.map(function (parentWay) {
60153                   return thresholdMetersForWay(parentWay);
60154                 });
60155                 var threshold = Math.min.apply(Math, _toConsumableArray(thresholds));
60156                 var distance = geoSphericalDistance(node1.loc, node2.loc);
60157                 if (distance > threshold) return null;
60158               }
60159
60160               return new validationIssue({
60161                 type: type,
60162                 subtype: 'vertices',
60163                 severity: 'warning',
60164                 message: function message(context) {
60165                   var entity = context.hasEntity(this.entityIds[0]);
60166                   return entity ? _t.html('issues.close_nodes.message', {
60167                     way: utilDisplayLabel(entity, context.graph())
60168                   }) : '';
60169                 },
60170                 reference: showReference,
60171                 entityIds: [way.id, node1.id, node2.id],
60172                 loc: node1.loc,
60173                 dynamicFixes: function dynamicFixes() {
60174                   return [new validationIssueFix({
60175                     icon: 'iD-icon-plus',
60176                     title: _t.html('issues.fix.merge_points.title'),
60177                     onClick: function onClick(context) {
60178                       var entityIds = this.issue.entityIds;
60179                       var action = actionMergeNodes([entityIds[1], entityIds[2]]);
60180                       context.perform(action, _t('issues.fix.merge_close_vertices.annotation'));
60181                     }
60182                   }), new validationIssueFix({
60183                     icon: 'iD-operation-disconnect',
60184                     title: _t.html('issues.fix.move_points_apart.title')
60185                   })];
60186                 }
60187               });
60188
60189               function showReference(selection) {
60190                 var referenceText = _t('issues.close_nodes.reference');
60191                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
60192               }
60193             }
60194           };
60195
60196           validation.type = type;
60197           return validation;
60198         }
60199
60200         function validationCrossingWays(context) {
60201           var type = 'crossing_ways'; // returns the way or its parent relation, whichever has a useful feature type
60202
60203           function getFeatureWithFeatureTypeTagsForWay(way, graph) {
60204             if (getFeatureType(way, graph) === null) {
60205               // if the way doesn't match a feature type, check its parent relations
60206               var parentRels = graph.parentRelations(way);
60207
60208               for (var i = 0; i < parentRels.length; i++) {
60209                 var rel = parentRels[i];
60210
60211                 if (getFeatureType(rel, graph) !== null) {
60212                   return rel;
60213                 }
60214               }
60215             }
60216
60217             return way;
60218           }
60219
60220           function hasTag(tags, key) {
60221             return tags[key] !== undefined && tags[key] !== 'no';
60222           }
60223
60224           function taggedAsIndoor(tags) {
60225             return hasTag(tags, 'indoor') || hasTag(tags, 'level') || tags.highway === 'corridor';
60226           }
60227
60228           function allowsBridge(featureType) {
60229             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
60230           }
60231
60232           function allowsTunnel(featureType) {
60233             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
60234           } // discard
60235
60236
60237           var ignoredBuildings = {
60238             demolished: true,
60239             dismantled: true,
60240             proposed: true,
60241             razed: true
60242           };
60243
60244           function getFeatureType(entity, graph) {
60245             var geometry = entity.geometry(graph);
60246             if (geometry !== 'line' && geometry !== 'area') return null;
60247             var tags = entity.tags;
60248             if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
60249             if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway'; // don't check railway or waterway areas
60250
60251             if (geometry !== 'line') return null;
60252             if (hasTag(tags, 'railway') && osmRailwayTrackTagValues[tags.railway]) return 'railway';
60253             if (hasTag(tags, 'waterway') && osmFlowingWaterwayTagValues[tags.waterway]) return 'waterway';
60254             return null;
60255           }
60256
60257           function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
60258             // assume 0 by default
60259             var level1 = tags1.level || '0';
60260             var level2 = tags2.level || '0';
60261
60262             if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
60263               // assume features don't interact if they're indoor on different levels
60264               return true;
60265             } // assume 0 by default; don't use way.layer() since we account for structures here
60266
60267
60268             var layer1 = tags1.layer || '0';
60269             var layer2 = tags2.layer || '0';
60270
60271             if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
60272               if (hasTag(tags1, 'bridge') && !hasTag(tags2, 'bridge')) return true;
60273               if (!hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge')) return true; // crossing bridges must use different layers
60274
60275               if (hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge') && layer1 !== layer2) return true;
60276             } else if (allowsBridge(featureType1) && hasTag(tags1, 'bridge')) return true;else if (allowsBridge(featureType2) && hasTag(tags2, 'bridge')) return true;
60277
60278             if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
60279               if (hasTag(tags1, 'tunnel') && !hasTag(tags2, 'tunnel')) return true;
60280               if (!hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel')) return true; // crossing tunnels must use different layers
60281
60282               if (hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel') && layer1 !== layer2) return true;
60283             } 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
60284
60285
60286             if (featureType1 === 'waterway' && featureType2 === 'highway' && tags2.man_made === 'pier') return true;
60287             if (featureType2 === 'waterway' && featureType1 === 'highway' && tags1.man_made === 'pier') return true;
60288
60289             if (featureType1 === 'building' || featureType2 === 'building') {
60290               // for building crossings, different layers are enough
60291               if (layer1 !== layer2) return true;
60292             }
60293
60294             return false;
60295           } // highway values for which we shouldn't recommend connecting to waterways
60296
60297
60298           var highwaysDisallowingFords = {
60299             motorway: true,
60300             motorway_link: true,
60301             trunk: true,
60302             trunk_link: true,
60303             primary: true,
60304             primary_link: true,
60305             secondary: true,
60306             secondary_link: true
60307           };
60308           var nonCrossingHighways = {
60309             track: true
60310           };
60311
60312           function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
60313             var featureType1 = getFeatureType(entity1, graph);
60314             var featureType2 = getFeatureType(entity2, graph);
60315             var geometry1 = entity1.geometry(graph);
60316             var geometry2 = entity2.geometry(graph);
60317             var bothLines = geometry1 === 'line' && geometry2 === 'line';
60318
60319             if (featureType1 === featureType2) {
60320               if (featureType1 === 'highway') {
60321                 var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
60322                 var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
60323
60324                 if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
60325                   // one feature is a path but not both
60326                   var roadFeature = entity1IsPath ? entity2 : entity1;
60327
60328                   if (nonCrossingHighways[roadFeature.tags.highway]) {
60329                     // don't mark path connections with certain roads as crossings
60330                     return {};
60331                   }
60332
60333                   var pathFeature = entity1IsPath ? entity1 : entity2;
60334
60335                   if (['marked', 'unmarked'].indexOf(pathFeature.tags.crossing) !== -1) {
60336                     // if the path is a crossing, match the crossing type
60337                     return bothLines ? {
60338                       highway: 'crossing',
60339                       crossing: pathFeature.tags.crossing
60340                     } : {};
60341                   } // don't add a `crossing` subtag to ambiguous crossings
60342
60343
60344                   return bothLines ? {
60345                     highway: 'crossing'
60346                   } : {};
60347                 }
60348
60349                 return {};
60350               }
60351
60352               if (featureType1 === 'waterway') return {};
60353               if (featureType1 === 'railway') return {};
60354             } else {
60355               var featureTypes = [featureType1, featureType2];
60356
60357               if (featureTypes.indexOf('highway') !== -1) {
60358                 if (featureTypes.indexOf('railway') !== -1) {
60359                   if (!bothLines) return {};
60360                   var isTram = entity1.tags.railway === 'tram' || entity2.tags.railway === 'tram';
60361
60362                   if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
60363                     // path-tram connections use this tag
60364                     if (isTram) return {
60365                       railway: 'tram_crossing'
60366                     }; // other path-rail connections use this tag
60367
60368                     return {
60369                       railway: 'crossing'
60370                     };
60371                   } else {
60372                     // path-tram connections use this tag
60373                     if (isTram) return {
60374                       railway: 'tram_level_crossing'
60375                     }; // other road-rail connections use this tag
60376
60377                     return {
60378                       railway: 'level_crossing'
60379                     };
60380                   }
60381                 }
60382
60383                 if (featureTypes.indexOf('waterway') !== -1) {
60384                   // do not allow fords on structures
60385                   if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return null;
60386                   if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return null;
60387
60388                   if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
60389                     // do not allow fords on major highways
60390                     return null;
60391                   }
60392
60393                   return bothLines ? {
60394                     ford: 'yes'
60395                   } : {};
60396                 }
60397               }
60398             }
60399
60400             return null;
60401           }
60402
60403           function findCrossingsByWay(way1, graph, tree) {
60404             var edgeCrossInfos = [];
60405             if (way1.type !== 'way') return edgeCrossInfos;
60406             var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
60407             var way1FeatureType = getFeatureType(taggedFeature1, graph);
60408             if (way1FeatureType === null) return edgeCrossInfos;
60409             var checkedSingleCrossingWays = {}; // declare vars ahead of time to reduce garbage collection
60410
60411             var i, j;
60412             var extent;
60413             var n1, n2, nA, nB, nAId, nBId;
60414             var segment1, segment2;
60415             var oneOnly;
60416             var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
60417             var way1Nodes = graph.childNodes(way1);
60418             var comparedWays = {};
60419
60420             for (i = 0; i < way1Nodes.length - 1; i++) {
60421               n1 = way1Nodes[i];
60422               n2 = way1Nodes[i + 1];
60423               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
60424               // of overlapping ways
60425
60426               segmentInfos = tree.waySegments(extent, graph);
60427
60428               for (j = 0; j < segmentInfos.length; j++) {
60429                 segment2Info = segmentInfos[j]; // don't check for self-intersection in this validation
60430
60431                 if (segment2Info.wayId === way1.id) continue; // skip if this way was already checked and only one issue is needed
60432
60433                 if (checkedSingleCrossingWays[segment2Info.wayId]) continue; // mark this way as checked even if there are no crossings
60434
60435                 comparedWays[segment2Info.wayId] = true;
60436                 way2 = graph.hasEntity(segment2Info.wayId);
60437                 if (!way2) continue;
60438                 taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph); // only check crossing highway, waterway, building, and railway
60439
60440                 way2FeatureType = getFeatureType(taggedFeature2, graph);
60441
60442                 if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
60443                   continue;
60444                 } // create only one issue for building crossings
60445
60446
60447                 oneOnly = way1FeatureType === 'building' || way2FeatureType === 'building';
60448                 nAId = segment2Info.nodes[0];
60449                 nBId = segment2Info.nodes[1];
60450
60451                 if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
60452                   // n1 or n2 is a connection node; skip
60453                   continue;
60454                 }
60455
60456                 nA = graph.hasEntity(nAId);
60457                 if (!nA) continue;
60458                 nB = graph.hasEntity(nBId);
60459                 if (!nB) continue;
60460                 segment1 = [n1.loc, n2.loc];
60461                 segment2 = [nA.loc, nB.loc];
60462                 var point = geoLineIntersection(segment1, segment2);
60463
60464                 if (point) {
60465                   edgeCrossInfos.push({
60466                     wayInfos: [{
60467                       way: way1,
60468                       featureType: way1FeatureType,
60469                       edge: [n1.id, n2.id]
60470                     }, {
60471                       way: way2,
60472                       featureType: way2FeatureType,
60473                       edge: [nA.id, nB.id]
60474                     }],
60475                     crossPoint: point
60476                   });
60477
60478                   if (oneOnly) {
60479                     checkedSingleCrossingWays[way2.id] = true;
60480                     break;
60481                   }
60482                 }
60483               }
60484             }
60485
60486             return edgeCrossInfos;
60487           }
60488
60489           function waysToCheck(entity, graph) {
60490             var featureType = getFeatureType(entity, graph);
60491             if (!featureType) return [];
60492
60493             if (entity.type === 'way') {
60494               return [entity];
60495             } else if (entity.type === 'relation') {
60496               return entity.members.reduce(function (array, member) {
60497                 if (member.type === 'way' && ( // only look at geometry ways
60498                 !member.role || member.role === 'outer' || member.role === 'inner')) {
60499                   var entity = graph.hasEntity(member.id); // don't add duplicates
60500
60501                   if (entity && array.indexOf(entity) === -1) {
60502                     array.push(entity);
60503                   }
60504                 }
60505
60506                 return array;
60507               }, []);
60508             }
60509
60510             return [];
60511           }
60512
60513           var validation = function checkCrossingWays(entity, graph) {
60514             var tree = context.history().tree();
60515             var ways = waysToCheck(entity, graph);
60516             var issues = []; // declare these here to reduce garbage collection
60517
60518             var wayIndex, crossingIndex, crossings;
60519
60520             for (wayIndex in ways) {
60521               crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
60522
60523               for (crossingIndex in crossings) {
60524                 issues.push(createIssue(crossings[crossingIndex], graph));
60525               }
60526             }
60527
60528             return issues;
60529           };
60530
60531           function createIssue(crossing, graph) {
60532             // use the entities with the tags that define the feature type
60533             crossing.wayInfos.sort(function (way1Info, way2Info) {
60534               var type1 = way1Info.featureType;
60535               var type2 = way2Info.featureType;
60536
60537               if (type1 === type2) {
60538                 return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
60539               } else if (type1 === 'waterway') {
60540                 return true;
60541               } else if (type2 === 'waterway') {
60542                 return false;
60543               }
60544
60545               return type1 < type2;
60546             });
60547             var entities = crossing.wayInfos.map(function (wayInfo) {
60548               return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
60549             });
60550             var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
60551             var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
60552             var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
60553             var featureType1 = crossing.wayInfos[0].featureType;
60554             var featureType2 = crossing.wayInfos[1].featureType;
60555             var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
60556             var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, 'tunnel') && allowsTunnel(featureType2) && hasTag(entities[1].tags, 'tunnel');
60557             var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, 'bridge') && allowsBridge(featureType2) && hasTag(entities[1].tags, 'bridge');
60558             var subtype = [featureType1, featureType2].sort().join('-');
60559             var crossingTypeID = subtype;
60560
60561             if (isCrossingIndoors) {
60562               crossingTypeID = 'indoor-indoor';
60563             } else if (isCrossingTunnels) {
60564               crossingTypeID = 'tunnel-tunnel';
60565             } else if (isCrossingBridges) {
60566               crossingTypeID = 'bridge-bridge';
60567             }
60568
60569             if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
60570               crossingTypeID += '_connectable';
60571             }
60572
60573             return new validationIssue({
60574               type: type,
60575               subtype: subtype,
60576               severity: 'warning',
60577               message: function message(context) {
60578                 var graph = context.graph();
60579                 var entity1 = graph.hasEntity(this.entityIds[0]),
60580                     entity2 = graph.hasEntity(this.entityIds[1]);
60581                 return entity1 && entity2 ? _t.html('issues.crossing_ways.message', {
60582                   feature: utilDisplayLabel(entity1, graph),
60583                   feature2: utilDisplayLabel(entity2, graph)
60584                 }) : '';
60585               },
60586               reference: showReference,
60587               entityIds: entities.map(function (entity) {
60588                 return entity.id;
60589               }),
60590               data: {
60591                 edges: edges,
60592                 featureTypes: featureTypes,
60593                 connectionTags: connectionTags
60594               },
60595               // differentiate based on the loc since two ways can cross multiple times
60596               hash: crossing.crossPoint.toString() + // if the edges change then so does the fix
60597               edges.slice().sort(function (edge1, edge2) {
60598                 // order to assure hash is deterministic
60599                 return edge1[0] < edge2[0] ? -1 : 1;
60600               }).toString() + // ensure the correct connection tags are added in the fix
60601               JSON.stringify(connectionTags),
60602               loc: crossing.crossPoint,
60603               dynamicFixes: function dynamicFixes(context) {
60604                 var mode = context.mode();
60605                 if (!mode || mode.id !== 'select' || mode.selectedIDs().length !== 1) return [];
60606                 var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
60607                 var selectedFeatureType = this.data.featureTypes[selectedIndex];
60608                 var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
60609                 var fixes = [];
60610
60611                 if (connectionTags) {
60612                   fixes.push(makeConnectWaysFix(this.data.connectionTags));
60613                 }
60614
60615                 if (isCrossingIndoors) {
60616                   fixes.push(new validationIssueFix({
60617                     icon: 'iD-icon-layers',
60618                     title: _t.html('issues.fix.use_different_levels.title')
60619                   }));
60620                 } else if (isCrossingTunnels || isCrossingBridges || featureType1 === 'building' || featureType2 === 'building') {
60621                   fixes.push(makeChangeLayerFix('higher'));
60622                   fixes.push(makeChangeLayerFix('lower')); // can only add bridge/tunnel if both features are lines
60623                 } else if (context.graph().geometry(this.entityIds[0]) === 'line' && context.graph().geometry(this.entityIds[1]) === 'line') {
60624                   // don't recommend adding bridges to waterways since they're uncommon
60625                   if (allowsBridge(selectedFeatureType) && selectedFeatureType !== 'waterway') {
60626                     fixes.push(makeAddBridgeOrTunnelFix('add_a_bridge', 'temaki-bridge', 'bridge'));
60627                   } // don't recommend adding tunnels under waterways since they're uncommon
60628
60629
60630                   var skipTunnelFix = otherFeatureType === 'waterway' && selectedFeatureType !== 'waterway';
60631
60632                   if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
60633                     fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
60634                   }
60635                 } // repositioning the features is always an option
60636
60637
60638                 fixes.push(new validationIssueFix({
60639                   icon: 'iD-operation-move',
60640                   title: _t.html('issues.fix.reposition_features.title')
60641                 }));
60642                 return fixes;
60643               }
60644             });
60645
60646             function showReference(selection) {
60647               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.crossing_ways.' + crossingTypeID + '.reference'));
60648             }
60649           }
60650
60651           function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
60652             return new validationIssueFix({
60653               icon: iconName,
60654               title: _t.html('issues.fix.' + fixTitleID + '.title'),
60655               onClick: function onClick(context) {
60656                 var mode = context.mode();
60657                 if (!mode || mode.id !== 'select') return;
60658                 var selectedIDs = mode.selectedIDs();
60659                 if (selectedIDs.length !== 1) return;
60660                 var selectedWayID = selectedIDs[0];
60661                 if (!context.hasEntity(selectedWayID)) return;
60662                 var resultWayIDs = [selectedWayID];
60663                 var edge, crossedEdge, crossedWayID;
60664
60665                 if (this.issue.entityIds[0] === selectedWayID) {
60666                   edge = this.issue.data.edges[0];
60667                   crossedEdge = this.issue.data.edges[1];
60668                   crossedWayID = this.issue.entityIds[1];
60669                 } else {
60670                   edge = this.issue.data.edges[1];
60671                   crossedEdge = this.issue.data.edges[0];
60672                   crossedWayID = this.issue.entityIds[0];
60673                 }
60674
60675                 var crossingLoc = this.issue.loc;
60676                 var projection = context.projection;
60677
60678                 var action = function actionAddStructure(graph) {
60679                   var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
60680                   var crossedWay = graph.hasEntity(crossedWayID); // use the explicit width of the crossed feature as the structure length, if available
60681
60682                   var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
60683
60684                   if (!structLengthMeters) {
60685                     // if no explicit width is set, approximate the width based on the tags
60686                     structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
60687                   }
60688
60689                   if (structLengthMeters) {
60690                     if (getFeatureType(crossedWay, graph) === 'railway') {
60691                       // bridges over railways are generally much longer than the rail bed itself, compensate
60692                       structLengthMeters *= 2;
60693                     }
60694                   } else {
60695                     // should ideally never land here since all rail/water/road tags should have an implied width
60696                     structLengthMeters = 8;
60697                   }
60698
60699                   var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection) + Math.PI;
60700                   var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection) + Math.PI;
60701                   var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
60702                   if (crossingAngle > Math.PI) crossingAngle -= Math.PI; // lengthen the structure to account for the angle of the crossing
60703
60704                   structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2; // add padding since the structure must extend past the edges of the crossed feature
60705
60706                   structLengthMeters += 4; // clamp the length to a reasonable range
60707
60708                   structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
60709
60710                   function geomToProj(geoPoint) {
60711                     return [geoLonToMeters(geoPoint[0], geoPoint[1]), geoLatToMeters(geoPoint[1])];
60712                   }
60713
60714                   function projToGeom(projPoint) {
60715                     var lat = geoMetersToLat(projPoint[1]);
60716                     return [geoMetersToLon(projPoint[0], lat), lat];
60717                   }
60718
60719                   var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
60720                   var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
60721                   var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
60722                   var projectedCrossingLoc = geomToProj(crossingLoc);
60723                   var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
60724
60725                   function locSphericalDistanceFromCrossingLoc(angle, distanceMeters) {
60726                     var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
60727                     return projToGeom([projectedCrossingLoc[0] + Math.cos(angle) * lengthSphericalMeters, projectedCrossingLoc[1] + Math.sin(angle) * lengthSphericalMeters]);
60728                   }
60729
60730                   var endpointLocGetter1 = function endpointLocGetter1(lengthMeters) {
60731                     return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
60732                   };
60733
60734                   var endpointLocGetter2 = function endpointLocGetter2(lengthMeters) {
60735                     return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
60736                   }; // avoid creating very short edges from splitting too close to another node
60737
60738
60739                   var minEdgeLengthMeters = 0.55; // decide where to bound the structure along the way, splitting as necessary
60740
60741                   function determineEndpoint(edge, endNode, locGetter) {
60742                     var newNode;
60743                     var idealLengthMeters = structLengthMeters / 2; // distance between the crossing location and the end of the edge,
60744                     // the maximum length of this side of the structure
60745
60746                     var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
60747
60748                     if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
60749                       // the edge is long enough to insert a new node
60750                       // the loc that would result in the full expected length
60751                       var idealNodeLoc = locGetter(idealLengthMeters);
60752                       newNode = osmNode();
60753                       graph = actionAddMidpoint({
60754                         loc: idealNodeLoc,
60755                         edge: edge
60756                       }, newNode)(graph);
60757                     } else {
60758                       var edgeCount = 0;
60759                       endNode.parentIntersectionWays(graph).forEach(function (way) {
60760                         way.nodes.forEach(function (nodeID) {
60761                           if (nodeID === endNode.id) {
60762                             if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
60763                               edgeCount += 1;
60764                             } else {
60765                               edgeCount += 2;
60766                             }
60767                           }
60768                         });
60769                       });
60770
60771                       if (edgeCount >= 3) {
60772                         // the end node is a junction, try to leave a segment
60773                         // between it and the structure - #7202
60774                         var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
60775
60776                         if (insetLength > minEdgeLengthMeters) {
60777                           var insetNodeLoc = locGetter(insetLength);
60778                           newNode = osmNode();
60779                           graph = actionAddMidpoint({
60780                             loc: insetNodeLoc,
60781                             edge: edge
60782                           }, newNode)(graph);
60783                         }
60784                       }
60785                     } // if the edge is too short to subdivide as desired, then
60786                     // just bound the structure at the existing end node
60787
60788
60789                     if (!newNode) newNode = endNode;
60790                     var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs); // only split selected or created ways
60791                     // do the split
60792
60793                     graph = splitAction(graph);
60794
60795                     if (splitAction.getCreatedWayIDs().length) {
60796                       resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
60797                     }
60798
60799                     return newNode;
60800                   }
60801
60802                   var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
60803                   var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
60804                   var structureWay = resultWayIDs.map(function (id) {
60805                     return graph.entity(id);
60806                   }).find(function (way) {
60807                     return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
60808                   });
60809                   var tags = Object.assign({}, structureWay.tags); // copy tags
60810
60811                   if (bridgeOrTunnel === 'bridge') {
60812                     tags.bridge = 'yes';
60813                     tags.layer = '1';
60814                   } else {
60815                     var tunnelValue = 'yes';
60816
60817                     if (getFeatureType(structureWay, graph) === 'waterway') {
60818                       // use `tunnel=culvert` for waterways by default
60819                       tunnelValue = 'culvert';
60820                     }
60821
60822                     tags.tunnel = tunnelValue;
60823                     tags.layer = '-1';
60824                   } // apply the structure tags to the way
60825
60826
60827                   graph = actionChangeTags(structureWay.id, tags)(graph);
60828                   return graph;
60829                 };
60830
60831                 context.perform(action, _t('issues.fix.' + fixTitleID + '.annotation'));
60832                 context.enter(modeSelect(context, resultWayIDs));
60833               }
60834             });
60835           }
60836
60837           function makeConnectWaysFix(connectionTags) {
60838             var fixTitleID = 'connect_features';
60839
60840             if (connectionTags.ford) {
60841               fixTitleID = 'connect_using_ford';
60842             }
60843
60844             return new validationIssueFix({
60845               icon: 'iD-icon-crossing',
60846               title: _t.html('issues.fix.' + fixTitleID + '.title'),
60847               onClick: function onClick(context) {
60848                 var loc = this.issue.loc;
60849                 var connectionTags = this.issue.data.connectionTags;
60850                 var edges = this.issue.data.edges;
60851                 context.perform(function actionConnectCrossingWays(graph) {
60852                   // create the new node for the points
60853                   var node = osmNode({
60854                     loc: loc,
60855                     tags: connectionTags
60856                   });
60857                   graph = graph.replace(node);
60858                   var nodesToMerge = [node.id];
60859                   var mergeThresholdInMeters = 0.75;
60860                   edges.forEach(function (edge) {
60861                     var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
60862                     var closestNodeInfo = geoSphericalClosestNode(edgeNodes, loc); // if there is already a point nearby, use that
60863
60864                     if (closestNodeInfo.distance < mergeThresholdInMeters) {
60865                       nodesToMerge.push(closestNodeInfo.node.id); // else add the new node to the way
60866                     } else {
60867                       graph = actionAddMidpoint({
60868                         loc: loc,
60869                         edge: edge
60870                       }, node)(graph);
60871                     }
60872                   });
60873
60874                   if (nodesToMerge.length > 1) {
60875                     // if we're using nearby nodes, merge them with the new node
60876                     graph = actionMergeNodes(nodesToMerge, loc)(graph);
60877                   }
60878
60879                   return graph;
60880                 }, _t('issues.fix.connect_crossing_features.annotation'));
60881               }
60882             });
60883           }
60884
60885           function makeChangeLayerFix(higherOrLower) {
60886             return new validationIssueFix({
60887               icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'),
60888               title: _t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'),
60889               onClick: function onClick(context) {
60890                 var mode = context.mode();
60891                 if (!mode || mode.id !== 'select') return;
60892                 var selectedIDs = mode.selectedIDs();
60893                 if (selectedIDs.length !== 1) return;
60894                 var selectedID = selectedIDs[0];
60895                 if (!this.issue.entityIds.some(function (entityId) {
60896                   return entityId === selectedID;
60897                 })) return;
60898                 var entity = context.hasEntity(selectedID);
60899                 if (!entity) return;
60900                 var tags = Object.assign({}, entity.tags); // shallow copy
60901
60902                 var layer = tags.layer && Number(tags.layer);
60903
60904                 if (layer && !isNaN(layer)) {
60905                   if (higherOrLower === 'higher') {
60906                     layer += 1;
60907                   } else {
60908                     layer -= 1;
60909                   }
60910                 } else {
60911                   if (higherOrLower === 'higher') {
60912                     layer = 1;
60913                   } else {
60914                     layer = -1;
60915                   }
60916                 }
60917
60918                 tags.layer = layer.toString();
60919                 context.perform(actionChangeTags(entity.id, tags), _t('operations.change_tags.annotation'));
60920               }
60921             });
60922           }
60923
60924           validation.type = type;
60925           return validation;
60926         }
60927
60928         function validationDisconnectedWay() {
60929           var type = 'disconnected_way';
60930
60931           function isTaggedAsHighway(entity) {
60932             return osmRoutableHighwayTagValues[entity.tags.highway];
60933           }
60934
60935           var validation = function checkDisconnectedWay(entity, graph) {
60936             var routingIslandWays = routingIslandForEntity(entity);
60937             if (!routingIslandWays) return [];
60938             return [new validationIssue({
60939               type: type,
60940               subtype: 'highway',
60941               severity: 'warning',
60942               message: function message(context) {
60943                 var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]);
60944                 var label = entity && utilDisplayLabel(entity, context.graph());
60945                 return _t.html('issues.disconnected_way.routable.message', {
60946                   count: this.entityIds.length,
60947                   highway: label
60948                 });
60949               },
60950               reference: showReference,
60951               entityIds: Array.from(routingIslandWays).map(function (way) {
60952                 return way.id;
60953               }),
60954               dynamicFixes: makeFixes
60955             })];
60956
60957             function makeFixes(context) {
60958               var fixes = [];
60959               var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
60960
60961               if (singleEntity) {
60962                 if (singleEntity.type === 'way' && !singleEntity.isClosed()) {
60963                   var textDirection = _mainLocalizer.textDirection();
60964                   var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), 'start');
60965                   if (startFix) fixes.push(startFix);
60966                   var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), 'end');
60967                   if (endFix) fixes.push(endFix);
60968                 }
60969
60970                 if (!fixes.length) {
60971                   fixes.push(new validationIssueFix({
60972                     title: _t.html('issues.fix.connect_feature.title')
60973                   }));
60974                 }
60975
60976                 fixes.push(new validationIssueFix({
60977                   icon: 'iD-operation-delete',
60978                   title: _t.html('issues.fix.delete_feature.title'),
60979                   entityIds: [singleEntity.id],
60980                   onClick: function onClick(context) {
60981                     var id = this.issue.entityIds[0];
60982                     var operation = operationDelete(context, [id]);
60983
60984                     if (!operation.disabled()) {
60985                       operation();
60986                     }
60987                   }
60988                 }));
60989               } else {
60990                 fixes.push(new validationIssueFix({
60991                   title: _t.html('issues.fix.connect_features.title')
60992                 }));
60993               }
60994
60995               return fixes;
60996             }
60997
60998             function showReference(selection) {
60999               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.disconnected_way.routable.reference'));
61000             }
61001
61002             function routingIslandForEntity(entity) {
61003               var routingIsland = new Set(); // the interconnected routable features
61004
61005               var waysToCheck = []; // the queue of remaining routable ways to traverse
61006
61007               function queueParentWays(node) {
61008                 graph.parentWays(node).forEach(function (parentWay) {
61009                   if (!routingIsland.has(parentWay) && // only check each feature once
61010                   isRoutableWay(parentWay, false)) {
61011                     // only check routable features
61012                     routingIsland.add(parentWay);
61013                     waysToCheck.push(parentWay);
61014                   }
61015                 });
61016               }
61017
61018               if (entity.type === 'way' && isRoutableWay(entity, true)) {
61019                 routingIsland.add(entity);
61020                 waysToCheck.push(entity);
61021               } else if (entity.type === 'node' && isRoutableNode(entity)) {
61022                 routingIsland.add(entity);
61023                 queueParentWays(entity);
61024               } else {
61025                 // this feature isn't routable, cannot be a routing island
61026                 return null;
61027               }
61028
61029               while (waysToCheck.length) {
61030                 var wayToCheck = waysToCheck.pop();
61031                 var childNodes = graph.childNodes(wayToCheck);
61032
61033                 for (var i in childNodes) {
61034                   var vertex = childNodes[i];
61035
61036                   if (isConnectedVertex(vertex)) {
61037                     // found a link to the wider network, not a routing island
61038                     return null;
61039                   }
61040
61041                   if (isRoutableNode(vertex)) {
61042                     routingIsland.add(vertex);
61043                   }
61044
61045                   queueParentWays(vertex);
61046                 }
61047               } // no network link found, this is a routing island, return its members
61048
61049
61050               return routingIsland;
61051             }
61052
61053             function isConnectedVertex(vertex) {
61054               // assume ways overlapping unloaded tiles are connected to the wider road network  - #5938
61055               var osm = services.osm;
61056               if (osm && !osm.isDataLoaded(vertex.loc)) return true; // entrances are considered connected
61057
61058               if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return true;
61059               if (vertex.tags.amenity === 'parking_entrance') return true;
61060               return false;
61061             }
61062
61063             function isRoutableNode(node) {
61064               // treat elevators as distinct features in the highway network
61065               if (node.tags.highway === 'elevator') return true;
61066               return false;
61067             }
61068
61069             function isRoutableWay(way, ignoreInnerWays) {
61070               if (isTaggedAsHighway(way) || way.tags.route === 'ferry') return true;
61071               return graph.parentRelations(way).some(function (parentRelation) {
61072                 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true;
61073                 if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== 'inner')) return true;
61074                 return false;
61075               });
61076             }
61077
61078             function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
61079               var vertex = graph.hasEntity(vertexID);
61080               if (!vertex || vertex.tags.noexit === 'yes') return null;
61081               var useLeftContinue = whichEnd === 'start' && textDirection === 'ltr' || whichEnd === 'end' && textDirection === 'rtl';
61082               return new validationIssueFix({
61083                 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
61084                 title: _t.html('issues.fix.continue_from_' + whichEnd + '.title'),
61085                 entityIds: [vertexID],
61086                 onClick: function onClick(context) {
61087                   var wayId = this.issue.entityIds[0];
61088                   var way = context.hasEntity(wayId);
61089                   var vertexId = this.entityIds[0];
61090                   var vertex = context.hasEntity(vertexId);
61091                   if (!way || !vertex) return; // make sure the vertex is actually visible and editable
61092
61093                   var map = context.map();
61094
61095                   if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
61096                     map.zoomToEase(vertex);
61097                   }
61098
61099                   context.enter(modeDrawLine(context, wayId, context.graph(), 'line', way.affix(vertexId), true));
61100                 }
61101               });
61102             }
61103           };
61104
61105           validation.type = type;
61106           return validation;
61107         }
61108
61109         function validationFormatting() {
61110           var type = 'invalid_format';
61111
61112           var validation = function validation(entity) {
61113             var issues = [];
61114
61115             function isValidEmail(email) {
61116               // Emails in OSM are going to be official so they should be pretty simple
61117               // Using negated lists to better support all possible unicode characters (#6494)
61118               var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i; // An empty value is also acceptable
61119
61120               return !email || valid_email.test(email);
61121             }
61122             /*
61123             function isSchemePresent(url) {
61124                 var valid_scheme = /^https?:\/\//i;
61125                 return (!url || valid_scheme.test(url));
61126             }
61127             */
61128
61129
61130             function showReferenceEmail(selection) {
61131               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.invalid_format.email.reference'));
61132             }
61133             /*
61134             function showReferenceWebsite(selection) {
61135                 selection.selectAll('.issue-reference')
61136                     .data([0])
61137                     .enter()
61138                     .append('div')
61139                     .attr('class', 'issue-reference')
61140                     .html(t.html('issues.invalid_format.website.reference'));
61141             }
61142              if (entity.tags.website) {
61143                 // Multiple websites are possible
61144                 // If ever we support ES6, arrow functions make this nicer
61145                 var websites = entity.tags.website
61146                     .split(';')
61147                     .map(function(s) { return s.trim(); })
61148                     .filter(function(x) { return !isSchemePresent(x); });
61149                  if (websites.length) {
61150                     issues.push(new validationIssue({
61151                         type: type,
61152                         subtype: 'website',
61153                         severity: 'warning',
61154                         message: function(context) {
61155                             var entity = context.hasEntity(this.entityIds[0]);
61156                             return entity ? t.html('issues.invalid_format.website.message' + this.data,
61157                                 { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : '';
61158                         },
61159                         reference: showReferenceWebsite,
61160                         entityIds: [entity.id],
61161                         hash: websites.join(),
61162                         data: (websites.length > 1) ? '_multi' : ''
61163                     }));
61164                 }
61165             }
61166             */
61167
61168
61169             if (entity.tags.email) {
61170               // Multiple emails are possible
61171               var emails = entity.tags.email.split(';').map(function (s) {
61172                 return s.trim();
61173               }).filter(function (x) {
61174                 return !isValidEmail(x);
61175               });
61176
61177               if (emails.length) {
61178                 issues.push(new validationIssue({
61179                   type: type,
61180                   subtype: 'email',
61181                   severity: 'warning',
61182                   message: function message(context) {
61183                     var entity = context.hasEntity(this.entityIds[0]);
61184                     return entity ? _t.html('issues.invalid_format.email.message' + this.data, {
61185                       feature: utilDisplayLabel(entity, context.graph()),
61186                       email: emails.join(', ')
61187                     }) : '';
61188                   },
61189                   reference: showReferenceEmail,
61190                   entityIds: [entity.id],
61191                   hash: emails.join(),
61192                   data: emails.length > 1 ? '_multi' : ''
61193                 }));
61194               }
61195             }
61196
61197             return issues;
61198           };
61199
61200           validation.type = type;
61201           return validation;
61202         }
61203
61204         function validationHelpRequest(context) {
61205           var type = 'help_request';
61206
61207           var validation = function checkFixmeTag(entity) {
61208             if (!entity.tags.fixme) return []; // don't flag fixmes on features added by the user
61209
61210             if (entity.version === undefined) return [];
61211
61212             if (entity.v !== undefined) {
61213               var baseEntity = context.history().base().hasEntity(entity.id); // don't flag fixmes added by the user on existing features
61214
61215               if (!baseEntity || !baseEntity.tags.fixme) return [];
61216             }
61217
61218             return [new validationIssue({
61219               type: type,
61220               subtype: 'fixme_tag',
61221               severity: 'warning',
61222               message: function message(context) {
61223                 var entity = context.hasEntity(this.entityIds[0]);
61224                 return entity ? _t.html('issues.fixme_tag.message', {
61225                   feature: utilDisplayLabel(entity, context.graph())
61226                 }) : '';
61227               },
61228               dynamicFixes: function dynamicFixes() {
61229                 return [new validationIssueFix({
61230                   title: _t.html('issues.fix.address_the_concern.title')
61231                 })];
61232               },
61233               reference: showReference,
61234               entityIds: [entity.id]
61235             })];
61236
61237             function showReference(selection) {
61238               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.fixme_tag.reference'));
61239             }
61240           };
61241
61242           validation.type = type;
61243           return validation;
61244         }
61245
61246         function validationImpossibleOneway() {
61247           var type = 'impossible_oneway';
61248
61249           var validation = function checkImpossibleOneway(entity, graph) {
61250             if (entity.type !== 'way' || entity.geometry(graph) !== 'line') return [];
61251             if (entity.isClosed()) return [];
61252             if (!typeForWay(entity)) return [];
61253             if (!isOneway(entity)) return [];
61254             var firstIssues = issuesForNode(entity, entity.first());
61255             var lastIssues = issuesForNode(entity, entity.last());
61256             return firstIssues.concat(lastIssues);
61257
61258             function typeForWay(way) {
61259               if (way.geometry(graph) !== 'line') return null;
61260               if (osmRoutableHighwayTagValues[way.tags.highway]) return 'highway';
61261               if (osmFlowingWaterwayTagValues[way.tags.waterway]) return 'waterway';
61262               return null;
61263             }
61264
61265             function isOneway(way) {
61266               if (way.tags.oneway === 'yes') return true;
61267               if (way.tags.oneway) return false;
61268
61269               for (var key in way.tags) {
61270                 if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
61271                   return true;
61272                 }
61273               }
61274
61275               return false;
61276             }
61277
61278             function nodeOccursMoreThanOnce(way, nodeID) {
61279               var occurrences = 0;
61280
61281               for (var index in way.nodes) {
61282                 if (way.nodes[index] === nodeID) {
61283                   occurrences += 1;
61284                   if (occurrences > 1) return true;
61285                 }
61286               }
61287
61288               return false;
61289             }
61290
61291             function isConnectedViaOtherTypes(way, node) {
61292               var wayType = typeForWay(way);
61293
61294               if (wayType === 'highway') {
61295                 // entrances are considered connected
61296                 if (node.tags.entrance && node.tags.entrance !== 'no') return true;
61297                 if (node.tags.amenity === 'parking_entrance') return true;
61298               } else if (wayType === 'waterway') {
61299                 if (node.id === way.first()) {
61300                   // multiple waterways may start at the same spring
61301                   if (node.tags.natural === 'spring') return true;
61302                 } else {
61303                   // multiple waterways may end at the same drain
61304                   if (node.tags.manhole === 'drain') return true;
61305                 }
61306               }
61307
61308               return graph.parentWays(node).some(function (parentWay) {
61309                 if (parentWay.id === way.id) return false;
61310
61311                 if (wayType === 'highway') {
61312                   // allow connections to highway areas
61313                   if (parentWay.geometry(graph) === 'area' && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true; // count connections to ferry routes as connected
61314
61315                   if (parentWay.tags.route === 'ferry') return true;
61316                   return graph.parentRelations(parentWay).some(function (parentRelation) {
61317                     if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true; // allow connections to highway multipolygons
61318
61319                     return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
61320                   });
61321                 } else if (wayType === 'waterway') {
61322                   // multiple waterways may start or end at a water body at the same node
61323                   if (parentWay.tags.natural === 'water' || parentWay.tags.natural === 'coastline') return true;
61324                 }
61325
61326                 return false;
61327               });
61328             }
61329
61330             function issuesForNode(way, nodeID) {
61331               var isFirst = nodeID === way.first();
61332               var wayType = typeForWay(way); // ignore if this way is self-connected at this node
61333
61334               if (nodeOccursMoreThanOnce(way, nodeID)) return [];
61335               var osm = services.osm;
61336               if (!osm) return [];
61337               var node = graph.hasEntity(nodeID); // ignore if this node or its tile are unloaded
61338
61339               if (!node || !osm.isDataLoaded(node.loc)) return [];
61340               if (isConnectedViaOtherTypes(way, node)) return [];
61341               var attachedWaysOfSameType = graph.parentWays(node).filter(function (parentWay) {
61342                 if (parentWay.id === way.id) return false;
61343                 return typeForWay(parentWay) === wayType;
61344               }); // assume it's okay for waterways to start or end disconnected for now
61345
61346               if (wayType === 'waterway' && attachedWaysOfSameType.length === 0) return [];
61347               var attachedOneways = attachedWaysOfSameType.filter(function (attachedWay) {
61348                 return isOneway(attachedWay);
61349               }); // ignore if the way is connected to some non-oneway features
61350
61351               if (attachedOneways.length < attachedWaysOfSameType.length) return [];
61352
61353               if (attachedOneways.length) {
61354                 var connectedEndpointsOkay = attachedOneways.some(function (attachedOneway) {
61355                   if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
61356                   if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
61357                   return false;
61358                 });
61359                 if (connectedEndpointsOkay) return [];
61360               }
61361
61362               var placement = isFirst ? 'start' : 'end',
61363                   messageID = wayType + '.',
61364                   referenceID = wayType + '.';
61365
61366               if (wayType === 'waterway') {
61367                 messageID += 'connected.' + placement;
61368                 referenceID += 'connected';
61369               } else {
61370                 messageID += placement;
61371                 referenceID += placement;
61372               }
61373
61374               return [new validationIssue({
61375                 type: type,
61376                 subtype: wayType,
61377                 severity: 'warning',
61378                 message: function message(context) {
61379                   var entity = context.hasEntity(this.entityIds[0]);
61380                   return entity ? _t.html('issues.impossible_oneway.' + messageID + '.message', {
61381                     feature: utilDisplayLabel(entity, context.graph())
61382                   }) : '';
61383                 },
61384                 reference: getReference(referenceID),
61385                 entityIds: [way.id, node.id],
61386                 dynamicFixes: function dynamicFixes() {
61387                   var fixes = [];
61388
61389                   if (attachedOneways.length) {
61390                     fixes.push(new validationIssueFix({
61391                       icon: 'iD-operation-reverse',
61392                       title: _t.html('issues.fix.reverse_feature.title'),
61393                       entityIds: [way.id],
61394                       onClick: function onClick(context) {
61395                         var id = this.issue.entityIds[0];
61396                         context.perform(actionReverse(id), _t('operations.reverse.annotation.line', {
61397                           n: 1
61398                         }));
61399                       }
61400                     }));
61401                   }
61402
61403                   if (node.tags.noexit !== 'yes') {
61404                     var textDirection = _mainLocalizer.textDirection();
61405                     var useLeftContinue = isFirst && textDirection === 'ltr' || !isFirst && textDirection === 'rtl';
61406                     fixes.push(new validationIssueFix({
61407                       icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
61408                       title: _t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'),
61409                       onClick: function onClick(context) {
61410                         var entityID = this.issue.entityIds[0];
61411                         var vertexID = this.issue.entityIds[1];
61412                         var way = context.entity(entityID);
61413                         var vertex = context.entity(vertexID);
61414                         continueDrawing(way, vertex, context);
61415                       }
61416                     }));
61417                   }
61418
61419                   return fixes;
61420                 },
61421                 loc: node.loc
61422               })];
61423
61424               function getReference(referenceID) {
61425                 return function showReference(selection) {
61426                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.impossible_oneway.' + referenceID + '.reference'));
61427                 };
61428               }
61429             }
61430           };
61431
61432           function continueDrawing(way, vertex, context) {
61433             // make sure the vertex is actually visible and editable
61434             var map = context.map();
61435
61436             if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
61437               map.zoomToEase(vertex);
61438             }
61439
61440             context.enter(modeDrawLine(context, way.id, context.graph(), 'line', way.affix(vertex.id), true));
61441           }
61442
61443           validation.type = type;
61444           return validation;
61445         }
61446
61447         function validationIncompatibleSource() {
61448           var type = 'incompatible_source';
61449           var invalidSources = [{
61450             id: 'google',
61451             regex: 'google',
61452             exceptRegex: 'books.google|Google Books|drive.google|googledrive|Google Drive'
61453           }];
61454
61455           var validation = function checkIncompatibleSource(entity) {
61456             var entitySources = entity.tags && entity.tags.source && entity.tags.source.split(';');
61457             if (!entitySources) return [];
61458             var issues = [];
61459             invalidSources.forEach(function (invalidSource) {
61460               var hasInvalidSource = entitySources.some(function (source) {
61461                 if (!source.match(new RegExp(invalidSource.regex, 'i'))) return false;
61462                 if (invalidSource.exceptRegex && source.match(new RegExp(invalidSource.exceptRegex, 'i'))) return false;
61463                 return true;
61464               });
61465               if (!hasInvalidSource) return;
61466               issues.push(new validationIssue({
61467                 type: type,
61468                 severity: 'warning',
61469                 message: function message(context) {
61470                   var entity = context.hasEntity(this.entityIds[0]);
61471                   return entity ? _t.html('issues.incompatible_source.' + invalidSource.id + '.feature.message', {
61472                     feature: utilDisplayLabel(entity, context.graph())
61473                   }) : '';
61474                 },
61475                 reference: getReference(invalidSource.id),
61476                 entityIds: [entity.id],
61477                 dynamicFixes: function dynamicFixes() {
61478                   return [new validationIssueFix({
61479                     title: _t.html('issues.fix.remove_proprietary_data.title')
61480                   })];
61481                 }
61482               }));
61483             });
61484             return issues;
61485
61486             function getReference(id) {
61487               return function showReference(selection) {
61488                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.incompatible_source.' + id + '.reference'));
61489               };
61490             }
61491           };
61492
61493           validation.type = type;
61494           return validation;
61495         }
61496
61497         function validationMaprules() {
61498           var type = 'maprules';
61499
61500           var validation = function checkMaprules(entity, graph) {
61501             if (!services.maprules) return [];
61502             var rules = services.maprules.validationRules();
61503             var issues = [];
61504
61505             for (var i = 0; i < rules.length; i++) {
61506               var rule = rules[i];
61507               rule.findIssues(entity, graph, issues);
61508             }
61509
61510             return issues;
61511           };
61512
61513           validation.type = type;
61514           return validation;
61515         }
61516
61517         function validationMismatchedGeometry() {
61518           var type = 'mismatched_geometry';
61519
61520           function tagSuggestingLineIsArea(entity) {
61521             if (entity.type !== 'way' || entity.isClosed()) return null;
61522             var tagSuggestingArea = entity.tagSuggestingArea();
61523
61524             if (!tagSuggestingArea) {
61525               return null;
61526             }
61527
61528             var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, 'line');
61529             var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, 'area');
61530
61531             if (asLine && asArea && asLine === asArea) {
61532               // these tags also allow lines and making this an area wouldn't matter
61533               return null;
61534             }
61535
61536             return tagSuggestingArea;
61537           }
61538
61539           function makeConnectEndpointsFixOnClick(way, graph) {
61540             // must have at least three nodes to close this automatically
61541             if (way.nodes.length < 3) return null;
61542             var nodes = graph.childNodes(way),
61543                 testNodes;
61544             var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc); // if the distance is very small, attempt to merge the endpoints
61545
61546             if (firstToLastDistanceMeters < 0.75) {
61547               testNodes = nodes.slice(); // shallow copy
61548
61549               testNodes.pop();
61550               testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
61551
61552               if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
61553                 return function (context) {
61554                   var way = context.entity(this.issue.entityIds[0]);
61555                   context.perform(actionMergeNodes([way.nodes[0], way.nodes[way.nodes.length - 1]], nodes[0].loc), _t('issues.fix.connect_endpoints.annotation'));
61556                 };
61557               }
61558             } // if the points were not merged, attempt to close the way
61559
61560
61561             testNodes = nodes.slice(); // shallow copy
61562
61563             testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
61564
61565             if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
61566               return function (context) {
61567                 var wayId = this.issue.entityIds[0];
61568                 var way = context.entity(wayId);
61569                 var nodeId = way.nodes[0];
61570                 var index = way.nodes.length;
61571                 context.perform(actionAddVertex(wayId, nodeId, index), _t('issues.fix.connect_endpoints.annotation'));
61572               };
61573             }
61574           }
61575
61576           function lineTaggedAsAreaIssue(entity) {
61577             var tagSuggestingArea = tagSuggestingLineIsArea(entity);
61578             if (!tagSuggestingArea) return null;
61579             return new validationIssue({
61580               type: type,
61581               subtype: 'area_as_line',
61582               severity: 'warning',
61583               message: function message(context) {
61584                 var entity = context.hasEntity(this.entityIds[0]);
61585                 return entity ? _t.html('issues.tag_suggests_area.message', {
61586                   feature: utilDisplayLabel(entity, 'area'),
61587                   tag: utilTagText({
61588                     tags: tagSuggestingArea
61589                   })
61590                 }) : '';
61591               },
61592               reference: showReference,
61593               entityIds: [entity.id],
61594               hash: JSON.stringify(tagSuggestingArea),
61595               dynamicFixes: function dynamicFixes(context) {
61596                 var fixes = [];
61597                 var entity = context.entity(this.entityIds[0]);
61598                 var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph());
61599                 fixes.push(new validationIssueFix({
61600                   title: _t.html('issues.fix.connect_endpoints.title'),
61601                   onClick: connectEndsOnClick
61602                 }));
61603                 fixes.push(new validationIssueFix({
61604                   icon: 'iD-operation-delete',
61605                   title: _t.html('issues.fix.remove_tag.title'),
61606                   onClick: function onClick(context) {
61607                     var entityId = this.issue.entityIds[0];
61608                     var entity = context.entity(entityId);
61609                     var tags = Object.assign({}, entity.tags); // shallow copy
61610
61611                     for (var key in tagSuggestingArea) {
61612                       delete tags[key];
61613                     }
61614
61615                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_tag.annotation'));
61616                   }
61617                 }));
61618                 return fixes;
61619               }
61620             });
61621
61622             function showReference(selection) {
61623               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.tag_suggests_area.reference'));
61624             }
61625           }
61626
61627           function vertexTaggedAsPointIssue(entity, graph) {
61628             // we only care about nodes
61629             if (entity.type !== 'node') return null; // ignore tagless points
61630
61631             if (Object.keys(entity.tags).length === 0) return null; // address lines are special so just ignore them
61632
61633             if (entity.isOnAddressLine(graph)) return null;
61634             var geometry = entity.geometry(graph);
61635             var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
61636
61637             if (geometry === 'point' && !allowedGeometries.point && allowedGeometries.vertex) {
61638               return new validationIssue({
61639                 type: type,
61640                 subtype: 'vertex_as_point',
61641                 severity: 'warning',
61642                 message: function message(context) {
61643                   var entity = context.hasEntity(this.entityIds[0]);
61644                   return entity ? _t.html('issues.vertex_as_point.message', {
61645                     feature: utilDisplayLabel(entity, 'vertex')
61646                   }) : '';
61647                 },
61648                 reference: function showReference(selection) {
61649                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.vertex_as_point.reference'));
61650                 },
61651                 entityIds: [entity.id]
61652               });
61653             } else if (geometry === 'vertex' && !allowedGeometries.vertex && allowedGeometries.point) {
61654               return new validationIssue({
61655                 type: type,
61656                 subtype: 'point_as_vertex',
61657                 severity: 'warning',
61658                 message: function message(context) {
61659                   var entity = context.hasEntity(this.entityIds[0]);
61660                   return entity ? _t.html('issues.point_as_vertex.message', {
61661                     feature: utilDisplayLabel(entity, 'point')
61662                   }) : '';
61663                 },
61664                 reference: function showReference(selection) {
61665                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.point_as_vertex.reference'));
61666                 },
61667                 entityIds: [entity.id],
61668                 dynamicFixes: function dynamicFixes(context) {
61669                   var entityId = this.entityIds[0];
61670                   var extractOnClick = null;
61671
61672                   if (!context.hasHiddenConnections(entityId)) {
61673                     extractOnClick = function extractOnClick(context) {
61674                       var entityId = this.issue.entityIds[0];
61675                       var action = actionExtract(entityId);
61676                       context.perform(action, _t('operations.extract.annotation', {
61677                         n: 1
61678                       })); // re-enter mode to trigger updates
61679
61680                       context.enter(modeSelect(context, [action.getExtractedNodeID()]));
61681                     };
61682                   }
61683
61684                   return [new validationIssueFix({
61685                     icon: 'iD-operation-extract',
61686                     title: _t.html('issues.fix.extract_point.title'),
61687                     onClick: extractOnClick
61688                   })];
61689                 }
61690               });
61691             }
61692
61693             return null;
61694           }
61695
61696           function unclosedMultipolygonPartIssues(entity, graph) {
61697             if (entity.type !== 'relation' || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
61698             !entity.isComplete(graph)) return null;
61699             var sequences = osmJoinWays(entity.members, graph);
61700             var issues = [];
61701
61702             for (var i in sequences) {
61703               var sequence = sequences[i];
61704               if (!sequence.nodes) continue;
61705               var firstNode = sequence.nodes[0];
61706               var lastNode = sequence.nodes[sequence.nodes.length - 1]; // part is closed if the first and last nodes are the same
61707
61708               if (firstNode === lastNode) continue;
61709               var issue = new validationIssue({
61710                 type: type,
61711                 subtype: 'unclosed_multipolygon_part',
61712                 severity: 'warning',
61713                 message: function message(context) {
61714                   var entity = context.hasEntity(this.entityIds[0]);
61715                   return entity ? _t.html('issues.unclosed_multipolygon_part.message', {
61716                     feature: utilDisplayLabel(entity, context.graph())
61717                   }) : '';
61718                 },
61719                 reference: showReference,
61720                 loc: sequence.nodes[0].loc,
61721                 entityIds: [entity.id],
61722                 hash: sequence.map(function (way) {
61723                   return way.id;
61724                 }).join()
61725               });
61726               issues.push(issue);
61727             }
61728
61729             return issues;
61730
61731             function showReference(selection) {
61732               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unclosed_multipolygon_part.reference'));
61733             }
61734           }
61735
61736           var validation = function checkMismatchedGeometry(entity, graph) {
61737             var issues = [vertexTaggedAsPointIssue(entity, graph), lineTaggedAsAreaIssue(entity)];
61738             issues = issues.concat(unclosedMultipolygonPartIssues(entity, graph));
61739             return issues.filter(Boolean);
61740           };
61741
61742           validation.type = type;
61743           return validation;
61744         }
61745
61746         function validationMissingRole() {
61747           var type = 'missing_role';
61748
61749           var validation = function checkMissingRole(entity, graph) {
61750             var issues = [];
61751
61752             if (entity.type === 'way') {
61753               graph.parentRelations(entity).forEach(function (relation) {
61754                 if (!relation.isMultipolygon()) return;
61755                 var member = relation.memberById(entity.id);
61756
61757                 if (member && isMissingRole(member)) {
61758                   issues.push(makeIssue(entity, relation, member));
61759                 }
61760               });
61761             } else if (entity.type === 'relation' && entity.isMultipolygon()) {
61762               entity.indexedMembers().forEach(function (member) {
61763                 var way = graph.hasEntity(member.id);
61764
61765                 if (way && isMissingRole(member)) {
61766                   issues.push(makeIssue(way, entity, member));
61767                 }
61768               });
61769             }
61770
61771             return issues;
61772           };
61773
61774           function isMissingRole(member) {
61775             return !member.role || !member.role.trim().length;
61776           }
61777
61778           function makeIssue(way, relation, member) {
61779             return new validationIssue({
61780               type: type,
61781               severity: 'warning',
61782               message: function message(context) {
61783                 var member = context.hasEntity(this.entityIds[1]),
61784                     relation = context.hasEntity(this.entityIds[0]);
61785                 return member && relation ? _t.html('issues.missing_role.message', {
61786                   member: utilDisplayLabel(member, context.graph()),
61787                   relation: utilDisplayLabel(relation, context.graph())
61788                 }) : '';
61789               },
61790               reference: showReference,
61791               entityIds: [relation.id, way.id],
61792               data: {
61793                 member: member
61794               },
61795               hash: member.index.toString(),
61796               dynamicFixes: function dynamicFixes() {
61797                 return [makeAddRoleFix('inner'), makeAddRoleFix('outer'), new validationIssueFix({
61798                   icon: 'iD-operation-delete',
61799                   title: _t.html('issues.fix.remove_from_relation.title'),
61800                   onClick: function onClick(context) {
61801                     context.perform(actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), _t('operations.delete_member.annotation', {
61802                       n: 1
61803                     }));
61804                   }
61805                 })];
61806               }
61807             });
61808
61809             function showReference(selection) {
61810               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.missing_role.multipolygon.reference'));
61811             }
61812           }
61813
61814           function makeAddRoleFix(role) {
61815             return new validationIssueFix({
61816               title: _t.html('issues.fix.set_as_' + role + '.title'),
61817               onClick: function onClick(context) {
61818                 var oldMember = this.issue.data.member;
61819                 var member = {
61820                   id: this.issue.entityIds[1],
61821                   type: oldMember.type,
61822                   role: role
61823                 };
61824                 context.perform(actionChangeMember(this.issue.entityIds[0], member, oldMember.index), _t('operations.change_role.annotation', {
61825                   n: 1
61826                 }));
61827               }
61828             });
61829           }
61830
61831           validation.type = type;
61832           return validation;
61833         }
61834
61835         function validationMissingTag(context) {
61836           var type = 'missing_tag';
61837
61838           function hasDescriptiveTags(entity, graph) {
61839             var keys = Object.keys(entity.tags).filter(function (k) {
61840               if (k === 'area' || k === 'name') {
61841                 return false;
61842               } else {
61843                 return osmIsInterestingTag(k);
61844               }
61845             });
61846
61847             if (entity.type === 'relation' && keys.length === 1 && entity.tags.type === 'multipolygon') {
61848               // this relation's only interesting tag just says its a multipolygon,
61849               // which is not descriptive enough
61850               // It's okay for a simple multipolygon to have no descriptive tags
61851               // if its outer way has them (old model, see `outdated_tags.js`)
61852               return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
61853             }
61854
61855             return keys.length > 0;
61856           }
61857
61858           function isUnknownRoad(entity) {
61859             return entity.type === 'way' && entity.tags.highway === 'road';
61860           }
61861
61862           function isUntypedRelation(entity) {
61863             return entity.type === 'relation' && !entity.tags.type;
61864           }
61865
61866           var validation = function checkMissingTag(entity, graph) {
61867             var subtype;
61868             var osm = context.connection();
61869             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
61870
61871             if (!isUnloadedNode && // allow untagged nodes that are part of ways
61872             entity.geometry(graph) !== 'vertex' && // allow untagged entities that are part of relations
61873             !entity.hasParentRelations(graph)) {
61874               if (Object.keys(entity.tags).length === 0) {
61875                 subtype = 'any';
61876               } else if (!hasDescriptiveTags(entity, graph)) {
61877                 subtype = 'descriptive';
61878               } else if (isUntypedRelation(entity)) {
61879                 subtype = 'relation_type';
61880               }
61881             } // flag an unknown road even if it's a member of a relation
61882
61883
61884             if (!subtype && isUnknownRoad(entity)) {
61885               subtype = 'highway_classification';
61886             }
61887
61888             if (!subtype) return [];
61889             var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
61890             var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag'; // can always delete if the user created it in the first place..
61891
61892             var canDelete = entity.version === undefined || entity.v !== undefined;
61893             var severity = canDelete && subtype !== 'highway_classification' ? 'error' : 'warning';
61894             return [new validationIssue({
61895               type: type,
61896               subtype: subtype,
61897               severity: severity,
61898               message: function message(context) {
61899                 var entity = context.hasEntity(this.entityIds[0]);
61900                 return entity ? _t.html('issues.' + messageID + '.message', {
61901                   feature: utilDisplayLabel(entity, context.graph())
61902                 }) : '';
61903               },
61904               reference: showReference,
61905               entityIds: [entity.id],
61906               dynamicFixes: function dynamicFixes(context) {
61907                 var fixes = [];
61908                 var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';
61909                 fixes.push(new validationIssueFix({
61910                   icon: 'iD-icon-search',
61911                   title: _t.html('issues.fix.' + selectFixType + '.title'),
61912                   onClick: function onClick(context) {
61913                     context.ui().sidebar.showPresetList();
61914                   }
61915                 }));
61916                 var deleteOnClick;
61917                 var id = this.entityIds[0];
61918                 var operation = operationDelete(context, [id]);
61919                 var disabledReasonID = operation.disabled();
61920
61921                 if (!disabledReasonID) {
61922                   deleteOnClick = function deleteOnClick(context) {
61923                     var id = this.issue.entityIds[0];
61924                     var operation = operationDelete(context, [id]);
61925
61926                     if (!operation.disabled()) {
61927                       operation();
61928                     }
61929                   };
61930                 }
61931
61932                 fixes.push(new validationIssueFix({
61933                   icon: 'iD-operation-delete',
61934                   title: _t.html('issues.fix.delete_feature.title'),
61935                   disabledReason: disabledReasonID ? _t('operations.delete.' + disabledReasonID + '.single') : undefined,
61936                   onClick: deleteOnClick
61937                 }));
61938                 return fixes;
61939               }
61940             })];
61941
61942             function showReference(selection) {
61943               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.' + referenceID + '.reference'));
61944             }
61945           };
61946
61947           validation.type = type;
61948           return validation;
61949         }
61950
61951         var simplify = function simplify(str) {
61952           return diacritics.remove(str.replace(/&/g, 'and').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\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\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, '').toLowerCase());
61953         };
61954
61955         // {
61956         //   kvnd:        "amenity/fast_food|Thaï Express~(North America)",
61957         //   kvn:         "amenity/fast_food|Thaï Express",
61958         //   kv:          "amenity/fast_food",
61959         //   k:           "amenity",
61960         //   v:           "fast_food",
61961         //   n:           "Thaï Express",
61962         //   d:           "(North America)",
61963         //   nsimple:     "thaiexpress",
61964         //   kvnnsimple:  "amenity/fast_food|thaiexpress"
61965         // }
61966
61967         var to_parts = function to_parts(kvnd) {
61968           var parts = {};
61969           parts.kvnd = kvnd;
61970           var kvndparts = kvnd.split('~', 2);
61971           if (kvndparts.length > 1) parts.d = kvndparts[1];
61972           parts.kvn = kvndparts[0];
61973           var kvnparts = parts.kvn.split('|', 2);
61974           if (kvnparts.length > 1) parts.n = kvnparts[1];
61975           parts.kv = kvnparts[0];
61976           var kvparts = parts.kv.split('/', 2);
61977           parts.k = kvparts[0];
61978           parts.v = kvparts[1];
61979           parts.nsimple = simplify(parts.n);
61980           parts.kvnsimple = parts.kv + '|' + parts.nsimple;
61981           return parts;
61982         };
61983
61984         var matchGroups = {adult_gaming_centre:["amenity/casino","amenity/gambling","leisure/adult_gaming_centre"],beauty:["shop/beauty","shop/hairdresser_supply"],bed:["shop/bed","shop/furniture"],beverages:["shop/alcohol","shop/beverages"],camping:["leisure/park","tourism/camp_site","tourism/caravan_site"],car_parts:["shop/car_parts","shop/car_repair","shop/tires","shop/tyres"],confectionery:["shop/candy","shop/chocolate","shop/confectionery"],convenience:["shop/beauty","shop/chemist","shop/convenience","shop/cosmetics","shop/newsagent"],coworking:["amenity/coworking_space","office/coworking","office/coworking_space"],electronics:["office/telecommunication","shop/computer","shop/electronics","shop/hifi","shop/mobile","shop/mobile_phone","shop/telecommunication"],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/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/carpet","shop/diy","shop/doityourself","shop/doors","shop/electrical","shop/flooring","shop/hardware","shop/power_tools","shop/tool_hire","shop/tools","shop/trade"],health_food:["shop/health","shop/health_food","shop/herbalist","shop/nutrition_supplements"],houseware:["shop/houseware","shop/interior_decoration"],lodging:["tourism/hotel","tourism/motel"],money_transfer:["amenity/money_transfer","shop/money_transfer"],outdoor:["shop/outdoor","shop/sports"],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/supermarket","shop/discount","shop/convenience"],vending:["amenity/vending_machine","shop/vending_machine"],wholesale:["shop/wholesale","shop/supermarket","shop/department_store"]};
61985         var require$$0 = {
61986         matchGroups: matchGroups
61987         };
61988
61989         var matchGroups$1 = require$$0.matchGroups;
61990
61991         var matcher$1 = function matcher() {
61992           var _warnings = []; // array of match conflict pairs
61993
61994           var _ambiguous = {};
61995           var _matchIndex = {};
61996           var matcher = {}; // Create an index of all the keys/simplenames for fast matching
61997
61998           matcher.buildMatchIndex = function (brands) {
61999             // two passes - once for primary names, once for secondary/alternate names
62000             Object.keys(brands).forEach(function (kvnd) {
62001               return insertNames(kvnd, 'primary');
62002             });
62003             Object.keys(brands).forEach(function (kvnd) {
62004               return insertNames(kvnd, 'secondary');
62005             });
62006
62007             function insertNames(kvnd, which) {
62008               var obj = brands[kvnd];
62009               var parts = to_parts(kvnd); // Exit early for ambiguous names in the second pass.
62010               // They were collected in the first pass and we don't gather alt names for them.
62011
62012               if (which === 'secondary' && parts.d) return;
62013
62014               if (obj.countryCodes) {
62015                 parts.countryCodes = obj.countryCodes.slice(); // copy
62016               }
62017
62018               var nomatches = obj.nomatch || [];
62019
62020               if (nomatches.some(function (s) {
62021                 return s === kvnd;
62022               })) {
62023                 console.log("WARNING match/nomatch conflict for ".concat(kvnd));
62024                 return;
62025               }
62026
62027               var match_kv = [parts.kv].concat(obj.matchTags || []).concat(["".concat(parts.k, "/yes"), "building/yes"]) // #3454 - match some generic tags
62028               .map(function (s) {
62029                 return s.toLowerCase();
62030               });
62031               var match_nsimple = [];
62032
62033               if (which === 'primary') {
62034                 match_nsimple = [parts.n].concat(obj.matchNames || []).concat(obj.tags.official_name || []) // #2732 - match alternate names
62035                 .map(simplify);
62036               } else if (which === 'secondary') {
62037                 match_nsimple = [].concat(obj.tags.alt_name || []) // #2732 - match alternate names
62038                 .concat(obj.tags.short_name || []) // #2732 - match alternate names
62039                 .map(simplify);
62040               }
62041
62042               if (!match_nsimple.length) return; // nothing to do
62043
62044               match_kv.forEach(function (kv) {
62045                 match_nsimple.forEach(function (nsimple) {
62046                   if (parts.d) {
62047                     // Known ambiguous names with disambiguation string ~(USA) / ~(Canada)
62048                     // FIXME: Name collisions will overwrite the initial entry (ok for now)
62049                     if (!_ambiguous[kv]) _ambiguous[kv] = {};
62050                     _ambiguous[kv][nsimple] = parts;
62051                   } else {
62052                     // Names we mostly expect to be unique..
62053                     if (!_matchIndex[kv]) _matchIndex[kv] = {};
62054                     var m = _matchIndex[kv][nsimple];
62055
62056                     if (m) {
62057                       // There already is a match for this name, skip it
62058                       // Warn if we detect collisions in a primary name.
62059                       // Skip warning if a secondary name or a generic `*=yes` tag - #2972 / #3454
62060                       if (which === 'primary' && !/\/yes$/.test(kv)) {
62061                         _warnings.push([m.kvnd, "".concat(kvnd, " (").concat(kv, "/").concat(nsimple, ")")]);
62062                       }
62063                     } else {
62064                       _matchIndex[kv][nsimple] = parts; // insert
62065                     }
62066                   }
62067                 });
62068               });
62069             }
62070           }; // pass a `key`, `value`, `name` and return the best match,
62071           // `countryCode` optional (if supplied, must match that too)
62072
62073
62074           matcher.matchKVN = function (key, value, name, countryCode) {
62075             return matcher.matchParts(to_parts("".concat(key, "/").concat(value, "|").concat(name)), countryCode);
62076           }; // pass a parts object and return the best match,
62077           // `countryCode` optional (if supplied, must match that too)
62078
62079
62080           matcher.matchParts = function (parts, countryCode) {
62081             var match = null;
62082             var inGroup = false; // fixme: we currently return a single match for ambiguous
62083
62084             match = _ambiguous[parts.kv] && _ambiguous[parts.kv][parts.nsimple];
62085             if (match && matchesCountryCode(match)) return match; // try to return an exact match
62086
62087             match = _matchIndex[parts.kv] && _matchIndex[parts.kv][parts.nsimple];
62088             if (match && matchesCountryCode(match)) return match; // look in match groups
62089
62090             for (var mg in matchGroups$1) {
62091               var matchGroup = matchGroups$1[mg];
62092               match = null;
62093               inGroup = false;
62094
62095               for (var i = 0; i < matchGroup.length; i++) {
62096                 var otherkv = matchGroup[i].toLowerCase();
62097
62098                 if (!inGroup) {
62099                   inGroup = otherkv === parts.kv;
62100                 }
62101
62102                 if (!match) {
62103                   // fixme: we currently return a single match for ambiguous
62104                   match = _ambiguous[otherkv] && _ambiguous[otherkv][parts.nsimple];
62105                 }
62106
62107                 if (!match) {
62108                   match = _matchIndex[otherkv] && _matchIndex[otherkv][parts.nsimple];
62109                 }
62110
62111                 if (match && !matchesCountryCode(match)) {
62112                   match = null;
62113                 }
62114
62115                 if (inGroup && match) {
62116                   return match;
62117                 }
62118               }
62119             }
62120
62121             return null;
62122
62123             function matchesCountryCode(match) {
62124               if (!countryCode) return true;
62125               if (!match.countryCodes) return true;
62126               return match.countryCodes.indexOf(countryCode) !== -1;
62127             }
62128           };
62129
62130           matcher.getWarnings = function () {
62131             return _warnings;
62132           };
62133
62134           return matcher;
62135         };
62136
62137         var fromCharCode = String.fromCharCode;
62138         var nativeFromCodePoint = String.fromCodePoint;
62139
62140         // length should be 1, old FF problem
62141         var INCORRECT_LENGTH = !!nativeFromCodePoint && nativeFromCodePoint.length != 1;
62142
62143         // `String.fromCodePoint` method
62144         // https://tc39.github.io/ecma262/#sec-string.fromcodepoint
62145         _export({ target: 'String', stat: true, forced: INCORRECT_LENGTH }, {
62146           fromCodePoint: function fromCodePoint(x) { // eslint-disable-line no-unused-vars
62147             var elements = [];
62148             var length = arguments.length;
62149             var i = 0;
62150             var code;
62151             while (length > i) {
62152               code = +arguments[i++];
62153               if (toAbsoluteIndex(code, 0x10FFFF) !== code) throw RangeError(code + ' is not a valid code point');
62154               elements.push(code < 0x10000
62155                 ? fromCharCode(code)
62156                 : fromCharCode(((code -= 0x10000) >> 10) + 0xD800, code % 0x400 + 0xDC00)
62157               );
62158             } return elements.join('');
62159           }
62160         });
62161
62162         var quickselect$2 = createCommonjsModule(function (module, exports) {
62163           (function (global, factory) {
62164              module.exports = factory() ;
62165           })(commonjsGlobal, function () {
62166
62167             function quickselect(arr, k, left, right, compare) {
62168               quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
62169             }
62170
62171             function quickselectStep(arr, k, left, right, compare) {
62172               while (right > left) {
62173                 if (right - left > 600) {
62174                   var n = right - left + 1;
62175                   var m = k - left + 1;
62176                   var z = Math.log(n);
62177                   var s = 0.5 * Math.exp(2 * z / 3);
62178                   var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
62179                   var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
62180                   var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
62181                   quickselectStep(arr, k, newLeft, newRight, compare);
62182                 }
62183
62184                 var t = arr[k];
62185                 var i = left;
62186                 var j = right;
62187                 swap(arr, left, k);
62188                 if (compare(arr[right], t) > 0) swap(arr, left, right);
62189
62190                 while (i < j) {
62191                   swap(arr, i, j);
62192                   i++;
62193                   j--;
62194
62195                   while (compare(arr[i], t) < 0) {
62196                     i++;
62197                   }
62198
62199                   while (compare(arr[j], t) > 0) {
62200                     j--;
62201                   }
62202                 }
62203
62204                 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
62205                   j++;
62206                   swap(arr, j, right);
62207                 }
62208                 if (j <= k) left = j + 1;
62209                 if (k <= j) right = j - 1;
62210               }
62211             }
62212
62213             function swap(arr, i, j) {
62214               var tmp = arr[i];
62215               arr[i] = arr[j];
62216               arr[j] = tmp;
62217             }
62218
62219             function defaultCompare(a, b) {
62220               return a < b ? -1 : a > b ? 1 : 0;
62221             }
62222
62223             return quickselect;
62224           });
62225         });
62226
62227         var rbush_1 = rbush;
62228         var _default$2 = rbush;
62229
62230         function rbush(maxEntries, format) {
62231           if (!(this instanceof rbush)) return new rbush(maxEntries, format); // max entries in a node is 9 by default; min node fill is 40% for best performance
62232
62233           this._maxEntries = Math.max(4, maxEntries || 9);
62234           this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
62235
62236           if (format) {
62237             this._initFormat(format);
62238           }
62239
62240           this.clear();
62241         }
62242
62243         rbush.prototype = {
62244           all: function all() {
62245             return this._all(this.data, []);
62246           },
62247           search: function search(bbox) {
62248             var node = this.data,
62249                 result = [],
62250                 toBBox = this.toBBox;
62251             if (!intersects$1(bbox, node)) return result;
62252             var nodesToSearch = [],
62253                 i,
62254                 len,
62255                 child,
62256                 childBBox;
62257
62258             while (node) {
62259               for (i = 0, len = node.children.length; i < len; i++) {
62260                 child = node.children[i];
62261                 childBBox = node.leaf ? toBBox(child) : child;
62262
62263                 if (intersects$1(bbox, childBBox)) {
62264                   if (node.leaf) result.push(child);else if (contains$1(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
62265                 }
62266               }
62267
62268               node = nodesToSearch.pop();
62269             }
62270
62271             return result;
62272           },
62273           collides: function collides(bbox) {
62274             var node = this.data,
62275                 toBBox = this.toBBox;
62276             if (!intersects$1(bbox, node)) return false;
62277             var nodesToSearch = [],
62278                 i,
62279                 len,
62280                 child,
62281                 childBBox;
62282
62283             while (node) {
62284               for (i = 0, len = node.children.length; i < len; i++) {
62285                 child = node.children[i];
62286                 childBBox = node.leaf ? toBBox(child) : child;
62287
62288                 if (intersects$1(bbox, childBBox)) {
62289                   if (node.leaf || contains$1(bbox, childBBox)) return true;
62290                   nodesToSearch.push(child);
62291                 }
62292               }
62293
62294               node = nodesToSearch.pop();
62295             }
62296
62297             return false;
62298           },
62299           load: function load(data) {
62300             if (!(data && data.length)) return this;
62301
62302             if (data.length < this._minEntries) {
62303               for (var i = 0, len = data.length; i < len; i++) {
62304                 this.insert(data[i]);
62305               }
62306
62307               return this;
62308             } // recursively build the tree with the given data from scratch using OMT algorithm
62309
62310
62311             var node = this._build(data.slice(), 0, data.length - 1, 0);
62312
62313             if (!this.data.children.length) {
62314               // save as is if tree is empty
62315               this.data = node;
62316             } else if (this.data.height === node.height) {
62317               // split root if trees have the same height
62318               this._splitRoot(this.data, node);
62319             } else {
62320               if (this.data.height < node.height) {
62321                 // swap trees if inserted one is bigger
62322                 var tmpNode = this.data;
62323                 this.data = node;
62324                 node = tmpNode;
62325               } // insert the small tree into the large tree at appropriate level
62326
62327
62328               this._insert(node, this.data.height - node.height - 1, true);
62329             }
62330
62331             return this;
62332           },
62333           insert: function insert(item) {
62334             if (item) this._insert(item, this.data.height - 1);
62335             return this;
62336           },
62337           clear: function clear() {
62338             this.data = createNode$1([]);
62339             return this;
62340           },
62341           remove: function remove(item, equalsFn) {
62342             if (!item) return this;
62343             var node = this.data,
62344                 bbox = this.toBBox(item),
62345                 path = [],
62346                 indexes = [],
62347                 i,
62348                 parent,
62349                 index,
62350                 goingUp; // depth-first iterative tree traversal
62351
62352             while (node || path.length) {
62353               if (!node) {
62354                 // go up
62355                 node = path.pop();
62356                 parent = path[path.length - 1];
62357                 i = indexes.pop();
62358                 goingUp = true;
62359               }
62360
62361               if (node.leaf) {
62362                 // check current node
62363                 index = findItem$1(item, node.children, equalsFn);
62364
62365                 if (index !== -1) {
62366                   // item found, remove the item and condense tree upwards
62367                   node.children.splice(index, 1);
62368                   path.push(node);
62369
62370                   this._condense(path);
62371
62372                   return this;
62373                 }
62374               }
62375
62376               if (!goingUp && !node.leaf && contains$1(node, bbox)) {
62377                 // go down
62378                 path.push(node);
62379                 indexes.push(i);
62380                 i = 0;
62381                 parent = node;
62382                 node = node.children[0];
62383               } else if (parent) {
62384                 // go right
62385                 i++;
62386                 node = parent.children[i];
62387                 goingUp = false;
62388               } else node = null; // nothing found
62389
62390             }
62391
62392             return this;
62393           },
62394           toBBox: function toBBox(item) {
62395             return item;
62396           },
62397           compareMinX: compareNodeMinX$1,
62398           compareMinY: compareNodeMinY$1,
62399           toJSON: function toJSON() {
62400             return this.data;
62401           },
62402           fromJSON: function fromJSON(data) {
62403             this.data = data;
62404             return this;
62405           },
62406           _all: function _all(node, result) {
62407             var nodesToSearch = [];
62408
62409             while (node) {
62410               if (node.leaf) result.push.apply(result, node.children);else nodesToSearch.push.apply(nodesToSearch, node.children);
62411               node = nodesToSearch.pop();
62412             }
62413
62414             return result;
62415           },
62416           _build: function _build(items, left, right, height) {
62417             var N = right - left + 1,
62418                 M = this._maxEntries,
62419                 node;
62420
62421             if (N <= M) {
62422               // reached leaf level; return leaf
62423               node = createNode$1(items.slice(left, right + 1));
62424               calcBBox$1(node, this.toBBox);
62425               return node;
62426             }
62427
62428             if (!height) {
62429               // target height of the bulk-loaded tree
62430               height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
62431
62432               M = Math.ceil(N / Math.pow(M, height - 1));
62433             }
62434
62435             node = createNode$1([]);
62436             node.leaf = false;
62437             node.height = height; // split the items into M mostly square tiles
62438
62439             var N2 = Math.ceil(N / M),
62440                 N1 = N2 * Math.ceil(Math.sqrt(M)),
62441                 i,
62442                 j,
62443                 right2,
62444                 right3;
62445             multiSelect$1(items, left, right, N1, this.compareMinX);
62446
62447             for (i = left; i <= right; i += N1) {
62448               right2 = Math.min(i + N1 - 1, right);
62449               multiSelect$1(items, i, right2, N2, this.compareMinY);
62450
62451               for (j = i; j <= right2; j += N2) {
62452                 right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
62453
62454                 node.children.push(this._build(items, j, right3, height - 1));
62455               }
62456             }
62457
62458             calcBBox$1(node, this.toBBox);
62459             return node;
62460           },
62461           _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
62462             var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
62463
62464             while (true) {
62465               path.push(node);
62466               if (node.leaf || path.length - 1 === level) break;
62467               minArea = minEnlargement = Infinity;
62468
62469               for (i = 0, len = node.children.length; i < len; i++) {
62470                 child = node.children[i];
62471                 area = bboxArea$1(child);
62472                 enlargement = enlargedArea$1(bbox, child) - area; // choose entry with the least area enlargement
62473
62474                 if (enlargement < minEnlargement) {
62475                   minEnlargement = enlargement;
62476                   minArea = area < minArea ? area : minArea;
62477                   targetNode = child;
62478                 } else if (enlargement === minEnlargement) {
62479                   // otherwise choose one with the smallest area
62480                   if (area < minArea) {
62481                     minArea = area;
62482                     targetNode = child;
62483                   }
62484                 }
62485               }
62486
62487               node = targetNode || node.children[0];
62488             }
62489
62490             return node;
62491           },
62492           _insert: function _insert(item, level, isNode) {
62493             var toBBox = this.toBBox,
62494                 bbox = isNode ? item : toBBox(item),
62495                 insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
62496
62497             var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
62498
62499
62500             node.children.push(item);
62501             extend$3(node, bbox); // split on node overflow; propagate upwards if necessary
62502
62503             while (level >= 0) {
62504               if (insertPath[level].children.length > this._maxEntries) {
62505                 this._split(insertPath, level);
62506
62507                 level--;
62508               } else break;
62509             } // adjust bboxes along the insertion path
62510
62511
62512             this._adjustParentBBoxes(bbox, insertPath, level);
62513           },
62514           // split overflowed node into two
62515           _split: function _split(insertPath, level) {
62516             var node = insertPath[level],
62517                 M = node.children.length,
62518                 m = this._minEntries;
62519
62520             this._chooseSplitAxis(node, m, M);
62521
62522             var splitIndex = this._chooseSplitIndex(node, m, M);
62523
62524             var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
62525             newNode.height = node.height;
62526             newNode.leaf = node.leaf;
62527             calcBBox$1(node, this.toBBox);
62528             calcBBox$1(newNode, this.toBBox);
62529             if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
62530           },
62531           _splitRoot: function _splitRoot(node, newNode) {
62532             // split root node
62533             this.data = createNode$1([node, newNode]);
62534             this.data.height = node.height + 1;
62535             this.data.leaf = false;
62536             calcBBox$1(this.data, this.toBBox);
62537           },
62538           _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
62539             var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
62540             minOverlap = minArea = Infinity;
62541
62542             for (i = m; i <= M - m; i++) {
62543               bbox1 = distBBox$1(node, 0, i, this.toBBox);
62544               bbox2 = distBBox$1(node, i, M, this.toBBox);
62545               overlap = intersectionArea$1(bbox1, bbox2);
62546               area = bboxArea$1(bbox1) + bboxArea$1(bbox2); // choose distribution with minimum overlap
62547
62548               if (overlap < minOverlap) {
62549                 minOverlap = overlap;
62550                 index = i;
62551                 minArea = area < minArea ? area : minArea;
62552               } else if (overlap === minOverlap) {
62553                 // otherwise choose distribution with minimum area
62554                 if (area < minArea) {
62555                   minArea = area;
62556                   index = i;
62557                 }
62558               }
62559             }
62560
62561             return index;
62562           },
62563           // sorts node children by the best axis for split
62564           _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
62565             var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
62566                 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
62567                 xMargin = this._allDistMargin(node, m, M, compareMinX),
62568                 yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
62569             // otherwise it's already sorted by minY
62570
62571
62572             if (xMargin < yMargin) node.children.sort(compareMinX);
62573           },
62574           // total margin of all possible split distributions where each node is at least m full
62575           _allDistMargin: function _allDistMargin(node, m, M, compare) {
62576             node.children.sort(compare);
62577             var toBBox = this.toBBox,
62578                 leftBBox = distBBox$1(node, 0, m, toBBox),
62579                 rightBBox = distBBox$1(node, M - m, M, toBBox),
62580                 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
62581                 i,
62582                 child;
62583
62584             for (i = m; i < M - m; i++) {
62585               child = node.children[i];
62586               extend$3(leftBBox, node.leaf ? toBBox(child) : child);
62587               margin += bboxMargin$1(leftBBox);
62588             }
62589
62590             for (i = M - m - 1; i >= m; i--) {
62591               child = node.children[i];
62592               extend$3(rightBBox, node.leaf ? toBBox(child) : child);
62593               margin += bboxMargin$1(rightBBox);
62594             }
62595
62596             return margin;
62597           },
62598           _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
62599             // adjust bboxes along the given tree path
62600             for (var i = level; i >= 0; i--) {
62601               extend$3(path[i], bbox);
62602             }
62603           },
62604           _condense: function _condense(path) {
62605             // go through the path, removing empty nodes and updating bboxes
62606             for (var i = path.length - 1, siblings; i >= 0; i--) {
62607               if (path[i].children.length === 0) {
62608                 if (i > 0) {
62609                   siblings = path[i - 1].children;
62610                   siblings.splice(siblings.indexOf(path[i]), 1);
62611                 } else this.clear();
62612               } else calcBBox$1(path[i], this.toBBox);
62613             }
62614           },
62615           _initFormat: function _initFormat(format) {
62616             // data format (minX, minY, maxX, maxY accessors)
62617             // uses eval-type function compilation instead of just accepting a toBBox function
62618             // because the algorithms are very sensitive to sorting functions performance,
62619             // so they should be dead simple and without inner calls
62620             var compareArr = ['return a', ' - b', ';'];
62621             this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
62622             this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
62623             this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
62624           }
62625         };
62626
62627         function findItem$1(item, items, equalsFn) {
62628           if (!equalsFn) return items.indexOf(item);
62629
62630           for (var i = 0; i < items.length; i++) {
62631             if (equalsFn(item, items[i])) return i;
62632           }
62633
62634           return -1;
62635         } // calculate node's bbox from bboxes of its children
62636
62637
62638         function calcBBox$1(node, toBBox) {
62639           distBBox$1(node, 0, node.children.length, toBBox, node);
62640         } // min bounding rectangle of node children from k to p-1
62641
62642
62643         function distBBox$1(node, k, p, toBBox, destNode) {
62644           if (!destNode) destNode = createNode$1(null);
62645           destNode.minX = Infinity;
62646           destNode.minY = Infinity;
62647           destNode.maxX = -Infinity;
62648           destNode.maxY = -Infinity;
62649
62650           for (var i = k, child; i < p; i++) {
62651             child = node.children[i];
62652             extend$3(destNode, node.leaf ? toBBox(child) : child);
62653           }
62654
62655           return destNode;
62656         }
62657
62658         function extend$3(a, b) {
62659           a.minX = Math.min(a.minX, b.minX);
62660           a.minY = Math.min(a.minY, b.minY);
62661           a.maxX = Math.max(a.maxX, b.maxX);
62662           a.maxY = Math.max(a.maxY, b.maxY);
62663           return a;
62664         }
62665
62666         function compareNodeMinX$1(a, b) {
62667           return a.minX - b.minX;
62668         }
62669
62670         function compareNodeMinY$1(a, b) {
62671           return a.minY - b.minY;
62672         }
62673
62674         function bboxArea$1(a) {
62675           return (a.maxX - a.minX) * (a.maxY - a.minY);
62676         }
62677
62678         function bboxMargin$1(a) {
62679           return a.maxX - a.minX + (a.maxY - a.minY);
62680         }
62681
62682         function enlargedArea$1(a, b) {
62683           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));
62684         }
62685
62686         function intersectionArea$1(a, b) {
62687           var minX = Math.max(a.minX, b.minX),
62688               minY = Math.max(a.minY, b.minY),
62689               maxX = Math.min(a.maxX, b.maxX),
62690               maxY = Math.min(a.maxY, b.maxY);
62691           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
62692         }
62693
62694         function contains$1(a, b) {
62695           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
62696         }
62697
62698         function intersects$1(a, b) {
62699           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
62700         }
62701
62702         function createNode$1(children) {
62703           return {
62704             children: children,
62705             height: 1,
62706             leaf: true,
62707             minX: Infinity,
62708             minY: Infinity,
62709             maxX: -Infinity,
62710             maxY: -Infinity
62711           };
62712         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
62713         // combines selection algorithm with binary divide & conquer approach
62714
62715
62716         function multiSelect$1(arr, left, right, n, compare) {
62717           var stack = [left, right],
62718               mid;
62719
62720           while (stack.length) {
62721             right = stack.pop();
62722             left = stack.pop();
62723             if (right - left <= n) continue;
62724             mid = left + Math.ceil((right - left) / n / 2) * n;
62725             quickselect$2(arr, mid, left, right, compare);
62726             stack.push(left, mid, mid, right);
62727           }
62728         }
62729         rbush_1["default"] = _default$2;
62730
62731         var lineclip_1$1 = lineclip$1;
62732         lineclip$1.polyline = lineclip$1;
62733         lineclip$1.polygon = polygonclip$1; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
62734         // handle polylines rather than just segments
62735
62736         function lineclip$1(points, bbox, result) {
62737           var len = points.length,
62738               codeA = bitCode$1(points[0], bbox),
62739               part = [],
62740               i,
62741               a,
62742               b,
62743               codeB,
62744               lastCode;
62745           if (!result) result = [];
62746
62747           for (i = 1; i < len; i++) {
62748             a = points[i - 1];
62749             b = points[i];
62750             codeB = lastCode = bitCode$1(b, bbox);
62751
62752             while (true) {
62753               if (!(codeA | codeB)) {
62754                 // accept
62755                 part.push(a);
62756
62757                 if (codeB !== lastCode) {
62758                   // segment went outside
62759                   part.push(b);
62760
62761                   if (i < len - 1) {
62762                     // start a new line
62763                     result.push(part);
62764                     part = [];
62765                   }
62766                 } else if (i === len - 1) {
62767                   part.push(b);
62768                 }
62769
62770                 break;
62771               } else if (codeA & codeB) {
62772                 // trivial reject
62773                 break;
62774               } else if (codeA) {
62775                 // a outside, intersect with clip edge
62776                 a = intersect$1(a, b, codeA, bbox);
62777                 codeA = bitCode$1(a, bbox);
62778               } else {
62779                 // b outside
62780                 b = intersect$1(a, b, codeB, bbox);
62781                 codeB = bitCode$1(b, bbox);
62782               }
62783             }
62784
62785             codeA = lastCode;
62786           }
62787
62788           if (part.length) result.push(part);
62789           return result;
62790         } // Sutherland-Hodgeman polygon clipping algorithm
62791
62792
62793         function polygonclip$1(points, bbox) {
62794           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
62795
62796           for (edge = 1; edge <= 8; edge *= 2) {
62797             result = [];
62798             prev = points[points.length - 1];
62799             prevInside = !(bitCode$1(prev, bbox) & edge);
62800
62801             for (i = 0; i < points.length; i++) {
62802               p = points[i];
62803               inside = !(bitCode$1(p, bbox) & edge); // if segment goes through the clip window, add an intersection
62804
62805               if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
62806               if (inside) result.push(p); // add a point if it's inside
62807
62808               prev = p;
62809               prevInside = inside;
62810             }
62811
62812             points = result;
62813             if (!points.length) break;
62814           }
62815
62816           return result;
62817         } // intersect a segment against one of the 4 lines that make up the bbox
62818
62819
62820         function intersect$1(a, b, edge, bbox) {
62821           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
62822           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
62823           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
62824           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
62825           null;
62826         } // bit code reflects the point position relative to the bbox:
62827         //         left  mid  right
62828         //    top  1001  1000  1010
62829         //    mid  0001  0000  0010
62830         // bottom  0101  0100  0110
62831
62832
62833         function bitCode$1(p, bbox) {
62834           var code = 0;
62835           if (p[0] < bbox[0]) code |= 1; // left
62836           else if (p[0] > bbox[2]) code |= 2; // right
62837
62838           if (p[1] < bbox[1]) code |= 4; // bottom
62839           else if (p[1] > bbox[3]) code |= 8; // top
62840
62841           return code;
62842         }
62843
62844         var whichPolygon_1 = whichPolygon;
62845
62846         function whichPolygon(data) {
62847           var bboxes = [];
62848
62849           for (var i = 0; i < data.features.length; i++) {
62850             var feature = data.features[i];
62851             var coords = feature.geometry.coordinates;
62852
62853             if (feature.geometry.type === 'Polygon') {
62854               bboxes.push(treeItem(coords, feature.properties));
62855             } else if (feature.geometry.type === 'MultiPolygon') {
62856               for (var j = 0; j < coords.length; j++) {
62857                 bboxes.push(treeItem(coords[j], feature.properties));
62858               }
62859             }
62860           }
62861
62862           var tree = rbush_1().load(bboxes);
62863
62864           function query(p, multi) {
62865             var output = [],
62866                 result = tree.search({
62867               minX: p[0],
62868               minY: p[1],
62869               maxX: p[0],
62870               maxY: p[1]
62871             });
62872
62873             for (var i = 0; i < result.length; i++) {
62874               if (insidePolygon(result[i].coords, p)) {
62875                 if (multi) output.push(result[i].props);else return result[i].props;
62876               }
62877             }
62878
62879             return multi && output.length ? output : null;
62880           }
62881
62882           query.tree = tree;
62883
62884           query.bbox = function queryBBox(bbox) {
62885             var output = [];
62886             var result = tree.search({
62887               minX: bbox[0],
62888               minY: bbox[1],
62889               maxX: bbox[2],
62890               maxY: bbox[3]
62891             });
62892
62893             for (var i = 0; i < result.length; i++) {
62894               if (polygonIntersectsBBox(result[i].coords, bbox)) {
62895                 output.push(result[i].props);
62896               }
62897             }
62898
62899             return output;
62900           };
62901
62902           return query;
62903         }
62904
62905         function polygonIntersectsBBox(polygon, bbox) {
62906           var bboxCenter = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
62907           if (insidePolygon(polygon, bboxCenter)) return true;
62908
62909           for (var i = 0; i < polygon.length; i++) {
62910             if (lineclip_1$1(polygon[i], bbox).length > 0) return true;
62911           }
62912
62913           return false;
62914         } // ray casting algorithm for detecting if point is in polygon
62915
62916
62917         function insidePolygon(rings, p) {
62918           var inside = false;
62919
62920           for (var i = 0, len = rings.length; i < len; i++) {
62921             var ring = rings[i];
62922
62923             for (var j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
62924               if (rayIntersect(p, ring[j], ring[k])) inside = !inside;
62925             }
62926           }
62927
62928           return inside;
62929         }
62930
62931         function rayIntersect(p, p1, p2) {
62932           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];
62933         }
62934
62935         function treeItem(coords, props) {
62936           var item = {
62937             minX: Infinity,
62938             minY: Infinity,
62939             maxX: -Infinity,
62940             maxY: -Infinity,
62941             coords: coords,
62942             props: props
62943           };
62944
62945           for (var i = 0; i < coords[0].length; i++) {
62946             var p = coords[0][i];
62947             item.minX = Math.min(item.minX, p[0]);
62948             item.minY = Math.min(item.minY, p[1]);
62949             item.maxX = Math.max(item.maxX, p[0]);
62950             item.maxY = Math.max(item.maxY, p[1]);
62951           }
62952
62953           return item;
62954         }
62955
62956         var type = "FeatureCollection";
62957         var features = [{type:"Feature",properties:{m49:"680",wikidata:"Q3405693",nameEn:"Sark",country:"GB",groups:["GG","830","154","150"],level:"subterritory",driveSide:"left",roadSpeedUnit:"mph",callingCodes:["44 01481"]},geometry:{type:"MultiPolygon",coordinates:[[[[-2.36485,49.48223],[-2.65349,49.15373],[-2.09454,49.46288],[-2.36485,49.48223]]]]}},{type:"Feature",properties:{m49:"001",wikidata:"Q2",nameEn:"World",aliases:["Earth","Planet"],level:"world"},geometry:null},{type:"Feature",properties:{m49:"142",wikidata:"Q48",nameEn:"Asia",level:"region"},geometry:null},{type:"Feature",properties:{m49:"143",wikidata:"Q27275",nameEn:"Central Asia",groups:["142"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"145",wikidata:"Q27293",nameEn:"Western Asia",groups:["142"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"150",wikidata:"Q46",nameEn:"Europe",level:"region"},geometry:null},{type:"Feature",properties:{m49:"151",wikidata:"Q27468",nameEn:"Eastern Europe",groups:["150"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"154",wikidata:"Q27479",nameEn:"Northern Europe",groups:["150"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"155",wikidata:"Q27496",nameEn:"Western Europe",groups:["150"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"202",wikidata:"Q132959",nameEn:"Sub-Saharan Africa",groups:["002"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"419",wikidata:"Q72829598",nameEn:"Latin America and the Caribbean",groups:["019"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"830",wikidata:"Q42314",nameEn:"Channel Islands",groups:["150","154"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"019",wikidata:"Q828",nameEn:"Americas",level:"region"},geometry:null},{type:"Feature",properties:{m49:"029",wikidata:"Q664609",nameEn:"Caribbean",groups:["419","019","003"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"034",wikidata:"Q771405",nameEn:"Southern Asia",groups:["142"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"002",wikidata:"Q15",nameEn:"Africa",level:"region"},geometry:null},{type:"Feature",properties:{m49:"003",wikidata:"Q49",nameEn:"North America",groups:["019"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"017",wikidata:"Q27433",nameEn:"Middle Africa",groups:["202","002"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"039",wikidata:"Q27449",nameEn:"Southern Europe",groups:["150"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"005",wikidata:"Q18",nameEn:"South America",groups:["419","019"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"009",wikidata:"Q538",nameEn:"Oceania",level:"region"},geometry:null},{type:"Feature",properties:{m49:"061",wikidata:"Q35942",nameEn:"Polynesia",groups:["009"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"014",wikidata:"Q27407",nameEn:"Eastern Africa",groups:["202","002"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"053",wikidata:"Q45256",nameEn:"Australia and New Zealand",aliases:["Australasia"],groups:["009"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"011",wikidata:"Q4412",nameEn:"Western Africa",groups:["202","002"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"013",wikidata:"Q27611",nameEn:"Central America",groups:["419","019","003"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"021",wikidata:"Q2017699",nameEn:"Northern America",groups:["019","003"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"035",wikidata:"Q11708",nameEn:"South-eastern Asia",groups:["142"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"018",wikidata:"Q27394",nameEn:"Southern Africa",groups:["202","002"],level:"intermediateRegion"},geometry:null},{type:"Feature",properties:{m49:"030",wikidata:"Q27231",nameEn:"Eastern Asia",groups:["142"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"015",wikidata:"Q27381",nameEn:"Northern Africa",groups:["002"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"054",wikidata:"Q37394",nameEn:"Melanesia",groups:["009"],level:"subregion"},geometry:null},{type:"Feature",properties:{m49:"057",wikidata:"Q3359409",nameEn:"Micronesia",groups:["009"],level:"subregion"},geometry:null},{type:"Feature",properties:{iso1A2:"AC",iso1A3:"ASC",wikidata:"Q46197",nameEn:"Ascension Island",country:"GB",groups:["SH","011","202","002"],isoStatus:"excRes",driveSide:"left",roadSpeedUnit:"mph",callingCodes:["247"]},geometry:{type:"MultiPolygon",coordinates:[[[[-14.82771,-8.70814],[-13.33271,-8.07391],[-14.91926,-6.63386],[-14.82771,-8.70814]]]]}},{type:"Feature",properties:{iso1A2:"AD",iso1A3:"AND",iso1N3:"020",wikidata:"Q228",nameEn:"Andorra",groups:["039","150"],callingCodes:["376"]},geometry:{type:"MultiPolygon",coordinates:[[[[1.72515,42.50338],[1.73683,42.55492],[1.7858,42.57698],[1.72588,42.59098],[1.73452,42.61515],[1.68267,42.62533],[1.6625,42.61982],[1.63485,42.62957],[1.60085,42.62703],[1.55418,42.65669],[1.50867,42.64483],[1.48043,42.65203],[1.46718,42.63296],[1.47986,42.61346],[1.44197,42.60217],[1.42512,42.58292],[1.44529,42.56722],[1.4234,42.55959],[1.41245,42.53539],[1.44759,42.54431],[1.46661,42.50949],[1.41648,42.48315],[1.43838,42.47848],[1.44529,42.43724],[1.5127,42.42959],[1.55073,42.43299],[1.55937,42.45808],[1.57953,42.44957],[1.58933,42.46275],[1.65674,42.47125],[1.66826,42.50779],[1.70571,42.48867],[1.72515,42.50338]]]]}},{type:"Feature",properties:{iso1A2:"AE",iso1A3:"ARE",iso1N3:"784",wikidata:"Q878",nameEn:"United Arab Emirates",groups:["145","142"],callingCodes:["971"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AF",iso1A3:"AFG",iso1N3:"004",wikidata:"Q889",nameEn:"Afghanistan",groups:["034","142"],callingCodes:["93"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AG",iso1A3:"ATG",iso1N3:"028",wikidata:"Q781",nameEn:"Antigua and Barbuda",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 268"]},geometry:{type:"MultiPolygon",coordinates:[[[[-62.12601,17.9235],[-62.27053,17.22145],[-62.62949,16.82364],[-62.52079,16.69392],[-62.14123,17.02632],[-61.83929,16.66647],[-61.44461,16.81958],[-61.45764,17.9187],[-62.12601,17.9235]]]]}},{type:"Feature",properties:{iso1A2:"AI",iso1A3:"AIA",iso1N3:"660",wikidata:"Q25228",nameEn:"Anguilla",country:"GB",groups:["029","003","419","019"],driveSide:"left",callingCodes:["1 264"]},geometry:{type:"MultiPolygon",coordinates:[[[[-63.83866,18.82518],[-63.35989,18.06012],[-62.86666,18.19278],[-62.75637,18.13489],[-62.46233,19.00569],[-63.83866,18.82518]]]]}},{type:"Feature",properties:{iso1A2:"AL",iso1A3:"ALB",iso1N3:"008",wikidata:"Q222",nameEn:"Albania",groups:["039","150"],callingCodes:["355"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AM",iso1A3:"ARM",iso1N3:"051",wikidata:"Q399",nameEn:"Armenia",groups:["145","142"],callingCodes:["374"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AO",iso1A3:"AGO",iso1N3:"024",wikidata:"Q916",nameEn:"Angola",groups:["017","202","002"],callingCodes:["244"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AQ",iso1A3:"ATA",iso1N3:"010",wikidata:"Q51",nameEn:"Antarctica",level:"region",callingCodes:["672"]},geometry:{type:"MultiPolygon",coordinates:[[[[180,-60],[-180,-60],[-180,-90],[180,-90],[180,-60]]]]}},{type:"Feature",properties:{iso1A2:"AR",iso1A3:"ARG",iso1N3:"032",wikidata:"Q414",nameEn:"Argentina",aliases:["RA"],groups:["005","419","019"],callingCodes:["54"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AS",iso1A3:"ASM",iso1N3:"016",wikidata:"Q16641",nameEn:"American Samoa",country:"US",groups:["061","009"],roadSpeedUnit:"mph",callingCodes:["1 684"]},geometry:{type:"MultiPolygon",coordinates:[[[[-174.18596,-12.48057],[-171.14953,-12.4725],[-171.14262,-14.93704],[-167.73854,-14.92809],[-167.75195,-10.12005],[-174.17993,-10.13616],[-174.18596,-12.48057]]]]}},{type:"Feature",properties:{iso1A2:"AT",iso1A3:"AUT",iso1N3:"040",wikidata:"Q40",nameEn:"Austria",groups:["EU","155","150"],callingCodes:["43"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AU",iso1A3:"AUS",iso1N3:"036",wikidata:"Q408",nameEn:"Australia",groups:["053","009"],driveSide:"left",callingCodes:["61"]},geometry:{type:"MultiPolygon",coordinates:[[[[156.55918,-21.85134],[158.60851,-15.7108],[144.30183,-9.48146],[142.81927,-9.31709],[142.5723,-9.35994],[142.31447,-9.24611],[142.23304,-9.19253],[142.1462,-9.19923],[142.0953,-9.23534],[142.0601,-9.56571],[140.88922,-9.34945],[127.55165,-9.05052],[96.7091,-25.20343],[159.69067,-56.28945],[165.46901,-28.32101],[156.55918,-21.85134]]]]}},{type:"Feature",properties:{iso1A2:"AW",iso1A3:"ABW",iso1N3:"533",wikidata:"Q21203",nameEn:"Aruba",country:"NL",groups:["029","003","419","019"],callingCodes:["297"]},geometry:{type:"MultiPolygon",coordinates:[[[[-70.00823,12.98375],[-70.35625,12.58277],[-69.60231,12.17],[-70.00823,12.98375]]]]}},{type:"Feature",properties:{iso1A2:"AX",iso1A3:"ALA",iso1N3:"248",wikidata:"Q5689",nameEn:"Åland Islands",country:"FI",groups:["EU","154","150"],callingCodes:["358 18","358 457"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"AZ",iso1A3:"AZE",iso1N3:"031",wikidata:"Q227",nameEn:"Azerbaijan",groups:["145","142"],callingCodes:["994"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BA",iso1A3:"BIH",iso1N3:"070",wikidata:"Q225",nameEn:"Bosnia and Herzegovina",groups:["039","150"],callingCodes:["387"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BB",iso1A3:"BRB",iso1N3:"052",wikidata:"Q244",nameEn:"Barbados",groups:["029","003","419","019"],driveSide:"left",callingCodes:["1 246"]},geometry:{type:"MultiPolygon",coordinates:[[[[-58.56442,13.24471],[-59.80731,13.87556],[-60.19227,12.37597],[-58.56442,13.24471]]]]}},{type:"Feature",properties:{iso1A2:"BD",iso1A3:"BGD",iso1N3:"050",wikidata:"Q902",nameEn:"Bangladesh",groups:["034","142"],driveSide:"left",callingCodes:["880"]},geometry:{type:"MultiPolygon",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.03553,21.77397],[89.13927,21.60785],[89.13606,21.42955],[92.39837,20.38919],[92.4302,20.5688],[92.31348,20.57137],[92.28464,20.63179],[92.37665,20.72172],[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]]]]}},{type:"Feature",properties:{iso1A2:"BE",iso1A3:"BEL",iso1N3:"056",wikidata:"Q31",nameEn:"Belgium",groups:["EU","155","150"],callingCodes:["32"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BF",iso1A3:"BFA",iso1N3:"854",wikidata:"Q965",nameEn:"Burkina Faso",groups:["011","202","002"],callingCodes:["226"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BG",iso1A3:"BGR",iso1N3:"100",wikidata:"Q219",nameEn:"Bulgaria",groups:["EU","151","150"],callingCodes:["359"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BH",iso1A3:"BHR",iso1N3:"048",wikidata:"Q398",nameEn:"Bahrain",groups:["145","142"],callingCodes:["973"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BI",iso1A3:"BDI",iso1N3:"108",wikidata:"Q967",nameEn:"Burundi",groups:["014","202","002"],callingCodes:["257"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BJ",iso1A3:"BEN",iso1N3:"204",wikidata:"Q962",nameEn:"Benin",aliases:["DY"],groups:["011","202","002"],callingCodes:["229"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BL",iso1A3:"BLM",iso1N3:"652",wikidata:"Q25362",nameEn:"Saint-Barthélemy",country:"FR",groups:["029","003","419","019"],callingCodes:["590"]},geometry:{type:"MultiPolygon",coordinates:[[[[-62.75637,18.13489],[-62.93924,18.02904],[-63.07669,17.79659],[-62.76692,17.64353],[-62.54836,17.8636],[-62.75637,18.13489]]]]}},{type:"Feature",properties:{iso1A2:"BM",iso1A3:"BMU",iso1N3:"060",wikidata:"Q23635",nameEn:"Bermuda",country:"GB",groups:["021","003","019"],driveSide:"left",callingCodes:["1 441"]},geometry:{type:"MultiPolygon",coordinates:[[[[-63.20987,32.6953],[-65.31453,32.68437],[-65.63955,31.43417],[-63.20987,32.6953]]]]}},{type:"Feature",properties:{iso1A2:"BN",iso1A3:"BRN",iso1N3:"096",wikidata:"Q921",nameEn:"Brunei",groups:["035","142"],driveSide:"left",callingCodes:["673"]},geometry:{type:"MultiPolygon",coordinates:[[[[115.16236,5.01011],[115.02521,5.35005],[114.08532,4.64632],[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]]]]}},{type:"Feature",properties:{iso1A2:"BO",iso1A3:"BOL",iso1N3:"068",wikidata:"Q750",nameEn:"Bolivia",groups:["005","419","019"],callingCodes:["591"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BQ",iso1A3:"BES",iso1N3:"535",wikidata:"Q27561",nameEn:"Caribbean Netherlands",country:"NL",groups:["029","003","419","019"],callingCodes:["599 3","599 4","599 7"]},geometry:{type:"MultiPolygon",coordinates:[[[[-63.07669,17.79659],[-63.22932,17.32592],[-63.11114,17.23125],[-62.76692,17.64353],[-63.07669,17.79659]]],[[[-63.29212,17.90532],[-63.58819,17.61311],[-63.22932,17.32592],[-63.07669,17.79659],[-63.29212,17.90532]]],[[[-67.89186,12.4116],[-68.90012,12.62309],[-68.33524,11.78151],[-68.01417,11.77722],[-67.89186,12.4116]]]]}},{type:"Feature",properties:{iso1A2:"BR",iso1A3:"BRA",iso1N3:"076",wikidata:"Q155",nameEn:"Brazil",groups:["005","419","019"],callingCodes:["55"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BS",iso1A3:"BHS",iso1N3:"044",wikidata:"Q778",nameEn:"The Bahamas",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 242"]},geometry:{type:"MultiPolygon",coordinates:[[[[-72.98446,20.4801],[-71.70065,25.7637],[-79.14818,27.83105],[-79.89631,24.6597],[-80.88924,23.80416],[-72.98446,20.4801]]]]}},{type:"Feature",properties:{iso1A2:"BT",iso1A3:"BTN",iso1N3:"064",wikidata:"Q917",nameEn:"Bhutan",groups:["034","142"],driveSide:"left",callingCodes:["975"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BV",iso1A3:"BVT",iso1N3:"074",wikidata:"Q23408",nameEn:"Bouvet Island",country:"NO",groups:["005","419","019"]},geometry:{type:"MultiPolygon",coordinates:[[[[4.54042,-54.0949],[2.28941,-54.13089],[3.35353,-55.17558],[4.54042,-54.0949]]]]}},{type:"Feature",properties:{iso1A2:"BW",iso1A3:"BWA",iso1N3:"072",wikidata:"Q963",nameEn:"Botswana",groups:["018","202","002"],driveSide:"left",callingCodes:["267"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BY",iso1A3:"BLR",iso1N3:"112",wikidata:"Q184",nameEn:"Belarus",groups:["151","150"],callingCodes:["375"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"BZ",iso1A3:"BLZ",iso1N3:"084",wikidata:"Q242",nameEn:"Belize",groups:["013","003","419","019"],roadSpeedUnit:"mph",callingCodes:["501"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"CA",iso1A3:"CAN",iso1N3:"124",wikidata:"Q16",nameEn:"Canada",groups:["021","003","019"],callingCodes:["1"]},geometry:{type:"MultiPolygon",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],[-76.75614,76.72014],[-68.21821,80.48551],[-45.47832,84.58738],[-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],[-117.03266,49.00056],[-116.04938,48.99999],[-114.0683,48.99885],[-110.0051,48.99901],[-104.05004,48.99925],[-101.36198,48.99935],[-97.24024,48.99952],[-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]]]]}},{type:"Feature",properties:{iso1A2:"CC",iso1A3:"CCK",iso1N3:"166",wikidata:"Q36004",nameEn:"Cocos (Keeling) Islands",country:"AU",groups:["053","009"],driveSide:"left",callingCodes:["61"]},geometry:{type:"MultiPolygon",coordinates:[[[[96.61846,-10.82438],[96.02343,-12.68334],[97.93979,-12.33309],[96.61846,-10.82438]]]]}},{type:"Feature",properties:{iso1A2:"CD",iso1A3:"COD",iso1N3:"180",wikidata:"Q974",nameEn:"Democratic Republic of the Congo",aliases:["ZR"],groups:["017","202","002"],callingCodes:["243"]},geometry:{type:"MultiPolygon",coordinates:[[[[27.44012,5.07349],[27.09575,5.22305],[26.93064,5.13535],[26.85579,5.03887],[26.74572,5.10685],[26.48595,5.04984],[26.13371,5.25594],[25.86073,5.19455],[25.53271,5.37431],[25.34558,5.29101],[25.31256,5.03668],[24.71816,4.90509],[24.46719,5.0915],[23.38847,4.60013],[22.94817,4.82392],[22.89094,4.79321],[22.84691,4.69887],[22.78526,4.71423],[22.6928,4.47285],[22.60915,4.48821],[22.5431,4.22041],[22.45504,4.13039],[22.27682,4.11347],[22.10721,4.20723],[21.6405,4.317],[21.55904,4.25553],[21.25744,4.33676],[21.21341,4.29285],[21.11214,4.33895],[21.08793,4.39603],[20.90383,4.44877],[20.60184,4.42394],[18.62755,3.47564],[18.63857,3.19342],[18.10683,2.26876],[18.08034,1.58553],[17.85887,1.04327],[17.86989,0.58873],[17.95255,0.48128],[17.93877,0.32424],[17.81204,0.23884],[17.66051,-0.26535],[17.72112,-0.52707],[17.32438,-0.99265],[16.97999,-1.12762],[16.70724,-1.45815],[16.50336,-1.8795],[16.16173,-2.16586],[16.22785,-2.59528],[16.1755,-3.25014],[16.21407,-3.2969],[15.89448,-3.9513],[15.53081,-4.042],[15.48121,-4.22062],[15.41785,-4.28381],[15.32693,-4.27282],[15.25411,-4.31121],[15.1978,-4.32388],[14.83101,-4.80838],[14.67948,-4.92093],[14.5059,-4.84956],[14.41499,-4.8825],[14.37366,-4.56125],[14.47284,-4.42941],[14.3957,-4.36623],[14.40672,-4.28381],[13.9108,-4.50906],[13.81162,-4.41842],[13.71794,-4.44864],[13.70417,-4.72601],[13.50305,-4.77818],[13.41764,-4.89897],[13.11182,-4.5942],[13.09648,-4.63739],[13.11195,-4.67745],[12.8733,-4.74346],[12.70868,-4.95505],[12.63465,-4.94632],[12.60251,-5.01715],[12.46297,-5.09408],[12.49815,-5.14058],[12.51589,-5.1332],[12.53586,-5.14658],[12.53599,-5.1618],[12.52301,-5.17481],[12.52318,-5.74353],[12.26557,-5.74031],[12.20376,-5.76338],[11.95767,-5.94705],[12.42245,-6.07585],[13.04371,-5.87078],[16.55507,-5.85631],[16.96282,-7.21787],[17.5828,-8.13784],[18.33635,-8.00126],[19.33698,-7.99743],[19.5469,-7.00195],[20.30218,-6.98955],[20.31846,-6.91953],[20.61689,-6.90876],[20.56263,-7.28566],[21.79824,-7.29628],[21.84856,-9.59871],[22.19039,-9.94628],[22.32604,-10.76291],[22.17954,-10.85884],[22.25951,-11.24911],[22.54205,-11.05784],[23.16602,-11.10577],[23.45631,-10.946],[23.86868,-11.02856],[24.00027,-10.89356],[24.34528,-11.06816],[24.42612,-11.44975],[25.34069,-11.19707],[25.33058,-11.65767],[26.01777,-11.91488],[26.88687,-12.01868],[27.04351,-11.61312],[27.22541,-11.60323],[27.21025,-11.76157],[27.59932,-12.22123],[28.33199,-12.41375],[29.01918,-13.41353],[29.60531,-13.21685],[29.65078,-13.41844],[29.81551,-13.44683],[29.8139,-12.14898],[29.48404,-12.23604],[29.4992,-12.43843],[29.18592,-12.37921],[28.48357,-11.87532],[28.37241,-11.57848],[28.65032,-10.65133],[28.62795,-9.92942],[28.68532,-9.78],[28.56208,-9.49122],[28.51627,-9.44726],[28.52636,-9.35379],[28.36562,-9.30091],[28.38526,-9.23393],[28.9711,-8.66935],[28.88917,-8.4831],[30.79243,-8.27382],[30.2567,-7.14121],[29.52552,-6.2731],[29.43673,-4.44845],[29.23708,-3.75856],[29.21463,-3.3514],[29.25633,-3.05471],[29.17258,-2.99385],[29.16037,-2.95457],[29.09797,-2.91935],[29.09119,-2.87871],[29.0505,-2.81774],[29.00404,-2.81978],[29.00167,-2.78523],[29.04081,-2.7416],[29.00357,-2.70596],[28.94346,-2.69124],[28.89793,-2.66111],[28.90226,-2.62385],[28.89288,-2.55848],[28.87943,-2.55165],[28.86193,-2.53185],[28.86209,-2.5231],[28.87497,-2.50887],[28.88846,-2.50493],[28.89342,-2.49017],[28.89132,-2.47557],[28.86846,-2.44866],[28.86826,-2.41888],[28.89601,-2.37321],[28.95642,-2.37321],[29.00051,-2.29001],[29.105,-2.27043],[29.17562,-2.12278],[29.11847,-1.90576],[29.24458,-1.69663],[29.24323,-1.66826],[29.36322,-1.50887],[29.45038,-1.5054],[29.53062,-1.40499],[29.59061,-1.39016],[29.58388,-0.89821],[29.63006,-0.8997],[29.62708,-0.71055],[29.67176,-0.55714],[29.67474,-0.47969],[29.65091,-0.46777],[29.72687,-0.08051],[29.7224,0.07291],[29.77454,0.16675],[29.81922,0.16824],[29.87284,0.39166],[29.97413,0.52124],[29.95477,0.64486],[29.98307,0.84295],[30.1484,0.89805],[30.22139,0.99635],[30.24671,1.14974],[30.48503,1.21675],[31.30127,2.11006],[31.28042,2.17853],[31.20148,2.2217],[31.1985,2.29462],[31.12104,2.27676],[31.07934,2.30207],[31.06593,2.35862],[30.96911,2.41071],[30.91102,2.33332],[30.83059,2.42559],[30.74271,2.43601],[30.75612,2.5863],[30.8857,2.83923],[30.8574,2.9508],[30.77101,3.04897],[30.84251,3.26908],[30.93486,3.40737],[30.94081,3.50847],[30.85153,3.48867],[30.85997,3.5743],[30.80713,3.60506],[30.78512,3.67097],[30.56277,3.62703],[30.57378,3.74567],[30.55396,3.84451],[30.47691,3.83353],[30.27658,3.95653],[30.22374,3.93896],[30.1621,4.10586],[30.06964,4.13221],[29.79666,4.37809],[29.82087,4.56246],[29.49726,4.7007],[29.43341,4.50101],[29.22207,4.34297],[29.03054,4.48784],[28.8126,4.48784],[28.6651,4.42638],[28.20719,4.35614],[27.79551,4.59976],[27.76469,4.79284],[27.65462,4.89375],[27.56656,4.89375],[27.44012,5.07349]]]]}},{type:"Feature",properties:{iso1A2:"CF",iso1A3:"CAF",iso1N3:"140",wikidata:"Q929",nameEn:"Central African Republic",groups:["017","202","002"],callingCodes:["236"]},geometry:{type:"MultiPolygon",coordinates:[[[[22.87758,10.91915],[22.45889,11.00246],[21.72139,10.64136],[21.71479,10.29932],[21.63553,10.217],[21.52766,10.2105],[21.34934,9.95907],[21.26348,9.97642],[20.82979,9.44696],[20.36748,9.11019],[19.06421,9.00367],[18.86388,8.87971],[19.11044,8.68172],[18.79783,8.25929],[18.67455,8.22226],[18.62612,8.14163],[18.64153,8.08714],[18.6085,8.05009],[18.02731,8.01085],[17.93926,7.95853],[17.67288,7.98905],[16.8143,7.53971],[16.6668,7.67281],[16.658,7.75353],[16.59415,7.76444],[16.58315,7.88657],[16.41583,7.77971],[16.40703,7.68809],[15.79942,7.44149],[15.73118,7.52006],[15.49743,7.52179],[15.23397,7.25135],[15.04717,6.77085],[14.96311,6.75693],[14.79966,6.39043],[14.80122,6.34866],[14.74206,6.26356],[14.56149,6.18928],[14.43073,6.08867],[14.42917,6.00508],[14.49455,5.91683],[14.60974,5.91838],[14.62375,5.70466],[14.58951,5.59777],[14.62531,5.51411],[14.52724,5.28319],[14.57083,5.23979],[14.65489,5.21343],[14.73383,4.6135],[15.00825,4.41458],[15.08609,4.30282],[15.10644,4.1362],[15.17482,4.05131],[15.07686,4.01805],[15.73522,3.24348],[15.77725,3.26835],[16.05449,3.02306],[16.08252,2.45708],[16.19357,2.21537],[16.50126,2.84739],[16.46701,2.92512],[16.57598,3.47999],[16.68283,3.54257],[17.01746,3.55136],[17.35649,3.63045],[17.46876,3.70515],[17.60966,3.63705],[17.83421,3.61068],[17.85842,3.53378],[18.05656,3.56893],[18.14902,3.54476],[18.17323,3.47665],[18.24148,3.50302],[18.2723,3.57992],[18.39558,3.58212],[18.49245,3.63924],[18.58711,3.49423],[18.62755,3.47564],[20.60184,4.42394],[20.90383,4.44877],[21.08793,4.39603],[21.11214,4.33895],[21.21341,4.29285],[21.25744,4.33676],[21.55904,4.25553],[21.6405,4.317],[22.10721,4.20723],[22.27682,4.11347],[22.45504,4.13039],[22.5431,4.22041],[22.60915,4.48821],[22.6928,4.47285],[22.78526,4.71423],[22.84691,4.69887],[22.89094,4.79321],[22.94817,4.82392],[23.38847,4.60013],[24.46719,5.0915],[24.71816,4.90509],[25.31256,5.03668],[25.34558,5.29101],[25.53271,5.37431],[25.86073,5.19455],[26.13371,5.25594],[26.48595,5.04984],[26.74572,5.10685],[26.85579,5.03887],[26.93064,5.13535],[27.09575,5.22305],[27.44012,5.07349],[27.26886,5.25876],[27.23017,5.37167],[27.28621,5.56382],[27.22705,5.62889],[27.22705,5.71254],[26.51721,6.09655],[26.58259,6.1987],[26.32729,6.36272],[26.38022,6.63493],[25.90076,7.09549],[25.37461,7.33024],[25.35281,7.42595],[25.20337,7.50312],[25.20649,7.61115],[25.29214,7.66675],[25.25319,7.8487],[24.98855,7.96588],[24.85156,8.16933],[24.35965,8.26177],[24.13238,8.36959],[24.25691,8.69288],[23.51905,8.71749],[23.59065,8.99743],[23.44744,8.99128],[23.4848,9.16959],[23.56263,9.19418],[23.64358,9.28637],[23.64981,9.44303],[23.62179,9.53823],[23.69155,9.67566],[23.67164,9.86923],[23.3128,10.45214],[23.02221,10.69235],[22.87758,10.91915]]]]}},{type:"Feature",properties:{iso1A2:"CG",iso1A3:"COG",iso1N3:"178",wikidata:"Q971",nameEn:"Republic of the Congo",groups:["017","202","002"],callingCodes:["242"]},geometry:{type:"MultiPolygon",coordinates:[[[[18.62755,3.47564],[18.58711,3.49423],[18.49245,3.63924],[18.39558,3.58212],[18.2723,3.57992],[18.24148,3.50302],[18.17323,3.47665],[18.14902,3.54476],[18.05656,3.56893],[17.85842,3.53378],[17.83421,3.61068],[17.60966,3.63705],[17.46876,3.70515],[17.35649,3.63045],[17.01746,3.55136],[16.68283,3.54257],[16.57598,3.47999],[16.46701,2.92512],[16.50126,2.84739],[16.19357,2.21537],[16.15568,2.18955],[16.08563,2.19733],[16.05294,1.9811],[16.14634,1.70259],[16.02647,1.65591],[16.02959,1.76483],[15.48942,1.98265],[15.34776,1.91264],[15.22634,2.03243],[15.00996,1.98887],[14.61145,2.17866],[13.29457,2.16106],[13.13461,1.57238],[13.25447,1.32339],[13.15519,1.23368],[13.89582,1.4261],[14.25186,1.39842],[14.48179,0.9152],[14.26066,0.57255],[14.10909,0.58563],[13.88648,0.26652],[13.90632,-0.2287],[14.06862,-0.20826],[14.2165,-0.38261],[14.41887,-0.44799],[14.52569,-0.57818],[14.41838,-1.89412],[14.25932,-1.97624],[14.23518,-2.15671],[14.16202,-2.23916],[14.23829,-2.33715],[14.10442,-2.49268],[13.85846,-2.46935],[13.92073,-2.35581],[13.75884,-2.09293],[13.47977,-2.43224],[13.02759,-2.33098],[12.82172,-1.91091],[12.61312,-1.8129],[12.44656,-1.92025],[12.47925,-2.32626],[12.04895,-2.41704],[11.96866,-2.33559],[11.74605,-2.39936],[11.57637,-2.33379],[11.64487,-2.61865],[11.5359,-2.85654],[11.64798,-2.81146],[11.80365,-3.00424],[11.70558,-3.0773],[11.70227,-3.17465],[11.96554,-3.30267],[11.8318,-3.5812],[11.92719,-3.62768],[11.87083,-3.71571],[11.68608,-3.68942],[11.57949,-3.52798],[11.48764,-3.51089],[11.22301,-3.69888],[11.12647,-3.94169],[10.75913,-4.39519],[11.50888,-5.33417],[12.00924,-5.02627],[12.16068,-4.90089],[12.20901,-4.75642],[12.25587,-4.79437],[12.32324,-4.78415],[12.40964,-4.60609],[12.64835,-4.55937],[12.76844,-4.38709],[12.87096,-4.40315],[12.91489,-4.47907],[13.09648,-4.63739],[13.11182,-4.5942],[13.41764,-4.89897],[13.50305,-4.77818],[13.70417,-4.72601],[13.71794,-4.44864],[13.81162,-4.41842],[13.9108,-4.50906],[14.40672,-4.28381],[14.3957,-4.36623],[14.47284,-4.42941],[14.37366,-4.56125],[14.41499,-4.8825],[14.5059,-4.84956],[14.67948,-4.92093],[14.83101,-4.80838],[15.1978,-4.32388],[15.25411,-4.31121],[15.32693,-4.27282],[15.41785,-4.28381],[15.48121,-4.22062],[15.53081,-4.042],[15.89448,-3.9513],[16.21407,-3.2969],[16.1755,-3.25014],[16.22785,-2.59528],[16.16173,-2.16586],[16.50336,-1.8795],[16.70724,-1.45815],[16.97999,-1.12762],[17.32438,-0.99265],[17.72112,-0.52707],[17.66051,-0.26535],[17.81204,0.23884],[17.93877,0.32424],[17.95255,0.48128],[17.86989,0.58873],[17.85887,1.04327],[18.08034,1.58553],[18.10683,2.26876],[18.63857,3.19342],[18.62755,3.47564]]]]}},{type:"Feature",properties:{iso1A2:"CH",iso1A3:"CHE",iso1N3:"756",wikidata:"Q39",nameEn:"Switzerland",groups:["155","150"],callingCodes:["41"]},geometry:{type:"MultiPolygon",coordinates:[[[[8.72809,47.69282],[8.72617,47.69651],[8.73671,47.7169],[8.70543,47.73121],[8.74251,47.75168],[8.71778,47.76571],[8.68985,47.75686],[8.68022,47.78599],[8.65292,47.80066],[8.64425,47.76398],[8.62408,47.7626],[8.61657,47.79998],[8.56415,47.80633],[8.56814,47.78001],[8.48868,47.77215],[8.45771,47.7493],[8.44807,47.72426],[8.40569,47.69855],[8.4211,47.68407],[8.40473,47.67499],[8.41346,47.66676],[8.42264,47.66667],[8.44711,47.65379],[8.4667,47.65747],[8.46605,47.64103],[8.49656,47.64709],[8.5322,47.64687],[8.52801,47.66059],[8.56141,47.67088],[8.57683,47.66158],[8.6052,47.67258],[8.61113,47.66332],[8.62884,47.65098],[8.62049,47.63757],[8.60412,47.63735],[8.61471,47.64514],[8.60701,47.65271],[8.59545,47.64298],[8.60348,47.61204],[8.57586,47.59537],[8.55756,47.62394],[8.51686,47.63476],[8.50747,47.61897],[8.45578,47.60121],[8.46637,47.58389],[8.48949,47.588],[8.49431,47.58107],[8.43235,47.56617],[8.39477,47.57826],[8.38273,47.56608],[8.32735,47.57133],[8.30277,47.58607],[8.29524,47.5919],[8.29722,47.60603],[8.2824,47.61225],[8.26313,47.6103],[8.25863,47.61571],[8.23809,47.61204],[8.22577,47.60385],[8.22011,47.6181],[8.20617,47.62141],[8.19378,47.61636],[8.1652,47.5945],[8.14947,47.59558],[8.13823,47.59147],[8.13662,47.58432],[8.11543,47.5841],[8.10395,47.57918],[8.10002,47.56504],[8.08557,47.55768],[8.06663,47.56374],[8.04383,47.55443],[8.02136,47.55096],[8.00113,47.55616],[7.97581,47.55493],[7.95682,47.55789],[7.94494,47.54511],[7.91251,47.55031],[7.90673,47.57674],[7.88664,47.58854],[7.84412,47.5841],[7.81901,47.58798],[7.79486,47.55691],[7.75261,47.54599],[7.71961,47.54219],[7.69642,47.53297],[7.68101,47.53232],[7.6656,47.53752],[7.66174,47.54554],[7.65083,47.54662],[7.63338,47.56256],[7.67655,47.56435],[7.68904,47.57133],[7.67115,47.5871],[7.68486,47.59601],[7.69385,47.60099],[7.68229,47.59905],[7.67395,47.59212],[7.64599,47.59695],[7.64213,47.5944],[7.64309,47.59151],[7.61929,47.57683],[7.60459,47.57869],[7.60523,47.58519],[7.58945,47.59017],[7.58386,47.57536],[7.56684,47.57785],[7.56548,47.57617],[7.55689,47.57232],[7.55652,47.56779],[7.53634,47.55553],[7.52831,47.55347],[7.51723,47.54578],[7.50873,47.54546],[7.49691,47.53821],[7.50588,47.52856],[7.51904,47.53515],[7.53199,47.5284],[7.5229,47.51644],[7.49804,47.51798],[7.51076,47.49651],[7.47534,47.47932],[7.43356,47.49712],[7.42923,47.48628],[7.4583,47.47216],[7.4462,47.46264],[7.43088,47.45846],[7.40308,47.43638],[7.35603,47.43432],[7.33526,47.44186],[7.24669,47.4205],[7.17026,47.44312],[7.19583,47.49455],[7.16249,47.49025],[7.12781,47.50371],[7.07425,47.48863],[7.0231,47.50522],[6.98425,47.49432],[7.0024,47.45264],[6.93953,47.43388],[6.93744,47.40714],[6.88542,47.37262],[6.87959,47.35335],[7.03125,47.36996],[7.0564,47.35134],[7.05305,47.33304],[6.94316,47.28747],[6.95108,47.26428],[6.9508,47.24338],[6.8489,47.15933],[6.76788,47.1208],[6.68823,47.06616],[6.71531,47.0494],[6.43341,46.92703],[6.46456,46.88865],[6.43216,46.80336],[6.45209,46.77502],[6.38351,46.73171],[6.27135,46.68251],[6.11084,46.57649],[6.1567,46.54402],[6.07269,46.46244],[6.08427,46.44305],[6.06407,46.41676],[6.09926,46.40768],[6.15016,46.3778],[6.15985,46.37721],[6.16987,46.36759],[6.15738,46.3491],[6.13876,46.33844],[6.1198,46.31157],[6.11697,46.29547],[6.1013,46.28512],[6.11926,46.2634],[6.12446,46.25059],[6.10071,46.23772],[6.08563,46.24651],[6.07072,46.24085],[6.0633,46.24583],[6.05029,46.23518],[6.04602,46.23127],[6.03342,46.2383],[6.02461,46.23313],[5.97542,46.21525],[5.96515,46.19638],[5.99573,46.18587],[5.98846,46.17046],[5.98188,46.17392],[5.97508,46.15863],[5.9641,46.14412],[5.95781,46.12925],[5.97893,46.13303],[5.9871,46.14499],[6.01791,46.14228],[6.03614,46.13712],[6.04564,46.14031],[6.05203,46.15191],[6.07491,46.14879],[6.09199,46.15191],[6.09926,46.14373],[6.13397,46.1406],[6.15305,46.15194],[6.18116,46.16187],[6.18871,46.16644],[6.18707,46.17999],[6.19552,46.18401],[6.19807,46.18369],[6.20539,46.19163],[6.21114,46.1927],[6.21273,46.19409],[6.21603,46.19507],[6.21844,46.19837],[6.22222,46.19888],[6.22175,46.20045],[6.23544,46.20714],[6.23913,46.20511],[6.24821,46.20531],[6.26007,46.21165],[6.27694,46.21566],[6.29663,46.22688],[6.31041,46.24417],[6.29474,46.26221],[6.26749,46.24745],[6.24952,46.26255],[6.23775,46.27822],[6.25137,46.29014],[6.24826,46.30175],[6.21981,46.31304],[6.25432,46.3632],[6.53358,46.45431],[6.82312,46.42661],[6.8024,46.39171],[6.77152,46.34784],[6.86052,46.28512],[6.78968,46.14058],[6.89321,46.12548],[6.87868,46.03855],[6.93862,46.06502],[7.00946,45.9944],[7.04151,45.92435],[7.10685,45.85653],[7.56343,45.97421],[7.85949,45.91485],[7.9049,45.99945],[7.98881,45.99867],[8.02906,46.10331],[8.11383,46.11577],[8.16866,46.17817],[8.08814,46.26692],[8.31162,46.38044],[8.30648,46.41587],[8.42464,46.46367],[8.46317,46.43712],[8.45032,46.26869],[8.62242,46.12112],[8.75697,46.10395],[8.80778,46.10085],[8.85617,46.0748],[8.79414,46.00913],[8.78585,45.98973],[8.79362,45.99207],[8.8319,45.9879],[8.85121,45.97239],[8.86688,45.96135],[8.88904,45.95465],[8.93649,45.86775],[8.94372,45.86587],[8.93504,45.86245],[8.91129,45.8388],[8.94737,45.84285],[8.9621,45.83707],[8.99663,45.83466],[9.00324,45.82055],[9.0298,45.82127],[9.03279,45.82865],[9.03793,45.83548],[9.03505,45.83976],[9.04059,45.8464],[9.04546,45.84968],[9.06642,45.8761],[9.09065,45.89906],[8.99257,45.9698],[9.01618,46.04928],[9.24503,46.23616],[9.29226,46.32717],[9.25502,46.43743],[9.28136,46.49685],[9.36128,46.5081],[9.40487,46.46621],[9.45936,46.50873],[9.46117,46.37481],[9.57015,46.2958],[9.71273,46.29266],[9.73086,46.35071],[9.95249,46.38045],[10.07055,46.21668],[10.14439,46.22992],[10.17862,46.25626],[10.10506,46.3372],[10.165,46.41051],[10.03715,46.44479],[10.10307,46.61003],[10.23674,46.63484],[10.25309,46.57432],[10.46136,46.53164],[10.49375,46.62049],[10.44686,46.64162],[10.40475,46.63671],[10.38659,46.67847],[10.47197,46.85698],[10.48376,46.93891],[10.36933,47.00212],[10.30031,46.92093],[10.24128,46.93147],[10.22675,46.86942],[10.10715,46.84296],[9.98058,46.91434],[9.88266,46.93343],[9.87935,47.01337],[9.60717,47.06091],[9.55721,47.04762],[9.54041,47.06495],[9.47548,47.05257],[9.47139,47.06402],[9.51362,47.08505],[9.52089,47.10019],[9.51044,47.13727],[9.48774,47.17402],[9.4891,47.19346],[9.50318,47.22153],[9.52406,47.24959],[9.53116,47.27029],[9.54773,47.2809],[9.55857,47.29919],[9.58513,47.31334],[9.59978,47.34671],[9.62476,47.36639],[9.65427,47.36824],[9.66243,47.37136],[9.6711,47.37824],[9.67445,47.38429],[9.67334,47.39191],[9.6629,47.39591],[9.65136,47.40504],[9.65043,47.41937],[9.6446,47.43233],[9.64483,47.43842],[9.65863,47.44847],[9.65728,47.45383],[9.6423,47.45599],[9.62475,47.45685],[9.62158,47.45858],[9.60841,47.47178],[9.60484,47.46358],[9.60205,47.46165],[9.59482,47.46305],[9.58208,47.48344],[9.56312,47.49495],[9.55125,47.53629],[9.25619,47.65939],[9.18203,47.65598],[9.17593,47.65399],[9.1755,47.65584],[9.1705,47.65513],[9.15181,47.66904],[9.13845,47.66389],[9.09891,47.67801],[9.02093,47.6868],[8.94093,47.65596],[8.89946,47.64769],[8.87625,47.65441],[8.87383,47.67045],[8.85065,47.68209],[8.86989,47.70504],[8.82002,47.71458],[8.80663,47.73821],[8.77309,47.72059],[8.76965,47.7075],[8.79966,47.70222],[8.79511,47.67462],[8.75856,47.68969],[8.72809,47.69282]],[[8.95861,45.96485],[8.96668,45.98436],[8.97741,45.98317],[8.97604,45.96151],[8.95861,45.96485]],[[8.70847,47.68904],[8.68985,47.69552],[8.66837,47.68437],[8.65769,47.68928],[8.67508,47.6979],[8.66416,47.71367],[8.70237,47.71453],[8.71773,47.69088],[8.70847,47.68904]]]]}},{type:"Feature",properties:{iso1A2:"CI",iso1A3:"CIV",iso1N3:"384",wikidata:"Q1008",nameEn:"Côte d'Ivoire",groups:["011","202","002"],callingCodes:["225"]},geometry:{type:"MultiPolygon",coordinates:[[[[-7.52774,3.7105],[-3.34019,4.17519],[-3.10675,5.08515],[-3.11073,5.12675],[-3.063,5.13665],[-2.96554,5.10397],[-2.95261,5.12477],[-2.75502,5.10657],[-2.73074,5.1364],[-2.77625,5.34621],[-2.72737,5.34789],[-2.76614,5.60963],[-2.85378,5.65156],[-2.93132,5.62137],[-2.96671,5.6415],[-2.95323,5.71865],[-3.01896,5.71697],[-3.25999,6.62521],[-3.21954,6.74407],[-3.23327,6.81744],[-2.95438,7.23737],[-2.97822,7.27165],[-2.92339,7.60847],[-2.79467,7.86002],[-2.78395,7.94974],[-2.74819,7.92613],[-2.67787,8.02055],[-2.61232,8.02645],[-2.62901,8.11495],[-2.49037,8.20872],[-2.58243,8.7789],[-2.66357,9.01771],[-2.77799,9.04949],[-2.69814,9.22717],[-2.68802,9.49343],[-2.76494,9.40778],[-2.93012,9.57403],[-3.00765,9.74019],[-3.16609,9.85147],[-3.19306,9.93781],[-3.27228,9.84981],[-3.31779,9.91125],[-3.69703,9.94279],[-4.25999,9.76012],[-4.31392,9.60062],[-4.6426,9.70696],[-4.96621,9.89132],[-4.96453,9.99923],[-5.12465,10.29788],[-5.39602,10.2929],[-5.51058,10.43177],[-5.65135,10.46767],[-5.78124,10.43952],[-5.99478,10.19694],[-6.18851,10.24244],[-6.1731,10.46983],[-6.24795,10.74248],[-6.325,10.68624],[-6.40646,10.69922],[-6.42847,10.5694],[-6.52974,10.59104],[-6.63541,10.66893],[-6.68164,10.35074],[-6.93921,10.35291],[-7.01186,10.25111],[-6.97444,10.21644],[-7.00966,10.15794],[-7.0603,10.14711],[-7.13331,10.24877],[-7.3707,10.24677],[-7.44555,10.44602],[-7.52261,10.4655],[-7.54462,10.40921],[-7.63048,10.46334],[-7.92107,10.15577],[-7.97971,10.17117],[-8.01225,10.1021],[-8.11921,10.04577],[-8.15652,9.94288],[-8.09434,9.86936],[-8.14657,9.55062],[-8.03463,9.39604],[-7.85056,9.41812],[-7.90777,9.20456],[-7.73862,9.08422],[-7.92518,8.99332],[-7.95503,8.81146],[-7.69882,8.66148],[-7.65653,8.36873],[-7.92518,8.50652],[-8.22991,8.48438],[-8.2411,8.24196],[-8.062,8.16071],[-7.98675,8.20134],[-7.99919,8.11023],[-7.94695,8.00925],[-8.06449,8.04989],[-8.13414,7.87991],[-8.09931,7.78626],[-8.21374,7.54466],[-8.4003,7.6285],[-8.47114,7.55676],[-8.41935,7.51203],[-8.37458,7.25794],[-8.29249,7.1691],[-8.31736,6.82837],[-8.59456,6.50612],[-8.48652,6.43797],[-8.45666,6.49977],[-8.38453,6.35887],[-8.3298,6.36381],[-8.17557,6.28222],[-8.00642,6.31684],[-7.90692,6.27728],[-7.83478,6.20309],[-7.8497,6.08932],[-7.79747,6.07696],[-7.78254,5.99037],[-7.70294,5.90625],[-7.67309,5.94337],[-7.48155,5.80974],[-7.46165,5.84934],[-7.43677,5.84687],[-7.43926,5.74787],[-7.37209,5.61173],[-7.43428,5.42355],[-7.36463,5.32944],[-7.46165,5.26256],[-7.48901,5.14118],[-7.55369,5.08667],[-7.53876,4.94294],[-7.59349,4.8909],[-7.53259,4.35145],[-7.52774,3.7105]]]]}},{type:"Feature",properties:{iso1A2:"CK",iso1A3:"COK",iso1N3:"184",wikidata:"Q26988",nameEn:"Cook Islands",country:"NZ",groups:["061","009"],driveSide:"left",callingCodes:["682"]},geometry:{type:"MultiPolygon",coordinates:[[[[-167.73854,-14.92809],[-167.73129,-23.22266],[-156.46451,-23.21255],[-156.4957,-12.32002],[-156.50903,-7.4975],[-167.75329,-7.52784],[-167.75195,-10.12005],[-167.73854,-14.92809]]]]}},{type:"Feature",properties:{iso1A2:"CL",iso1A3:"CHL",iso1N3:"152",wikidata:"Q298",nameEn:"Chile",groups:["005","419","019"],callingCodes:["56"]},geometry:{type:"MultiPolygon",coordinates:[[[[-68.60702,-52.65781],[-68.41683,-52.33516],[-69.97824,-52.00845],[-71.99889,-51.98018],[-72.33873,-51.59954],[-72.31343,-50.58411],[-73.15765,-50.78337],[-73.55259,-49.92488],[-73.45156,-49.79461],[-73.09655,-49.14342],[-72.56894,-48.81116],[-72.54042,-48.52392],[-72.27662,-48.28727],[-72.50478,-47.80586],[-71.94152,-47.13595],[-71.68577,-46.55385],[-71.75614,-45.61611],[-71.35687,-45.22075],[-72.06985,-44.81756],[-71.26418,-44.75684],[-71.16436,-44.46244],[-71.81318,-44.38097],[-71.64206,-43.64774],[-72.14828,-42.85321],[-72.15541,-42.15941],[-71.74901,-42.11711],[-71.92726,-40.72714],[-71.37826,-38.91474],[-70.89532,-38.6923],[-71.24279,-37.20264],[-70.95047,-36.4321],[-70.38008,-36.02375],[-70.49416,-35.24145],[-69.87386,-34.13344],[-69.88099,-33.34489],[-70.55832,-31.51559],[-70.14479,-30.36595],[-69.8596,-30.26131],[-69.99507,-29.28351],[-69.80969,-29.07185],[-69.66709,-28.44055],[-69.22504,-27.95042],[-68.77586,-27.16029],[-68.43363,-27.08414],[-68.27677,-26.90626],[-68.59048,-26.49861],[-68.56909,-26.28146],[-68.38372,-26.15353],[-68.57622,-25.32505],[-68.38372,-25.08636],[-68.56909,-24.69831],[-68.24825,-24.42596],[-67.33563,-24.04237],[-66.99632,-22.99839],[-67.18382,-22.81525],[-67.54284,-22.89771],[-67.85114,-22.87076],[-68.18816,-21.28614],[-68.40403,-20.94562],[-68.53957,-20.91542],[-68.55383,-20.7355],[-68.44023,-20.62701],[-68.7276,-20.46178],[-68.74273,-20.08817],[-68.57132,-20.03134],[-68.54611,-19.84651],[-68.66761,-19.72118],[-68.41218,-19.40499],[-68.61989,-19.27584],[-68.80602,-19.08355],[-68.87082,-19.06003],[-68.94987,-18.93302],[-69.07432,-18.28259],[-69.14807,-18.16893],[-69.07496,-18.03715],[-69.28671,-17.94844],[-69.34126,-17.72753],[-69.46623,-17.60518],[-69.46897,-17.4988],[-69.66483,-17.65083],[-69.79087,-17.65563],[-69.82868,-17.72048],[-69.75305,-17.94605],[-69.81607,-18.12582],[-69.96732,-18.25992],[-70.16394,-18.31737],[-70.31267,-18.31258],[-70.378,-18.3495],[-70.59118,-18.35072],[-113.52687,-26.52828],[-68.11646,-58.14883],[-66.07313,-55.19618],[-67.11046,-54.94199],[-67.46182,-54.92205],[-68.01394,-54.8753],[-68.60733,-54.9125],[-68.60702,-52.65781]]]]}},{type:"Feature",properties:{iso1A2:"CM",iso1A3:"CMR",iso1N3:"120",wikidata:"Q1009",nameEn:"Cameroon",groups:["017","202","002"],callingCodes:["237"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"CN",iso1A3:"CHN",iso1N3:"156",wikidata:"Q148",nameEn:"China",aliases:["RC"],groups:["030","142"],callingCodes:["86"]},geometry:{type:"MultiPolygon",coordinates:[[[[125.6131,53.07229],[125.17522,53.20225],[124.46078,53.21881],[123.86158,53.49391],[123.26989,53.54843],[122.85966,53.47395],[122.35063,53.49565],[121.39213,53.31888],[120.85633,53.28499],[120.0451,52.7359],[120.04049,52.58773],[120.46454,52.63811],[120.71673,52.54099],[120.61346,52.32447],[120.77337,52.20805],[120.65907,51.93544],[120.10963,51.671],[119.13553,50.37412],[119.38598,50.35162],[119.27996,50.13348],[119.11003,50.00276],[118.61623,49.93809],[117.82343,49.52696],[117.48208,49.62324],[117.27597,49.62544],[117.07142,49.68482],[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.08431,47.80693],[116.2527,47.87766],[116.4465,47.83662],[116.67405,47.89039],[116.87527,47.88836],[117.08918,47.82242],[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.37306,46.61132],[119.30261,46.6083],[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],[117.07252,46.35818],[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.91898,45.6227],[115.69688,45.45761],[115.35757,45.39106],[114.94546,45.37377],[114.74612,45.43585],[114.54801,45.38337],[114.5166,45.27189],[114.08071,44.92847],[113.909,44.91444],[113.63821,44.74326],[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],[108.23156,42.45532],[107.57258,42.40898],[107.49681,42.46221],[107.29755,42.41395],[107.24774,42.36107],[106.76517,42.28741],[105.24708,41.7442],[105.01119,41.58382],[104.91272,41.64619],[104.51667,41.66113],[104.52258,41.8706],[103.92804,41.78246],[103.3685,41.89696],[102.72403,42.14675],[102.42826,42.15137],[102.07645,42.22519],[101.80515,42.50074],[101.28833,42.58524],[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],[79.01931,31.42817],[79.14016,31.43403],[79.22805,31.34963],[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.62033,30.44703],[81.99082,30.33423],[82.10135,30.35439],[82.10757,30.23745],[82.19475,30.16884],[82.16984,30.0692],[82.38622,30.02608],[82.5341,29.9735],[82.73024,29.81695],[83.07116,29.61957],[83.28131,29.56813],[83.44787,29.30513],[83.63156,29.16249],[83.82303,29.30513],[83.97559,29.33091],[84.18107,29.23451],[84.24801,29.02783],[84.2231,28.89571],[84.47528,28.74023],[84.62317,28.73887],[84.85511,28.58041],[85.06059,28.68562],[85.19135,28.62825],[85.18668,28.54076],[85.10729,28.34092],[85.38127,28.28336],[85.4233,28.32996],[85.59765,28.30529],[85.60854,28.25045],[85.69105,28.38475],[85.71907,28.38064],[85.74864,28.23126],[85.84672,28.18187],[85.90743,28.05144],[85.97813,27.99023],[85.94946,27.9401],[86.06309,27.90021],[86.12069,27.93047],[86.08333,28.02121],[86.088,28.09264],[86.18607,28.17364],[86.22966,27.9786],[86.42736,27.91122],[86.51609,27.96623],[86.56265,28.09569],[86.74181,28.10638],[86.75582,28.04182],[87.03757,27.94835],[87.11696,27.84104],[87.56996,27.84517],[87.72718,27.80938],[87.82681,27.95248],[88.13378,27.88015],[88.1278,27.95417],[88.25332,27.9478],[88.54858,28.06057],[88.63235,28.12356],[88.83559,28.01936],[88.88091,27.85192],[88.77517,27.45415],[88.82981,27.38814],[88.91901,27.32483],[88.93678,27.33777],[88.96947,27.30319],[89.00216,27.32532],[88.95355,27.4106],[88.97213,27.51671],[89.0582,27.60985],[89.12825,27.62502],[89.59525,28.16433],[89.79762,28.23979],[90.13387,28.19178],[90.58842,28.02838],[90.69894,28.07784],[91.20019,27.98715],[91.25779,28.07509],[91.46327,28.0064],[91.48973,27.93903],[91.5629,27.84823],[91.6469,27.76358],[91.84722,27.76325],[91.87057,27.7195],[92.27432,27.89077],[92.32101,27.79363],[92.42538,27.80092],[92.7275,27.98662],[92.73025,28.05814],[92.65472,28.07632],[92.67486,28.15018],[92.93075,28.25671],[93.14635,28.37035],[93.18069,28.50319],[93.44621,28.67189],[93.72797,28.68821],[94.35897,29.01965],[94.2752,29.11687],[94.69318,29.31739],[94.81353,29.17804],[95.0978,29.14446],[95.11291,29.09527],[95.2214,29.10727],[95.26122,29.07727],[95.3038,29.13847],[95.41091,29.13007],[95.50842,29.13487],[95.72086,29.20797],[95.75149,29.32063],[95.84899,29.31464],[96.05361,29.38167],[96.31316,29.18643],[96.18682,29.11087],[96.20467,29.02325],[96.3626,29.10607],[96.61391,28.72742],[96.40929,28.51526],[96.48895,28.42955],[96.6455,28.61657],[96.85561,28.4875],[96.88445,28.39452],[96.98882,28.32564],[97.1289,28.3619],[97.34547,28.21385],[97.41729,28.29783],[97.47085,28.2688],[97.50518,28.49716],[97.56835,28.55628],[97.70705,28.5056],[97.79632,28.33168],[97.90069,28.3776],[98.15337,28.12114],[98.13964,27.9478],[98.32641,27.51385],[98.42529,27.55404],[98.43353,27.67086],[98.69582,27.56499],[98.7333,26.85615],[98.77547,26.61994],[98.72741,26.36183],[98.67797,26.24487],[98.7329,26.17218],[98.66884,26.09165],[98.63128,26.15492],[98.57085,26.11547],[98.60763,26.01512],[98.70818,25.86241],[98.63128,25.79937],[98.54064,25.85129],[98.40606,25.61129],[98.31268,25.55307],[98.25774,25.6051],[98.16848,25.62739],[98.18084,25.56298],[98.12591,25.50722],[98.14925,25.41547],[97.92541,25.20815],[97.83614,25.2715],[97.77023,25.11492],[97.72216,25.08508],[97.72903,24.91332],[97.79949,24.85655],[97.76481,24.8289],[97.73127,24.83015],[97.70181,24.84557],[97.64354,24.79171],[97.56648,24.76475],[97.56383,24.75535],[97.5542,24.74943],[97.54675,24.74202],[97.56525,24.72838],[97.56286,24.54535],[97.52757,24.43748],[97.60029,24.4401],[97.66998,24.45288],[97.7098,24.35658],[97.65624,24.33781],[97.66723,24.30027],[97.71941,24.29652],[97.76799,24.26365],[97.72998,24.2302],[97.72799,24.18883],[97.75305,24.16902],[97.72903,24.12606],[97.62363,24.00506],[97.5247,23.94032],[97.64667,23.84574],[97.72302,23.89288],[97.79456,23.94836],[97.79416,23.95663],[97.84328,23.97603],[97.86545,23.97723],[97.88811,23.97446],[97.8955,23.97758],[97.89676,23.97931],[97.89683,23.98389],[97.88814,23.98605],[97.88414,23.99405],[97.88616,24.00463],[97.90998,24.02094],[97.93951,24.01953],[97.98691,24.03897],[97.99583,24.04932],[98.04709,24.07616],[98.05302,24.07408],[98.05671,24.07961],[98.0607,24.07812],[98.06703,24.08028],[98.07806,24.07988],[98.20666,24.11406],[98.54476,24.13119],[98.59256,24.08371],[98.85319,24.13042],[98.87998,24.15624],[98.89632,24.10612],[98.67797,23.9644],[98.68209,23.80492],[98.79607,23.77947],[98.82933,23.72921],[98.81775,23.694],[98.88396,23.59555],[98.80294,23.5345],[98.82877,23.47908],[98.87683,23.48995],[98.92104,23.36946],[98.87573,23.33038],[98.93958,23.31414],[98.92515,23.29535],[98.88597,23.18656],[99.05975,23.16382],[99.04601,23.12215],[99.25741,23.09025],[99.34127,23.13099],[99.52214,23.08218],[99.54218,22.90014],[99.43537,22.94086],[99.45654,22.85726],[99.31243,22.73893],[99.38247,22.57544],[99.37972,22.50188],[99.28771,22.4105],[99.17318,22.18025],[99.19176,22.16983],[99.1552,22.15874],[99.33166,22.09656],[99.47585,22.13345],[99.85351,22.04183],[99.96612,22.05965],[99.99084,21.97053],[99.94003,21.82782],[99.98654,21.71064],[100.04956,21.66843],[100.12679,21.70539],[100.17486,21.65306],[100.10757,21.59945],[100.12542,21.50365],[100.1625,21.48704],[100.18447,21.51898],[100.25863,21.47043],[100.35201,21.53176],[100.42892,21.54325],[100.4811,21.46148],[100.57861,21.45637],[100.72143,21.51898],[100.87265,21.67396],[101.11744,21.77659],[101.15156,21.56129],[101.2124,21.56422],[101.19349,21.41959],[101.26912,21.36482],[101.2229,21.23271],[101.29326,21.17254],[101.54563,21.25668],[101.6068,21.23329],[101.59491,21.18621],[101.60886,21.17947],[101.66977,21.20004],[101.70548,21.14911],[101.7622,21.14813],[101.79266,21.19025],[101.76745,21.21571],[101.83887,21.20983],[101.84412,21.25291],[101.74014,21.30967],[101.74224,21.48276],[101.7727,21.51794],[101.7475,21.5873],[101.80001,21.57461],[101.83257,21.61562],[101.74555,21.72852],[101.7791,21.83019],[101.62566,21.96574],[101.57525,22.13026],[101.60675,22.13513],[101.53638,22.24794],[101.56789,22.28876],[101.61306,22.27515],[101.68973,22.46843],[101.7685,22.50337],[101.86828,22.38397],[101.90714,22.38688],[101.91344,22.44417],[101.98487,22.42766],[102.03633,22.46164],[102.1245,22.43372],[102.14099,22.40092],[102.16621,22.43336],[102.26428,22.41321],[102.25339,22.4607],[102.41061,22.64184],[102.38415,22.67919],[102.42618,22.69212],[102.46665,22.77108],[102.51802,22.77969],[102.57095,22.7036],[102.60675,22.73376],[102.8636,22.60735],[102.9321,22.48659],[103.0722,22.44775],[103.07843,22.50097],[103.17961,22.55705],[103.15782,22.59873],[103.18895,22.64471],[103.28079,22.68063],[103.32282,22.8127],[103.43179,22.75816],[103.43646,22.70648],[103.52675,22.59155],[103.57812,22.65764],[103.56255,22.69499],[103.64506,22.79979],[103.87904,22.56683],[103.93286,22.52703],[103.94513,22.52553],[103.95191,22.5134],[103.96352,22.50584],[103.96783,22.51173],[103.97384,22.50634],[103.99247,22.51958],[104.01088,22.51823],[104.03734,22.72945],[104.11384,22.80363],[104.27084,22.8457],[104.25683,22.76534],[104.35593,22.69353],[104.47225,22.75813],[104.58122,22.85571],[104.60457,22.81841],[104.65283,22.83419],[104.72755,22.81984],[104.77114,22.90017],[104.84942,22.93631],[104.86765,22.95178],[104.8334,23.01484],[104.79478,23.12934],[104.87382,23.12854],[104.87992,23.17141],[104.91435,23.18666],[104.9486,23.17235],[104.96532,23.20463],[104.98712,23.19176],[105.07002,23.26248],[105.11672,23.25247],[105.17276,23.28679],[105.22569,23.27249],[105.32376,23.39684],[105.40782,23.28107],[105.42805,23.30824],[105.49966,23.20669],[105.56037,23.16806],[105.57594,23.075],[105.72382,23.06641],[105.8726,22.92756],[105.90119,22.94168],[105.99568,22.94178],[106.00179,22.99049],[106.19705,22.98475],[106.27022,22.87722],[106.34961,22.86718],[106.49749,22.91164],[106.51306,22.94891],[106.55976,22.92311],[106.60179,22.92884],[106.6516,22.86862],[106.6734,22.89587],[106.71387,22.88296],[106.71128,22.85982],[106.78422,22.81532],[106.81271,22.8226],[106.83685,22.8098],[106.82404,22.7881],[106.76293,22.73491],[106.72321,22.63606],[106.71698,22.58432],[106.65316,22.5757],[106.61269,22.60301],[106.58395,22.474],[106.55665,22.46498],[106.57221,22.37],[106.55976,22.34841],[106.6516,22.33977],[106.69986,22.22309],[106.67495,22.1885],[106.6983,22.15102],[106.70142,22.02409],[106.68274,21.99811],[106.69276,21.96013],[106.72551,21.97923],[106.74345,22.00965],[106.81038,21.97934],[106.9178,21.97357],[106.92714,21.93459],[106.97228,21.92592],[106.99252,21.95191],[107.05634,21.92303],[107.06101,21.88982],[107.00964,21.85948],[107.02615,21.81981],[107.10771,21.79879],[107.20734,21.71493],[107.24625,21.7077],[107.29296,21.74674],[107.35834,21.6672],[107.35989,21.60063],[107.38636,21.59774],[107.41593,21.64839],[107.47197,21.6672],[107.49532,21.62958],[107.49065,21.59774],[107.54047,21.5934],[107.56537,21.61945],[107.66967,21.60787],[107.80355,21.66141],[107.86114,21.65128],[107.90006,21.5905],[107.92652,21.58906],[107.95232,21.5388],[107.96774,21.53601],[107.97074,21.54072],[107.97383,21.53961],[107.97932,21.54503],[108.02926,21.54997],[108.0569,21.53604],[108.10003,21.47338],[108.00365,17.98159],[111.60491,13.57105],[118.41371,24.06775],[118.11703,24.39734],[118.28244,24.51231],[118.35291,24.51645],[118.42453,24.54644],[118.56434,24.49266],[120.49232,25.22863],[121.03532,26.8787],[123.5458,31.01942],[122.29378,31.76513],[122.80525,33.30571],[123.85601,37.49093],[123.90497,38.79949],[124.17532,39.8232],[124.23201,39.9248],[124.35029,39.95639],[124.37089,40.03004],[124.3322,40.05573],[124.38556,40.11047],[124.40719,40.13655],[124.86913,40.45387],[125.71172,40.85223],[125.76869,40.87908],[126.00335,40.92835],[126.242,41.15454],[126.53189,41.35206],[126.60631,41.65565],[126.90729,41.79955],[127.17841,41.59714],[127.29712,41.49473],[127.92943,41.44291],[128.02633,41.42103],[128.03311,41.39232],[128.12967,41.37931],[128.18546,41.41279],[128.20061,41.40895],[128.30716,41.60322],[128.15119,41.74568],[128.04487,42.01769],[128.94007,42.03537],[128.96068,42.06657],[129.15178,42.17224],[129.22285,42.26491],[129.22423,42.3553],[129.28541,42.41574],[129.42882,42.44702],[129.54701,42.37254],[129.60482,42.44461],[129.72541,42.43739],[129.75294,42.59409],[129.77183,42.69435],[129.7835,42.76521],[129.80719,42.79218],[129.83277,42.86746],[129.85261,42.96494],[129.8865,43.00395],[129.95082,43.01051],[129.96409,42.97306],[130.12957,42.98361],[130.09764,42.91425],[130.26095,42.9027],[130.23068,42.80125],[130.2385,42.71127],[130.41826,42.6011],[130.44361,42.54849],[130.50123,42.61636],[130.55143,42.52158],[130.62107,42.58413],[130.56576,42.68925],[130.40213,42.70788],[130.44361,42.76205],[130.66524,42.84753],[131.02438,42.86518],[131.02668,42.91246],[131.135,42.94114],[131.10274,43.04734],[131.20414,43.13654],[131.19031,43.21385],[131.30324,43.39498],[131.29402,43.46695],[131.19492,43.53047],[131.21105,43.82383],[131.26176,43.94011],[131.23583,43.96085],[131.25484,44.03131],[131.30365,44.04262],[131.1108,44.70266],[130.95639,44.85154],[131.48415,44.99513],[131.68466,45.12374],[131.66852,45.2196],[131.76532,45.22609],[131.86903,45.33636],[131.99417,45.2567],[132.83978,45.05916],[132.96373,45.0212],[133.12293,45.1332],[133.09279,45.25693],[133.19419,45.51913],[133.41083,45.57723],[133.48457,45.86203],[133.60442,45.90053],[133.67569,45.9759],[133.72695,46.05576],[133.68047,46.14697],[133.88097,46.25066],[133.91496,46.4274],[133.84104,46.46681],[134.03538,46.75668],[134.20016,47.33458],[134.50898,47.4812],[134.7671,47.72051],[134.55508,47.98651],[134.67098,48.1564],[134.75328,48.36763],[134.49516,48.42884],[132.66989,47.96491],[132.57309,47.71741],[131.90448,47.68011],[131.2635,47.73325],[131.09871,47.6852],[130.95985,47.6957],[130.90915,47.90623],[130.65103,48.10052],[130.84462,48.30942],[130.52147,48.61745],[130.66946,48.88251],[130.43232,48.90844],[130.2355,48.86741],[129.85416,49.11067],[129.67598,49.29596],[129.50685,49.42398],[129.40398,49.44194],[129.35317,49.3481],[129.23232,49.40353],[129.11153,49.36813],[128.72896,49.58676],[127.83476,49.5748],[127.53516,49.84306],[127.49299,50.01251],[127.60515,50.23503],[127.37384,50.28393],[127.36009,50.43787],[127.28765,50.46585],[127.36335,50.58306],[127.28165,50.72075],[127.14586,50.91152],[126.93135,51.0841],[126.90369,51.3238],[126.68349,51.70607],[126.44606,51.98254],[126.558,52.13738],[125.6131,53.07229]],[[113.56865,22.20973],[113.57123,22.20416],[113.60504,22.20464],[113.63011,22.10782],[113.57191,22.07696],[113.54839,22.10909],[113.54942,22.14519],[113.54093,22.15497],[113.52659,22.18271],[113.53552,22.20607],[113.53301,22.21235],[113.53591,22.21369],[113.54093,22.21314],[113.54333,22.21688],[113.5508,22.21672],[113.56865,22.20973]],[[114.50148,22.15017],[113.92195,22.13873],[113.83338,22.1826],[113.81621,22.2163],[113.86771,22.42972],[114.03113,22.5065],[114.05438,22.5026],[114.05729,22.51104],[114.06272,22.51617],[114.07267,22.51855],[114.07817,22.52997],[114.08606,22.53276],[114.09048,22.53716],[114.09692,22.53435],[114.1034,22.5352],[114.11181,22.52878],[114.11656,22.53415],[114.12665,22.54003],[114.13823,22.54319],[114.1482,22.54091],[114.15123,22.55163],[114.1597,22.56041],[114.17247,22.55944],[114.18338,22.55444],[114.20655,22.55706],[114.22185,22.55343],[114.22888,22.5436],[114.25154,22.55977],[114.44998,22.55977],[114.50148,22.15017]]]]}},{type:"Feature",properties:{iso1A2:"CO",iso1A3:"COL",iso1N3:"170",wikidata:"Q739",nameEn:"Colombia",groups:["005","419","019"],callingCodes:["57"]},geometry:{type:"MultiPolygon",coordinates:[[[[-71.19849,12.65801],[-81.58685,18.0025],[-82.06974,14.49418],[-82.56142,11.91792],[-78.79327,9.93766],[-77.58292,9.22278],[-77.32389,8.81247],[-77.45064,8.49991],[-77.17257,7.97422],[-77.57185,7.51147],[-77.72514,7.72348],[-77.72157,7.47612],[-77.81426,7.48319],[-77.89178,7.22681],[-78.06168,7.07793],[-82.12561,4.00341],[-78.87137,1.47457],[-78.42749,1.15389],[-77.85677,0.80197],[-77.7148,0.85003],[-77.68613,0.83029],[-77.66416,0.81604],[-77.67815,0.73863],[-77.49984,0.64476],[-77.52001,0.40782],[-76.89177,0.24736],[-76.4094,0.24015],[-76.41215,0.38228],[-76.23441,0.42294],[-75.82927,0.09578],[-75.25764,-0.11943],[-75.18513,-0.0308],[-74.42701,-0.50218],[-74.26675,-0.97229],[-73.65312,-1.26222],[-72.92587,-2.44514],[-71.75223,-2.15058],[-70.94377,-2.23142],[-70.04609,-2.73906],[-70.71396,-3.7921],[-70.52393,-3.87553],[-70.3374,-3.79505],[-69.94708,-4.2431],[-69.43395,-1.42219],[-69.4215,-1.01853],[-69.59796,-0.75136],[-69.603,-0.51947],[-70.03658,-0.19681],[-70.04162,0.55437],[-69.47696,0.71065],[-69.20976,0.57958],[-69.14422,0.84172],[-69.26017,1.06856],[-69.82987,1.07864],[-69.83491,1.69353],[-69.53746,1.76408],[-69.38621,1.70865],[-68.18128,1.72881],[-68.26699,1.83463],[-68.18632,2.00091],[-67.9292,1.82455],[-67.40488,2.22258],[-67.299,1.87494],[-67.15784,1.80439],[-67.08222,1.17441],[-66.85795,1.22998],[-67.21967,2.35778],[-67.65696,2.81691],[-67.85862,2.79173],[-67.85862,2.86727],[-67.30945,3.38393],[-67.50067,3.75812],[-67.62671,3.74303],[-67.85358,4.53249],[-67.83341,5.31104],[-67.59141,5.5369],[-67.63914,5.64963],[-67.58558,5.84537],[-67.43513,5.98835],[-67.4625,6.20625],[-67.60654,6.2891],[-69.41843,6.1072],[-70.10716,6.96516],[-70.7596,7.09799],[-71.03941,6.98163],[-71.37234,7.01588],[-71.42212,7.03854],[-71.44118,7.02116],[-71.82441,7.04314],[-72.04895,7.03837],[-72.19437,7.37034],[-72.43132,7.40034],[-72.47415,7.48928],[-72.45321,7.57232],[-72.47827,7.65604],[-72.46763,7.79518],[-72.44454,7.86031],[-72.46183,7.90682],[-72.45806,7.91141],[-72.47042,7.92306],[-72.48183,7.92909],[-72.48801,7.94329],[-72.47213,7.96106],[-72.39137,8.03534],[-72.35163,8.01163],[-72.36987,8.19976],[-72.4042,8.36513],[-72.65474,8.61428],[-72.77415,9.10165],[-72.94052,9.10663],[-73.02119,9.27584],[-73.36905,9.16636],[-72.98085,9.85253],[-72.88002,10.44309],[-72.4767,11.1117],[-72.24983,11.14138],[-71.9675,11.65536],[-71.3275,11.85],[-70.92579,11.96275],[-71.19849,12.65801]]]]}},{type:"Feature",properties:{iso1A2:"CP",iso1A3:"CPT",wikidata:"Q161258",nameEn:"Clipperton Island",country:"FR",isoStatus:"excRes"},geometry:{type:"MultiPolygon",coordinates:[[[[-110.36279,9.79626],[-108.755,9.84085],[-109.04145,11.13245],[-110.36279,9.79626]]]]}},{type:"Feature",properties:{iso1A2:"CR",iso1A3:"CRI",iso1N3:"188",wikidata:"Q800",nameEn:"Costa Rica",groups:["013","003","419","019"],callingCodes:["506"]},geometry:{type:"MultiPolygon",coordinates:[[[[-83.68276,11.01562],[-83.66597,10.79916],[-83.90838,10.71161],[-84.68197,11.07568],[-84.92439,10.9497],[-85.60529,11.22607],[-85.71223,11.06868],[-86.14524,11.09059],[-87.41779,5.02401],[-82.94503,7.93865],[-82.89978,8.04083],[-82.89137,8.05755],[-82.88641,8.10219],[-82.9388,8.26634],[-83.05209,8.33394],[-82.93056,8.43465],[-82.8679,8.44042],[-82.8382,8.48117],[-82.83322,8.52464],[-82.83975,8.54755],[-82.82739,8.60153],[-82.8794,8.6981],[-82.92068,8.74832],[-82.91377,8.774],[-82.88253,8.83331],[-82.72126,8.97125],[-82.93516,9.07687],[-82.93516,9.46741],[-82.84871,9.4973],[-82.87919,9.62645],[-82.77206,9.59573],[-82.66667,9.49746],[-82.61345,9.49881],[-82.56507,9.57279],[-82.51044,9.65379],[-83.54024,10.96805],[-83.68276,11.01562]]]]}},{type:"Feature",properties:{iso1A2:"CU",iso1A3:"CUB",iso1N3:"192",wikidata:"Q241",nameEn:"Cuba",groups:["029","003","419","019"],callingCodes:["53"]},geometry:{type:"MultiPolygon",coordinates:[[[[-73.62304,20.6935],[-82.02215,24.23074],[-85.77883,21.92705],[-74.81171,18.82201],[-73.62304,20.6935]]]]}},{type:"Feature",properties:{iso1A2:"CV",iso1A3:"CPV",iso1N3:"132",wikidata:"Q1011",nameEn:"Cape Verde",groups:["011","202","002"],callingCodes:["238"]},geometry:{type:"MultiPolygon",coordinates:[[[[-28.81604,14.57305],[-20.39702,14.12816],[-23.37101,19.134],[-28.81604,14.57305]]]]}},{type:"Feature",properties:{iso1A2:"CW",iso1A3:"CUW",iso1N3:"531",wikidata:"Q25279",nameEn:"Curaçao",country:"NL",groups:["029","003","419","019"],callingCodes:["599"]},geometry:{type:"MultiPolygon",coordinates:[[[[-68.90012,12.62309],[-69.59009,12.46019],[-68.99639,11.79035],[-68.33524,11.78151],[-68.90012,12.62309]]]]}},{type:"Feature",properties:{iso1A2:"CX",iso1A3:"CXR",iso1N3:"162",wikidata:"Q31063",nameEn:"Christmas Island",country:"AU",groups:["053","009"],driveSide:"left",callingCodes:["61"]},geometry:{type:"MultiPolygon",coordinates:[[[[105.66835,-9.31927],[104.67494,-11.2566],[106.66176,-11.14349],[105.66835,-9.31927]]]]}},{type:"Feature",properties:{iso1A2:"CY",iso1A3:"CYP",iso1N3:"196",wikidata:"Q229",nameEn:"Cyprus",groups:["EU","145","142"],driveSide:"left",callingCodes:["357"]},geometry:{type:"MultiPolygon",coordinates:[[[[33.70639,34.99303],[33.71514,35.00294],[33.69731,35.01754],[33.69938,35.03123],[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],[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.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]]]]}},{type:"Feature",properties:{iso1A2:"CZ",iso1A3:"CZE",iso1N3:"203",wikidata:"Q213",nameEn:"Czechia",groups:["EU","151","150"],callingCodes:["420"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"DE",iso1A3:"DEU",iso1N3:"276",wikidata:"Q183",nameEn:"Germany",groups:["EU","155","150"],callingCodes:["49"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"DG",iso1A3:"DGA",wikidata:"Q184851",nameEn:"Diego Garcia",country:"GB",groups:["IO","014","202","002"],isoStatus:"excRes",callingCodes:["246"]},geometry:{type:"MultiPolygon",coordinates:[[[[73.14823,-7.76302],[73.09982,-6.07324],[71.43792,-7.73904],[73.14823,-7.76302]]]]}},{type:"Feature",properties:{iso1A2:"DJ",iso1A3:"DJI",iso1N3:"262",wikidata:"Q977",nameEn:"Djibouti",groups:["014","202","002"],callingCodes:["253"]},geometry:{type:"MultiPolygon",coordinates:[[[[43.42425,11.70983],[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.42425,11.70983]]]]}},{type:"Feature",properties:{iso1A2:"DK",iso1A3:"DNK",iso1N3:"208",wikidata:"Q35",nameEn:"Denmark",groups:["EU","154","150"],callingCodes:["45"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"DM",iso1A3:"DMA",iso1N3:"212",wikidata:"Q784",nameEn:"Dominica",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 767"]},geometry:{type:"MultiPolygon",coordinates:[[[[-61.51867,14.96709],[-60.69955,15.22234],[-60.95725,15.70997],[-61.44899,15.79571],[-61.81728,15.58058],[-61.51867,14.96709]]]]}},{type:"Feature",properties:{iso1A2:"DO",iso1A3:"DOM",iso1N3:"214",wikidata:"Q786",nameEn:"Dominican Republic",groups:["029","003","419","019"],callingCodes:["1 809","1 829","1 849"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"DZ",iso1A3:"DZA",iso1N3:"012",wikidata:"Q262",nameEn:"Algeria",groups:["015","002"],callingCodes:["213"]},geometry:{type:"MultiPolygon",coordinates:[[[[8.59123,37.14286],[2.46645,37.97429],[-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]]]]}},{type:"Feature",properties:{iso1A2:"EA",wikidata:"Q28868874",nameEn:"Ceuta, Melilla",country:"ES",groups:["015","002"],isoStatus:"excRes",callingCodes:["34"]},geometry:{type:"MultiPolygon",coordinates:[[[[-5.38491,35.92591],[-5.37338,35.88417],[-5.35844,35.87375],[-5.34379,35.8711],[-5.27056,35.88794],[-5.27635,35.91222],[-5.38491,35.92591]]],[[[-2.92224,35.3401],[-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.92674,35.27313],[-2.92181,35.28599],[-2.92224,35.3401]]]]}},{type:"Feature",properties:{iso1A2:"EC",iso1A3:"ECU",iso1N3:"218",wikidata:"Q736",nameEn:"Ecuador",groups:["005","419","019"],callingCodes:["593"]},geometry:{type:"MultiPolygon",coordinates:[[[[-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],[-93.12365,2.64343],[-92.46744,-2.52874],[-80.30602,-3.39149],[-80.20647,-3.431],[-80.24123,-3.46124],[-80.24475,-3.47846],[-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]]]]}},{type:"Feature",properties:{iso1A2:"EE",iso1A3:"EST",iso1N3:"233",wikidata:"Q191",nameEn:"Estonia",aliases:["EW"],groups:["EU","154","150"],callingCodes:["372"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"EG",iso1A3:"EGY",iso1N3:"818",wikidata:"Q79",nameEn:"Egypt",groups:["015","002"],callingCodes:["20"]},geometry:{type:"MultiPolygon",coordinates:[[[[33.62659,31.82938],[25.63787,31.9359],[25.14001,31.67534],[25.06041,31.57937],[24.83101,31.31921],[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.51305,27.70027],[34.46254,27.99552],[34.88293,29.37455],[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]]]]}},{type:"Feature",properties:{iso1A2:"EH",iso1A3:"ESH",iso1N3:"732",wikidata:"Q6250",nameEn:"Western Sahara",groups:["015","002"],callingCodes:["212"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"ER",iso1A3:"ERI",iso1N3:"232",wikidata:"Q986",nameEn:"Eritrea",groups:["014","202","002"],callingCodes:["291"]},geometry:{type:"MultiPolygon",coordinates:[[[[41.37609,16.19728],[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],[42.63806,13.58268],[41.29956,15.565],[41.37609,16.19728]]]]}},{type:"Feature",properties:{iso1A2:"ES",iso1A3:"ESP",iso1N3:"724",wikidata:"Q29",nameEn:"Spain",groups:["EU","039","150"],callingCodes:["34"]},geometry:{type:"MultiPolygon",coordinates:[[[[-2.41312,35.17111],[-2.41265,35.1877],[-2.44896,35.18777],[-2.44887,35.17075],[-2.41312,35.17111]]],[[[-3.90602,35.21494],[-3.88926,35.20841],[-3.88617,35.21406],[-3.90288,35.22024],[-3.90602,35.21494]]],[[[-4.30191,35.17419],[-4.30112,35.17058],[-4.29436,35.17149],[-4.30191,35.17419]]],[[[-7.27694,35.93599],[-5.64962,35.93752],[-5.10878,36.05227],[-2.85819,35.63219],[-2.27707,35.35051],[2.46645,37.97429],[5.18061,39.43581],[3.4481,42.4358],[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],[-9.14112,41.86623],[-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.27694,35.93599]],[[-5.28217,36.09907],[-5.3004,36.07439],[-5.32837,36.05935],[-5.36503,36.06205],[-5.39074,36.10278],[-5.40134,36.14896],[-5.38545,36.15481],[-5.36494,36.15496],[-5.34536,36.15501],[-5.33822,36.15272],[-5.27801,36.14942],[-5.28217,36.09907]]],[[[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]]]]}},{type:"Feature",properties:{iso1A2:"ET",iso1A3:"ETH",iso1N3:"231",wikidata:"Q115",nameEn:"Ethiopia",groups:["014","202","002"],callingCodes:["251"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"EU",iso1A3:"EUE",wikidata:"Q458",nameEn:"European Union",level:"union",isoStatus:"excRes"},geometry:null},{type:"Feature",properties:{iso1A2:"FI",iso1A3:"FIN",iso1N3:"246",wikidata:"Q33",nameEn:"Finland",aliases:["SF"],groups:["EU","154","150"],callingCodes:["358"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"FJ",iso1A3:"FJI",iso1N3:"242",wikidata:"Q712",nameEn:"Fiji",groups:["054","009"],driveSide:"left",callingCodes:["679"]},geometry:{type:"MultiPolygon",coordinates:[[[[174,-22.5],[179.99999,-22.5],[179.99999,-11.5],[174,-11.5],[174,-22.5]]],[[[-178.60161,-14.95666],[-180,-14.96041],[-180,-22.90585],[-176.74538,-22.89767],[-176.76826,-14.95183],[-178.60161,-14.95666]]]]}},{type:"Feature",properties:{iso1A2:"FK",iso1A3:"FLK",iso1N3:"238",wikidata:"Q9648",nameEn:"Falkland Islands",country:"GB",groups:["005","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["500"]},geometry:{type:"MultiPolygon",coordinates:[[[[-63.67376,-55.11859],[-54.56126,-51.26248],[-61.26735,-50.63919],[-63.67376,-55.11859]]]]}},{type:"Feature",properties:{iso1A2:"FM",iso1A3:"FSM",iso1N3:"583",wikidata:"Q702",nameEn:"Federated States of Micronesia",groups:["057","009"],roadSpeedUnit:"mph",callingCodes:["691"]},geometry:{type:"MultiPolygon",coordinates:[[[[136.04605,12.45908],[136.27107,6.73747],[156.88247,-1.39237],[165.35175,6.367],[159.04653,10.59067],[136.04605,12.45908]]]]}},{type:"Feature",properties:{iso1A2:"FO",iso1A3:"FRO",iso1N3:"234",wikidata:"Q4628",nameEn:"Faroe Islands",country:"DK",groups:["154","150"],callingCodes:["298"]},geometry:{type:"MultiPolygon",coordinates:[[[[-8.51774,62.35338],[-6.51083,60.95272],[-5.70102,62.77194],[-8.51774,62.35338]]]]}},{type:"Feature",properties:{iso1A2:"FR",iso1A3:"FRA",iso1N3:"250",wikidata:"Q142",nameEn:"France",groups:["EU","155","150"],callingCodes:["33"]},geometry:null},{type:"Feature",properties:{iso1A2:"FX",iso1A3:"FXX",iso1N3:"249",wikidata:"Q212429",nameEn:"Metropolitan France",country:"FR",groups:["EU","155","150"],isoStatus:"excRes",callingCodes:["33"]},geometry:{type:"MultiPolygon",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.13339,48.73907],[-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.4481,42.4358],[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]]]]}},{type:"Feature",properties:{iso1A2:"GA",iso1A3:"GAB",iso1N3:"266",wikidata:"Q1000",nameEn:"Gabon",groups:["017","202","002"],callingCodes:["241"]},geometry:{type:"MultiPolygon",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.78058,1.03996],[9.76085,1.05949],[9.73014,1.06721],[9.68638,1.06836],[9.66092,1.05865],[9.62096,1.03039],[9.54793,1.0185],[9.51998,0.96418],[9.35563,0.84865],[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]]]]}},{type:"Feature",properties:{iso1A2:"GB",iso1A3:"GBR",iso1N3:"826",wikidata:"Q145",nameEn:"United Kingdom",aliases:["UK","Britain","Great Britain"],groups:["154","150"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["44"]},geometry:{type:"MultiPolygon",coordinates:[[[[-5.83481,53.87749],[-4.1819,54.57861],[-3.64906,54.12723],[-5.37267,53.63269],[-5.79914,52.03902],[-7.74976,48.64773],[1.17405,50.74239],[2.18458,51.52087],[2.56575,51.85301],[-0.3751,61.32236],[-14.78497,57.60709],[-7.93366,55.84142],[-6.79943,55.54107],[-6.71944,55.27952],[-6.9734,55.19878],[-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]]],[[[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]]],[[[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]]]]}},{type:"Feature",properties:{iso1A2:"GD",iso1A3:"GRD",iso1N3:"308",wikidata:"Q769",nameEn:"Grenada",aliases:["WG"],groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 473"]},geometry:{type:"MultiPolygon",coordinates:[[[[-62.14806,11.87638],[-61.57265,11.65795],[-61.13395,12.51526],[-61.38256,12.52991],[-61.73897,12.61191],[-62.14806,11.87638]]]]}},{type:"Feature",properties:{iso1A2:"GE",iso1A3:"GEO",iso1N3:"268",wikidata:"Q230",nameEn:"Georgia",groups:["145","142"],callingCodes:["995"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"GF",iso1A3:"GUF",iso1N3:"254",wikidata:"Q3769",nameEn:"French Guiana",country:"FR",groups:["EU","005","419","019"],callingCodes:["594"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"GG",iso1A3:"GGY",iso1N3:"831",wikidata:"Q25230",nameEn:"Guernsey",country:"GB",groups:["830","154","150"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["44 01481"]},geometry:{type:"MultiPolygon",coordinates:[[[[-2.65349,49.15373],[-2.36485,49.48223],[-2.09454,49.46288],[-2.02963,49.91866],[-3.28154,49.57329],[-2.65349,49.15373]]]]}},{type:"Feature",properties:{iso1A2:"GH",iso1A3:"GHA",iso1N3:"288",wikidata:"Q117",nameEn:"Ghana",groups:["011","202","002"],callingCodes:["233"]},geometry:{type:"MultiPolygon",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],[-0.00908,10.91644],[-0.0063,10.96417],[0.03355,10.9807],[0.02395,11.06229],[0.00342,11.08317],[-0.00514,11.10763],[-0.0275,11.11202],[-0.05733,11.08628],[-0.14462,11.10811],[-0.13493,11.14075]]]]}},{type:"Feature",properties:{iso1A2:"GI",iso1A3:"GIB",iso1N3:"292",wikidata:"Q1410",nameEn:"Gibraltar",country:"GB",groups:["039","150"],callingCodes:["350"]},geometry:{type:"MultiPolygon",coordinates:[[[[-5.28217,36.09907],[-5.27801,36.14942],[-5.33822,36.15272],[-5.34536,36.15501],[-5.36494,36.15496],[-5.38545,36.15481],[-5.40134,36.14896],[-5.39074,36.10278],[-5.36503,36.06205],[-5.32837,36.05935],[-5.3004,36.07439],[-5.28217,36.09907]]]]}},{type:"Feature",properties:{iso1A2:"GL",iso1A3:"GRL",iso1N3:"304",wikidata:"Q223",nameEn:"Greenland",country:"DK",groups:["021","003","019"],callingCodes:["299"]},geometry:{type:"MultiPolygon",coordinates:[[[[-45.47832,84.58738],[-68.21821,80.48551],[-76.75614,76.72014],[-46.37635,57.3249],[-9.68082,72.73731],[-5.7106,84.28058],[-45.47832,84.58738]]]]}},{type:"Feature",properties:{iso1A2:"GM",iso1A3:"GMB",iso1N3:"270",wikidata:"Q1005",nameEn:"The Gambia",groups:["011","202","002"],callingCodes:["220"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"GN",iso1A3:"GIN",iso1N3:"324",wikidata:"Q1006",nameEn:"Guinea",groups:["011","202","002"],callingCodes:["224"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"GP",iso1A3:"GLP",iso1N3:"312",wikidata:"Q17012",nameEn:"Guadeloupe",country:"FR",groups:["EU","029","003","419","019"],callingCodes:["590"]},geometry:{type:"MultiPolygon",coordinates:[[[[-60.95725,15.70997],[-60.71337,16.48911],[-61.44461,16.81958],[-61.83929,16.66647],[-62.17275,16.35721],[-61.81728,15.58058],[-61.44899,15.79571],[-60.95725,15.70997]]]]}},{type:"Feature",properties:{iso1A2:"GQ",iso1A3:"GNQ",iso1N3:"226",wikidata:"Q983",nameEn:"Equatorial Guinea",groups:["017","202","002"],callingCodes:["240"]},geometry:{type:"MultiPolygon",coordinates:[[[[9.22018,3.72052],[8.34397,4.30689],[8.05799,3.48284],[8.0168,1.79377],[6.69416,-0.53945],[5.38965,-1.19244],[5.3459,-2.30107],[7.24416,-0.64092],[9.35563,0.84865],[9.51998,0.96418],[9.54793,1.0185],[9.62096,1.03039],[9.66092,1.05865],[9.68638,1.06836],[9.73014,1.06721],[9.76085,1.05949],[9.78058,1.03996],[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]]]]}},{type:"Feature",properties:{iso1A2:"GR",iso1A3:"GRC",iso1N3:"300",wikidata:"Q41",nameEn:"Greece",aliases:["EL"],groups:["EU","039","150"],callingCodes:["30"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"GS",iso1A3:"SGS",iso1N3:"239",wikidata:"Q35086",nameEn:"South Georgia and South Sandwich Islands",country:"GB",groups:["005","419","019"],driveSide:"left",callingCodes:["500"]},geometry:{type:"MultiPolygon",coordinates:[[[[-35.26394,-43.68272],[-53.39656,-59.87088],[-22.31757,-59.85974],[-35.26394,-43.68272]]]]}},{type:"Feature",properties:{iso1A2:"GT",iso1A3:"GTM",iso1N3:"320",wikidata:"Q774",nameEn:"Guatemala",groups:["013","003","419","019"],callingCodes:["502"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"GU",iso1A3:"GUM",iso1N3:"316",wikidata:"Q16635",nameEn:"Guam",country:"US",groups:["057","009"],roadSpeedUnit:"mph",callingCodes:["1 671"]},geometry:{type:"MultiPolygon",coordinates:[[[[146.25931,13.85876],[143.82485,13.92273],[144.61642,12.82462],[146.25931,13.85876]]]]}},{type:"Feature",properties:{iso1A2:"GW",iso1A3:"GNB",iso1N3:"624",wikidata:"Q1007",nameEn:"Guinea-Bissau",groups:["011","202","002"],callingCodes:["245"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"GY",iso1A3:"GUY",iso1N3:"328",wikidata:"Q734",nameEn:"Guyana",groups:["005","419","019"],driveSide:"left",callingCodes:["592"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"HK",iso1A3:"HKG",iso1N3:"344",wikidata:"Q8646",nameEn:"Hong Kong",country:"CN",groups:["030","142"],driveSide:"left",callingCodes:["852"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"HM",iso1A3:"HMD",iso1N3:"334",wikidata:"Q131198",nameEn:"Heard Island and McDonald Islands",country:"AU",groups:["053","009"],driveSide:"left"},geometry:{type:"MultiPolygon",coordinates:[[[[71.08716,-53.87687],[75.44182,-53.99822],[72.87012,-51.48322],[71.08716,-53.87687]]]]}},{type:"Feature",properties:{iso1A2:"HN",iso1A3:"HND",iso1N3:"340",wikidata:"Q783",nameEn:"Honduras",groups:["013","003","419","019"],callingCodes:["504"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"HR",iso1A3:"HRV",iso1N3:"191",wikidata:"Q224",nameEn:"Croatia",groups:["EU","039","150"],callingCodes:["385"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"HT",iso1A3:"HTI",iso1N3:"332",wikidata:"Q790",nameEn:"Haiti",aliases:["RH"],groups:["029","003","419","019"],callingCodes:["509"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"HU",iso1A3:"HUN",iso1N3:"348",wikidata:"Q28",nameEn:"Hungary",groups:["EU","151","150"],callingCodes:["36"]},geometry:{type:"MultiPolygon",coordinates:[[[[21.72525,48.34628],[21.67134,48.3989],[21.6068,48.50365],[21.44063,48.58456],[21.11516,48.49546],[20.83248,48.5824],[20.5215,48.53336],[20.29943,48.26104],[20.24312,48.2784],[19.92452,48.1283],[19.63338,48.25006],[19.52489,48.19791],[19.47957,48.09437],[19.28182,48.08336],[19.23924,48.0595],[19.01952,48.07052],[18.82176,48.04206],[18.76134,47.97499],[18.76821,47.87469],[18.8506,47.82308],[18.74074,47.8157],[18.66521,47.76772],[18.56496,47.76588],[18.29305,47.73541],[18.02938,47.75665],[17.71215,47.7548],[17.23699,48.02094],[17.16001,48.00636],[17.09786,47.97336],[17.11022,47.92461],[17.08275,47.87719],[17.00997,47.86245],[17.07039,47.81129],[17.05048,47.79377],[17.08893,47.70928],[16.87538,47.68895],[16.86509,47.72268],[16.82938,47.68432],[16.7511,47.67878],[16.72089,47.73469],[16.65679,47.74197],[16.61183,47.76171],[16.54779,47.75074],[16.53514,47.73837],[16.55129,47.72268],[16.4222,47.66537],[16.58699,47.61772],[16.64193,47.63114],[16.71059,47.52692],[16.64821,47.50155],[16.6718,47.46139],[16.57152,47.40868],[16.52414,47.41007],[16.49908,47.39416],[16.45104,47.41181],[16.47782,47.25918],[16.44142,47.25079],[16.43663,47.21127],[16.41739,47.20649],[16.42801,47.18422],[16.4523,47.18812],[16.46442,47.16845],[16.44932,47.14418],[16.52863,47.13974],[16.46134,47.09395],[16.52176,47.05747],[16.43936,47.03548],[16.51369,47.00084],[16.28202,47.00159],[16.27594,46.9643],[16.22403,46.939],[16.19904,46.94134],[16.10983,46.867],[16.14365,46.8547],[16.15711,46.85434],[16.21892,46.86961],[16.2365,46.87775],[16.2941,46.87137],[16.34547,46.83836],[16.3408,46.80641],[16.31303,46.79838],[16.30966,46.7787],[16.37816,46.69975],[16.42641,46.69228],[16.41863,46.66238],[16.38594,46.6549],[16.39217,46.63673],[16.50139,46.56684],[16.52885,46.53303],[16.52604,46.5051],[16.59527,46.47524],[16.6639,46.45203],[16.7154,46.39523],[16.8541,46.36255],[16.8903,46.28122],[17.14592,46.16697],[17.35672,45.95209],[17.56821,45.93728],[17.66545,45.84207],[17.87377,45.78522],[17.99805,45.79671],[18.08869,45.76511],[18.12439,45.78905],[18.44368,45.73972],[18.57483,45.80772],[18.6792,45.92057],[18.80211,45.87995],[18.81394,45.91329],[18.99712,45.93537],[19.01284,45.96529],[19.0791,45.96458],[19.10388,46.04015],[19.14543,45.9998],[19.28826,45.99694],[19.52473,46.1171],[19.56113,46.16824],[19.66007,46.19005],[19.81491,46.1313],[19.93508,46.17553],[20.01816,46.17696],[20.03533,46.14509],[20.09713,46.17315],[20.26068,46.12332],[20.28324,46.1438],[20.35573,46.16629],[20.45377,46.14405],[20.49718,46.18721],[20.63863,46.12728],[20.76085,46.21002],[20.74574,46.25467],[20.86797,46.28884],[21.06572,46.24897],[21.16872,46.30118],[21.28061,46.44941],[21.26929,46.4993],[21.33214,46.63035],[21.43926,46.65109],[21.5151,46.72147],[21.48935,46.7577],[21.52028,46.84118],[21.59307,46.86935],[21.59581,46.91628],[21.68645,46.99595],[21.648,47.03902],[21.78395,47.11104],[21.94463,47.38046],[22.01055,47.37767],[22.03389,47.42508],[22.00917,47.50492],[22.31816,47.76126],[22.41979,47.7391],[22.46559,47.76583],[22.67247,47.7871],[22.76617,47.8417],[22.77991,47.87211],[22.89849,47.95851],[22.84276,47.98602],[22.87847,48.04665],[22.81804,48.11363],[22.73427,48.12005],[22.66835,48.09162],[22.58733,48.10813],[22.59007,48.15121],[22.49806,48.25189],[22.38133,48.23726],[22.2083,48.42534],[22.14689,48.4005],[21.83339,48.36242],[21.8279,48.33321],[21.72525,48.34628]]]]}},{type:"Feature",properties:{iso1A2:"IC",wikidata:"Q5813",nameEn:"Canary Islands",country:"ES",groups:["EU","039","150"],isoStatus:"excRes",callingCodes:["34"]},geometry:{type:"MultiPolygon",coordinates:[[[[-15.92339,29.50503],[-25.3475,27.87574],[-14.43883,27.02969],[-9.94494,32.97138],[-15.92339,29.50503]]]]}},{type:"Feature",properties:{iso1A2:"ID",iso1A3:"IDN",iso1N3:"360",wikidata:"Q252",nameEn:"Indonesia",aliases:["RI"],groups:["035","142"],driveSide:"left",callingCodes:["62"]},geometry:{type:"MultiPolygon",coordinates:[[[[141.02352,0.08993],[128.97621,3.08804],[126.69413,6.02692],[124.97752,4.82064],[118.41402,3.99509],[118.07935,4.15511],[117.89538,4.16637],[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.64506,2.08014],[109.71058,2.32059],[108.10426,5.42408],[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],[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.31127,-8.22976],[125.65946,-8.06136],[125.87691,-8.31789],[127.42116,-8.22471],[127.55165,-9.05052],[140.88922,-9.34945],[141.00782,-9.1242],[141.01763,-6.90181],[140.85295,-6.72996],[140.99813,-6.3233],[141.02352,0.08993]]]]}},{type:"Feature",properties:{iso1A2:"IE",iso1A3:"IRL",iso1N3:"372",wikidata:"Q27",nameEn:"Ireland",groups:["EU","154","150"],driveSide:"left",callingCodes:["353"]},geometry:{type:"MultiPolygon",coordinates:[[[[-6.26218,54.09785],[-6.29003,54.11278],[-6.32694,54.09337],[-6.36279,54.11248],[-6.36605,54.07234],[-6.47849,54.06947],[-6.62842,54.03503],[-6.66264,54.0666],[-6.6382,54.17071],[-6.70175,54.20218],[-6.74575,54.18788],[-6.81583,54.22791],[-6.85179,54.29176],[-6.87775,54.34682],[-7.02034,54.4212],[-7.19145,54.31296],[-7.14908,54.22732],[-7.25012,54.20063],[-7.26316,54.13863],[-7.29493,54.12013],[-7.29687,54.1354],[-7.28017,54.16714],[-7.29157,54.17191],[-7.34005,54.14698],[-7.30553,54.11869],[-7.32834,54.11475],[-7.44567,54.1539],[-7.4799,54.12239],[-7.55812,54.12239],[-7.69501,54.20731],[-7.81397,54.20159],[-7.8596,54.21779],[-7.87101,54.29299],[-8.04555,54.36292],[-8.179,54.46763],[-8.04538,54.48941],[-7.99812,54.54427],[-7.8596,54.53671],[-7.70315,54.62077],[-7.93293,54.66603],[-7.83352,54.73854],[-7.75041,54.7103],[-7.64449,54.75265],[-7.54671,54.74606],[-7.54508,54.79401],[-7.47626,54.83084],[-7.4473,54.87003],[-7.44404,54.9403],[-7.40004,54.94498],[-7.4033,55.00391],[-7.34464,55.04688],[-7.2471,55.06933],[-6.9734,55.19878],[-6.71944,55.27952],[-6.79943,55.54107],[-7.93366,55.84142],[-22.01468,48.19557],[-5.79914,52.03902],[-5.37267,53.63269],[-5.83481,53.87749],[-6.26218,54.09785]]]]}},{type:"Feature",properties:{iso1A2:"IL",iso1A3:"ISR",iso1N3:"376",wikidata:"Q801",nameEn:"Israel",groups:["145","142"],callingCodes:["972"]},geometry:{type:"MultiPolygon",coordinates:[[[[34.052,31.46619],[34.29262,31.70393],[34.48681,31.59711],[34.56797,31.54197],[34.48892,31.48365],[34.40077,31.40926],[34.36505,31.36404],[34.37381,31.30598],[34.36523,31.28963],[34.29417,31.24194],[34.26742,31.21998],[34.92298,29.45305],[34.97718,29.54294],[34.98207,29.58147],[35.02147,29.66343],[35.14108,30.07374],[35.19183,30.34636],[35.16218,30.43535],[35.19595,30.50297],[35.21379,30.60401],[35.29311,30.71365],[35.33456,30.81224],[35.33984,30.8802],[35.41371,30.95565],[35.43658,31.12444],[35.40316,31.25535],[35.47672,31.49578],[35.39675,31.49572],[35.22921,31.37445],[35.13033,31.3551],[35.02459,31.35979],[34.92571,31.34337],[34.88932,31.37093],[34.87833,31.39321],[34.89756,31.43891],[34.93258,31.47816],[34.94356,31.50743],[34.9415,31.55601],[34.95249,31.59813],[35.00879,31.65426],[35.08226,31.69107],[35.10782,31.71594],[35.11895,31.71454],[35.12933,31.7325],[35.13931,31.73012],[35.15119,31.73634],[35.15474,31.73352],[35.16478,31.73242],[35.18023,31.72067],[35.20538,31.72388],[35.21937,31.71578],[35.22392,31.71899],[35.23972,31.70896],[35.24315,31.71244],[35.2438,31.7201],[35.24981,31.72543],[35.25182,31.73945],[35.26319,31.74846],[35.25225,31.7678],[35.26058,31.79064],[35.25573,31.81362],[35.26404,31.82567],[35.251,31.83085],[35.25753,31.8387],[35.24816,31.8458],[35.2304,31.84222],[35.2249,31.85433],[35.22817,31.8638],[35.22567,31.86745],[35.22294,31.87889],[35.22014,31.88264],[35.2136,31.88241],[35.21276,31.88153],[35.21016,31.88237],[35.20945,31.8815],[35.20791,31.8821],[35.20673,31.88151],[35.20381,31.86716],[35.21128,31.863],[35.216,31.83894],[35.21469,31.81835],[35.19461,31.82687],[35.18169,31.82542],[35.18603,31.80901],[35.14174,31.81325],[35.07677,31.85627],[35.05617,31.85685],[35.01978,31.82944],[34.9724,31.83352],[34.99712,31.85569],[35.03489,31.85919],[35.03978,31.89276],[35.03489,31.92448],[35.00124,31.93264],[34.98682,31.96935],[35.00261,32.027],[34.9863,32.09551],[34.99437,32.10962],[34.98507,32.12606],[34.99039,32.14626],[34.96009,32.17503],[34.95703,32.19522],[34.98885,32.20758],[35.01841,32.23981],[35.02939,32.2671],[35.01119,32.28684],[35.01772,32.33863],[35.04243,32.35008],[35.05142,32.3667],[35.0421,32.38242],[35.05311,32.4024],[35.05423,32.41754],[35.07059,32.4585],[35.08564,32.46948],[35.09236,32.47614],[35.10024,32.47856],[35.10882,32.4757],[35.15937,32.50466],[35.2244,32.55289],[35.25049,32.52453],[35.29306,32.50947],[35.30685,32.51024],[35.35212,32.52047],[35.40224,32.50136],[35.42034,32.46009],[35.41598,32.45593],[35.41048,32.43706],[35.42078,32.41562],[35.55807,32.38674],[35.55494,32.42687],[35.57485,32.48669],[35.56614,32.64393],[35.59813,32.65159],[35.61669,32.67999],[35.66527,32.681],[35.68467,32.70715],[35.75983,32.74803],[35.78745,32.77938],[35.83758,32.82817],[35.84021,32.8725],[35.87012,32.91976],[35.89298,32.9456],[35.87188,32.98028],[35.84802,33.1031],[35.81911,33.11077],[35.81911,33.1336],[35.84285,33.16673],[35.83846,33.19397],[35.81647,33.2028],[35.81295,33.24841],[35.77513,33.27342],[35.813,33.3172],[35.77477,33.33609],[35.62019,33.27278],[35.62283,33.24226],[35.58502,33.26653],[35.58326,33.28381],[35.56523,33.28969],[35.55555,33.25844],[35.54544,33.25513],[35.54808,33.236],[35.5362,33.23196],[35.54228,33.19865],[35.52573,33.11921],[35.50335,33.114],[35.50272,33.09056],[35.448,33.09264],[35.43059,33.06659],[35.35223,33.05617],[35.31429,33.10515],[35.1924,33.08743],[35.10645,33.09318],[34.78515,33.20368],[33.62659,31.82938],[34.052,31.46619]]]]}},{type:"Feature",properties:{iso1A2:"IM",iso1A3:"IMN",iso1N3:"833",wikidata:"Q9676",nameEn:"Isle of Man",country:"GB",groups:["154","150"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["44 01624","44 07624","44 07524","44 07924"]},geometry:{type:"MultiPolygon",coordinates:[[[[-3.64906,54.12723],[-4.1819,54.57861],[-5.83481,53.87749],[-5.37267,53.63269],[-3.64906,54.12723]]]]}},{type:"Feature",properties:{iso1A2:"IN",iso1A3:"IND",iso1N3:"356",wikidata:"Q668",nameEn:"India",groups:["034","142"],driveSide:"left",callingCodes:["91"]},geometry:{type:"MultiPolygon",coordinates:[[[[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],[72.15131,7.6285],[78.52781,7.63099],[79.50447,8.91876],[79.42124,9.80115],[80.48418,10.20786],[94.53911,5.99016],[94.6371,13.81803],[92.61042,13.76986],[89.13606,21.42955],[89.13927,21.60785],[89.03553,21.77397],[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.08507,28.38346],[80.89648,28.47237],[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.56957,29.88176],[80.60226,29.95732],[80.67076,29.95732],[80.8778,30.13384],[80.93695,30.18229],[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.22805,31.34963],[79.14016,31.43403],[79.01931,31.42817],[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]]]]}},{type:"Feature",properties:{iso1A2:"IO",iso1A3:"IOT",iso1N3:"086",wikidata:"Q43448",nameEn:"British Indian Ocean Territory",country:"GB",groups:["014","202","002"],callingCodes:["246"]},geometry:{type:"MultiPolygon",coordinates:[[[[70.64754,-4.95745],[70.67958,-8.2663],[73.70488,-4.92492],[70.64754,-4.95745]]]]}},{type:"Feature",properties:{iso1A2:"IQ",iso1A3:"IRQ",iso1N3:"368",wikidata:"Q796",nameEn:"Iraq",groups:["145","142"],callingCodes:["964"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"IR",iso1A3:"IRN",iso1N3:"364",wikidata:"Q794",nameEn:"Iran",groups:["034","142"],callingCodes:["98"]},geometry:{type:"MultiPolygon",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.5251,24.57287],[61.57592,25.0492],[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]]]]}},{type:"Feature",properties:{iso1A2:"IS",iso1A3:"ISL",iso1N3:"352",wikidata:"Q189",nameEn:"Iceland",groups:["154","150"],callingCodes:["354"]},geometry:{type:"MultiPolygon",coordinates:[[[[-33.15676,62.62995],[-8.25539,63.0423],[-15.70914,69.67442],[-33.15676,62.62995]]]]}},{type:"Feature",properties:{iso1A2:"IT",iso1A3:"ITA",iso1N3:"380",wikidata:"Q38",nameEn:"Italy",groups:["EU","039","150"],callingCodes:["39"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"JE",iso1A3:"JEY",iso1N3:"832",wikidata:"Q785",nameEn:"Jersey",country:"GB",groups:["830","154","150"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["44 01534"]},geometry:{type:"MultiPolygon",coordinates:[[[[-2.00491,48.86706],[-1.83944,49.23037],[-2.09454,49.46288],[-2.65349,49.15373],[-2.00491,48.86706]]]]}},{type:"Feature",properties:{iso1A2:"JM",iso1A3:"JAM",iso1N3:"388",wikidata:"Q766",nameEn:"Jamaica",aliases:["JA"],groups:["029","003","419","019"],driveSide:"left",callingCodes:["1 876","1 658"]},geometry:{type:"MultiPolygon",coordinates:[[[[-75.50728,17.08879],[-76.34192,18.86145],[-78.75694,18.78765],[-78.34606,16.57862],[-75.50728,17.08879]]]]}},{type:"Feature",properties:{iso1A2:"JO",iso1A3:"JOR",iso1N3:"400",wikidata:"Q810",nameEn:"Jordan",groups:["145","142"],callingCodes:["962"]},geometry:{type:"MultiPolygon",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.88293,29.37455],[34.95987,29.35727],[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]]]]}},{type:"Feature",properties:{iso1A2:"JP",iso1A3:"JPN",iso1N3:"392",wikidata:"Q17",nameEn:"Japan",groups:["030","142"],driveSide:"left",callingCodes:["81"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"KE",iso1A3:"KEN",iso1N3:"404",wikidata:"Q114",nameEn:"Kenya",groups:["014","202","002"],driveSide:"left",callingCodes:["254"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"KG",iso1A3:"KGZ",iso1N3:"417",wikidata:"Q813",nameEn:"Kyrgyzstan",groups:["143","142"],callingCodes:["996"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"KH",iso1A3:"KHM",iso1N3:"116",wikidata:"Q424",nameEn:"Cambodia",groups:["035","142"],callingCodes:["855"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"KI",iso1A3:"KIR",iso1N3:"296",wikidata:"Q710",nameEn:"Kiribati",groups:["057","009"],driveSide:"left",callingCodes:["686"]},geometry:{type:"MultiPolygon",coordinates:[[[[169,3.9],[169,-3.5],[178,-3.5],[178,3.9],[169,3.9]]],[[[-158.62058,-1.35506],[-161.04969,-1.36251],[-175.33482,-1.40631],[-175.31804,-7.54825],[-174.18707,-7.54408],[-167.75329,-7.52784],[-156.50903,-7.4975],[-156.4957,-12.32002],[-149.61166,-12.30171],[-149.6249,-7.51261],[-149.65979,5.27712],[-161.06795,5.2462],[-161.05669,1.11722],[-158.62734,1.1296],[-158.62058,-1.35506]]]]}},{type:"Feature",properties:{iso1A2:"KM",iso1A3:"COM",iso1N3:"174",wikidata:"Q970",nameEn:"Comoros",groups:["014","202","002"],callingCodes:["269"]},geometry:{type:"MultiPolygon",coordinates:[[[[42.93552,-11.11413],[42.99868,-12.65261],[44.75722,-12.58368],[44.69407,-11.04481],[42.93552,-11.11413]]]]}},{type:"Feature",properties:{iso1A2:"KN",iso1A3:"KNA",iso1N3:"659",wikidata:"Q763",nameEn:"St. Kitts and Nevis",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 869"]},geometry:{type:"MultiPolygon",coordinates:[[[[-62.27053,17.22145],[-62.76692,17.64353],[-63.11114,17.23125],[-62.62949,16.82364],[-62.27053,17.22145]]]]}},{type:"Feature",properties:{iso1A2:"KP",iso1A3:"PRK",iso1N3:"408",wikidata:"Q423",nameEn:"North Korea",groups:["030","142"],callingCodes:["850"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"KR",iso1A3:"KOR",iso1N3:"410",wikidata:"Q884",nameEn:"South Korea",groups:["030","142"],callingCodes:["82"]},geometry:{type:"MultiPolygon",coordinates:[[[[133.61399,37.41],[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.61399,37.41]]]]}},{type:"Feature",properties:{iso1A2:"KW",iso1A3:"KWT",iso1N3:"414",wikidata:"Q817",nameEn:"Kuwait",groups:["145","142"],callingCodes:["965"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"KY",iso1A3:"CYM",iso1N3:"136",wikidata:"Q5785",nameEn:"Cayman Islands",country:"GB",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 345"]},geometry:{type:"MultiPolygon",coordinates:[[[[-82.11509,19.60401],[-80.36068,18.11751],[-79.32727,20.06742],[-82.11509,19.60401]]]]}},{type:"Feature",properties:{iso1A2:"KZ",iso1A3:"KAZ",iso1N3:"398",wikidata:"Q232",nameEn:"Kazakhstan",groups:["143","142"],callingCodes:["7"]},geometry:{type:"MultiPolygon",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],[46.98795,49.23531],[47.04416,49.17152],[47.01458,49.07085],[46.91104,48.99715],[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]]]]}},{type:"Feature",properties:{iso1A2:"LA",iso1A3:"LAO",iso1N3:"418",wikidata:"Q819",nameEn:"Laos",groups:["035","142"],callingCodes:["856"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LB",iso1A3:"LBN",iso1N3:"422",wikidata:"Q822",nameEn:"Lebanon",aliases:["RL"],groups:["145","142"],callingCodes:["961"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LC",iso1A3:"LCA",iso1N3:"662",wikidata:"Q760",nameEn:"St. Lucia",aliases:["WL"],groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 758"]},geometry:{type:"MultiPolygon",coordinates:[[[[-60.5958,14.23076],[-61.26561,14.25664],[-61.43129,13.68336],[-60.70539,13.41452],[-60.5958,14.23076]]]]}},{type:"Feature",properties:{iso1A2:"LI",iso1A3:"LIE",iso1N3:"438",wikidata:"Q347",nameEn:"Liechtenstein",aliases:["FL"],groups:["155","150"],callingCodes:["423"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LK",iso1A3:"LKA",iso1N3:"144",wikidata:"Q854",nameEn:"Sri Lanka",groups:["034","142"],driveSide:"left",callingCodes:["94"]},geometry:{type:"MultiPolygon",coordinates:[[[[76.25812,4.62435],[85.15017,5.21497],[80.48418,10.20786],[79.42124,9.80115],[79.50447,8.91876],[76.25812,4.62435]]]]}},{type:"Feature",properties:{iso1A2:"LR",iso1A3:"LBR",iso1N3:"430",wikidata:"Q1014",nameEn:"Liberia",groups:["011","202","002"],callingCodes:["231"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LS",iso1A3:"LSO",iso1N3:"426",wikidata:"Q1013",nameEn:"Lesotho",groups:["018","202","002"],driveSide:"left",callingCodes:["266"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LT",iso1A3:"LTU",iso1N3:"440",wikidata:"Q37",nameEn:"Lithuania",groups:["EU","154","150"],callingCodes:["370"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LU",iso1A3:"LUX",iso1N3:"442",wikidata:"Q32",nameEn:"Luxembourg",groups:["EU","155","150"],callingCodes:["352"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LV",iso1A3:"LVA",iso1N3:"428",wikidata:"Q211",nameEn:"Latvia",groups:["EU","154","150"],callingCodes:["371"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"LY",iso1A3:"LBY",iso1N3:"434",wikidata:"Q1016",nameEn:"Libya",groups:["015","002"],callingCodes:["218"]},geometry:{type:"MultiPolygon",coordinates:[[[[22.5213,33.45682],[11.66543,33.34642],[11.56255,33.16754],[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.83101,31.31921],[25.06041,31.57937],[25.14001,31.67534],[25.63787,31.9359],[22.5213,33.45682]]]]}},{type:"Feature",properties:{iso1A2:"MA",iso1A3:"MAR",iso1N3:"504",wikidata:"Q1028",nameEn:"Morocco",groups:["015","002"],callingCodes:["212"]},geometry:{type:"MultiPolygon",coordinates:[[[[-2.27707,35.35051],[-2.85819,35.63219],[-5.10878,36.05227],[-5.64962,35.93752],[-7.27694,35.93599],[-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.92224,35.3401],[-2.92181,35.28599],[-2.92674,35.27313],[-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.92224,35.3401]],[[-3.90602,35.21494],[-3.90288,35.22024],[-3.88617,35.21406],[-3.88926,35.20841],[-3.90602,35.21494]],[[-4.30191,35.17419],[-4.29436,35.17149],[-4.30112,35.17058],[-4.30191,35.17419]],[[-2.41312,35.17111],[-2.44887,35.17075],[-2.44896,35.18777],[-2.41265,35.1877],[-2.41312,35.17111]],[[-5.38491,35.92591],[-5.27635,35.91222],[-5.27056,35.88794],[-5.34379,35.8711],[-5.35844,35.87375],[-5.37338,35.88417],[-5.38491,35.92591]]]]}},{type:"Feature",properties:{iso1A2:"MC",iso1A3:"MCO",iso1N3:"492",wikidata:"Q235",nameEn:"Monaco",groups:["155","150"],callingCodes:["377"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"MD",iso1A3:"MDA",iso1N3:"498",wikidata:"Q217",nameEn:"Moldova",groups:["151","150"],callingCodes:["373"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"ME",iso1A3:"MNE",iso1N3:"499",wikidata:"Q236",nameEn:"Montenegro",groups:["039","150"],callingCodes:["382"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"MF",iso1A3:"MAF",iso1N3:"663",wikidata:"Q126125",nameEn:"Saint-Martin",country:"FR",groups:["EU","029","003","419","019"],callingCodes:["590"]},geometry:{type:"MultiPolygon",coordinates:[[[[-62.93924,18.02904],[-62.75637,18.13489],[-62.86666,18.19278],[-63.35989,18.06012],[-63.33064,17.9615],[-63.13584,18.0541],[-63.11096,18.05368],[-63.09686,18.04608],[-63.07759,18.04943],[-63.0579,18.06614],[-63.04039,18.05619],[-63.02323,18.05757],[-62.93924,18.02904]]]]}},{type:"Feature",properties:{iso1A2:"MG",iso1A3:"MDG",iso1N3:"450",wikidata:"Q1019",nameEn:"Madagascar",aliases:["RM"],groups:["014","202","002"],callingCodes:["261"]},geometry:{type:"MultiPolygon",coordinates:[[[[51.94557,-12.74579],[49.10033,-10.96054],[43.72277,-16.09877],[40.40841,-23.17181],[45.90777,-29.77366],[51.94557,-12.74579]]]]}},{type:"Feature",properties:{iso1A2:"MH",iso1A3:"MHL",iso1N3:"584",wikidata:"Q709",nameEn:"Marshall Islands",groups:["057","009"],roadSpeedUnit:"mph",callingCodes:["692"]},geometry:{type:"MultiPolygon",coordinates:[[[[169,3.9],[173.53711,5.70687],[169.29099,15.77133],[159.04653,10.59067],[169,3.9]]]]}},{type:"Feature",properties:{iso1A2:"MK",iso1A3:"MKD",iso1N3:"807",wikidata:"Q221",nameEn:"North Macedonia",groups:["039","150"],callingCodes:["389"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"ML",iso1A3:"MLI",iso1N3:"466",wikidata:"Q912",nameEn:"Mali",groups:["011","202","002"],callingCodes:["223"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"MM",iso1A3:"MMR",iso1N3:"104",wikidata:"Q836",nameEn:"Myanmar",aliases:["Burma","BU"],groups:["035","142"],callingCodes:["95"]},geometry:{type:"MultiPolygon",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.37665,20.72172],[92.28464,20.63179],[92.31348,20.57137],[92.4302,20.5688],[92.39837,20.38919],[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]]]]}},{type:"Feature",properties:{iso1A2:"MN",iso1A3:"MNG",iso1N3:"496",wikidata:"Q711",nameEn:"Mongolia",groups:["030","142"],callingCodes:["976"]},geometry:{type:"MultiPolygon",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.28833,42.58524],[101.80515,42.50074],[102.07645,42.22519],[102.42826,42.15137],[102.72403,42.14675],[103.3685,41.89696],[103.92804,41.78246],[104.52258,41.8706],[104.51667,41.66113],[104.91272,41.64619],[105.01119,41.58382],[105.24708,41.7442],[106.76517,42.28741],[107.24774,42.36107],[107.29755,42.41395],[107.49681,42.46221],[107.57258,42.40898],[108.23156,42.45532],[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.63821,44.74326],[113.909,44.91444],[114.08071,44.92847],[114.5166,45.27189],[114.54801,45.38337],[114.74612,45.43585],[114.94546,45.37377],[115.35757,45.39106],[115.69688,45.45761],[115.91898,45.6227],[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.07252,46.35818],[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.30261,46.6083],[119.37306,46.61132],[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],[117.08918,47.82242],[116.87527,47.88836],[116.67405,47.89039],[116.4465,47.83662],[116.2527,47.87766],[116.08431,47.80693],[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]]]]}},{type:"Feature",properties:{iso1A2:"MO",iso1A3:"MAC",iso1N3:"446",wikidata:"Q14773",nameEn:"Macau",aliases:["Macao"],country:"CN",groups:["030","142"],driveSide:"left",callingCodes:["853"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"MP",iso1A3:"MNP",iso1N3:"580",wikidata:"Q16644",nameEn:"Northern Mariana Islands",country:"US",groups:["057","009"],roadSpeedUnit:"mph",callingCodes:["1 670"]},geometry:{type:"MultiPolygon",coordinates:[[[[143.82485,13.92273],[146.25931,13.85876],[146.6755,21.00809],[144.18594,21.03576],[143.82485,13.92273]]]]}},{type:"Feature",properties:{iso1A2:"MQ",iso1A3:"MTQ",iso1N3:"474",wikidata:"Q17054",nameEn:"Martinique",country:"FR",groups:["EU","029","003","419","019"],callingCodes:["596"]},geometry:{type:"MultiPolygon",coordinates:[[[[-60.5958,14.23076],[-60.69955,15.22234],[-61.51867,14.96709],[-61.26561,14.25664],[-60.5958,14.23076]]]]}},{type:"Feature",properties:{iso1A2:"MR",iso1A3:"MRT",iso1N3:"478",wikidata:"Q1025",nameEn:"Mauritania",groups:["011","202","002"],callingCodes:["222"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"MS",iso1A3:"MSR",iso1N3:"500",wikidata:"Q13353",nameEn:"Montserrat",country:"GB",groups:["029","003","419","019"],driveSide:"left",callingCodes:["1 664"]},geometry:{type:"MultiPolygon",coordinates:[[[[-61.83929,16.66647],[-62.14123,17.02632],[-62.52079,16.69392],[-62.17275,16.35721],[-61.83929,16.66647]]]]}},{type:"Feature",properties:{iso1A2:"MT",iso1A3:"MLT",iso1N3:"470",wikidata:"Q233",nameEn:"Malta",groups:["EU","039","150"],driveSide:"left",callingCodes:["356"]},geometry:{type:"MultiPolygon",coordinates:[[[[15.70991,35.79901],[14.07544,36.41525],[13.27636,35.20764],[15.70991,35.79901]]]]}},{type:"Feature",properties:{iso1A2:"MU",iso1A3:"MUS",iso1N3:"480",wikidata:"Q1027",nameEn:"Mauritius",groups:["014","202","002"],driveSide:"left",callingCodes:["230"]},geometry:{type:"MultiPolygon",coordinates:[[[[56.73473,-21.9174],[64.11105,-21.5783],[63.47388,-9.1938],[56.09755,-9.55401],[56.73473,-21.9174]]]]}},{type:"Feature",properties:{iso1A2:"MV",iso1A3:"MDV",iso1N3:"462",wikidata:"Q826",nameEn:"Maldives",groups:["034","142"],driveSide:"left",callingCodes:["960"]},geometry:{type:"MultiPolygon",coordinates:[[[[71.27292,7.36038],[73.37814,-3.88401],[74.6203,7.39289],[71.27292,7.36038]]]]}},{type:"Feature",properties:{iso1A2:"MW",iso1A3:"MWI",iso1N3:"454",wikidata:"Q1020",nameEn:"Malawi",groups:["014","202","002"],driveSide:"left",callingCodes:["265"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"MX",iso1A3:"MEX",iso1N3:"484",wikidata:"Q96",nameEn:"Mexico",groups:["013","003","419","019"],callingCodes:["52"]},geometry:{type:"MultiPolygon",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],[-109.05235,31.3333],[-111.07523,31.33232],[-112.34553,31.7357],[-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]]]]}},{type:"Feature",properties:{iso1A2:"MY",iso1A3:"MYS",iso1N3:"458",wikidata:"Q833",nameEn:"Malaysia",groups:["035","142"],driveSide:"left",callingCodes:["60"]},geometry:{type:"MultiPolygon",coordinates:[[[[114.08532,4.64632],[109.55486,8.10026],[104.81582,8.03101],[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],[108.10426,5.42408],[109.71058,2.32059],[109.64506,2.08014],[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],[117.89538,4.16637],[118.07935,4.15511],[118.8663,4.44172],[118.75416,4.59798],[119.44841,5.09568],[119.34756,5.53889],[117.89159,6.25755],[117.43832,7.3895],[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.08532,4.64632]]]]}},{type:"Feature",properties:{iso1A2:"MZ",iso1A3:"MOZ",iso1N3:"508",wikidata:"Q1029",nameEn:"Mozambique",groups:["014","202","002"],driveSide:"left",callingCodes:["258"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"NA",iso1A3:"NAM",iso1N3:"516",wikidata:"Q1030",nameEn:"Namibia",groups:["018","202","002"],driveSide:"left",callingCodes:["264"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"NC",iso1A3:"NCL",iso1N3:"540",wikidata:"Q33788",nameEn:"New Caledonia",country:"FR",groups:["054","009"],callingCodes:["687"]},geometry:{type:"MultiPolygon",coordinates:[[[[158.65519,-23.4036],[174.90025,-23.53966],[162.93363,-17.28904],[157.83842,-18.82563],[158.65519,-23.4036]]]]}},{type:"Feature",properties:{iso1A2:"NE",iso1A3:"NER",iso1N3:"562",wikidata:"Q1032",nameEn:"Niger",aliases:["RN"],groups:["011","202","002"],callingCodes:["227"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"NF",iso1A3:"NFK",iso1N3:"574",wikidata:"Q31057",nameEn:"Norfolk Island",country:"AU",groups:["053","009"],driveSide:"left",callingCodes:["672 3"]},geometry:{type:"MultiPolygon",coordinates:[[[[169.82316,-28.16667],[166.29505,-28.29175],[167.94076,-30.60745],[169.82316,-28.16667]]]]}},{type:"Feature",properties:{iso1A2:"NG",iso1A3:"NGA",iso1N3:"566",wikidata:"Q1033",nameEn:"Nigeria",groups:["011","202","002"],callingCodes:["234"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"NI",iso1A3:"NIC",iso1N3:"558",wikidata:"Q811",nameEn:"Nicaragua",groups:["013","003","419","019"],callingCodes:["505"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"NL",iso1A3:"NLD",iso1N3:"528",wikidata:"Q55",nameEn:"Netherlands",groups:["EU","155","150"],callingCodes:["31"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"NO",iso1A3:"NOR",iso1N3:"578",wikidata:"Q20",nameEn:"Norway",groups:["154","150"],callingCodes:["47"]},geometry:{type:"MultiPolygon",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],[18.46509,71.28681],[-0.3751,61.32236],[7.28637,57.35913],[10.40861,58.38489]]]]}},{type:"Feature",properties:{iso1A2:"NP",iso1A3:"NPL",iso1N3:"524",wikidata:"Q837",nameEn:"Nepal",groups:["034","142"],driveSide:"left",callingCodes:["977"]},geometry:{type:"MultiPolygon",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.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.93695,30.18229],[80.8778,30.13384],[80.67076,29.95732],[80.60226,29.95732],[80.56957,29.88176],[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],[80.89648,28.47237],[81.08507,28.38346],[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]]]]}},{type:"Feature",properties:{iso1A2:"NR",iso1A3:"NRU",iso1N3:"520",wikidata:"Q697",nameEn:"Nauru",groups:["057","009"],driveSide:"left",callingCodes:["674"]},geometry:{type:"MultiPolygon",coordinates:[[[[166.95155,0.14829],[166.21778,-0.7977],[167.60042,-0.88259],[166.95155,0.14829]]]]}},{type:"Feature",properties:{iso1A2:"NU",iso1A3:"NIU",iso1N3:"570",wikidata:"Q34020",nameEn:"Niue",country:"NZ",groups:["061","009"],driveSide:"left",callingCodes:["683"]},geometry:{type:"MultiPolygon",coordinates:[[[[-173.13438,-14.94228],[-173.11048,-23.23027],[-167.73129,-23.22266],[-167.73854,-14.92809],[-171.14262,-14.93704],[-173.13438,-14.94228]]]]}},{type:"Feature",properties:{iso1A2:"NZ",iso1A3:"NZL",iso1N3:"554",wikidata:"Q664",nameEn:"New Zealand",groups:["053","009"],driveSide:"left",callingCodes:["64"]},geometry:{type:"MultiPolygon",coordinates:[[[[-180,-24.21376],[-179.93224,-45.18423],[-155.99562,-45.16785],[-180,-24.21376]]],[[[161.96603,-56.07661],[179.49541,-50.04657],[179.49541,-36.79303],[169.6687,-29.09191],[161.96603,-56.07661]]]]}},{type:"Feature",properties:{iso1A2:"OM",iso1A3:"OMN",iso1N3:"512",wikidata:"Q842",nameEn:"Oman",groups:["145","142"],callingCodes:["968"]},geometry:{type:"MultiPolygon",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],[53.09917,16.67084],[53.32998,16.16312],[56.66759,17.24021],[61.45114,22.55394]]]]}},{type:"Feature",properties:{iso1A2:"PA",iso1A3:"PAN",iso1N3:"591",wikidata:"Q804",nameEn:"Panama",groups:["013","003","419","019"],callingCodes:["507"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"PE",iso1A3:"PER",iso1N3:"604",wikidata:"Q419",nameEn:"Peru",groups:["005","419","019"],callingCodes:["51"]},geometry:{type:"MultiPolygon",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.24475,-3.47846],[-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]]]]}},{type:"Feature",properties:{iso1A2:"PF",iso1A3:"PYF",iso1N3:"258",wikidata:"Q30971",nameEn:"French Polynesia",country:"FR",groups:["061","009"],callingCodes:["689"]},geometry:{type:"MultiPolygon",coordinates:[[[[-149.6249,-7.51261],[-149.61166,-12.30171],[-156.4957,-12.32002],[-156.46451,-23.21255],[-156.44843,-28.52556],[-133.59543,-28.4709],[-133.61511,-21.93325],[-133.65593,-7.46952],[-149.6249,-7.51261]]]]}},{type:"Feature",properties:{iso1A2:"PG",iso1A3:"PNG",iso1N3:"598",wikidata:"Q691",nameEn:"Papua New Guinea",groups:["054","009"],driveSide:"left",callingCodes:["675"]},geometry:{type:"MultiPolygon",coordinates:[[[[141.03157,2.12829],[140.99813,-6.3233],[140.85295,-6.72996],[141.01763,-6.90181],[141.00782,-9.1242],[140.88922,-9.34945],[142.0601,-9.56571],[142.0953,-9.23534],[142.1462,-9.19923],[142.23304,-9.19253],[142.31447,-9.24611],[142.5723,-9.35994],[142.81927,-9.31709],[144.30183,-9.48146],[155.22803,-12.9001],[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]]]]}},{type:"Feature",properties:{iso1A2:"PH",iso1A3:"PHL",iso1N3:"608",wikidata:"Q928",nameEn:"Philippines",aliases:["PI","RP"],groups:["035","142"],callingCodes:["63"]},geometry:{type:"MultiPolygon",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.43832,7.3895],[117.89159,6.25755],[119.34756,5.53889],[119.44841,5.09568],[118.75416,4.59798],[118.8663,4.44172],[118.07935,4.15511],[118.41402,3.99509],[124.97752,4.82064],[129.19694,7.84182]]]]}},{type:"Feature",properties:{iso1A2:"PK",iso1A3:"PAK",iso1N3:"586",wikidata:"Q843",nameEn:"Pakistan",groups:["034","142"],driveSide:"left",callingCodes:["92"]},geometry:{type:"MultiPolygon",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.57592,25.0492],[61.5251,24.57287],[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]]]]}},{type:"Feature",properties:{iso1A2:"PL",iso1A3:"POL",iso1N3:"616",wikidata:"Q36",nameEn:"Poland",groups:["EU","151","150"],callingCodes:["48"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"PM",iso1A3:"SPM",iso1N3:"666",wikidata:"Q34617",nameEn:"Saint Pierre and Miquelon",country:"FR",groups:["021","003","019"],callingCodes:["508"]},geometry:{type:"MultiPolygon",coordinates:[[[[-56.72993,46.65575],[-55.90758,46.6223],[-56.27503,47.39728],[-56.72993,46.65575]]]]}},{type:"Feature",properties:{iso1A2:"PN",iso1A3:"PCN",iso1N3:"612",wikidata:"Q35672",nameEn:"Pitcairn Islands",country:"GB",groups:["061","009"],driveSide:"left",callingCodes:["64"]},geometry:{type:"MultiPolygon",coordinates:[[[[-133.59543,-28.4709],[-122.0366,-24.55017],[-133.61511,-21.93325],[-133.59543,-28.4709]]]]}},{type:"Feature",properties:{iso1A2:"PR",iso1A3:"PRI",iso1N3:"630",wikidata:"Q1183",nameEn:"Puerto Rico",country:"US",groups:["029","003","419","019"],roadSpeedUnit:"mph",callingCodes:["1 787","1 939"]},geometry:{type:"MultiPolygon",coordinates:[[[[-65.27974,17.56928],[-65.02435,18.73231],[-67.99519,18.97186],[-68.20301,17.83927],[-65.27974,17.56928]]]]}},{type:"Feature",properties:{iso1A2:"PS",iso1A3:"PSE",iso1N3:"275",wikidata:"Q23792",nameEn:"Palestine",country:"IL",groups:["145","142"],callingCodes:["970"]},geometry:{type:"MultiPolygon",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]]],[[[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]]]]}},{type:"Feature",properties:{iso1A2:"PT",iso1A3:"PRT",iso1N3:"620",wikidata:"Q45",nameEn:"Portugal",groups:["EU","039","150"],callingCodes:["351"]},geometry:{type:"MultiPolygon",coordinates:[[[[-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],[-9.14112,41.86623],[-36.43765,41.39418],[-15.92339,29.50503],[-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]]]]}},{type:"Feature",properties:{iso1A2:"PW",iso1A3:"PLW",iso1N3:"585",wikidata:"Q695",nameEn:"Palau",groups:["057","009"],roadSpeedUnit:"mph",callingCodes:["680"]},geometry:{type:"MultiPolygon",coordinates:[[[[128.97621,3.08804],[134.40878,1.79674],[136.27107,6.73747],[136.04605,12.45908],[128.97621,3.08804]]]]}},{type:"Feature",properties:{iso1A2:"PY",iso1A3:"PRY",iso1N3:"600",wikidata:"Q733",nameEn:"Paraguay",groups:["005","419","019"],callingCodes:["595"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"QA",iso1A3:"QAT",iso1N3:"634",wikidata:"Q846",nameEn:"Qatar",groups:["145","142"],callingCodes:["974"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"RE",iso1A3:"REU",iso1N3:"638",wikidata:"Q17070",nameEn:"Réunion",country:"FR",groups:["EU","014","202","002"],callingCodes:["262"]},geometry:{type:"MultiPolygon",coordinates:[[[[53.37984,-21.23941],[56.73473,-21.9174],[56.62373,-20.2711],[53.37984,-21.23941]]]]}},{type:"Feature",properties:{iso1A2:"RO",iso1A3:"ROU",iso1N3:"642",wikidata:"Q218",nameEn:"Romania",groups:["EU","151","150"],callingCodes:["40"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"RS",iso1A3:"SRB",iso1N3:"688",wikidata:"Q403",nameEn:"Serbia",groups:["039","150"],callingCodes:["381"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"RU",iso1A3:"RUS",iso1N3:"643",wikidata:"Q159",nameEn:"Russia",groups:["151","150"],callingCodes:["7"]},geometry:{type:"MultiPolygon",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]]],[[[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],[46.91104,48.99715],[47.01458,49.07085],[47.04416,49.17152],[46.98795,49.23531],[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],[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.07142,49.68482],[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],[36.48095,82.16765],[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],[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],[34.96015,45.75634],[34.79905,45.81009],[34.80153,45.90047],[34.75479,45.90705],[34.66679,45.97136],[34.60861,45.99347],[34.55889,45.99347],[34.52011,45.95097],[34.48729,45.94267],[34.44155,45.95995],[34.41221,46.00245],[34.33912,46.06114],[34.25111,46.0532],[34.181,46.06804],[34.12929,46.10494],[34.07311,46.11769],[34.05272,46.10838],[33.91549,46.15938],[33.85234,46.19863],[33.79715,46.20482],[33.74047,46.18555],[33.646,46.23028],[33.61517,46.22615],[33.63854,46.14147],[33.61467,46.13561],[33.57318,46.10317],[33.59087,46.06013],[33.54017,46.0123],[31.62627,45.50633],[32.99857,44.48323],[33.66142,43.9825],[39.81147,43.06294]]],[[[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],[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]]]]}},{type:"Feature",properties:{iso1A2:"RW",iso1A3:"RWA",iso1N3:"646",wikidata:"Q1037",nameEn:"Rwanda",groups:["014","202","002"],callingCodes:["250"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SA",iso1A3:"SAU",iso1N3:"682",wikidata:"Q851",nameEn:"Saudi Arabia",groups:["145","142"],callingCodes:["966"]},geometry:{type:"MultiPolygon",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.95987,29.35727],[34.88293,29.37455],[34.46254,27.99552],[34.51305,27.70027],[37.8565,22.00903],[39.63762,18.37348],[41.37609,16.19728],[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]]]]}},{type:"Feature",properties:{iso1A2:"SB",iso1A3:"SLB",iso1N3:"090",wikidata:"Q685",nameEn:"Solomon Islands",groups:["054","009"],driveSide:"left",callingCodes:["677"]},geometry:{type:"MultiPolygon",coordinates:[[[[174,-12.72535],[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],[160.04026,-13.08769],[174,-12.72535]]]]}},{type:"Feature",properties:{iso1A2:"SC",iso1A3:"SYC",iso1N3:"690",wikidata:"Q1042",nameEn:"Seychelles",groups:["014","202","002"],driveSide:"left",callingCodes:["248"]},geometry:{type:"MultiPolygon",coordinates:[[[[43.75112,-10.38913],[54.83239,-10.93575],[66.3222,5.65313],[43.75112,-10.38913]]]]}},{type:"Feature",properties:{iso1A2:"SD",iso1A3:"SDN",iso1N3:"729",wikidata:"Q1049",nameEn:"Sudan",groups:["015","002"],callingCodes:["249"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SE",iso1A3:"SWE",iso1N3:"752",wikidata:"Q34",nameEn:"Sweden",groups:["EU","154","150"],callingCodes:["46"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SG",iso1A3:"SGP",iso1N3:"702",wikidata:"Q334",nameEn:"Singapore",groups:["035","142"],driveSide:"left",callingCodes:["65"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SH",iso1A3:"SHN",iso1N3:"654",wikidata:"Q34497",nameEn:"Saint Helena, Ascension and Tristan da Cunha",country:"GB",groups:["011","202","002"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["290"]},geometry:{type:"MultiPolygon",coordinates:[[[[-14.82771,-8.70814],[-13.48367,-36.6746],[-11.55782,-36.60319],[-11.48092,-37.8367],[-13.41694,-37.88844],[-13.29655,-40.02846],[-9.34669,-41.00353],[-4.97086,-15.55882],[-13.33271,-8.07391],[-14.82771,-8.70814]]]]}},{type:"Feature",properties:{iso1A2:"SI",iso1A3:"SVN",iso1N3:"705",wikidata:"Q215",nameEn:"Slovenia",groups:["EU","039","150"],callingCodes:["386"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SJ",iso1A3:"SJM",iso1N3:"744",wikidata:"Q842829",nameEn:"Svalbard and Jan Mayen",country:"NO",groups:["154","150"],callingCodes:["47 79"]},geometry:{type:"MultiPolygon",coordinates:[[[[-7.49892,77.24208],[32.07813,72.01005],[36.85549,84.09565],[-7.49892,77.24208]]],[[[-9.18243,72.23144],[-10.71459,70.09565],[-5.93364,70.76368],[-9.18243,72.23144]]]]}},{type:"Feature",properties:{iso1A2:"SK",iso1A3:"SVK",iso1N3:"703",wikidata:"Q214",nameEn:"Slovakia",groups:["EU","151","150"],callingCodes:["421"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SL",iso1A3:"SLE",iso1N3:"694",wikidata:"Q1044",nameEn:"Sierra Leone",groups:["011","202","002"],callingCodes:["232"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SM",iso1A3:"SMR",iso1N3:"674",wikidata:"Q238",nameEn:"San Marino",groups:["039","150"],callingCodes:["378"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SN",iso1A3:"SEN",iso1N3:"686",wikidata:"Q1041",nameEn:"Senegal",groups:["011","202","002"],callingCodes:["221"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SO",iso1A3:"SOM",iso1N3:"706",wikidata:"Q1045",nameEn:"Somalia",groups:["014","202","002"],callingCodes:["252"]},geometry:{type:"MultiPolygon",coordinates:[[[[48.95249,11.56816],[43.42425,11.70983],[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],[49.16337,2.78611],[52.253,11.68582],[51.12877,12.56479],[48.95249,11.56816]]]]}},{type:"Feature",properties:{iso1A2:"SR",iso1A3:"SUR",iso1N3:"740",wikidata:"Q730",nameEn:"Suriname",groups:["005","419","019"],driveSide:"left",callingCodes:["597"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SS",iso1A3:"SSD",iso1N3:"728",wikidata:"Q958",nameEn:"South Sudan",groups:["014","202","002"],callingCodes:["211"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"ST",iso1A3:"STP",iso1N3:"678",wikidata:"Q1039",nameEn:"São Tomé and Principe",groups:["017","202","002"],callingCodes:["239"]},geometry:{type:"MultiPolygon",coordinates:[[[[5.9107,-0.09539],[6.69416,-0.53945],[8.0168,1.79377],[7.23334,2.23756],[5.9107,-0.09539]]]]}},{type:"Feature",properties:{iso1A2:"SV",iso1A3:"SLV",iso1N3:"222",wikidata:"Q792",nameEn:"El Salvador",groups:["013","003","419","019"],callingCodes:["503"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SX",iso1A3:"SXM",iso1N3:"534",wikidata:"Q26273",nameEn:"Sint Maarten",country:"NL",groups:["029","003","419","019"],callingCodes:["1 721"]},geometry:{type:"MultiPolygon",coordinates:[[[[-63.29212,17.90532],[-63.07669,17.79659],[-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.11096,18.05368],[-63.13584,18.0541],[-63.33064,17.9615],[-63.29212,17.90532]]]]}},{type:"Feature",properties:{iso1A2:"SY",iso1A3:"SYR",iso1N3:"760",wikidata:"Q858",nameEn:"Syria",groups:["145","142"],callingCodes:["963"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"SZ",iso1A3:"SWZ",iso1N3:"748",wikidata:"Q1050",nameEn:"Eswatini",aliases:["Swaziland"],groups:["018","202","002"],driveSide:"left",callingCodes:["268"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"TA",iso1A3:"TAA",wikidata:"Q220982",nameEn:"Tristan da Cunha",country:"GB",groups:["SH","011","202","002"],isoStatus:"excRes",driveSide:"left",roadSpeedUnit:"mph",callingCodes:["290 8","44 20"]},geometry:{type:"MultiPolygon",coordinates:[[[[-13.48367,-36.6746],[-13.41694,-37.88844],[-11.48092,-37.8367],[-11.55782,-36.60319],[-13.48367,-36.6746]]]]}},{type:"Feature",properties:{iso1A2:"TC",iso1A3:"TCA",iso1N3:"796",wikidata:"Q18221",nameEn:"Turks and Caicos Islands",country:"GB",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 649"]},geometry:{type:"MultiPolygon",coordinates:[[[[-72.41726,22.40371],[-72.72017,21.48055],[-71.46138,20.64433],[-70.63262,21.53631],[-72.41726,22.40371]]]]}},{type:"Feature",properties:{iso1A2:"TD",iso1A3:"TCD",iso1N3:"148",wikidata:"Q657",nameEn:"Chad",groups:["017","202","002"],callingCodes:["235"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"TF",iso1A3:"ATF",iso1N3:"260",wikidata:"Q129003",nameEn:"French Southern and Antarctic Lands",country:"FR",groups:["014","202","002"]},geometry:{type:"MultiPolygon",coordinates:[[[[53.53458,-16.36909],[54.96649,-16.28353],[54.61476,-15.02273],[53.53458,-16.36909]]],[[[39.10324,-21.48967],[40.40841,-23.17181],[43.72277,-16.09877],[41.06663,-17.08802],[39.10324,-21.48967]]],[[[46.52682,-10.83678],[47.29063,-12.45583],[48.86266,-10.8109],[46.52682,-10.83678]]],[[[80.15867,-36.04977],[46.31615,-46.28749],[70.67507,-51.14192],[80.15867,-36.04977]]]]}},{type:"Feature",properties:{iso1A2:"TG",iso1A3:"TGO",iso1N3:"768",wikidata:"Q945",nameEn:"Togo",groups:["011","202","002"],callingCodes:["228"]},geometry:{type:"MultiPolygon",coordinates:[[[[0.50388,11.01011],[-0.13493,11.14075],[-0.14462,11.10811],[-0.05733,11.08628],[-0.0275,11.11202],[-0.00514,11.10763],[0.00342,11.08317],[0.02395,11.06229],[0.03355,10.9807],[-0.0063,10.96417],[-0.00908,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]]]]}},{type:"Feature",properties:{iso1A2:"TH",iso1A3:"THA",iso1N3:"764",wikidata:"Q869",nameEn:"Thailand",groups:["035","142"],driveSide:"left",callingCodes:["66"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"TJ",iso1A3:"TJK",iso1N3:"762",wikidata:"Q863",nameEn:"Tajikistan",groups:["143","142"],callingCodes:["992"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"TK",iso1A3:"TKL",iso1N3:"772",wikidata:"Q36823",nameEn:"Tokelau",country:"NZ",groups:["061","009"],driveSide:"left",callingCodes:["690"]},geometry:{type:"MultiPolygon",coordinates:[[[[-167.75195,-10.12005],[-167.75329,-7.52784],[-174.18707,-7.54408],[-174.17993,-10.13616],[-167.75195,-10.12005]]]]}},{type:"Feature",properties:{iso1A2:"TL",iso1A3:"TLS",iso1N3:"626",wikidata:"Q574",nameEn:"East Timor",aliases:["Timor-Leste","TP"],groups:["035","142"],driveSide:"left",callingCodes:["670"]},geometry:{type:"MultiPolygon",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.65946,-8.06136],[125.31127,-8.22976],[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]]]]}},{type:"Feature",properties:{iso1A2:"TM",iso1A3:"TKM",iso1N3:"795",wikidata:"Q874",nameEn:"Turkmenistan",groups:["143","142"],callingCodes:["993"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"TN",iso1A3:"TUN",iso1N3:"788",wikidata:"Q948",nameEn:"Tunisia",groups:["015","002"],callingCodes:["216"]},geometry:{type:"MultiPolygon",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.56255,33.16754],[11.66543,33.34642],[11.2718,37.6713]]]]}},{type:"Feature",properties:{iso1A2:"TO",iso1A3:"TON",iso1N3:"776",wikidata:"Q678",nameEn:"Tonga",groups:["061","009"],driveSide:"left",callingCodes:["676"]},geometry:{type:"MultiPolygon",coordinates:[[[[-176.74538,-22.89767],[-180,-22.90585],[-180,-24.21376],[-173.10761,-24.19665],[-173.11048,-23.23027],[-173.13438,-14.94228],[-174.17905,-14.94502],[-176.76826,-14.95183],[-176.74538,-22.89767]]]]}},{type:"Feature",properties:{iso1A2:"TR",iso1A3:"TUR",iso1N3:"792",wikidata:"Q43",nameEn:"Turkey",groups:["145","142"],callingCodes:["90"]},geometry:{type:"MultiPolygon",coordinates:[[[[41.54366,41.52185],[40.89217,41.72528],[34.8305,42.4581],[28.32297,41.98371],[28.02971,41.98066],[27.91479,41.97902],[27.83492,41.99709],[27.81235,41.94803],[27.69949,41.97515],[27.55191,41.90928],[27.52379,41.93756],[27.45478,41.96591],[27.27411,42.10409],[27.22376,42.10152],[27.19251,42.06028],[27.08486,42.08735],[27.03277,42.0809],[26.95638,42.00741],[26.79143,41.97386],[26.62996,41.97644],[26.56051,41.92995],[26.57961,41.90024],[26.53968,41.82653],[26.36952,41.82265],[26.33589,41.76802],[26.32952,41.73637],[26.35957,41.71149],[26.47958,41.67037],[26.5209,41.62592],[26.59196,41.60491],[26.59742,41.48058],[26.61767,41.42281],[26.62997,41.34613],[26.5837,41.32131],[26.5209,41.33993],[26.39861,41.25053],[26.32259,41.24929],[26.31928,41.07386],[26.3606,41.02027],[26.33297,40.98388],[26.35894,40.94292],[26.32259,40.94042],[26.28623,40.93005],[26.29441,40.89119],[26.26169,40.9168],[26.20856,40.86048],[26.21351,40.83298],[26.15685,40.80709],[26.12854,40.77339],[26.12495,40.74283],[26.08638,40.73214],[26.0754,40.72772],[26.03489,40.73051],[25.94795,40.72797],[26.04292,40.3958],[25.61285,40.17161],[25.94257,39.39358],[26.43357,39.43096],[26.70773,39.0312],[26.61814,38.81372],[26.21136,38.65436],[26.32173,38.48731],[26.24183,38.44695],[26.21136,38.17558],[27.05537,37.9131],[27.16428,37.72343],[26.99377,37.69034],[26.95583,37.64989],[27.14757,37.32],[27.20312,36.94571],[27.45627,36.9008],[27.24613,36.71622],[27.46117,36.53789],[27.89482,36.69898],[27.95037,36.46155],[28.23708,36.56812],[29.30783,36.01033],[29.48192,36.18377],[29.61002,36.1731],[29.61805,36.14179],[29.69611,36.10365],[29.73302,35.92555],[32.82353,35.70297],[35.51152,36.10954],[35.931,35.92109],[35.98499,35.94107],[36.00514,35.94113],[36.01844,35.92403],[35.99829,35.88242],[36.11827,35.85923],[36.13919,35.83692],[36.14029,35.81015],[36.1623,35.80925],[36.17441,35.92076],[36.19973,35.95195],[36.25366,35.96264],[36.27678,35.94839],[36.29769,35.96086],[36.28338,36.00273],[36.30099,36.00985],[36.33956,35.98687],[36.37474,36.01163],[36.39206,36.22088],[36.4617,36.20461],[36.50463,36.2419],[36.6125,36.22592],[36.68672,36.23677],[36.65653,36.33861],[36.6081,36.33772],[36.54206,36.49539],[36.58829,36.58295],[36.57398,36.65186],[36.62681,36.71189],[36.61581,36.74629],[36.66727,36.82901],[36.99557,36.75997],[36.99886,36.74012],[37.04399,36.73483],[37.04619,36.71101],[37.01647,36.69512],[37.02088,36.66422],[37.08279,36.63495],[37.10894,36.6704],[37.16177,36.66069],[37.21988,36.6736],[37.47253,36.63243],[37.49103,36.66904],[37.68048,36.75065],[37.81974,36.76055],[38.21064,36.91842],[38.38859,36.90064],[38.55908,36.84429],[38.74042,36.70629],[39.03217,36.70911],[39.21538,36.66834],[39.81589,36.75538],[40.69136,37.0996],[40.90856,37.13147],[41.21937,37.07665],[41.515,37.08084],[42.00894,37.17209],[42.18225,37.28569],[42.19301,37.31323],[42.2112,37.32491],[42.22257,37.31395],[42.22381,37.30238],[42.20454,37.28715],[42.21548,37.28026],[42.23683,37.2863],[42.26039,37.27017],[42.2824,37.2798],[42.34735,37.22548],[42.32313,37.17814],[42.35724,37.10998],[42.56725,37.14878],[42.78887,37.38615],[42.93705,37.32015],[43.11403,37.37436],[43.30083,37.30629],[43.33508,37.33105],[43.50787,37.24436],[43.56702,37.25675],[43.63085,37.21957],[43.7009,37.23692],[43.8052,37.22825],[43.82699,37.19477],[43.84878,37.22205],[43.90949,37.22453],[44.02002,37.33229],[44.13521,37.32486],[44.2613,37.25055],[44.27998,37.16501],[44.22239,37.15756],[44.18503,37.09551],[44.25975,36.98119],[44.30645,36.97373],[44.35937,37.02843],[44.35315,37.04955],[44.38117,37.05825],[44.42631,37.05825],[44.63179,37.19229],[44.76698,37.16162],[44.78319,37.1431],[44.7868,37.16644],[44.75986,37.21549],[44.81021,37.2915],[44.58449,37.45018],[44.61401,37.60165],[44.56887,37.6429],[44.62096,37.71985],[44.55498,37.783],[44.45948,37.77065],[44.3883,37.85433],[44.22509,37.88859],[44.42476,38.25763],[44.50115,38.33939],[44.44386,38.38295],[44.38309,38.36117],[44.3119,38.37887],[44.3207,38.49799],[44.32058,38.62752],[44.28065,38.6465],[44.26155,38.71427],[44.30322,38.81581],[44.18863,38.93881],[44.20946,39.13975],[44.1043,39.19842],[44.03667,39.39223],[44.22452,39.4169],[44.29818,39.378],[44.37921,39.4131],[44.42832,39.4131],[44.41849,39.56659],[44.48111,39.61579],[44.47298,39.68788],[44.6137,39.78393],[44.65422,39.72163],[44.71806,39.71124],[44.81043,39.62677],[44.80977,39.65768],[44.75779,39.7148],[44.61845,39.8281],[44.46635,39.97733],[44.26973,40.04866],[44.1778,40.02845],[44.1057,40.03555],[43.92307,40.01787],[43.65688,40.11199],[43.65221,40.14889],[43.71136,40.16673],[43.59928,40.34019],[43.60862,40.43267],[43.54791,40.47413],[43.63664,40.54159],[43.7425,40.66805],[43.74872,40.7365],[43.67712,40.84846],[43.67712,40.93084],[43.58683,40.98961],[43.47319,41.02251],[43.44984,41.0988],[43.4717,41.12611],[43.44973,41.17666],[43.36118,41.2028],[43.23096,41.17536],[43.1945,41.25242],[43.13373,41.25503],[43.21707,41.30331],[43.02956,41.37891],[42.8785,41.50516],[42.84899,41.47265],[42.78995,41.50126],[42.84471,41.58912],[42.72794,41.59714],[42.59202,41.58183],[42.51772,41.43606],[42.26387,41.49346],[41.95134,41.52466],[41.81939,41.43621],[41.7124,41.47417],[41.7148,41.4932],[41.54366,41.52185]]]]}},{type:"Feature",properties:{iso1A2:"TT",iso1A3:"TTO",iso1N3:"780",wikidata:"Q754",nameEn:"Trinidad and Tobago",groups:["029","003","419","019"],driveSide:"left",callingCodes:["1 868"]},geometry:{type:"MultiPolygon",coordinates:[[[[-61.62505,11.18974],[-62.08693,10.04435],[-60.89962,9.81445],[-60.07172,11.77667],[-61.62505,11.18974]]]]}},{type:"Feature",properties:{iso1A2:"TV",iso1A3:"TUV",iso1N3:"798",wikidata:"Q672",nameEn:"Tuvalu",groups:["061","009"],driveSide:"left",callingCodes:["688"]},geometry:{type:"MultiPolygon",coordinates:[[[[174,-5],[174,-11.5],[179.99999,-11.5],[179.99999,-5],[174,-5]]]]}},{type:"Feature",properties:{iso1A2:"TW",iso1A3:"TWN",iso1N3:"158",wikidata:"Q865",nameEn:"Taiwan",groups:["030","142"],callingCodes:["886"]},geometry:{type:"MultiPolygon",coordinates:[[[[123.0791,22.07818],[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],[123.0791,22.07818]]]]}},{type:"Feature",properties:{iso1A2:"TZ",iso1A3:"TZA",iso1N3:"834",wikidata:"Q924",nameEn:"Tanzania",groups:["014","202","002"],driveSide:"left",callingCodes:["255"]},geometry:{type:"MultiPolygon",coordinates:[[[[30.80408,-0.99911],[30.76635,-0.9852],[30.70631,-1.01175],[30.64166,-1.06601],[30.47194,-1.0555],[30.45116,-1.10641],[30.50889,-1.16412],[30.57123,-1.33264],[30.71974,-1.43244],[30.84079,-1.64652],[30.80802,-1.91477],[30.89303,-2.08223],[30.83915,-2.35795],[30.54501,-2.41404],[30.41789,-2.66266],[30.52747,-2.65841],[30.40662,-2.86151],[30.4987,-2.9573],[30.57926,-2.89791],[30.6675,-2.98987],[30.83823,-2.97837],[30.84165,-3.25152],[30.45915,-3.56532],[30.22042,-4.01738],[30.03323,-4.26631],[29.88172,-4.35743],[29.82885,-4.36153],[29.77289,-4.41733],[29.75109,-4.45836],[29.63827,-4.44681],[29.43673,-4.44845],[29.52552,-6.2731],[30.2567,-7.14121],[30.79243,-8.27382],[31.00796,-8.58615],[31.37533,-8.60769],[31.57147,-8.70619],[31.57147,-8.81388],[31.71158,-8.91386],[31.81587,-8.88618],[31.94663,-8.93846],[31.94196,-9.02303],[31.98866,-9.07069],[32.08206,-9.04609],[32.16146,-9.05993],[32.25486,-9.13371],[32.43543,-9.11988],[32.49147,-9.14754],[32.53661,-9.24281],[32.75611,-9.28583],[32.76233,-9.31963],[32.95389,-9.40138],[32.99397,-9.36712],[33.14925,-9.49322],[33.31581,-9.48554],[33.48052,-9.62442],[33.76677,-9.58516],[33.93298,-9.71647],[33.9638,-9.62206],[33.95829,-9.54066],[34.03865,-9.49398],[34.54499,-10.0678],[34.51911,-10.12279],[34.57581,-10.56271],[34.65946,-10.6828],[34.67047,-10.93796],[34.61161,-11.01611],[34.63305,-11.11731],[34.79375,-11.32245],[34.91153,-11.39799],[34.96296,-11.57354],[35.63599,-11.55927],[35.82767,-11.41081],[36.19094,-11.57593],[36.19094,-11.70008],[36.62068,-11.72884],[36.80309,-11.56836],[37.3936,-11.68949],[37.76614,-11.53352],[37.8388,-11.3123],[37.93618,-11.26228],[38.21598,-11.27289],[38.47258,-11.4199],[38.88996,-11.16978],[39.24395,-11.17433],[39.58249,-10.96043],[40.00295,-10.80255],[40.44265,-10.4618],[40.74206,-10.25691],[40.14328,-4.64201],[39.62121,-4.68136],[39.44306,-4.93877],[39.21631,-4.67835],[37.81321,-3.69179],[37.75036,-3.54243],[37.63099,-3.50723],[37.5903,-3.42735],[37.71745,-3.304],[37.67199,-3.06222],[34.0824,-1.02264],[34.03084,-1.05101],[34.02286,-1.00779],[33.93107,-0.99298],[30.80408,-0.99911]]]]}},{type:"Feature",properties:{iso1A2:"UA",iso1A3:"UKR",iso1N3:"804",wikidata:"Q212",nameEn:"Ukraine",groups:["151","150"],callingCodes:["380"]},geometry:{type:"MultiPolygon",coordinates:[[[[33.57318,46.10317],[33.61467,46.13561],[33.63854,46.14147],[33.61517,46.22615],[33.646,46.23028],[33.74047,46.18555],[33.79715,46.20482],[33.85234,46.19863],[33.91549,46.15938],[34.05272,46.10838],[34.07311,46.11769],[34.12929,46.10494],[34.181,46.06804],[34.25111,46.0532],[34.33912,46.06114],[34.41221,46.00245],[34.44155,45.95995],[34.48729,45.94267],[34.52011,45.95097],[34.55889,45.99347],[34.60861,45.99347],[34.66679,45.97136],[34.75479,45.90705],[34.80153,45.90047],[34.79905,45.81009],[34.96015,45.75634],[35.23066,45.79231],[37.62608,46.82615],[38.12112,46.86078],[38.3384,46.98085],[38.22955,47.12069],[38.23049,47.2324],[38.32112,47.2585],[38.33074,47.30508],[38.22225,47.30788],[38.28954,47.39255],[38.28679,47.53552],[38.35062,47.61631],[38.76379,47.69346],[38.79628,47.81109],[38.87979,47.87719],[39.73935,47.82876],[39.82213,47.96396],[39.77544,48.04206],[39.88256,48.04482],[39.83724,48.06501],[39.94847,48.22811],[40.00752,48.22445],[39.99241,48.31768],[39.97325,48.31399],[39.9693,48.29904],[39.95248,48.29972],[39.91465,48.26743],[39.90041,48.3049],[39.84273,48.30947],[39.84136,48.33321],[39.94847,48.35055],[39.88794,48.44226],[39.86196,48.46633],[39.84548,48.57821],[39.79764,48.58668],[39.67226,48.59368],[39.71765,48.68673],[39.73104,48.7325],[39.79466,48.83739],[39.97182,48.79398],[40.08168,48.87443],[40.03636,48.91957],[39.98967,48.86901],[39.78368,48.91596],[39.74874,48.98675],[39.72649,48.9754],[39.71353,48.98959],[39.6683,48.99454],[39.6836,49.05121],[39.93437,49.05709],[40.01988,49.1761],[40.22176,49.25683],[40.18331,49.34996],[40.14912,49.37681],[40.1141,49.38798],[40.03087,49.45452],[40.03636,49.52321],[40.16683,49.56865],[40.13249,49.61672],[39.84548,49.56064],[39.65047,49.61761],[39.59142,49.73758],[39.44496,49.76067],[39.27968,49.75976],[39.1808,49.88911],[38.9391,49.79524],[38.90477,49.86787],[38.73311,49.90238],[38.68677,50.00904],[38.65688,49.97176],[38.35408,50.00664],[38.32524,50.08866],[38.18517,50.08161],[38.21675,49.98104],[38.02999,49.90592],[38.02999,49.94482],[37.90776,50.04194],[37.79515,50.08425],[37.75807,50.07896],[37.61113,50.21976],[37.62879,50.24481],[37.62486,50.29966],[37.47243,50.36277],[37.48204,50.46079],[37.08468,50.34935],[36.91762,50.34963],[36.69377,50.26982],[36.64571,50.218],[36.56655,50.2413],[36.58371,50.28563],[36.47817,50.31457],[36.30101,50.29088],[36.20763,50.3943],[36.06893,50.45205],[35.8926,50.43829],[35.80388,50.41356],[35.73659,50.35489],[35.61711,50.35707],[35.58003,50.45117],[35.47463,50.49247],[35.39464,50.64751],[35.48116,50.66405],[35.47704,50.77274],[35.41367,50.80227],[35.39307,50.92145],[35.32598,50.94524],[35.40837,51.04119],[35.31774,51.08434],[35.20375,51.04723],[35.12685,51.16191],[35.14058,51.23162],[34.97304,51.2342],[34.82472,51.17483],[34.6874,51.18],[34.6613,51.25053],[34.38802,51.2746],[34.31661,51.23936],[34.23009,51.26429],[34.33446,51.363],[34.22048,51.4187],[34.30562,51.5205],[34.17599,51.63253],[34.07765,51.67065],[34.42922,51.72852],[34.41136,51.82793],[34.09413,52.00835],[34.11199,52.14087],[34.05239,52.20132],[33.78789,52.37204],[33.55718,52.30324],[33.48027,52.31499],[33.51323,52.35779],[33.18913,52.3754],[32.89937,52.2461],[32.85405,52.27888],[32.69475,52.25535],[32.54781,52.32423],[32.3528,52.32842],[32.38988,52.24946],[32.33083,52.23685],[32.34044,52.1434],[32.2777,52.10266],[32.23331,52.08085],[32.08813,52.03319],[31.92159,52.05144],[31.96141,52.08015],[31.85018,52.11305],[31.81722,52.09955],[31.7822,52.11406],[31.38326,52.12991],[31.25142,52.04131],[31.13332,52.1004],[30.95589,52.07775],[30.90897,52.00699],[30.76443,51.89739],[30.68804,51.82806],[30.51946,51.59649],[30.64992,51.35014],[30.56203,51.25655],[30.36153,51.33984],[30.34642,51.42555],[30.17888,51.51025],[29.77376,51.4461],[29.7408,51.53417],[29.54372,51.48372],[29.49773,51.39814],[29.42357,51.4187],[29.32881,51.37843],[29.25191,51.49828],[29.25603,51.57089],[29.20659,51.56918],[29.16402,51.64679],[29.1187,51.65872],[28.99098,51.56833],[28.95528,51.59222],[28.81795,51.55552],[28.76027,51.48802],[28.78224,51.45294],[28.75615,51.41442],[28.73143,51.46236],[28.69161,51.44695],[28.64429,51.5664],[28.47051,51.59734],[28.37592,51.54505],[28.23452,51.66988],[28.10658,51.57857],[27.95827,51.56065],[27.91844,51.61952],[27.85253,51.62293],[27.76052,51.47604],[27.67125,51.50854],[27.71932,51.60672],[27.55727,51.63486],[27.51058,51.5854],[27.47212,51.61184],[27.24828,51.60161],[27.26613,51.65957],[27.20948,51.66713],[27.20602,51.77291],[26.99422,51.76933],[26.9489,51.73788],[26.80043,51.75777],[26.69759,51.82284],[26.46962,51.80501],[26.39367,51.87315],[26.19084,51.86781],[26.00408,51.92967],[25.83217,51.92587],[25.80574,51.94556],[25.73673,51.91973],[25.46163,51.92205],[25.20228,51.97143],[24.98784,51.91273],[24.37123,51.88222],[24.29021,51.80841],[24.3163,51.75063],[24.13075,51.66979],[23.99907,51.58369],[23.8741,51.59734],[23.91118,51.63316],[23.7766,51.66809],[23.60906,51.62122],[23.6736,51.50255],[23.62751,51.50512],[23.69905,51.40871],[23.63858,51.32182],[23.80678,51.18405],[23.90376,51.07697],[23.92217,51.00836],[24.04576,50.90196],[24.14524,50.86128],[24.0952,50.83262],[23.99254,50.83847],[23.95925,50.79271],[24.0595,50.71625],[24.0996,50.60752],[24.07048,50.5071],[24.03668,50.44507],[23.99563,50.41289],[23.79445,50.40481],[23.71382,50.38248],[23.67635,50.33385],[23.28221,50.0957],[22.99329,49.84249],[22.83179,49.69875],[22.80261,49.69098],[22.78304,49.65543],[22.64534,49.53094],[22.69444,49.49378],[22.748,49.32759],[22.72009,49.20288],[22.86336,49.10513],[22.89122,49.00725],[22.56155,49.08865],[22.54338,49.01424],[22.48296,48.99172],[22.42934,48.92857],[22.34151,48.68893],[22.21379,48.6218],[22.16023,48.56548],[22.14689,48.4005],[22.2083,48.42534],[22.38133,48.23726],[22.49806,48.25189],[22.59007,48.15121],[22.58733,48.10813],[22.66835,48.09162],[22.73427,48.12005],[22.81804,48.11363],[22.87847,48.04665],[22.84276,47.98602],[22.89849,47.95851],[22.94301,47.96672],[22.92241,48.02002],[23.0158,47.99338],[23.08858,48.00716],[23.1133,48.08061],[23.15999,48.12188],[23.27397,48.08245],[23.33577,48.0237],[23.4979,47.96858],[23.52803,48.01818],[23.5653,48.00499],[23.63894,48.00293],[23.66262,47.98786],[23.75188,47.99705],[23.80904,47.98142],[23.8602,47.9329],[23.89352,47.94512],[23.94192,47.94868],[23.96337,47.96672],[23.98553,47.96076],[24.00801,47.968],[24.02999,47.95087],[24.06466,47.95317],[24.11281,47.91487],[24.22566,47.90231],[24.34926,47.9244],[24.43578,47.97131],[24.61994,47.95062],[24.70632,47.84428],[24.81893,47.82031],[24.88896,47.7234],[25.11144,47.75203],[25.23778,47.89403],[25.63878,47.94924],[25.77723,47.93919],[26.05901,47.9897],[26.17711,47.99246],[26.33504,48.18418],[26.55202,48.22445],[26.62823,48.25804],[26.6839,48.35828],[26.79239,48.29071],[26.82809,48.31629],[26.71274,48.40388],[26.85556,48.41095],[26.93384,48.36558],[27.03821,48.37653],[27.0231,48.42485],[27.08078,48.43214],[27.13434,48.37288],[27.27855,48.37534],[27.32159,48.4434],[27.37604,48.44398],[27.37741,48.41026],[27.44333,48.41209],[27.46942,48.454],[27.5889,48.49224],[27.59027,48.46311],[27.6658,48.44034],[27.74422,48.45926],[27.79225,48.44244],[27.81902,48.41874],[27.87533,48.4037],[27.88391,48.36699],[27.95883,48.32368],[28.04527,48.32661],[28.09873,48.3124],[28.07504,48.23494],[28.17666,48.25963],[28.19314,48.20749],[28.2856,48.23202],[28.32508,48.23384],[28.35519,48.24957],[28.36996,48.20543],[28.34912,48.1787],[28.30586,48.1597],[28.30609,48.14018],[28.34009,48.13147],[28.38712,48.17567],[28.43701,48.15832],[28.42454,48.12047],[28.48428,48.0737],[28.53921,48.17453],[28.69896,48.13106],[28.85232,48.12506],[28.8414,48.03392],[28.9306,47.96255],[29.1723,47.99013],[29.19839,47.89261],[29.27804,47.88893],[29.20663,47.80367],[29.27255,47.79953],[29.22242,47.73607],[29.22414,47.60012],[29.11743,47.55001],[29.18603,47.43387],[29.3261,47.44664],[29.39889,47.30179],[29.47854,47.30366],[29.48678,47.36043],[29.5733,47.36508],[29.59665,47.25521],[29.54996,47.24962],[29.57696,47.13581],[29.49732,47.12878],[29.53044,47.07851],[29.61038,47.09932],[29.62137,47.05069],[29.57056,46.94766],[29.72986,46.92234],[29.75458,46.8604],[29.87405,46.88199],[29.98814,46.82358],[29.94522,46.80055],[29.9743,46.75325],[29.94409,46.56002],[29.88916,46.54302],[30.02511,46.45132],[30.16794,46.40967],[30.09103,46.38694],[29.94114,46.40114],[29.88329,46.35851],[29.74496,46.45605],[29.66359,46.4215],[29.6763,46.36041],[29.5939,46.35472],[29.49914,46.45889],[29.35357,46.49505],[29.24886,46.37912],[29.23547,46.55435],[29.02409,46.49582],[29.01241,46.46177],[28.9306,46.45699],[29.004,46.31495],[28.98478,46.31803],[28.94953,46.25852],[29.06656,46.19716],[28.94643,46.09176],[29.00613,46.04962],[28.98004,46.00385],[28.74383,45.96664],[28.78503,45.83475],[28.69852,45.81753],[28.70401,45.78019],[28.52823,45.73803],[28.47879,45.66994],[28.51587,45.6613],[28.54196,45.58062],[28.49252,45.56716],[28.51449,45.49982],[28.43072,45.48538],[28.41836,45.51715],[28.30201,45.54744],[28.21139,45.46895],[28.28504,45.43907],[28.34554,45.32102],[28.5735,45.24759],[28.71358,45.22631],[28.78911,45.24179],[28.81383,45.3384],[28.94292,45.28045],[28.96077,45.33164],[29.24779,45.43388],[29.42632,45.44545],[29.59798,45.38857],[29.68175,45.26885],[29.65428,45.25629],[29.69272,45.19227],[30.04414,45.08461],[31.62627,45.50633],[33.54017,46.0123],[33.59087,46.06013],[33.57318,46.10317]]]]}},{type:"Feature",properties:{iso1A2:"UG",iso1A3:"UGA",iso1N3:"800",wikidata:"Q1036",nameEn:"Uganda",groups:["014","202","002"],driveSide:"left",callingCodes:["256"]},geometry:{type:"MultiPolygon",coordinates:[[[[33.93107,-0.99298],[33.9264,-0.54188],[33.98449,-0.13079],[33.90936,0.10581],[34.10067,0.36372],[34.08727,0.44713],[34.11408,0.48884],[34.13493,0.58118],[34.20196,0.62289],[34.27345,0.63182],[34.31516,0.75693],[34.40041,0.80266],[34.43349,0.85254],[34.52369,1.10692],[34.57427,1.09868],[34.58029,1.14712],[34.67562,1.21265],[34.80223,1.22754],[34.82606,1.26626],[34.82606,1.30944],[34.7918,1.36752],[34.87819,1.5596],[34.92734,1.56109],[34.9899,1.6668],[34.98692,1.97348],[34.90947,2.42447],[34.95267,2.47209],[34.77244,2.70272],[34.78137,2.76223],[34.73967,2.85447],[34.65774,2.8753],[34.60114,2.93034],[34.56242,3.11478],[34.45815,3.18319],[34.40006,3.37949],[34.41794,3.44342],[34.39112,3.48802],[34.44922,3.51627],[34.45815,3.67385],[34.15429,3.80464],[34.06046,4.15235],[33.9873,4.23316],[33.51264,3.75068],[33.18356,3.77812],[33.02852,3.89296],[32.89746,3.81339],[32.72021,3.77327],[32.41337,3.748],[32.20782,3.6053],[32.19888,3.50867],[32.08866,3.53543],[32.08491,3.56287],[32.05187,3.589],[31.95907,3.57408],[31.96205,3.6499],[31.86821,3.78664],[31.81459,3.82083],[31.72075,3.74354],[31.50776,3.63652],[31.50478,3.67814],[31.29476,3.8015],[31.16666,3.79853],[30.97601,3.693],[30.85153,3.48867],[30.94081,3.50847],[30.93486,3.40737],[30.84251,3.26908],[30.77101,3.04897],[30.8574,2.9508],[30.8857,2.83923],[30.75612,2.5863],[30.74271,2.43601],[30.83059,2.42559],[30.91102,2.33332],[30.96911,2.41071],[31.06593,2.35862],[31.07934,2.30207],[31.12104,2.27676],[31.1985,2.29462],[31.20148,2.2217],[31.28042,2.17853],[31.30127,2.11006],[30.48503,1.21675],[30.24671,1.14974],[30.22139,0.99635],[30.1484,0.89805],[29.98307,0.84295],[29.95477,0.64486],[29.97413,0.52124],[29.87284,0.39166],[29.81922,0.16824],[29.77454,0.16675],[29.7224,0.07291],[29.72687,-0.08051],[29.65091,-0.46777],[29.67474,-0.47969],[29.67176,-0.55714],[29.62708,-0.71055],[29.63006,-0.8997],[29.58388,-0.89821],[29.59061,-1.39016],[29.82657,-1.31187],[29.912,-1.48269],[30.16369,-1.34303],[30.35212,-1.06896],[30.47194,-1.0555],[30.64166,-1.06601],[30.70631,-1.01175],[30.76635,-0.9852],[30.80408,-0.99911],[33.93107,-0.99298]]]]}},{type:"Feature",properties:{iso1A2:"UM",iso1A3:"UMI",iso1N3:"581",wikidata:"Q16645",nameEn:"United States Minor Outlying Islands",country:"US",groups:["057","009"]},geometry:{type:"MultiPolygon",coordinates:[[[[-175.33482,-1.40631],[-175.33167,1.67574],[-177.43928,1.65656],[-177.43039,-1.43294],[-175.33482,-1.40631]]],[[[-161.04969,-1.36251],[-158.62058,-1.35506],[-158.62734,1.1296],[-161.05669,1.11722],[-161.04969,-1.36251]]],[[[-161.06795,5.2462],[-161.0731,7.1291],[-163.24994,7.12322],[-163.24478,5.24198],[-161.06795,5.2462]]],[[[-170.65691,16.57199],[-168.87689,16.01159],[-169.2329,17.4933],[-170.65691,16.57199]]],[[[-176.29741,29.09786],[-177.77531,29.29793],[-177.5224,27.7635],[-176.29741,29.09786]]],[[[-74.7289,18.71009],[-75.71816,18.46438],[-74.76465,18.06252],[-74.7289,18.71009]]],[[[167.34779,18.97692],[166.67967,20.14834],[165.82549,18.97692],[167.34779,18.97692]]]]}},{type:"Feature",properties:{iso1A2:"US",iso1A3:"USA",iso1N3:"840",wikidata:"Q30",nameEn:"United States of America",groups:["021","003","019"],roadSpeedUnit:"mph",callingCodes:["1"]},geometry:{type:"MultiPolygon",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]]],[[[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]]],[[[-97.13927,25.96583],[-96.92418,25.97377],[-82.02215,24.23074],[-79.89631,24.6597],[-79.14818,27.83105],[-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],[-97.24024,48.99952],[-101.36198,48.99935],[-104.05004,48.99925],[-110.0051,48.99901],[-114.0683,48.99885],[-116.04938,48.99999],[-117.03266,49.00056],[-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],[-112.34553,31.7357],[-111.07523,31.33232],[-109.05235,31.3333],[-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]]]]}},{type:"Feature",properties:{iso1A2:"UY",iso1A3:"URY",iso1N3:"858",wikidata:"Q77",nameEn:"Uruguay",groups:["005","419","019"],callingCodes:["598"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"UZ",iso1A3:"UZB",iso1N3:"860",wikidata:"Q265",nameEn:"Uzbekistan",groups:["143","142"],callingCodes:["998"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"VA",iso1A3:"VAT",iso1N3:"336",wikidata:"Q237",nameEn:"Vatican City",aliases:["Holy See"],groups:["039","150"],callingCodes:["379","39 06"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"VC",iso1A3:"VCT",iso1N3:"670",wikidata:"Q757",nameEn:"St. Vincent and the Grenadines",aliases:["WV"],groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 784"]},geometry:{type:"MultiPolygon",coordinates:[[[[-61.73897,12.61191],[-61.38256,12.52991],[-61.13395,12.51526],[-60.70539,13.41452],[-61.43129,13.68336],[-61.73897,12.61191]]]]}},{type:"Feature",properties:{iso1A2:"VE",iso1A3:"VEN",iso1N3:"862",wikidata:"Q717",nameEn:"Venezuela",aliases:["YV"],groups:["005","419","019"],callingCodes:["58"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"VG",iso1A3:"VGB",iso1N3:"092",wikidata:"Q25305",nameEn:"British Virgin Islands",country:"GB",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 284"]},geometry:{type:"MultiPolygon",coordinates:[[[[-64.03057,18.08241],[-63.75633,19.39745],[-65.02435,18.73231],[-64.86027,18.39056],[-64.64067,18.36478],[-64.646,18.10286],[-64.03057,18.08241]]]]}},{type:"Feature",properties:{iso1A2:"VI",iso1A3:"VIR",iso1N3:"850",wikidata:"Q11703",nameEn:"United States Virgin Islands",country:"US",groups:["029","003","419","019"],driveSide:"left",roadSpeedUnit:"mph",callingCodes:["1 340"]},geometry:{type:"MultiPolygon",coordinates:[[[[-65.02435,18.73231],[-65.27974,17.56928],[-64.35558,17.48384],[-64.646,18.10286],[-64.64067,18.36478],[-64.86027,18.39056],[-65.02435,18.73231]]]]}},{type:"Feature",properties:{iso1A2:"VN",iso1A3:"VNM",iso1N3:"704",wikidata:"Q881",nameEn:"Vietnam",groups:["035","142"],callingCodes:["84"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"VU",iso1A3:"VUT",iso1N3:"548",wikidata:"Q686",nameEn:"Vanuatu",groups:["054","009"],callingCodes:["678"]},geometry:{type:"MultiPolygon",coordinates:[[[[162.93363,-17.28904],[173.26254,-22.69968],[168.21179,-12.88558],[166.02864,-12.9396],[162.93363,-17.28904]]]]}},{type:"Feature",properties:{iso1A2:"WF",iso1A3:"WLF",iso1N3:"876",wikidata:"Q35555",nameEn:"Wallis and Futuna",country:"FR",groups:["061","009"],callingCodes:["681"]},geometry:{type:"MultiPolygon",coordinates:[[[[-178.60161,-14.95666],[-176.76826,-14.95183],[-174.17905,-14.94502],[-174.18596,-12.48057],[-178.60852,-12.49232],[-178.60161,-14.95666]]]]}},{type:"Feature",properties:{iso1A2:"WS",iso1A3:"WSM",iso1N3:"882",wikidata:"Q683",nameEn:"Samoa",groups:["061","009"],driveSide:"left",callingCodes:["685"]},geometry:{type:"MultiPolygon",coordinates:[[[[-174.17905,-14.94502],[-173.13438,-14.94228],[-171.14262,-14.93704],[-171.14953,-12.4725],[-174.18596,-12.48057],[-174.17905,-14.94502]]]]}},{type:"Feature",properties:{iso1A2:"XK",iso1A3:"XKX",wikidata:"Q1246",nameEn:"Kosovo",aliases:["KV"],groups:["039","150"],isoStatus:"usrAssn",callingCodes:["383"]},geometry:{type:"MultiPolygon",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]]]]}},{type:"Feature",properties:{iso1A2:"YE",iso1A3:"YEM",iso1N3:"887",wikidata:"Q805",nameEn:"Yemen",groups:["145","142"],callingCodes:["967"]},geometry:{type:"MultiPolygon",coordinates:[[[[53.32998,16.16312],[53.09917,16.67084],[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],[41.37609,16.19728],[41.29956,15.565],[42.63806,13.58268],[43.29075,12.79154],[43.32909,12.59711],[43.90659,12.3823],[50.51849,13.0483],[51.12877,12.56479],[52.253,11.68582],[55.69862,12.12478],[53.32998,16.16312]]]]}},{type:"Feature",properties:{iso1A2:"YT",iso1A3:"MYT",iso1N3:"175",wikidata:"Q17063",nameEn:"Mayotte",country:"FR",groups:["EU","014","202","002"],callingCodes:["262"]},geometry:{type:"MultiPolygon",coordinates:[[[[43.83794,-13.66915],[45.54824,-13.22353],[45.50237,-11.90315],[43.83794,-13.66915]]]]}},{type:"Feature",properties:{iso1A2:"ZA",iso1A3:"ZAF",iso1N3:"710",wikidata:"Q258",nameEn:"South Africa",groups:["018","202","002"],driveSide:"left",callingCodes:["27"]},geometry:{type:"MultiPolygon",coordinates:[[[[31.30611,-22.422],[31.16344,-22.32599],[31.08932,-22.34884],[30.86696,-22.28907],[30.6294,-22.32599],[30.48686,-22.31368],[30.38614,-22.34533],[30.28351,-22.35587],[30.2265,-22.2961],[30.13147,-22.30841],[29.92242,-22.19408],[29.76848,-22.14128],[29.64609,-22.12917],[29.37703,-22.19581],[29.21955,-22.17771],[29.18974,-22.18599],[29.15268,-22.21399],[29.10881,-22.21202],[29.0151,-22.22907],[28.91889,-22.44299],[28.63287,-22.55887],[28.34874,-22.5694],[28.04562,-22.8394],[28.04752,-22.90243],[27.93729,-22.96194],[27.93539,-23.04941],[27.74154,-23.2137],[27.6066,-23.21894],[27.52393,-23.37952],[27.33768,-23.40917],[26.99749,-23.65486],[26.84165,-24.24885],[26.51667,-24.47219],[26.46346,-24.60358],[26.39409,-24.63468],[25.8515,-24.75727],[25.84295,-24.78661],[25.88571,-24.87802],[25.72702,-25.25503],[25.69661,-25.29284],[25.6643,-25.4491],[25.58543,-25.6343],[25.33076,-25.76616],[25.12266,-25.75931],[25.01718,-25.72507],[24.8946,-25.80723],[24.67319,-25.81749],[24.44703,-25.73021],[24.36531,-25.773],[24.18287,-25.62916],[23.9244,-25.64286],[23.47588,-25.29971],[23.03497,-25.29971],[22.86012,-25.50572],[22.70808,-25.99186],[22.56365,-26.19668],[22.41921,-26.23078],[22.21206,-26.3773],[22.06192,-26.61882],[21.90703,-26.66808],[21.83291,-26.65959],[21.77114,-26.69015],[21.7854,-26.79199],[21.69322,-26.86152],[21.37869,-26.82083],[21.13353,-26.86661],[20.87031,-26.80047],[20.68596,-26.9039],[20.63275,-26.78181],[20.61754,-26.4692],[20.86081,-26.14892],[20.64795,-25.47827],[20.29826,-24.94869],[20.03678,-24.81004],[20.02809,-24.78725],[19.99817,-24.76768],[19.99882,-28.42622],[18.99885,-28.89165],[17.4579,-28.68718],[17.15405,-28.08573],[16.90446,-28.057],[16.59922,-28.53246],[16.46592,-28.57126],[16.45332,-28.63117],[12.51595,-32.27486],[38.88176,-48.03306],[34.51034,-26.91792],[32.35222,-26.86027],[32.29584,-26.852],[32.22302,-26.84136],[32.19409,-26.84032],[32.13315,-26.84345],[32.09664,-26.80721],[32.00893,-26.8096],[31.97463,-27.11057],[31.97592,-27.31675],[31.49834,-27.31549],[31.15027,-27.20151],[30.96088,-27.0245],[30.97757,-26.92706],[30.88826,-26.79622],[30.81101,-26.84722],[30.78927,-26.48271],[30.95819,-26.26303],[31.13073,-25.91558],[31.31237,-25.7431],[31.4175,-25.71886],[31.86881,-25.99973],[31.974,-25.95387],[31.92649,-25.84216],[32.00631,-25.65044],[31.97875,-25.46356],[32.01676,-25.38117],[32.03196,-25.10785],[31.9835,-24.29983],[31.90368,-24.18892],[31.87707,-23.95293],[31.77445,-23.90082],[31.70223,-23.72695],[31.67942,-23.60858],[31.56539,-23.47268],[31.55779,-23.176],[31.30611,-22.422]],[[29.33204,-29.45598],[29.28545,-29.58456],[29.12553,-29.76266],[29.16548,-29.91706],[28.9338,-30.05072],[28.80222,-30.10579],[28.68627,-30.12885],[28.399,-30.1592],[28.2319,-30.28476],[28.12073,-30.68072],[27.74814,-30.60635],[27.69467,-30.55862],[27.67819,-30.53437],[27.6521,-30.51707],[27.62137,-30.50509],[27.56781,-30.44562],[27.56901,-30.42504],[27.45452,-30.32239],[27.38108,-30.33456],[27.36649,-30.27246],[27.37293,-30.19401],[27.40778,-30.14577],[27.32555,-30.14785],[27.29603,-30.05473],[27.22719,-30.00718],[27.09489,-29.72796],[27.01016,-29.65439],[27.33464,-29.48161],[27.4358,-29.33465],[27.47254,-29.31968],[27.45125,-29.29708],[27.48679,-29.29349],[27.54258,-29.25575],[27.5158,-29.2261],[27.55974,-29.18954],[27.75458,-28.89839],[27.8907,-28.91612],[27.88933,-28.88156],[27.9392,-28.84864],[27.98675,-28.8787],[28.02503,-28.85991],[28.1317,-28.7293],[28.2348,-28.69471],[28.30518,-28.69531],[28.40612,-28.6215],[28.65091,-28.57025],[28.68043,-28.58744],[29.40524,-29.21246],[29.44883,-29.3772],[29.33204,-29.45598]]]]}},{type:"Feature",properties:{iso1A2:"ZM",iso1A3:"ZMB",iso1N3:"894",wikidata:"Q953",nameEn:"Zambia",groups:["014","202","002"],driveSide:"left",callingCodes:["260"]},geometry:{type:"MultiPolygon",coordinates:[[[[32.95389,-9.40138],[32.76233,-9.31963],[32.75611,-9.28583],[32.53661,-9.24281],[32.49147,-9.14754],[32.43543,-9.11988],[32.25486,-9.13371],[32.16146,-9.05993],[32.08206,-9.04609],[31.98866,-9.07069],[31.94196,-9.02303],[31.94663,-8.93846],[31.81587,-8.88618],[31.71158,-8.91386],[31.57147,-8.81388],[31.57147,-8.70619],[31.37533,-8.60769],[31.00796,-8.58615],[30.79243,-8.27382],[28.88917,-8.4831],[28.9711,-8.66935],[28.38526,-9.23393],[28.36562,-9.30091],[28.52636,-9.35379],[28.51627,-9.44726],[28.56208,-9.49122],[28.68532,-9.78],[28.62795,-9.92942],[28.65032,-10.65133],[28.37241,-11.57848],[28.48357,-11.87532],[29.18592,-12.37921],[29.4992,-12.43843],[29.48404,-12.23604],[29.8139,-12.14898],[29.81551,-13.44683],[29.65078,-13.41844],[29.60531,-13.21685],[29.01918,-13.41353],[28.33199,-12.41375],[27.59932,-12.22123],[27.21025,-11.76157],[27.22541,-11.60323],[27.04351,-11.61312],[26.88687,-12.01868],[26.01777,-11.91488],[25.33058,-11.65767],[25.34069,-11.19707],[24.42612,-11.44975],[24.34528,-11.06816],[24.00027,-10.89356],[24.02603,-11.15368],[23.98804,-12.13149],[24.06672,-12.29058],[23.90937,-12.844],[24.03339,-12.99091],[21.97988,-13.00148],[22.00323,-16.18028],[22.17217,-16.50269],[23.20038,-17.47563],[23.47474,-17.62877],[24.23619,-17.47489],[24.32811,-17.49082],[24.38712,-17.46818],[24.5621,-17.52963],[24.70864,-17.49501],[25.00198,-17.58221],[25.26433,-17.79571],[25.51646,-17.86232],[25.6827,-17.81987],[25.85738,-17.91403],[25.85892,-17.97726],[26.08925,-17.98168],[26.0908,-17.93021],[26.21601,-17.88608],[26.55918,-17.99638],[26.68403,-18.07411],[26.74314,-18.0199],[26.89926,-17.98756],[27.14196,-17.81398],[27.30736,-17.60487],[27.61377,-17.34378],[27.62795,-17.24365],[27.83141,-16.96274],[28.73725,-16.5528],[28.76199,-16.51575],[28.81454,-16.48611],[28.8501,-16.04537],[28.9243,-15.93987],[29.01298,-15.93805],[29.21955,-15.76589],[29.4437,-15.68702],[29.8317,-15.6126],[30.35574,-15.6513],[30.41902,-15.62269],[30.22098,-14.99447],[33.24249,-14.00019],[33.16749,-13.93992],[33.07568,-13.98447],[33.02977,-14.05022],[32.99042,-13.95689],[32.88985,-13.82956],[32.79015,-13.80755],[32.76962,-13.77224],[32.84528,-13.71576],[32.7828,-13.64805],[32.68654,-13.64268],[32.66468,-13.60019],[32.68436,-13.55769],[32.73683,-13.57682],[32.84176,-13.52794],[32.86113,-13.47292],[33.0078,-13.19492],[32.98289,-13.12671],[33.02181,-12.88707],[32.96733,-12.88251],[32.94397,-12.76868],[33.05917,-12.59554],[33.18837,-12.61377],[33.28177,-12.54692],[33.37517,-12.54085],[33.54485,-12.35996],[33.47636,-12.32498],[33.3705,-12.34931],[33.25998,-12.14242],[33.33937,-11.91252],[33.32692,-11.59248],[33.24252,-11.59302],[33.23663,-11.40637],[33.29267,-11.43536],[33.29267,-11.3789],[33.39697,-11.15296],[33.25998,-10.88862],[33.28022,-10.84428],[33.47636,-10.78465],[33.70675,-10.56896],[33.54797,-10.36077],[33.53863,-10.20148],[33.31297,-10.05133],[33.37902,-9.9104],[33.36581,-9.81063],[33.31517,-9.82364],[33.2095,-9.61099],[33.12144,-9.58929],[33.10163,-9.66525],[33.05485,-9.61316],[33.00256,-9.63053],[33.00476,-9.5133],[32.95389,-9.40138]]]]}},{type:"Feature",properties:{iso1A2:"ZW",iso1A3:"ZWE",iso1N3:"716",wikidata:"Q954",nameEn:"Zimbabwe",groups:["014","202","002"],driveSide:"left",callingCodes:["263"]},geometry:{type:"MultiPolygon",coordinates:[[[[30.41902,-15.62269],[30.35574,-15.6513],[29.8317,-15.6126],[29.4437,-15.68702],[29.21955,-15.76589],[29.01298,-15.93805],[28.9243,-15.93987],[28.8501,-16.04537],[28.81454,-16.48611],[28.76199,-16.51575],[28.73725,-16.5528],[27.83141,-16.96274],[27.62795,-17.24365],[27.61377,-17.34378],[27.30736,-17.60487],[27.14196,-17.81398],[26.89926,-17.98756],[26.74314,-18.0199],[26.68403,-18.07411],[26.55918,-17.99638],[26.21601,-17.88608],[26.0908,-17.93021],[26.08925,-17.98168],[25.85892,-17.97726],[25.85738,-17.91403],[25.6827,-17.81987],[25.51646,-17.86232],[25.26433,-17.79571],[25.23909,-17.90832],[25.31799,-18.07091],[25.39972,-18.12691],[25.53465,-18.39041],[25.68859,-18.56165],[25.79217,-18.6355],[25.82353,-18.82808],[25.94326,-18.90362],[25.99837,-19.02943],[25.96226,-19.08152],[26.17227,-19.53709],[26.72246,-19.92707],[27.21278,-20.08244],[27.29831,-20.28935],[27.28865,-20.49873],[27.69361,-20.48531],[27.72972,-20.51735],[27.69171,-21.08409],[27.91407,-21.31621],[28.01669,-21.57624],[28.29416,-21.59037],[28.49942,-21.66634],[28.58114,-21.63455],[29.07763,-21.81877],[29.04023,-21.85864],[29.02191,-21.90647],[29.02191,-21.95665],[29.04108,-22.00563],[29.08495,-22.04867],[29.14501,-22.07275],[29.1974,-22.07472],[29.24648,-22.05967],[29.3533,-22.18363],[29.37703,-22.19581],[29.64609,-22.12917],[29.76848,-22.14128],[29.92242,-22.19408],[30.13147,-22.30841],[30.2265,-22.2961],[30.28351,-22.35587],[30.38614,-22.34533],[30.48686,-22.31368],[30.6294,-22.32599],[30.86696,-22.28907],[31.08932,-22.34884],[31.16344,-22.32599],[31.30611,-22.422],[31.38336,-22.36919],[32.41234,-21.31246],[32.48236,-21.32873],[32.37115,-21.133],[32.51644,-20.91929],[32.48122,-20.63319],[32.55167,-20.56312],[32.66174,-20.56106],[32.85987,-20.27841],[32.85987,-20.16686],[32.93032,-20.03868],[33.01178,-20.02007],[33.06461,-19.77787],[32.95013,-19.67219],[32.84666,-19.68462],[32.84446,-19.48343],[32.78282,-19.47513],[32.77966,-19.36098],[32.85107,-19.29238],[32.87088,-19.09279],[32.84006,-19.0262],[32.72118,-19.02204],[32.69917,-18.94293],[32.73439,-18.92628],[32.70137,-18.84712],[32.82465,-18.77419],[32.9017,-18.7992],[32.95013,-18.69079],[32.88629,-18.58023],[32.88629,-18.51344],[33.02278,-18.4696],[33.03159,-18.35054],[32.94133,-17.99705],[33.0492,-17.60298],[32.98536,-17.55891],[32.96554,-17.48964],[33.0426,-17.3468],[33.00517,-17.30477],[32.96554,-17.11971],[32.84113,-16.92259],[32.91051,-16.89446],[32.97655,-16.70689],[32.78943,-16.70267],[32.69917,-16.66893],[32.71017,-16.59932],[32.42838,-16.4727],[32.28529,-16.43892],[32.02772,-16.43892],[31.91324,-16.41569],[31.90223,-16.34388],[31.67988,-16.19595],[31.42451,-16.15154],[31.30563,-16.01193],[31.13171,-15.98019],[30.97761,-16.05848],[30.91597,-15.99924],[30.42568,-15.9962],[30.41902,-15.62269]]]]}}];
62958         var rawBorders = {
62959         type: type,
62960         features: features
62961         };
62962
62963         var borders = rawBorders;
62964         var whichPolygonGetter = {};
62965         var featuresByCode = {};
62966         var idFilterRegex = /\bThe\b|\bthe\b|\band\b|\bof\b|[-_ .,()&[\]/]/g;
62967         var levels = ['subterritory', 'territory', 'country', 'intermediateRegion', 'subregion', 'region', 'union', 'world'];
62968         loadDerivedDataAndCaches(borders);
62969
62970         function loadDerivedDataAndCaches(borders) {
62971           var identifierProps = ['iso1A2', 'iso1A3', 'm49', 'wikidata', 'emojiFlag', 'nameEn'];
62972           var geometryFeatures = [];
62973
62974           for (var i in borders.features) {
62975             var _feature = borders.features[i];
62976             _feature.properties.id = _feature.properties.iso1A2 || _feature.properties.m49;
62977             loadM49(_feature);
62978             loadIsoStatus(_feature);
62979             loadLevel(_feature);
62980             loadGroups(_feature);
62981             loadRoadSpeedUnit(_feature);
62982             loadDriveSide(_feature);
62983             loadFlag(_feature);
62984             cacheFeatureByIDs(_feature);
62985             if (_feature.geometry) geometryFeatures.push(_feature);
62986           }
62987
62988           for (var _i in borders.features) {
62989             var _feature2 = borders.features[_i];
62990
62991             _feature2.properties.groups.sort(function (groupID1, groupID2) {
62992               return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
62993             });
62994
62995             loadMembersForGroupsOf(_feature2);
62996           }
62997
62998           var geometryOnlyCollection = {
62999             type: 'RegionFeatureCollection',
63000             features: geometryFeatures
63001           };
63002           whichPolygonGetter = whichPolygon_1(geometryOnlyCollection);
63003
63004           function loadGroups(feature) {
63005             var props = feature.properties;
63006
63007             if (!props.groups) {
63008               props.groups = [];
63009             }
63010
63011             if (props.country) {
63012               props.groups.push(props.country);
63013             }
63014
63015             if (props.m49 !== '001') {
63016               props.groups.push('001');
63017             }
63018           }
63019
63020           function loadM49(feature) {
63021             var props = feature.properties;
63022
63023             if (!props.m49 && props.iso1N3) {
63024               props.m49 = props.iso1N3;
63025             }
63026           }
63027
63028           function loadIsoStatus(feature) {
63029             var props = feature.properties;
63030
63031             if (!props.isoStatus && props.iso1A2) {
63032               props.isoStatus = 'official';
63033             }
63034           }
63035
63036           function loadLevel(feature) {
63037             var props = feature.properties;
63038             if (props.level) return;
63039
63040             if (!props.country) {
63041               props.level = 'country';
63042             } else if (props.isoStatus === 'official') {
63043               props.level = 'territory';
63044             } else {
63045               props.level = 'subterritory';
63046             }
63047           }
63048
63049           function loadRoadSpeedUnit(feature) {
63050             var props = feature.properties;
63051
63052             if (props.roadSpeedUnit === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
63053               props.roadSpeedUnit = 'km/h';
63054             }
63055           }
63056
63057           function loadDriveSide(feature) {
63058             var props = feature.properties;
63059
63060             if (props.driveSide === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
63061               props.driveSide = 'right';
63062             }
63063           }
63064
63065           function loadFlag(feature) {
63066             if (!feature.properties.iso1A2) return;
63067             var flag = feature.properties.iso1A2.replace(/./g, function (_char) {
63068               return String.fromCodePoint(_char.charCodeAt(0) + 127397);
63069             });
63070             feature.properties.emojiFlag = flag;
63071           }
63072
63073           function loadMembersForGroupsOf(feature) {
63074             var featureID = feature.properties.id;
63075             var standardizedGroupIDs = [];
63076
63077             for (var j in feature.properties.groups) {
63078               var groupID = feature.properties.groups[j];
63079               var groupFeature = featuresByCode[groupID];
63080               standardizedGroupIDs.push(groupFeature.properties.id);
63081
63082               if (groupFeature.properties.members) {
63083                 groupFeature.properties.members.push(featureID);
63084               } else {
63085                 groupFeature.properties.members = [featureID];
63086               }
63087             }
63088
63089             feature.properties.groups = standardizedGroupIDs;
63090           }
63091
63092           function cacheFeatureByIDs(feature) {
63093             for (var k in identifierProps) {
63094               var prop = identifierProps[k];
63095               var id = prop && feature.properties[prop];
63096
63097               if (id) {
63098                 id = id.replace(idFilterRegex, '').toUpperCase();
63099                 featuresByCode[id] = feature;
63100               }
63101             }
63102
63103             if (feature.properties.aliases) {
63104               for (var j in feature.properties.aliases) {
63105                 var alias = feature.properties.aliases[j].replace(idFilterRegex, '').toUpperCase();
63106                 featuresByCode[alias] = feature;
63107               }
63108             }
63109           }
63110         }
63111
63112         function locArray(loc) {
63113           if (Array.isArray(loc)) {
63114             return loc;
63115           } else if (loc.coordinates) {
63116             return loc.coordinates;
63117           }
63118
63119           return loc.geometry.coordinates;
63120         }
63121
63122         function smallestFeature(loc) {
63123           var query = locArray(loc);
63124           var featureProperties = whichPolygonGetter(query);
63125           if (!featureProperties) return null;
63126           return featuresByCode[featureProperties.id];
63127         }
63128
63129         function countryFeature(loc) {
63130           var feature = smallestFeature(loc);
63131           if (!feature) return null;
63132           var countryCode = feature.properties.country || feature.properties.iso1A2;
63133           return featuresByCode[countryCode];
63134         }
63135
63136         function featureForLoc(loc, opts) {
63137           if (opts && opts.level && opts.level !== 'country') {
63138             var features = featuresContaining(loc);
63139             var targetLevel = opts.level;
63140             var targetLevelIndex = levels.indexOf(targetLevel);
63141             if (targetLevelIndex === -1) return null;
63142
63143             for (var i in features) {
63144               var _feature3 = features[i];
63145
63146               if (_feature3.properties.level === targetLevel || levels.indexOf(_feature3.properties.level) > targetLevelIndex) {
63147                 return _feature3;
63148               }
63149             }
63150
63151             return null;
63152           }
63153
63154           return countryFeature(loc);
63155         }
63156
63157         function featureForID(id) {
63158           var stringID;
63159
63160           if (typeof id === 'number') {
63161             stringID = id.toString();
63162
63163             if (stringID.length === 1) {
63164               stringID = '00' + stringID;
63165             } else if (stringID.length === 2) {
63166               stringID = '0' + stringID;
63167             }
63168           } else {
63169             stringID = id.replace(idFilterRegex, '').toUpperCase();
63170           }
63171
63172           return featuresByCode[stringID] || null;
63173         }
63174
63175         function smallestOrMatchingFeature(query) {
63176           if (_typeof(query) === 'object') {
63177             return smallestFeature(query);
63178           }
63179
63180           return featureForID(query);
63181         }
63182
63183         function feature(query, opts) {
63184           if (_typeof(query) === 'object') {
63185             return featureForLoc(query, opts);
63186           }
63187
63188           return featureForID(query);
63189         }
63190         function iso1A2Code(query, opts) {
63191           var match = feature(query, opts);
63192           if (!match) return null;
63193           return match.properties.iso1A2 || null;
63194         }
63195         function featuresContaining(query, strict) {
63196           var feature = smallestOrMatchingFeature(query);
63197           if (!feature) return [];
63198           var features = [];
63199
63200           if (!strict || _typeof(query) === 'object') {
63201             features.push(feature);
63202           }
63203
63204           var properties = feature.properties;
63205
63206           for (var i in properties.groups) {
63207             var groupID = properties.groups[i];
63208             features.push(featuresByCode[groupID]);
63209           }
63210
63211           return features;
63212         }
63213         function roadSpeedUnit(query) {
63214           var feature = smallestOrMatchingFeature(query);
63215           return feature && feature.properties.roadSpeedUnit || null;
63216         }
63217
63218         var _dataDeprecated;
63219
63220         var _nsi;
63221
63222         function validationOutdatedTags() {
63223           var type = 'outdated_tags';
63224           var nsiKeys = ['amenity', 'shop', 'tourism', 'leisure', 'office']; // A concern here in switching to async data means that `_dataDeprecated`
63225           // and `_nsi` will not be available at first, so the data on early tiles
63226           // may not have tags validated fully.
63227           // initialize deprecated tags array
63228
63229           _mainFileFetcher.get('deprecated').then(function (d) {
63230             return _dataDeprecated = d;
63231           })["catch"](function () {
63232             /* ignore */
63233           });
63234           _mainFileFetcher.get('nsi_brands').then(function (d) {
63235             _nsi = {
63236               brands: d.brands,
63237               matcher: matcher$1(),
63238               wikidata: {},
63239               wikipedia: {}
63240             }; // initialize name-suggestion-index matcher
63241
63242             _nsi.matcher.buildMatchIndex(d.brands); // index all known wikipedia and wikidata tags
63243
63244
63245             Object.keys(d.brands).forEach(function (kvnd) {
63246               var brand = d.brands[kvnd];
63247               var wd = brand.tags['brand:wikidata'];
63248               var wp = brand.tags['brand:wikipedia'];
63249
63250               if (wd) {
63251                 _nsi.wikidata[wd] = kvnd;
63252               }
63253
63254               if (wp) {
63255                 _nsi.wikipedia[wp] = kvnd;
63256               }
63257             });
63258             return _nsi;
63259           })["catch"](function () {
63260             /* ignore */
63261           });
63262
63263           function oldTagIssues(entity, graph) {
63264             var oldTags = Object.assign({}, entity.tags); // shallow copy
63265
63266             var preset = _mainPresetIndex.match(entity, graph);
63267             var subtype = 'deprecated_tags';
63268             if (!preset) return []; // upgrade preset..
63269
63270             if (preset.replacement) {
63271               var newPreset = _mainPresetIndex.item(preset.replacement);
63272               graph = actionChangePreset(entity.id, preset, newPreset, true
63273               /* skip field defaults */
63274               )(graph);
63275               entity = graph.entity(entity.id);
63276               preset = newPreset;
63277             } // upgrade tags..
63278
63279
63280             if (_dataDeprecated) {
63281               var deprecatedTags = entity.deprecatedTags(_dataDeprecated);
63282
63283               if (deprecatedTags.length) {
63284                 deprecatedTags.forEach(function (tag) {
63285                   graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
63286                 });
63287                 entity = graph.entity(entity.id);
63288               }
63289             } // add missing addTags..
63290
63291
63292             var newTags = Object.assign({}, entity.tags); // shallow copy
63293
63294             if (preset.tags !== preset.addTags) {
63295               Object.keys(preset.addTags).forEach(function (k) {
63296                 if (!newTags[k]) {
63297                   if (preset.addTags[k] === '*') {
63298                     newTags[k] = 'yes';
63299                   } else {
63300                     newTags[k] = preset.addTags[k];
63301                   }
63302                 }
63303               });
63304             }
63305
63306             if (_nsi) {
63307               // Do `wikidata` or `wikipedia` identify this entity as a brand?  #6416
63308               // If so, these tags can be swapped to `brand:wikidata`/`brand:wikipedia`
63309               var isBrand;
63310
63311               if (newTags.wikidata) {
63312                 // try matching `wikidata`
63313                 isBrand = _nsi.wikidata[newTags.wikidata];
63314               }
63315
63316               if (!isBrand && newTags.wikipedia) {
63317                 // fallback to `wikipedia`
63318                 isBrand = _nsi.wikipedia[newTags.wikipedia];
63319               }
63320
63321               if (isBrand && !newTags.office) {
63322                 // but avoid doing this for corporate offices
63323                 if (newTags.wikidata) {
63324                   newTags['brand:wikidata'] = newTags.wikidata;
63325                   delete newTags.wikidata;
63326                 }
63327
63328                 if (newTags.wikipedia) {
63329                   newTags['brand:wikipedia'] = newTags.wikipedia;
63330                   delete newTags.wikipedia;
63331                 } // I considered setting `name` and other tags here, but they aren't unique per wikidata
63332                 // (Q2759586 -> in USA "Papa John's", in Russia "Папа Джонс")
63333                 // So users will really need to use a preset or assign `name` themselves.
63334
63335               } // try key/value|name match against name-suggestion-index
63336
63337
63338               if (newTags.name) {
63339                 for (var i = 0; i < nsiKeys.length; i++) {
63340                   var k = nsiKeys[i];
63341                   if (!newTags[k]) continue;
63342                   var center = entity.extent(graph).center();
63343                   var countryCode = iso1A2Code(center);
63344
63345                   var match = _nsi.matcher.matchKVN(k, newTags[k], newTags.name, countryCode && countryCode.toLowerCase());
63346
63347                   if (!match) continue; // for now skip ambiguous matches (like Target~(USA) vs Target~(Australia))
63348
63349                   if (match.d) continue;
63350                   var brand = _nsi.brands[match.kvnd];
63351
63352                   if (brand && brand.tags['brand:wikidata'] && brand.tags['brand:wikidata'] !== entity.tags['not:brand:wikidata']) {
63353                     subtype = 'noncanonical_brand';
63354                     var keepTags = ['takeaway'].reduce(function (acc, k) {
63355                       if (newTags[k]) {
63356                         acc[k] = newTags[k];
63357                       }
63358
63359                       return acc;
63360                     }, {});
63361                     nsiKeys.forEach(function (k) {
63362                       return delete newTags[k];
63363                     });
63364                     Object.assign(newTags, brand.tags, keepTags);
63365                     break;
63366                   }
63367                 }
63368               }
63369             } // determine diff
63370
63371
63372             var tagDiff = utilTagDiff(oldTags, newTags);
63373             if (!tagDiff.length) return [];
63374             var isOnlyAddingTags = tagDiff.every(function (d) {
63375               return d.type === '+';
63376             });
63377             var prefix = '';
63378
63379             if (subtype === 'noncanonical_brand') {
63380               prefix = 'noncanonical_brand.';
63381             } else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
63382               subtype = 'incomplete_tags';
63383               prefix = 'incomplete.';
63384             } // don't allow autofixing brand tags
63385
63386
63387             var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, _t('issues.fix.upgrade_tags.annotation')] : null;
63388             return [new validationIssue({
63389               type: type,
63390               subtype: subtype,
63391               severity: 'warning',
63392               message: showMessage,
63393               reference: showReference,
63394               entityIds: [entity.id],
63395               hash: JSON.stringify(tagDiff),
63396               dynamicFixes: function dynamicFixes() {
63397                 return [new validationIssueFix({
63398                   autoArgs: autoArgs,
63399                   title: _t.html('issues.fix.upgrade_tags.title'),
63400                   onClick: function onClick(context) {
63401                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
63402                   }
63403                 })];
63404               }
63405             })];
63406
63407             function doUpgrade(graph) {
63408               var currEntity = graph.hasEntity(entity.id);
63409               if (!currEntity) return graph;
63410               var newTags = Object.assign({}, currEntity.tags); // shallow copy
63411
63412               tagDiff.forEach(function (diff) {
63413                 if (diff.type === '-') {
63414                   delete newTags[diff.key];
63415                 } else if (diff.type === '+') {
63416                   newTags[diff.key] = diff.newVal;
63417                 }
63418               });
63419               return actionChangeTags(currEntity.id, newTags)(graph);
63420             }
63421
63422             function showMessage(context) {
63423               var currEntity = context.hasEntity(entity.id);
63424               if (!currEntity) return '';
63425               var messageID = "issues.outdated_tags.".concat(prefix, "message");
63426
63427               if (subtype === 'noncanonical_brand' && isOnlyAddingTags) {
63428                 messageID += '_incomplete';
63429               }
63430
63431               return _t.html(messageID, {
63432                 feature: utilDisplayLabel(currEntity, context.graph())
63433               });
63434             }
63435
63436             function showReference(selection) {
63437               var enter = selection.selectAll('.issue-reference').data([0]).enter();
63438               enter.append('div').attr('class', 'issue-reference').html(_t.html("issues.outdated_tags.".concat(prefix, "reference")));
63439               enter.append('strong').html(_t.html('issues.suggested'));
63440               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) {
63441                 var klass = d.type === '+' ? 'add' : 'remove';
63442                 return "tagDiff-cell tagDiff-cell-".concat(klass);
63443               }).html(function (d) {
63444                 return d.display;
63445               });
63446             }
63447           }
63448
63449           function oldMultipolygonIssues(entity, graph) {
63450             var multipolygon, outerWay;
63451
63452             if (entity.type === 'relation') {
63453               outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
63454               multipolygon = entity;
63455             } else if (entity.type === 'way') {
63456               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
63457               outerWay = entity;
63458             } else {
63459               return [];
63460             }
63461
63462             if (!multipolygon || !outerWay) return [];
63463             return [new validationIssue({
63464               type: type,
63465               subtype: 'old_multipolygon',
63466               severity: 'warning',
63467               message: showMessage,
63468               reference: showReference,
63469               entityIds: [outerWay.id, multipolygon.id],
63470               dynamicFixes: function dynamicFixes() {
63471                 return [new validationIssueFix({
63472                   autoArgs: [doUpgrade, _t('issues.fix.move_tags.annotation')],
63473                   title: _t.html('issues.fix.move_tags.title'),
63474                   onClick: function onClick(context) {
63475                     context.perform(doUpgrade, _t('issues.fix.move_tags.annotation'));
63476                   }
63477                 })];
63478               }
63479             })];
63480
63481             function doUpgrade(graph) {
63482               var currMultipolygon = graph.hasEntity(multipolygon.id);
63483               var currOuterWay = graph.hasEntity(outerWay.id);
63484               if (!currMultipolygon || !currOuterWay) return graph;
63485               currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
63486               graph = graph.replace(currMultipolygon);
63487               return actionChangeTags(currOuterWay.id, {})(graph);
63488             }
63489
63490             function showMessage(context) {
63491               var currMultipolygon = context.hasEntity(multipolygon.id);
63492               if (!currMultipolygon) return '';
63493               return _t.html('issues.old_multipolygon.message', {
63494                 multipolygon: utilDisplayLabel(currMultipolygon, context.graph())
63495               });
63496             }
63497
63498             function showReference(selection) {
63499               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.old_multipolygon.reference'));
63500             }
63501           }
63502
63503           var validation = function checkOutdatedTags(entity, graph) {
63504             var issues = oldMultipolygonIssues(entity, graph);
63505             if (!issues.length) issues = oldTagIssues(entity, graph);
63506             return issues;
63507           };
63508
63509           validation.type = type;
63510           return validation;
63511         }
63512
63513         function validationPrivateData() {
63514           var type = 'private_data'; // assume that some buildings are private
63515
63516           var privateBuildingValues = {
63517             detached: true,
63518             farm: true,
63519             house: true,
63520             houseboat: true,
63521             residential: true,
63522             semidetached_house: true,
63523             static_caravan: true
63524           }; // but they might be public if they have one of these other tags
63525
63526           var publicKeys = {
63527             amenity: true,
63528             craft: true,
63529             historic: true,
63530             leisure: true,
63531             office: true,
63532             shop: true,
63533             tourism: true
63534           }; // these tags may contain personally identifying info
63535
63536           var personalTags = {
63537             'contact:email': true,
63538             'contact:fax': true,
63539             'contact:phone': true,
63540             email: true,
63541             fax: true,
63542             phone: true
63543           };
63544
63545           var validation = function checkPrivateData(entity) {
63546             var tags = entity.tags;
63547             if (!tags.building || !privateBuildingValues[tags.building]) return [];
63548             var keepTags = {};
63549
63550             for (var k in tags) {
63551               if (publicKeys[k]) return []; // probably a public feature
63552
63553               if (!personalTags[k]) {
63554                 keepTags[k] = tags[k];
63555               }
63556             }
63557
63558             var tagDiff = utilTagDiff(tags, keepTags);
63559             if (!tagDiff.length) return [];
63560             var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
63561             return [new validationIssue({
63562               type: type,
63563               severity: 'warning',
63564               message: showMessage,
63565               reference: showReference,
63566               entityIds: [entity.id],
63567               dynamicFixes: function dynamicFixes() {
63568                 return [new validationIssueFix({
63569                   icon: 'iD-operation-delete',
63570                   title: _t.html('issues.fix.' + fixID + '.title'),
63571                   onClick: function onClick(context) {
63572                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
63573                   }
63574                 })];
63575               }
63576             })];
63577
63578             function doUpgrade(graph) {
63579               var currEntity = graph.hasEntity(entity.id);
63580               if (!currEntity) return graph;
63581               var newTags = Object.assign({}, currEntity.tags); // shallow copy
63582
63583               tagDiff.forEach(function (diff) {
63584                 if (diff.type === '-') {
63585                   delete newTags[diff.key];
63586                 } else if (diff.type === '+') {
63587                   newTags[diff.key] = diff.newVal;
63588                 }
63589               });
63590               return actionChangeTags(currEntity.id, newTags)(graph);
63591             }
63592
63593             function showMessage(context) {
63594               var currEntity = context.hasEntity(this.entityIds[0]);
63595               if (!currEntity) return '';
63596               return _t.html('issues.private_data.contact.message', {
63597                 feature: utilDisplayLabel(currEntity, context.graph())
63598               });
63599             }
63600
63601             function showReference(selection) {
63602               var enter = selection.selectAll('.issue-reference').data([0]).enter();
63603               enter.append('div').attr('class', 'issue-reference').html(_t.html('issues.private_data.reference'));
63604               enter.append('strong').html(_t.html('issues.suggested'));
63605               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) {
63606                 var klass = d.type === '+' ? 'add' : 'remove';
63607                 return 'tagDiff-cell tagDiff-cell-' + klass;
63608               }).html(function (d) {
63609                 return d.display;
63610               });
63611             }
63612           };
63613
63614           validation.type = type;
63615           return validation;
63616         }
63617
63618         var _discardNameRegexes = [];
63619         function validationSuspiciousName() {
63620           var type = 'suspicious_name';
63621           var keysToTestForGenericValues = ['aerialway', 'aeroway', 'amenity', 'building', 'craft', 'highway', 'leisure', 'railway', 'man_made', 'office', 'shop', 'tourism', 'waterway']; // A concern here in switching to async data means that `_nsiFilters` will not
63622           // be available at first, so the data on early tiles may not have tags validated fully.
63623
63624           _mainFileFetcher.get('nsi_filters').then(function (filters) {
63625             // known list of generic names (e.g. "bar")
63626             _discardNameRegexes = filters.discardNames.map(function (discardName) {
63627               return new RegExp(discardName, 'i');
63628             });
63629           })["catch"](function () {
63630             /* ignore */
63631           });
63632
63633           function isDiscardedSuggestionName(lowercaseName) {
63634             return _discardNameRegexes.some(function (regex) {
63635               return regex.test(lowercaseName);
63636             });
63637           } // test if the name is just the key or tag value (e.g. "park")
63638
63639
63640           function nameMatchesRawTag(lowercaseName, tags) {
63641             for (var i = 0; i < keysToTestForGenericValues.length; i++) {
63642               var key = keysToTestForGenericValues[i];
63643               var val = tags[key];
63644
63645               if (val) {
63646                 val = val.toLowerCase();
63647
63648                 if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, ' ') === lowercaseName || val.replace(/\_/g, ' ') === lowercaseName) {
63649                   return true;
63650                 }
63651               }
63652             }
63653
63654             return false;
63655           }
63656
63657           function isGenericName(name, tags) {
63658             name = name.toLowerCase();
63659             return nameMatchesRawTag(name, tags) || isDiscardedSuggestionName(name);
63660           }
63661
63662           function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
63663             return new validationIssue({
63664               type: type,
63665               subtype: 'generic_name',
63666               severity: 'warning',
63667               message: function message(context) {
63668                 var entity = context.hasEntity(this.entityIds[0]);
63669                 if (!entity) return '';
63670                 var preset = _mainPresetIndex.match(entity, context.graph());
63671                 var langName = langCode && _mainLocalizer.languageName(langCode);
63672                 return _t.html('issues.generic_name.message' + (langName ? '_language' : ''), {
63673                   feature: preset.name(),
63674                   name: genericName,
63675                   language: langName
63676                 });
63677               },
63678               reference: showReference,
63679               entityIds: [entityId],
63680               hash: nameKey + '=' + genericName,
63681               dynamicFixes: function dynamicFixes() {
63682                 return [new validationIssueFix({
63683                   icon: 'iD-operation-delete',
63684                   title: _t.html('issues.fix.remove_the_name.title'),
63685                   onClick: function onClick(context) {
63686                     var entityId = this.issue.entityIds[0];
63687                     var entity = context.entity(entityId);
63688                     var tags = Object.assign({}, entity.tags); // shallow copy
63689
63690                     delete tags[nameKey];
63691                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_generic_name.annotation'));
63692                   }
63693                 })];
63694               }
63695             });
63696
63697             function showReference(selection) {
63698               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
63699             }
63700           }
63701
63702           function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
63703             return new validationIssue({
63704               type: type,
63705               subtype: 'not_name',
63706               severity: 'warning',
63707               message: function message(context) {
63708                 var entity = context.hasEntity(this.entityIds[0]);
63709                 if (!entity) return '';
63710                 var preset = _mainPresetIndex.match(entity, context.graph());
63711                 var langName = langCode && _mainLocalizer.languageName(langCode);
63712                 return _t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), {
63713                   feature: preset.name(),
63714                   name: incorrectName,
63715                   language: langName
63716                 });
63717               },
63718               reference: showReference,
63719               entityIds: [entityId],
63720               hash: nameKey + '=' + incorrectName,
63721               dynamicFixes: function dynamicFixes() {
63722                 return [new validationIssueFix({
63723                   icon: 'iD-operation-delete',
63724                   title: _t.html('issues.fix.remove_the_name.title'),
63725                   onClick: function onClick(context) {
63726                     var entityId = this.issue.entityIds[0];
63727                     var entity = context.entity(entityId);
63728                     var tags = Object.assign({}, entity.tags); // shallow copy
63729
63730                     delete tags[nameKey];
63731                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_mistaken_name.annotation'));
63732                   }
63733                 })];
63734               }
63735             });
63736
63737             function showReference(selection) {
63738               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
63739             }
63740           }
63741
63742           var validation = function checkGenericName(entity) {
63743             // a generic name is okay if it's a known brand or entity
63744             if (entity.hasWikidata()) return [];
63745             var issues = [];
63746             var notNames = (entity.tags['not:name'] || '').split(';');
63747
63748             for (var key in entity.tags) {
63749               var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
63750               if (!m) continue;
63751               var langCode = m.length >= 2 ? m[1] : null;
63752               var value = entity.tags[key];
63753
63754               if (notNames.length) {
63755                 for (var i in notNames) {
63756                   var notName = notNames[i];
63757
63758                   if (notName && value === notName) {
63759                     issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
63760                     continue;
63761                   }
63762                 }
63763               }
63764
63765               if (isGenericName(value, entity.tags)) {
63766                 issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
63767               }
63768             }
63769
63770             return issues;
63771           };
63772
63773           validation.type = type;
63774           return validation;
63775         }
63776
63777         function validationUnsquareWay(context) {
63778           var type = 'unsquare_way';
63779           var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
63780           // use looser epsilon for detection to reduce warnings of buildings that are essentially square already
63781
63782           var epsilon = 0.05;
63783           var nodeThreshold = 10;
63784
63785           function isBuilding(entity, graph) {
63786             if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
63787             return entity.tags.building && entity.tags.building !== 'no';
63788           }
63789
63790           var validation = function checkUnsquareWay(entity, graph) {
63791             if (!isBuilding(entity, graph)) return []; // don't flag ways marked as physically unsquare
63792
63793             if (entity.tags.nonsquare === 'yes') return [];
63794             var isClosed = entity.isClosed();
63795             if (!isClosed) return []; // this building has bigger problems
63796             // don't flag ways with lots of nodes since they are likely detail-mapped
63797
63798             var nodes = graph.childNodes(entity).slice(); // shallow copy
63799
63800             if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
63801             // ignore if not all nodes are fully downloaded
63802
63803             var osm = services.osm;
63804             if (!osm || nodes.some(function (node) {
63805               return !osm.isDataLoaded(node.loc);
63806             })) return []; // don't flag connected ways to avoid unresolvable unsquare loops
63807
63808             var hasConnectedSquarableWays = nodes.some(function (node) {
63809               return graph.parentWays(node).some(function (way) {
63810                 if (way.id === entity.id) return false;
63811                 if (isBuilding(way, graph)) return true;
63812                 return graph.parentRelations(way).some(function (parentRelation) {
63813                   return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== 'no';
63814                 });
63815               });
63816             });
63817             if (hasConnectedSquarableWays) return []; // user-configurable square threshold
63818
63819             var storedDegreeThreshold = corePreferences('validate-square-degrees');
63820             var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
63821             var points = nodes.map(function (node) {
63822               return context.projection(node.loc);
63823             });
63824             if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
63825             var autoArgs; // don't allow autosquaring features linked to wikidata
63826
63827             if (!entity.tags.wikidata) {
63828               // use same degree threshold as for detection
63829               var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
63830               autoAction.transitionable = false; // when autofixing, do it instantly
63831
63832               autoArgs = [autoAction, _t('operations.orthogonalize.annotation.feature', {
63833                 n: 1
63834               })];
63835             }
63836
63837             return [new validationIssue({
63838               type: type,
63839               subtype: 'building',
63840               severity: 'warning',
63841               message: function message(context) {
63842                 var entity = context.hasEntity(this.entityIds[0]);
63843                 return entity ? _t.html('issues.unsquare_way.message', {
63844                   feature: utilDisplayLabel(entity, context.graph())
63845                 }) : '';
63846               },
63847               reference: showReference,
63848               entityIds: [entity.id],
63849               hash: JSON.stringify(autoArgs !== undefined) + degreeThreshold,
63850               dynamicFixes: function dynamicFixes() {
63851                 return [new validationIssueFix({
63852                   icon: 'iD-operation-orthogonalize',
63853                   title: _t.html('issues.fix.square_feature.title'),
63854                   autoArgs: autoArgs,
63855                   onClick: function onClick(context, completionHandler) {
63856                     var entityId = this.issue.entityIds[0]; // use same degree threshold as for detection
63857
63858                     context.perform(actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold), _t('operations.orthogonalize.annotation.feature', {
63859                       n: 1
63860                     })); // run after the squaring transition (currently 150ms)
63861
63862                     window.setTimeout(function () {
63863                       completionHandler();
63864                     }, 175);
63865                   }
63866                 })
63867                 /*
63868                 new validationIssueFix({
63869                     title: t.html('issues.fix.tag_as_unsquare.title'),
63870                     onClick: function(context) {
63871                         var entityId = this.issue.entityIds[0];
63872                         var entity = context.entity(entityId);
63873                         var tags = Object.assign({}, entity.tags);  // shallow copy
63874                         tags.nonsquare = 'yes';
63875                         context.perform(
63876                             actionChangeTags(entityId, tags),
63877                             t('issues.fix.tag_as_unsquare.annotation')
63878                         );
63879                     }
63880                 })
63881                 */
63882                 ];
63883               }
63884             })];
63885
63886             function showReference(selection) {
63887               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unsquare_way.buildings.reference'));
63888             }
63889           };
63890
63891           validation.type = type;
63892           return validation;
63893         }
63894
63895         var Validations = /*#__PURE__*/Object.freeze({
63896                 __proto__: null,
63897                 validationAlmostJunction: validationAlmostJunction,
63898                 validationCloseNodes: validationCloseNodes,
63899                 validationCrossingWays: validationCrossingWays,
63900                 validationDisconnectedWay: validationDisconnectedWay,
63901                 validationFormatting: validationFormatting,
63902                 validationHelpRequest: validationHelpRequest,
63903                 validationImpossibleOneway: validationImpossibleOneway,
63904                 validationIncompatibleSource: validationIncompatibleSource,
63905                 validationMaprules: validationMaprules,
63906                 validationMismatchedGeometry: validationMismatchedGeometry,
63907                 validationMissingRole: validationMissingRole,
63908                 validationMissingTag: validationMissingTag,
63909                 validationOutdatedTags: validationOutdatedTags,
63910                 validationPrivateData: validationPrivateData,
63911                 validationSuspiciousName: validationSuspiciousName,
63912                 validationUnsquareWay: validationUnsquareWay
63913         });
63914
63915         function coreValidator(context) {
63916           var dispatch$1 = dispatch('validated', 'focusedIssue');
63917           var validator = utilRebind({}, dispatch$1, 'on');
63918           var _rules = {};
63919           var _disabledRules = {};
63920           var _ignoredIssueIDs = {}; // issue.id -> true
63921
63922           var _baseCache = validationCache(); // issues before any user edits
63923
63924
63925           var _headCache = validationCache(); // issues after all user edits
63926
63927
63928           var _validatedGraph = null;
63929
63930           var _deferred = new Set(); //
63931           // initialize the validator rulesets
63932           //
63933
63934
63935           validator.init = function () {
63936             Object.values(Validations).forEach(function (validation) {
63937               if (typeof validation !== 'function') return;
63938               var fn = validation(context);
63939               var key = fn.type;
63940               _rules[key] = fn;
63941             });
63942             var disabledRules = corePreferences('validate-disabledRules');
63943
63944             if (disabledRules) {
63945               disabledRules.split(',').forEach(function (key) {
63946                 _disabledRules[key] = true;
63947               });
63948             }
63949           };
63950
63951           function reset(resetIgnored) {
63952             Array.from(_deferred).forEach(function (handle) {
63953               window.cancelIdleCallback(handle);
63954
63955               _deferred["delete"](handle);
63956             }); // clear caches
63957
63958             if (resetIgnored) _ignoredIssueIDs = {};
63959             _baseCache = validationCache();
63960             _headCache = validationCache();
63961             _validatedGraph = null;
63962           } //
63963           // clear caches, called whenever iD resets after a save
63964           //
63965
63966
63967           validator.reset = function () {
63968             reset(true);
63969           };
63970
63971           validator.resetIgnoredIssues = function () {
63972             _ignoredIssueIDs = {}; // reload UI
63973
63974             dispatch$1.call('validated');
63975           }; // must update issues when the user changes the unsquare thereshold
63976
63977
63978           validator.reloadUnsquareIssues = function () {
63979             reloadUnsquareIssues(_headCache, context.graph());
63980             reloadUnsquareIssues(_baseCache, context.history().base());
63981             dispatch$1.call('validated');
63982           };
63983
63984           function reloadUnsquareIssues(cache, graph) {
63985             var checkUnsquareWay = _rules.unsquare_way;
63986             if (typeof checkUnsquareWay !== 'function') return; // uncache existing
63987
63988             cache.uncacheIssuesOfType('unsquare_way');
63989             var buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), graph) // everywhere
63990             .filter(function (entity) {
63991               return entity.type === 'way' && entity.tags.building && entity.tags.building !== 'no';
63992             }); // rerun for all buildings
63993
63994             buildings.forEach(function (entity) {
63995               var detected = checkUnsquareWay(entity, graph);
63996               if (detected.length !== 1) return;
63997               var issue = detected[0];
63998
63999               if (!cache.issuesByEntityID[entity.id]) {
64000                 cache.issuesByEntityID[entity.id] = new Set();
64001               }
64002
64003               cache.issuesByEntityID[entity.id].add(issue.id);
64004               cache.issuesByIssueID[issue.id] = issue;
64005             });
64006           } // options = {
64007           //     what: 'all',     // 'all' or 'edited'
64008           //     where: 'all',   // 'all' or 'visible'
64009           //     includeIgnored: false   // true, false, or 'only'
64010           //     includeDisabledRules: false   // true, false, or 'only'
64011           // };
64012
64013
64014           validator.getIssues = function (options) {
64015             var opts = Object.assign({
64016               what: 'all',
64017               where: 'all',
64018               includeIgnored: false,
64019               includeDisabledRules: false
64020             }, options);
64021             var issues = Object.values(_headCache.issuesByIssueID);
64022             var view = context.map().extent();
64023             return issues.filter(function (issue) {
64024               if (!issue) return false;
64025               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
64026               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
64027               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
64028               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false; // Sanity check:  This issue may be for an entity that not longer exists.
64029               // If we detect this, uncache and return false so it is not included..
64030
64031               var entityIds = issue.entityIds || [];
64032
64033               for (var i = 0; i < entityIds.length; i++) {
64034                 var entityId = entityIds[i];
64035
64036                 if (!context.hasEntity(entityId)) {
64037                   delete _headCache.issuesByEntityID[entityId];
64038                   delete _headCache.issuesByIssueID[issue.id];
64039                   return false;
64040                 }
64041               }
64042
64043               if (opts.what === 'edited' && _baseCache.issuesByIssueID[issue.id]) return false;
64044
64045               if (opts.where === 'visible') {
64046                 var extent = issue.extent(context.graph());
64047                 if (!view.intersects(extent)) return false;
64048               }
64049
64050               return true;
64051             });
64052           };
64053
64054           validator.getResolvedIssues = function () {
64055             var baseIssues = Object.values(_baseCache.issuesByIssueID);
64056             return baseIssues.filter(function (issue) {
64057               return !_headCache.issuesByIssueID[issue.id];
64058             });
64059           };
64060
64061           validator.focusIssue = function (issue) {
64062             var extent = issue.extent(context.graph());
64063
64064             if (extent) {
64065               var setZoom = Math.max(context.map().zoom(), 19);
64066               context.map().unobscuredCenterZoomEase(extent.center(), setZoom); // select the first entity
64067
64068               if (issue.entityIds && issue.entityIds.length) {
64069                 window.setTimeout(function () {
64070                   var ids = issue.entityIds;
64071                   context.enter(modeSelect(context, [ids[0]]));
64072                   dispatch$1.call('focusedIssue', this, issue);
64073                 }, 250); // after ease
64074               }
64075             }
64076           };
64077
64078           validator.getIssuesBySeverity = function (options) {
64079             var groups = utilArrayGroupBy(validator.getIssues(options), 'severity');
64080             groups.error = groups.error || [];
64081             groups.warning = groups.warning || [];
64082             return groups;
64083           }; // show some issue types in a particular order
64084
64085
64086           var orderedIssueTypes = [// flag missing data first
64087           'missing_tag', 'missing_role', // then flag identity issues
64088           'outdated_tags', 'mismatched_geometry', // flag geometry issues where fixing them might solve connectivity issues
64089           'crossing_ways', 'almost_junction', // then flag connectivity issues
64090           'disconnected_way', 'impossible_oneway']; // returns the issues that the given entity IDs have in common, matching the given options
64091
64092           validator.getSharedEntityIssues = function (entityIDs, options) {
64093             var cache = _headCache; // gather the issues that are common to all the entities
64094
64095             var issueIDs = entityIDs.reduce(function (acc, entityID) {
64096               var entityIssueIDs = cache.issuesByEntityID[entityID] || new Set();
64097
64098               if (!acc) {
64099                 return new Set(entityIssueIDs);
64100               }
64101
64102               return new Set(_toConsumableArray(acc).filter(function (elem) {
64103                 return entityIssueIDs.has(elem);
64104               }));
64105             }, null) || [];
64106             var opts = options || {};
64107             return Array.from(issueIDs).map(function (id) {
64108               return cache.issuesByIssueID[id];
64109             }).filter(function (issue) {
64110               if (!issue) return false;
64111               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
64112               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
64113               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
64114               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false;
64115               return true;
64116             }).sort(function (issue1, issue2) {
64117               if (issue1.type === issue2.type) {
64118                 // issues of the same type, sort deterministically
64119                 return issue1.id < issue2.id ? -1 : 1;
64120               }
64121
64122               var index1 = orderedIssueTypes.indexOf(issue1.type);
64123               var index2 = orderedIssueTypes.indexOf(issue2.type);
64124
64125               if (index1 !== -1 && index2 !== -1) {
64126                 // both issue types have explicit sort orders
64127                 return index1 - index2;
64128               } else if (index1 === -1 && index2 === -1) {
64129                 // neither issue type has an explicit sort order, sort by type
64130                 return issue1.type < issue2.type ? -1 : 1;
64131               } else {
64132                 // order explicit types before everything else
64133                 return index1 !== -1 ? -1 : 1;
64134               }
64135             });
64136           };
64137
64138           validator.getEntityIssues = function (entityID, options) {
64139             return validator.getSharedEntityIssues([entityID], options);
64140           };
64141
64142           validator.getRuleKeys = function () {
64143             return Object.keys(_rules);
64144           };
64145
64146           validator.isRuleEnabled = function (key) {
64147             return !_disabledRules[key];
64148           };
64149
64150           validator.toggleRule = function (key) {
64151             if (_disabledRules[key]) {
64152               delete _disabledRules[key];
64153             } else {
64154               _disabledRules[key] = true;
64155             }
64156
64157             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
64158             validator.validate();
64159           };
64160
64161           validator.disableRules = function (keys) {
64162             _disabledRules = {};
64163             keys.forEach(function (k) {
64164               _disabledRules[k] = true;
64165             });
64166             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
64167             validator.validate();
64168           };
64169
64170           validator.ignoreIssue = function (id) {
64171             _ignoredIssueIDs[id] = true;
64172           }; //
64173           // Run validation on a single entity for the given graph
64174           //
64175
64176
64177           function validateEntity(entity, graph) {
64178             var entityIssues = []; // runs validation and appends resulting issues
64179
64180             function runValidation(key) {
64181               var fn = _rules[key];
64182
64183               if (typeof fn !== 'function') {
64184                 console.error('no such validation rule = ' + key); // eslint-disable-line no-console
64185
64186                 return;
64187               }
64188
64189               var detected = fn(entity, graph);
64190               entityIssues = entityIssues.concat(detected);
64191             } // run all rules
64192
64193
64194             Object.keys(_rules).forEach(runValidation);
64195             return entityIssues;
64196           }
64197
64198           function entityIDsToValidate(entityIDs, graph) {
64199             var processedIDs = new Set();
64200             return entityIDs.reduce(function (acc, entityID) {
64201               // keep redundancy check separate from `acc` because an `entityID`
64202               // could have been added to `acc` as a related entity through an earlier pass
64203               if (processedIDs.has(entityID)) return acc;
64204               processedIDs.add(entityID);
64205               var entity = graph.hasEntity(entityID);
64206               if (!entity) return acc;
64207               acc.add(entityID);
64208               var checkParentRels = [entity];
64209
64210               if (entity.type === 'node') {
64211                 graph.parentWays(entity).forEach(function (parentWay) {
64212                   acc.add(parentWay.id); // include parent ways
64213
64214                   checkParentRels.push(parentWay);
64215                 });
64216               } else if (entity.type === 'relation') {
64217                 entity.members.forEach(function (member) {
64218                   acc.add(member.id); // include members
64219                 });
64220               } else if (entity.type === 'way') {
64221                 entity.nodes.forEach(function (nodeID) {
64222                   acc.add(nodeID); // include child nodes
64223
64224                   graph._parentWays[nodeID].forEach(function (wayID) {
64225                     acc.add(wayID); // include connected ways
64226                   });
64227                 });
64228               }
64229
64230               checkParentRels.forEach(function (entity) {
64231                 // include parent relations
64232                 if (entity.type !== 'relation') {
64233                   // but not super-relations
64234                   graph.parentRelations(entity).forEach(function (parentRelation) {
64235                     acc.add(parentRelation.id);
64236                   });
64237                 }
64238               });
64239               return acc;
64240             }, new Set());
64241           } //
64242           // Run validation for several entities, supplied `entityIDs`,
64243           // against `graph` for the given `cache`
64244           //
64245
64246
64247           function validateEntities(entityIDs, graph, cache) {
64248             // clear caches for existing issues related to these entities
64249             entityIDs.forEach(cache.uncacheEntityID); // detect new issues and update caches
64250
64251             entityIDs.forEach(function (entityID) {
64252               var entity = graph.hasEntity(entityID); // don't validate deleted entities
64253
64254               if (!entity) return;
64255               var issues = validateEntity(entity, graph);
64256               cache.cacheIssues(issues);
64257             });
64258           } //
64259           // Validates anything that has changed since the last time it was run.
64260           // Also updates the "validatedGraph" to be the current graph
64261           // and dispatches a `validated` event when finished.
64262           //
64263
64264
64265           validator.validate = function () {
64266             var currGraph = context.graph();
64267             _validatedGraph = _validatedGraph || context.history().base();
64268
64269             if (currGraph === _validatedGraph) {
64270               dispatch$1.call('validated');
64271               return;
64272             }
64273
64274             var oldGraph = _validatedGraph;
64275             var difference = coreDifference(oldGraph, currGraph);
64276             _validatedGraph = currGraph;
64277             var createdAndModifiedEntityIDs = difference.extantIDs(true); // created/modified (true = w/relation members)
64278
64279             var entityIDsToCheck = entityIDsToValidate(createdAndModifiedEntityIDs, currGraph); // check modified and deleted entities against the old graph in order to update their related entities
64280             // (e.g. deleting the only highway connected to a road should create a disconnected highway issue)
64281
64282             var modifiedAndDeletedEntityIDs = difference.deleted().concat(difference.modified()).map(function (entity) {
64283               return entity.id;
64284             });
64285             var entityIDsToCheckForOldGraph = entityIDsToValidate(modifiedAndDeletedEntityIDs, oldGraph); // concat the sets
64286
64287             entityIDsToCheckForOldGraph.forEach(entityIDsToCheck.add, entityIDsToCheck);
64288             validateEntities(entityIDsToCheck, context.graph(), _headCache);
64289             dispatch$1.call('validated');
64290           };
64291
64292           context.history().on('reset.validator', function () {
64293             // cached issues aren't valid any longer if the history has been reset
64294             reset(false);
64295             validator.validate();
64296           }); // WHEN TO RUN VALIDATION:
64297           // When graph changes:
64298
64299           context.history().on('restore.validator', validator.validate) // restore saved history
64300           .on('undone.validator', validator.validate) // undo
64301           .on('redone.validator', validator.validate); // redo
64302           // but not on 'change' (e.g. while drawing)
64303           // When user changes editing modes:
64304
64305           context.on('exit.validator', validator.validate); // When merging fetched data:
64306
64307           context.history().on('merge.validator', function (entities) {
64308             if (!entities) return;
64309             var handle = window.requestIdleCallback(function () {
64310               var entityIDs = entities.map(function (entity) {
64311                 return entity.id;
64312               });
64313               var headGraph = context.graph();
64314               validateEntities(entityIDsToValidate(entityIDs, headGraph), headGraph, _headCache);
64315               var baseGraph = context.history().base();
64316               validateEntities(entityIDsToValidate(entityIDs, baseGraph), baseGraph, _baseCache);
64317               dispatch$1.call('validated');
64318             });
64319
64320             _deferred.add(handle);
64321           });
64322           return validator;
64323         }
64324
64325         function validationCache() {
64326           var cache = {
64327             issuesByIssueID: {},
64328             // issue.id -> issue
64329             issuesByEntityID: {} // entity.id -> set(issue.id)
64330
64331           };
64332
64333           cache.cacheIssues = function (issues) {
64334             issues.forEach(function (issue) {
64335               var entityIds = issue.entityIds || [];
64336               entityIds.forEach(function (entityId) {
64337                 if (!cache.issuesByEntityID[entityId]) {
64338                   cache.issuesByEntityID[entityId] = new Set();
64339                 }
64340
64341                 cache.issuesByEntityID[entityId].add(issue.id);
64342               });
64343               cache.issuesByIssueID[issue.id] = issue;
64344             });
64345           };
64346
64347           cache.uncacheIssue = function (issue) {
64348             // When multiple entities are involved (e.g. crossing_ways),
64349             // remove this issue from the other entity caches too..
64350             var entityIds = issue.entityIds || [];
64351             entityIds.forEach(function (entityId) {
64352               if (cache.issuesByEntityID[entityId]) {
64353                 cache.issuesByEntityID[entityId]["delete"](issue.id);
64354               }
64355             });
64356             delete cache.issuesByIssueID[issue.id];
64357           };
64358
64359           cache.uncacheIssues = function (issues) {
64360             issues.forEach(cache.uncacheIssue);
64361           };
64362
64363           cache.uncacheIssuesOfType = function (type) {
64364             var issuesOfType = Object.values(cache.issuesByIssueID).filter(function (issue) {
64365               return issue.type === type;
64366             });
64367             cache.uncacheIssues(issuesOfType);
64368           }; //
64369           // Remove a single entity and all its related issues from the caches
64370           //
64371
64372
64373           cache.uncacheEntityID = function (entityID) {
64374             var issueIDs = cache.issuesByEntityID[entityID];
64375             if (!issueIDs) return;
64376             issueIDs.forEach(function (issueID) {
64377               var issue = cache.issuesByIssueID[issueID];
64378
64379               if (issue) {
64380                 cache.uncacheIssue(issue);
64381               } else {
64382                 delete cache.issuesByIssueID[issueID];
64383               }
64384             });
64385             delete cache.issuesByEntityID[entityID];
64386           };
64387
64388           return cache;
64389         }
64390
64391         function coreUploader(context) {
64392           var dispatch$1 = dispatch( // Start and end events are dispatched exactly once each per legitimate outside call to `save`
64393           'saveStarted', // dispatched as soon as a call to `save` has been deemed legitimate
64394           'saveEnded', // dispatched after the result event has been dispatched
64395           'willAttemptUpload', // dispatched before the actual upload call occurs, if it will
64396           'progressChanged', // Each save results in one of these outcomes:
64397           'resultNoChanges', // upload wasn't attempted since there were no edits
64398           'resultErrors', // upload failed due to errors
64399           'resultConflicts', // upload failed due to data conflicts
64400           'resultSuccess' // upload completed without errors
64401           );
64402           var _isSaving = false;
64403           var _conflicts = [];
64404           var _errors = [];
64405
64406           var _origChanges;
64407
64408           var _discardTags = {};
64409           _mainFileFetcher.get('discarded').then(function (d) {
64410             _discardTags = d;
64411           })["catch"](function () {
64412             /* ignore */
64413           });
64414           var uploader = utilRebind({}, dispatch$1, 'on');
64415
64416           uploader.isSaving = function () {
64417             return _isSaving;
64418           };
64419
64420           uploader.save = function (changeset, tryAgain, checkConflicts) {
64421             // Guard against accidentally entering save code twice - #4641
64422             if (_isSaving && !tryAgain) {
64423               return;
64424             }
64425
64426             var osm = context.connection();
64427             if (!osm) return; // If user somehow got logged out mid-save, try to reauthenticate..
64428             // This can happen if they were logged in from before, but the tokens are no longer valid.
64429
64430             if (!osm.authenticated()) {
64431               osm.authenticate(function (err) {
64432                 if (!err) {
64433                   uploader.save(changeset, tryAgain, checkConflicts); // continue where we left off..
64434                 }
64435               });
64436               return;
64437             }
64438
64439             if (!_isSaving) {
64440               _isSaving = true;
64441               dispatch$1.call('saveStarted', this);
64442             }
64443
64444             var history = context.history();
64445             _conflicts = [];
64446             _errors = []; // Store original changes, in case user wants to download them as an .osc file
64447
64448             _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags)); // First time, `history.perform` a no-op action.
64449             // Any conflict resolutions will be done as `history.replace`
64450             // Remember to pop this later if needed
64451
64452             if (!tryAgain) {
64453               history.perform(actionNoop());
64454             } // Attempt a fast upload.. If there are conflicts, re-enter with `checkConflicts = true`
64455
64456
64457             if (!checkConflicts) {
64458               upload(changeset); // Do the full (slow) conflict check..
64459             } else {
64460               performFullConflictCheck(changeset);
64461             }
64462           };
64463
64464           function performFullConflictCheck(changeset) {
64465             var osm = context.connection();
64466             if (!osm) return;
64467             var history = context.history();
64468             var localGraph = context.graph();
64469             var remoteGraph = coreGraph(history.base(), true);
64470             var summary = history.difference().summary();
64471             var _toCheck = [];
64472
64473             for (var i = 0; i < summary.length; i++) {
64474               var item = summary[i];
64475
64476               if (item.changeType === 'modified') {
64477                 _toCheck.push(item.entity.id);
64478               }
64479             }
64480
64481             var _toLoad = withChildNodes(_toCheck, localGraph);
64482
64483             var _loaded = {};
64484             var _toLoadCount = 0;
64485             var _toLoadTotal = _toLoad.length;
64486
64487             if (_toCheck.length) {
64488               dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
64489
64490               _toLoad.forEach(function (id) {
64491                 _loaded[id] = false;
64492               });
64493
64494               osm.loadMultiple(_toLoad, loaded);
64495             } else {
64496               upload(changeset);
64497             }
64498
64499             return;
64500
64501             function withChildNodes(ids, graph) {
64502               var s = new Set(ids);
64503               ids.forEach(function (id) {
64504                 var entity = graph.entity(id);
64505                 if (entity.type !== 'way') return;
64506                 graph.childNodes(entity).forEach(function (child) {
64507                   if (child.version !== undefined) {
64508                     s.add(child.id);
64509                   }
64510                 });
64511               });
64512               return Array.from(s);
64513             } // Reload modified entities into an alternate graph and check for conflicts..
64514
64515
64516             function loaded(err, result) {
64517               if (_errors.length) return;
64518
64519               if (err) {
64520                 _errors.push({
64521                   msg: err.message || err.responseText,
64522                   details: [_t('save.status_code', {
64523                     code: err.status
64524                   })]
64525                 });
64526
64527                 didResultInErrors();
64528               } else {
64529                 var loadMore = [];
64530                 result.data.forEach(function (entity) {
64531                   remoteGraph.replace(entity);
64532                   _loaded[entity.id] = true;
64533                   _toLoad = _toLoad.filter(function (val) {
64534                     return val !== entity.id;
64535                   });
64536                   if (!entity.visible) return; // Because loadMultiple doesn't download /full like loadEntity,
64537                   // need to also load children that aren't already being checked..
64538
64539                   var i, id;
64540
64541                   if (entity.type === 'way') {
64542                     for (i = 0; i < entity.nodes.length; i++) {
64543                       id = entity.nodes[i];
64544
64545                       if (_loaded[id] === undefined) {
64546                         _loaded[id] = false;
64547                         loadMore.push(id);
64548                       }
64549                     }
64550                   } else if (entity.type === 'relation' && entity.isMultipolygon()) {
64551                     for (i = 0; i < entity.members.length; i++) {
64552                       id = entity.members[i].id;
64553
64554                       if (_loaded[id] === undefined) {
64555                         _loaded[id] = false;
64556                         loadMore.push(id);
64557                       }
64558                     }
64559                   }
64560                 });
64561                 _toLoadCount += result.data.length;
64562                 _toLoadTotal += loadMore.length;
64563                 dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
64564
64565                 if (loadMore.length) {
64566                   _toLoad.push.apply(_toLoad, loadMore);
64567
64568                   osm.loadMultiple(loadMore, loaded);
64569                 }
64570
64571                 if (!_toLoad.length) {
64572                   detectConflicts();
64573                   upload(changeset);
64574                 }
64575               }
64576             }
64577
64578             function detectConflicts() {
64579               function choice(id, text, _action) {
64580                 return {
64581                   id: id,
64582                   text: text,
64583                   action: function action() {
64584                     history.replace(_action);
64585                   }
64586                 };
64587               }
64588
64589               function formatUser(d) {
64590                 return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
64591               }
64592
64593               function entityName(entity) {
64594                 return utilDisplayName(entity) || utilDisplayType(entity.id) + ' ' + entity.id;
64595               }
64596
64597               function sameVersions(local, remote) {
64598                 if (local.version !== remote.version) return false;
64599
64600                 if (local.type === 'way') {
64601                   var children = utilArrayUnion(local.nodes, remote.nodes);
64602
64603                   for (var i = 0; i < children.length; i++) {
64604                     var a = localGraph.hasEntity(children[i]);
64605                     var b = remoteGraph.hasEntity(children[i]);
64606                     if (a && b && a.version !== b.version) return false;
64607                   }
64608                 }
64609
64610                 return true;
64611               }
64612
64613               _toCheck.forEach(function (id) {
64614                 var local = localGraph.entity(id);
64615                 var remote = remoteGraph.entity(id);
64616                 if (sameVersions(local, remote)) return;
64617                 var merge = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags, formatUser);
64618                 history.replace(merge);
64619                 var mergeConflicts = merge.conflicts();
64620                 if (!mergeConflicts.length) return; // merged safely
64621
64622                 var forceLocal = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_local');
64623                 var forceRemote = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_remote');
64624                 var keepMine = _t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore'));
64625                 var keepTheirs = _t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
64626
64627                 _conflicts.push({
64628                   id: id,
64629                   name: entityName(local),
64630                   details: mergeConflicts,
64631                   chosen: 1,
64632                   choices: [choice(id, keepMine, forceLocal), choice(id, keepTheirs, forceRemote)]
64633                 });
64634               });
64635             }
64636           }
64637
64638           function upload(changeset) {
64639             var osm = context.connection();
64640
64641             if (!osm) {
64642               _errors.push({
64643                 msg: 'No OSM Service'
64644               });
64645             }
64646
64647             if (_conflicts.length) {
64648               didResultInConflicts(changeset);
64649             } else if (_errors.length) {
64650               didResultInErrors();
64651             } else {
64652               var history = context.history();
64653               var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
64654
64655               if (changes.modified.length || changes.created.length || changes.deleted.length) {
64656                 dispatch$1.call('willAttemptUpload', this);
64657                 osm.putChangeset(changeset, changes, uploadCallback);
64658               } else {
64659                 // changes were insignificant or reverted by user
64660                 didResultInNoChanges();
64661               }
64662             }
64663           }
64664
64665           function uploadCallback(err, changeset) {
64666             if (err) {
64667               if (err.status === 409) {
64668                 // 409 Conflict
64669                 uploader.save(changeset, true, true); // tryAgain = true, checkConflicts = true
64670               } else {
64671                 _errors.push({
64672                   msg: err.message || err.responseText,
64673                   details: [_t('save.status_code', {
64674                     code: err.status
64675                   })]
64676                 });
64677
64678                 didResultInErrors();
64679               }
64680             } else {
64681               didResultInSuccess(changeset);
64682             }
64683           }
64684
64685           function didResultInNoChanges() {
64686             dispatch$1.call('resultNoChanges', this);
64687             endSave();
64688             context.flush(); // reset iD
64689           }
64690
64691           function didResultInErrors() {
64692             context.history().pop();
64693             dispatch$1.call('resultErrors', this, _errors);
64694             endSave();
64695           }
64696
64697           function didResultInConflicts(changeset) {
64698             _conflicts.sort(function (a, b) {
64699               return b.id.localeCompare(a.id);
64700             });
64701
64702             dispatch$1.call('resultConflicts', this, changeset, _conflicts, _origChanges);
64703             endSave();
64704           }
64705
64706           function didResultInSuccess(changeset) {
64707             // delete the edit stack cached to local storage
64708             context.history().clearSaved();
64709             dispatch$1.call('resultSuccess', this, changeset); // Add delay to allow for postgres replication #1646 #2678
64710
64711             window.setTimeout(function () {
64712               endSave();
64713               context.flush(); // reset iD
64714             }, 2500);
64715           }
64716
64717           function endSave() {
64718             _isSaving = false;
64719             dispatch$1.call('saveEnded', this);
64720           }
64721
64722           uploader.cancelConflictResolution = function () {
64723             context.history().pop();
64724           };
64725
64726           uploader.processResolvedConflicts = function (changeset) {
64727             var history = context.history();
64728
64729             for (var i = 0; i < _conflicts.length; i++) {
64730               if (_conflicts[i].chosen === 1) {
64731                 // user chose "use theirs"
64732                 var entity = context.hasEntity(_conflicts[i].id);
64733
64734                 if (entity && entity.type === 'way') {
64735                   var children = utilArrayUniq(entity.nodes);
64736
64737                   for (var j = 0; j < children.length; j++) {
64738                     history.replace(actionRevert(children[j]));
64739                   }
64740                 }
64741
64742                 history.replace(actionRevert(_conflicts[i].id));
64743               }
64744             }
64745
64746             uploader.save(changeset, true, false); // tryAgain = true, checkConflicts = false
64747           };
64748
64749           uploader.reset = function () {};
64750
64751           return uploader;
64752         }
64753
64754         var abs$4 = Math.abs;
64755         var exp$2 = Math.exp;
64756         var E = Math.E;
64757
64758         var FORCED$g = fails(function () {
64759           return Math.sinh(-2e-17) != -2e-17;
64760         });
64761
64762         // `Math.sinh` method
64763         // https://tc39.github.io/ecma262/#sec-math.sinh
64764         // V8 near Chromium 38 has a problem with very small numbers
64765         _export({ target: 'Math', stat: true, forced: FORCED$g }, {
64766           sinh: function sinh(x) {
64767             return abs$4(x = +x) < 1 ? (mathExpm1(x) - mathExpm1(-x)) / 2 : (exp$2(x - 1) - exp$2(-x - 1)) * (E / 2);
64768           }
64769         });
64770
64771         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
64772
64773         window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function () {
64774           isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
64775         });
64776
64777         function localeDateString(s) {
64778           if (!s) return null;
64779           var options = {
64780             day: 'numeric',
64781             month: 'short',
64782             year: 'numeric'
64783           };
64784           var d = new Date(s);
64785           if (isNaN(d.getTime())) return null;
64786           return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
64787         }
64788
64789         function vintageRange(vintage) {
64790           var s;
64791
64792           if (vintage.start || vintage.end) {
64793             s = vintage.start || '?';
64794
64795             if (vintage.start !== vintage.end) {
64796               s += ' - ' + (vintage.end || '?');
64797             }
64798           }
64799
64800           return s;
64801         }
64802
64803         function rendererBackgroundSource(data) {
64804           var source = Object.assign({}, data); // shallow copy
64805
64806           var _offset = [0, 0];
64807           var _name = source.name;
64808           var _description = source.description;
64809
64810           var _best = !!source.best;
64811
64812           var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
64813
64814           source.tileSize = data.tileSize || 256;
64815           source.zoomExtent = data.zoomExtent || [0, 22];
64816           source.overzoom = data.overzoom !== false;
64817
64818           source.offset = function (val) {
64819             if (!arguments.length) return _offset;
64820             _offset = val;
64821             return source;
64822           };
64823
64824           source.nudge = function (val, zoomlevel) {
64825             _offset[0] += val[0] / Math.pow(2, zoomlevel);
64826             _offset[1] += val[1] / Math.pow(2, zoomlevel);
64827             return source;
64828           };
64829
64830           source.name = function () {
64831             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64832             return _t('imagery.' + id_safe + '.name', {
64833               "default": _name
64834             });
64835           };
64836
64837           source.label = function () {
64838             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64839             return _t.html('imagery.' + id_safe + '.name', {
64840               "default": _name
64841             });
64842           };
64843
64844           source.description = function () {
64845             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64846             return _t.html('imagery.' + id_safe + '.description', {
64847               "default": _description
64848             });
64849           };
64850
64851           source.best = function () {
64852             return _best;
64853           };
64854
64855           source.area = function () {
64856             if (!data.polygon) return Number.MAX_VALUE; // worldwide
64857
64858             var area = d3_geoArea({
64859               type: 'MultiPolygon',
64860               coordinates: [data.polygon]
64861             });
64862             return isNaN(area) ? 0 : area;
64863           };
64864
64865           source.imageryUsed = function () {
64866             return _name || source.id;
64867           };
64868
64869           source.template = function (val) {
64870             if (!arguments.length) return _template;
64871
64872             if (source.id === 'custom') {
64873               _template = val;
64874             }
64875
64876             return source;
64877           };
64878
64879           source.url = function (coord) {
64880             var result = _template;
64881             if (result === '') return result; // source 'none'
64882             // Guess a type based on the tokens present in the template
64883             // (This is for 'custom' source, where we don't know)
64884
64885             if (!source.type) {
64886               if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(_template)) {
64887                 source.type = 'wms';
64888                 source.projection = 'EPSG:3857'; // guess
64889               } else if (/\{(x|y)\}/.test(_template)) {
64890                 source.type = 'tms';
64891               } else if (/\{u\}/.test(_template)) {
64892                 source.type = 'bing';
64893               }
64894             }
64895
64896             if (source.type === 'wms') {
64897               var tileToProjectedCoords = function tileToProjectedCoords(x, y, z) {
64898                 //polyfill for IE11, PhantomJS
64899                 var sinh = Math.sinh || function (x) {
64900                   var y = Math.exp(x);
64901                   return (y - 1 / y) / 2;
64902                 };
64903
64904                 var zoomSize = Math.pow(2, z);
64905                 var lon = x / zoomSize * Math.PI * 2 - Math.PI;
64906                 var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
64907
64908                 switch (source.projection) {
64909                   case 'EPSG:4326':
64910                     return {
64911                       x: lon * 180 / Math.PI,
64912                       y: lat * 180 / Math.PI
64913                     };
64914
64915                   default:
64916                     // EPSG:3857 and synonyms
64917                     var mercCoords = mercatorRaw(lon, lat);
64918                     return {
64919                       x: 20037508.34 / Math.PI * mercCoords[0],
64920                       y: 20037508.34 / Math.PI * mercCoords[1]
64921                     };
64922                 }
64923               };
64924
64925               var tileSize = source.tileSize;
64926               var projection = source.projection;
64927               var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
64928               var maxXminY = tileToProjectedCoords(coord[0] + 1, coord[1] + 1, coord[2]);
64929               result = result.replace(/\{(\w+)\}/g, function (token, key) {
64930                 switch (key) {
64931                   case 'width':
64932                   case 'height':
64933                     return tileSize;
64934
64935                   case 'proj':
64936                     return projection;
64937
64938                   case 'wkid':
64939                     return projection.replace(/^EPSG:/, '');
64940
64941                   case 'bbox':
64942                     // WMS 1.3 flips x/y for some coordinate systems including EPSG:4326 - #7557
64943                     if (projection === 'EPSG:4326' && // The CRS parameter implies version 1.3 (prior versions use SRS)
64944                     /VERSION=1.3|CRS={proj}/.test(source.template())) {
64945                       return maxXminY.y + ',' + minXmaxY.x + ',' + minXmaxY.y + ',' + maxXminY.x;
64946                     } else {
64947                       return minXmaxY.x + ',' + maxXminY.y + ',' + maxXminY.x + ',' + minXmaxY.y;
64948                     }
64949
64950                   case 'w':
64951                     return minXmaxY.x;
64952
64953                   case 's':
64954                     return maxXminY.y;
64955
64956                   case 'n':
64957                     return maxXminY.x;
64958
64959                   case 'e':
64960                     return minXmaxY.y;
64961
64962                   default:
64963                     return token;
64964                 }
64965               });
64966             } else if (source.type === 'tms') {
64967               result = result.replace('{x}', coord[0]).replace('{y}', coord[1]) // TMS-flipped y coordinate
64968               .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1).replace(/\{z(oom)?\}/, coord[2]) // only fetch retina tiles for retina screens
64969               .replace(/\{@2x\}|\{r\}/, isRetina ? '@2x' : '');
64970             } else if (source.type === 'bing') {
64971               result = result.replace('{u}', function () {
64972                 var u = '';
64973
64974                 for (var zoom = coord[2]; zoom > 0; zoom--) {
64975                   var b = 0;
64976                   var mask = 1 << zoom - 1;
64977                   if ((coord[0] & mask) !== 0) b++;
64978                   if ((coord[1] & mask) !== 0) b += 2;
64979                   u += b.toString();
64980                 }
64981
64982                 return u;
64983               });
64984             } // these apply to any type..
64985
64986
64987             result = result.replace(/\{switch:([^}]+)\}/, function (s, r) {
64988               var subdomains = r.split(',');
64989               return subdomains[(coord[0] + coord[1]) % subdomains.length];
64990             });
64991             return result;
64992           };
64993
64994           source.validZoom = function (z) {
64995             return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
64996           };
64997
64998           source.isLocatorOverlay = function () {
64999             return source.id === 'mapbox_locator_overlay';
65000           };
65001           /* hides a source from the list, but leaves it available for use */
65002
65003
65004           source.isHidden = function () {
65005             return source.id === 'DigitalGlobe-Premium-vintage' || source.id === 'DigitalGlobe-Standard-vintage';
65006           };
65007
65008           source.copyrightNotices = function () {};
65009
65010           source.getMetadata = function (center, tileCoord, callback) {
65011             var vintage = {
65012               start: localeDateString(source.startDate),
65013               end: localeDateString(source.endDate)
65014             };
65015             vintage.range = vintageRange(vintage);
65016             var metadata = {
65017               vintage: vintage
65018             };
65019             callback(null, metadata);
65020           };
65021
65022           return source;
65023         }
65024
65025         rendererBackgroundSource.Bing = function (data, dispatch) {
65026           // http://msdn.microsoft.com/en-us/library/ff701716.aspx
65027           // http://msdn.microsoft.com/en-us/library/ff701701.aspx
65028           data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
65029           var bing = rendererBackgroundSource(data); // var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc
65030
65031           var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD
65032
65033           var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' + key;
65034           var cache = {};
65035           var inflight = {};
65036           var providers = [];
65037           d3_json(url).then(function (json) {
65038             providers = json.resourceSets[0].resources[0].imageryProviders.map(function (provider) {
65039               return {
65040                 attribution: provider.attribution,
65041                 areas: provider.coverageAreas.map(function (area) {
65042                   return {
65043                     zoom: [area.zoomMin, area.zoomMax],
65044                     extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
65045                   };
65046                 })
65047               };
65048             });
65049             dispatch.call('change');
65050           })["catch"](function () {
65051             /* ignore */
65052           });
65053
65054           bing.copyrightNotices = function (zoom, extent) {
65055             zoom = Math.min(zoom, 21);
65056             return providers.filter(function (provider) {
65057               return provider.areas.some(function (area) {
65058                 return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
65059               });
65060             }).map(function (provider) {
65061               return provider.attribution;
65062             }).join(', ');
65063           };
65064
65065           bing.getMetadata = function (center, tileCoord, callback) {
65066             var tileID = tileCoord.slice(0, 3).join('/');
65067             var zoom = Math.min(tileCoord[2], 21);
65068             var centerPoint = center[1] + ',' + center[0]; // lat,lng
65069
65070             var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + '?zl=' + zoom + '&key=' + key;
65071             if (inflight[tileID]) return;
65072
65073             if (!cache[tileID]) {
65074               cache[tileID] = {};
65075             }
65076
65077             if (cache[tileID] && cache[tileID].metadata) {
65078               return callback(null, cache[tileID].metadata);
65079             }
65080
65081             inflight[tileID] = true;
65082             d3_json(url).then(function (result) {
65083               delete inflight[tileID];
65084
65085               if (!result) {
65086                 throw new Error('Unknown Error');
65087               }
65088
65089               var vintage = {
65090                 start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
65091                 end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
65092               };
65093               vintage.range = vintageRange(vintage);
65094               var metadata = {
65095                 vintage: vintage
65096               };
65097               cache[tileID].metadata = metadata;
65098               if (callback) callback(null, metadata);
65099             })["catch"](function (err) {
65100               delete inflight[tileID];
65101               if (callback) callback(err.message);
65102             });
65103           };
65104
65105           bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
65106           return bing;
65107         };
65108
65109         rendererBackgroundSource.Esri = function (data) {
65110           // in addition to using the tilemap at zoom level 20, overzoom real tiles - #4327 (deprecated technique, but it works)
65111           if (data.template.match(/blankTile/) === null) {
65112             data.template = data.template + '?blankTile=false';
65113           }
65114
65115           var esri = rendererBackgroundSource(data);
65116           var cache = {};
65117           var inflight = {};
65118
65119           var _prevCenter; // use a tilemap service to set maximum zoom for esri tiles dynamically
65120           // https://developers.arcgis.com/documentation/tiled-elevation-service/
65121
65122
65123           esri.fetchTilemap = function (center) {
65124             // skip if we have already fetched a tilemap within 5km
65125             if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
65126             _prevCenter = center; // tiles are available globally to zoom level 19, afterward they may or may not be present
65127
65128             var z = 20; // first generate a random url using the template
65129
65130             var dummyUrl = esri.url([1, 2, 3]); // calculate url z/y/x from the lat/long of the center of the map
65131
65132             var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
65133             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
65134
65135             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
65136
65137             d3_json(tilemapUrl).then(function (tilemap) {
65138               if (!tilemap) {
65139                 throw new Error('Unknown Error');
65140               }
65141
65142               var hasTiles = true;
65143
65144               for (var i = 0; i < tilemap.data.length; i++) {
65145                 // 0 means an individual tile in the grid doesn't exist
65146                 if (!tilemap.data[i]) {
65147                   hasTiles = false;
65148                   break;
65149                 }
65150               } // if any tiles are missing at level 20 we restrict maxZoom to 19
65151
65152
65153               esri.zoomExtent[1] = hasTiles ? 22 : 19;
65154             })["catch"](function () {
65155               /* ignore */
65156             });
65157           };
65158
65159           esri.getMetadata = function (center, tileCoord, callback) {
65160             var tileID = tileCoord.slice(0, 3).join('/');
65161             var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
65162             var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
65163
65164             var unknown = _t('info_panels.background.unknown');
65165             var metadataLayer;
65166             var vintage = {};
65167             var metadata = {};
65168             if (inflight[tileID]) return;
65169
65170             switch (true) {
65171               case zoom >= 20 && esri.id === 'EsriWorldImageryClarity':
65172                 metadataLayer = 4;
65173                 break;
65174
65175               case zoom >= 19:
65176                 metadataLayer = 3;
65177                 break;
65178
65179               case zoom >= 17:
65180                 metadataLayer = 2;
65181                 break;
65182
65183               case zoom >= 13:
65184                 metadataLayer = 0;
65185                 break;
65186
65187               default:
65188                 metadataLayer = 99;
65189             }
65190
65191             var url; // build up query using the layer appropriate to the current zoom
65192
65193             if (esri.id === 'EsriWorldImagery') {
65194               url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
65195             } else if (esri.id === 'EsriWorldImageryClarity') {
65196               url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
65197             }
65198
65199             url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
65200
65201             if (!cache[tileID]) {
65202               cache[tileID] = {};
65203             }
65204
65205             if (cache[tileID] && cache[tileID].metadata) {
65206               return callback(null, cache[tileID].metadata);
65207             } // accurate metadata is only available >= 13
65208
65209
65210             if (metadataLayer === 99) {
65211               vintage = {
65212                 start: null,
65213                 end: null,
65214                 range: null
65215               };
65216               metadata = {
65217                 vintage: null,
65218                 source: unknown,
65219                 description: unknown,
65220                 resolution: unknown,
65221                 accuracy: unknown
65222               };
65223               callback(null, metadata);
65224             } else {
65225               inflight[tileID] = true;
65226               d3_json(url).then(function (result) {
65227                 delete inflight[tileID];
65228
65229                 if (!result) {
65230                   throw new Error('Unknown Error');
65231                 } else if (result.features && result.features.length < 1) {
65232                   throw new Error('No Results');
65233                 } else if (result.error && result.error.message) {
65234                   throw new Error(result.error.message);
65235                 } // pass through the discrete capture date from metadata
65236
65237
65238                 var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
65239                 vintage = {
65240                   start: captureDate,
65241                   end: captureDate,
65242                   range: captureDate
65243                 };
65244                 metadata = {
65245                   vintage: vintage,
65246                   source: clean(result.features[0].attributes.NICE_NAME),
65247                   description: clean(result.features[0].attributes.NICE_DESC),
65248                   resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
65249                   accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
65250                 }; // append units - meters
65251
65252                 if (isFinite(metadata.resolution)) {
65253                   metadata.resolution += ' m';
65254                 }
65255
65256                 if (isFinite(metadata.accuracy)) {
65257                   metadata.accuracy += ' m';
65258                 }
65259
65260                 cache[tileID].metadata = metadata;
65261                 if (callback) callback(null, metadata);
65262               })["catch"](function (err) {
65263                 delete inflight[tileID];
65264                 if (callback) callback(err.message);
65265               });
65266             }
65267
65268             function clean(val) {
65269               return String(val).trim() || unknown;
65270             }
65271           };
65272
65273           return esri;
65274         };
65275
65276         rendererBackgroundSource.None = function () {
65277           var source = rendererBackgroundSource({
65278             id: 'none',
65279             template: ''
65280           });
65281
65282           source.name = function () {
65283             return _t('background.none');
65284           };
65285
65286           source.label = function () {
65287             return _t.html('background.none');
65288           };
65289
65290           source.imageryUsed = function () {
65291             return null;
65292           };
65293
65294           source.area = function () {
65295             return -1; // sources in background pane are sorted by area
65296           };
65297
65298           return source;
65299         };
65300
65301         rendererBackgroundSource.Custom = function (template) {
65302           var source = rendererBackgroundSource({
65303             id: 'custom',
65304             template: template
65305           });
65306
65307           source.name = function () {
65308             return _t('background.custom');
65309           };
65310
65311           source.label = function () {
65312             return _t.html('background.custom');
65313           };
65314
65315           source.imageryUsed = function () {
65316             // sanitize personal connection tokens - #6801
65317             var cleaned = source.template(); // from query string parameters
65318
65319             if (cleaned.indexOf('?') !== -1) {
65320               var parts = cleaned.split('?', 2);
65321               var qs = utilStringQs(parts[1]);
65322               ['access_token', 'connectId', 'token'].forEach(function (param) {
65323                 if (qs[param]) {
65324                   qs[param] = '{apikey}';
65325                 }
65326               });
65327               cleaned = parts[0] + '?' + utilQsString(qs, true); // true = soft encode
65328             } // from wms/wmts api path parameters
65329
65330
65331             cleaned = cleaned.replace(/token\/(\w+)/, 'token/{apikey}');
65332             return 'Custom (' + cleaned + ' )';
65333           };
65334
65335           source.area = function () {
65336             return -2; // sources in background pane are sorted by area
65337           };
65338
65339           return source;
65340         };
65341
65342         function rendererTileLayer(context) {
65343           var transformProp = utilPrefixCSSProperty('Transform');
65344           var tiler = utilTiler();
65345           var _tileSize = 256;
65346
65347           var _projection;
65348
65349           var _cache = {};
65350
65351           var _tileOrigin;
65352
65353           var _zoom;
65354
65355           var _source;
65356
65357           function tileSizeAtZoom(d, z) {
65358             var EPSILON = 0.002; // close seams
65359
65360             return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
65361           }
65362
65363           function atZoom(t, distance) {
65364             var power = Math.pow(2, distance);
65365             return [Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance];
65366           }
65367
65368           function lookUp(d) {
65369             for (var up = -1; up > -d[2]; up--) {
65370               var tile = atZoom(d, up);
65371
65372               if (_cache[_source.url(tile)] !== false) {
65373                 return tile;
65374               }
65375             }
65376           }
65377
65378           function uniqueBy(a, n) {
65379             var o = [];
65380             var seen = {};
65381
65382             for (var i = 0; i < a.length; i++) {
65383               if (seen[a[i][n]] === undefined) {
65384                 o.push(a[i]);
65385                 seen[a[i][n]] = true;
65386               }
65387             }
65388
65389             return o;
65390           }
65391
65392           function addSource(d) {
65393             d.push(_source.url(d));
65394             return d;
65395           } // Update tiles based on current state of `projection`.
65396
65397
65398           function background(selection) {
65399             _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
65400             var pixelOffset;
65401
65402             if (_source) {
65403               pixelOffset = [_source.offset()[0] * Math.pow(2, _zoom), _source.offset()[1] * Math.pow(2, _zoom)];
65404             } else {
65405               pixelOffset = [0, 0];
65406             }
65407
65408             var translate = [_projection.translate()[0] + pixelOffset[0], _projection.translate()[1] + pixelOffset[1]];
65409             tiler.scale(_projection.scale() * 2 * Math.PI).translate(translate);
65410             _tileOrigin = [_projection.scale() * Math.PI - translate[0], _projection.scale() * Math.PI - translate[1]];
65411             render(selection);
65412           } // Derive the tiles onscreen, remove those offscreen and position them.
65413           // Important that this part not depend on `_projection` because it's
65414           // rentered when tiles load/error (see #644).
65415
65416
65417           function render(selection) {
65418             if (!_source) return;
65419             var requests = [];
65420             var showDebug = context.getDebug('tile') && !_source.overlay;
65421
65422             if (_source.validZoom(_zoom)) {
65423               tiler.skipNullIsland(!!_source.overlay);
65424               tiler().forEach(function (d) {
65425                 addSource(d);
65426                 if (d[3] === '') return;
65427                 if (typeof d[3] !== 'string') return; // Workaround for #2295
65428
65429                 requests.push(d);
65430
65431                 if (_cache[d[3]] === false && lookUp(d)) {
65432                   requests.push(addSource(lookUp(d)));
65433                 }
65434               });
65435               requests = uniqueBy(requests, 3).filter(function (r) {
65436                 // don't re-request tiles which have failed in the past
65437                 return _cache[r[3]] !== false;
65438               });
65439             }
65440
65441             function load(d3_event, d) {
65442               _cache[d[3]] = true;
65443               select(this).on('error', null).on('load', null).classed('tile-loaded', true);
65444               render(selection);
65445             }
65446
65447             function error(d3_event, d) {
65448               _cache[d[3]] = false;
65449               select(this).on('error', null).on('load', null).remove();
65450               render(selection);
65451             }
65452
65453             function imageTransform(d) {
65454               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
65455
65456               var scale = tileSizeAtZoom(d, _zoom);
65457               return 'translate(' + (d[0] * ts - _tileOrigin[0]) + 'px,' + (d[1] * ts - _tileOrigin[1]) + 'px) ' + 'scale(' + scale + ',' + scale + ')';
65458             }
65459
65460             function tileCenter(d) {
65461               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
65462
65463               return [d[0] * ts - _tileOrigin[0] + ts / 2, d[1] * ts - _tileOrigin[1] + ts / 2];
65464             }
65465
65466             function debugTransform(d) {
65467               var coord = tileCenter(d);
65468               return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
65469             } // Pick a representative tile near the center of the viewport
65470             // (This is useful for sampling the imagery vintage)
65471
65472
65473             var dims = tiler.size();
65474             var mapCenter = [dims[0] / 2, dims[1] / 2];
65475             var minDist = Math.max(dims[0], dims[1]);
65476             var nearCenter;
65477             requests.forEach(function (d) {
65478               var c = tileCenter(d);
65479               var dist = geoVecLength(c, mapCenter);
65480
65481               if (dist < minDist) {
65482                 minDist = dist;
65483                 nearCenter = d;
65484               }
65485             });
65486             var image = selection.selectAll('img').data(requests, function (d) {
65487               return d[3];
65488             });
65489             image.exit().style(transformProp, imageTransform).classed('tile-removing', true).classed('tile-center', false).each(function () {
65490               var tile = select(this);
65491               window.setTimeout(function () {
65492                 if (tile.classed('tile-removing')) {
65493                   tile.remove();
65494                 }
65495               }, 300);
65496             });
65497             image.enter().append('img').attr('class', 'tile').attr('draggable', 'false').style('width', _tileSize + 'px').style('height', _tileSize + 'px').attr('src', function (d) {
65498               return d[3];
65499             }).on('error', error).on('load', load).merge(image).style(transformProp, imageTransform).classed('tile-debug', showDebug).classed('tile-removing', false).classed('tile-center', function (d) {
65500               return d === nearCenter;
65501             });
65502             var debug = selection.selectAll('.tile-label-debug').data(showDebug ? requests : [], function (d) {
65503               return d[3];
65504             });
65505             debug.exit().remove();
65506
65507             if (showDebug) {
65508               var debugEnter = debug.enter().append('div').attr('class', 'tile-label-debug');
65509               debugEnter.append('div').attr('class', 'tile-label-debug-coord');
65510               debugEnter.append('div').attr('class', 'tile-label-debug-vintage');
65511               debug = debug.merge(debugEnter);
65512               debug.style(transformProp, debugTransform);
65513               debug.selectAll('.tile-label-debug-coord').html(function (d) {
65514                 return d[2] + ' / ' + d[0] + ' / ' + d[1];
65515               });
65516               debug.selectAll('.tile-label-debug-vintage').each(function (d) {
65517                 var span = select(this);
65518                 var center = context.projection.invert(tileCenter(d));
65519
65520                 _source.getMetadata(center, d, function (err, result) {
65521                   span.html(result && result.vintage && result.vintage.range || _t('info_panels.background.vintage') + ': ' + _t('info_panels.background.unknown'));
65522                 });
65523               });
65524             }
65525           }
65526
65527           background.projection = function (val) {
65528             if (!arguments.length) return _projection;
65529             _projection = val;
65530             return background;
65531           };
65532
65533           background.dimensions = function (val) {
65534             if (!arguments.length) return tiler.size();
65535             tiler.size(val);
65536             return background;
65537           };
65538
65539           background.source = function (val) {
65540             if (!arguments.length) return _source;
65541             _source = val;
65542             _tileSize = _source.tileSize;
65543             _cache = {};
65544             tiler.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
65545             return background;
65546           };
65547
65548           return background;
65549         }
65550
65551         var _imageryIndex = null;
65552         function rendererBackground(context) {
65553           var dispatch$1 = dispatch('change');
65554           var detected = utilDetect();
65555           var baseLayer = rendererTileLayer(context).projection(context.projection);
65556           var _isValid = true;
65557           var _overlayLayers = [];
65558           var _brightness = 1;
65559           var _contrast = 1;
65560           var _saturation = 1;
65561           var _sharpness = 1;
65562
65563           function ensureImageryIndex() {
65564             return _mainFileFetcher.get('imagery').then(function (sources) {
65565               if (_imageryIndex) return _imageryIndex;
65566               _imageryIndex = {
65567                 imagery: sources,
65568                 features: {}
65569               }; // use which-polygon to support efficient index and querying for imagery
65570
65571               var features = sources.map(function (source) {
65572                 if (!source.polygon) return null; // workaround for editor-layer-index weirdness..
65573                 // Add an extra array nest to each element in `source.polygon`
65574                 // so the rings are not treated as a bunch of holes:
65575                 // what we have: [ [[outer],[hole],[hole]] ]
65576                 // what we want: [ [[outer]],[[outer]],[[outer]] ]
65577
65578                 var rings = source.polygon.map(function (ring) {
65579                   return [ring];
65580                 });
65581                 var feature = {
65582                   type: 'Feature',
65583                   properties: {
65584                     id: source.id
65585                   },
65586                   geometry: {
65587                     type: 'MultiPolygon',
65588                     coordinates: rings
65589                   }
65590                 };
65591                 _imageryIndex.features[source.id] = feature;
65592                 return feature;
65593               }).filter(Boolean);
65594               _imageryIndex.query = whichPolygon_1({
65595                 type: 'FeatureCollection',
65596                 features: features
65597               }); // Instantiate `rendererBackgroundSource` objects for each source
65598
65599               _imageryIndex.backgrounds = sources.map(function (source) {
65600                 if (source.type === 'bing') {
65601                   return rendererBackgroundSource.Bing(source, dispatch$1);
65602                 } else if (/^EsriWorldImagery/.test(source.id)) {
65603                   return rendererBackgroundSource.Esri(source);
65604                 } else {
65605                   return rendererBackgroundSource(source);
65606                 }
65607               }); // Add 'None'
65608
65609               _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None()); // Add 'Custom'
65610
65611
65612               var template = corePreferences('background-custom-template') || '';
65613               var custom = rendererBackgroundSource.Custom(template);
65614
65615               _imageryIndex.backgrounds.unshift(custom);
65616
65617               return _imageryIndex;
65618             });
65619           }
65620
65621           function background(selection) {
65622             var currSource = baseLayer.source(); // If we are displaying an Esri basemap at high zoom,
65623             // check its tilemap to see how high the zoom can go
65624
65625             if (context.map().zoom() > 18) {
65626               if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
65627                 var center = context.map().center();
65628                 currSource.fetchTilemap(center);
65629               }
65630             } // Is the imagery valid here? - #4827
65631
65632
65633             var sources = background.sources(context.map().extent());
65634             var wasValid = _isValid;
65635             _isValid = !!sources.filter(function (d) {
65636               return d === currSource;
65637             }).length;
65638
65639             if (wasValid !== _isValid) {
65640               // change in valid status
65641               background.updateImagery();
65642             }
65643
65644             var baseFilter = '';
65645
65646             if (detected.cssfilters) {
65647               if (_brightness !== 1) {
65648                 baseFilter += " brightness(".concat(_brightness, ")");
65649               }
65650
65651               if (_contrast !== 1) {
65652                 baseFilter += " contrast(".concat(_contrast, ")");
65653               }
65654
65655               if (_saturation !== 1) {
65656                 baseFilter += " saturate(".concat(_saturation, ")");
65657               }
65658
65659               if (_sharpness < 1) {
65660                 // gaussian blur
65661                 var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
65662                 baseFilter += " blur(".concat(blur, "px)");
65663               }
65664             }
65665
65666             var base = selection.selectAll('.layer-background').data([0]);
65667             base = base.enter().insert('div', '.layer-data').attr('class', 'layer layer-background').merge(base);
65668
65669             if (detected.cssfilters) {
65670               base.style('filter', baseFilter || null);
65671             } else {
65672               base.style('opacity', _brightness);
65673             }
65674
65675             var imagery = base.selectAll('.layer-imagery').data([0]);
65676             imagery.enter().append('div').attr('class', 'layer layer-imagery').merge(imagery).call(baseLayer);
65677             var maskFilter = '';
65678             var mixBlendMode = '';
65679
65680             if (detected.cssfilters && _sharpness > 1) {
65681               // apply unsharp mask
65682               mixBlendMode = 'overlay';
65683               maskFilter = 'saturate(0) blur(3px) invert(1)';
65684               var contrast = _sharpness - 1;
65685               maskFilter += " contrast(".concat(contrast, ")");
65686               var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
65687               maskFilter += " brightness(".concat(brightness, ")");
65688             }
65689
65690             var mask = base.selectAll('.layer-unsharp-mask').data(detected.cssfilters && _sharpness > 1 ? [0] : []);
65691             mask.exit().remove();
65692             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);
65693             var overlays = selection.selectAll('.layer-overlay').data(_overlayLayers, function (d) {
65694               return d.source().name();
65695             });
65696             overlays.exit().remove();
65697             overlays.enter().insert('div', '.layer-data').attr('class', 'layer layer-overlay').merge(overlays).each(function (layer, i, nodes) {
65698               return select(nodes[i]).call(layer);
65699             });
65700           }
65701
65702           background.updateImagery = function () {
65703             var currSource = baseLayer.source();
65704             if (context.inIntro() || !currSource) return;
65705
65706             var o = _overlayLayers.filter(function (d) {
65707               return !d.source().isLocatorOverlay() && !d.source().isHidden();
65708             }).map(function (d) {
65709               return d.source().id;
65710             }).join(',');
65711
65712             var meters = geoOffsetToMeters(currSource.offset());
65713             var EPSILON = 0.01;
65714             var x = +meters[0].toFixed(2);
65715             var y = +meters[1].toFixed(2);
65716             var hash = utilStringQs(window.location.hash);
65717             var id = currSource.id;
65718
65719             if (id === 'custom') {
65720               id = "custom:".concat(currSource.template());
65721             }
65722
65723             if (id) {
65724               hash.background = id;
65725             } else {
65726               delete hash.background;
65727             }
65728
65729             if (o) {
65730               hash.overlays = o;
65731             } else {
65732               delete hash.overlays;
65733             }
65734
65735             if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
65736               hash.offset = "".concat(x, ",").concat(y);
65737             } else {
65738               delete hash.offset;
65739             }
65740
65741             if (!window.mocha) {
65742               window.location.replace('#' + utilQsString(hash, true));
65743             }
65744
65745             var imageryUsed = [];
65746             var photoOverlaysUsed = [];
65747             var currUsed = currSource.imageryUsed();
65748
65749             if (currUsed && _isValid) {
65750               imageryUsed.push(currUsed);
65751             }
65752
65753             _overlayLayers.filter(function (d) {
65754               return !d.source().isLocatorOverlay() && !d.source().isHidden();
65755             }).forEach(function (d) {
65756               return imageryUsed.push(d.source().imageryUsed());
65757             });
65758
65759             var dataLayer = context.layers().layer('data');
65760
65761             if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
65762               imageryUsed.push(dataLayer.getSrc());
65763             }
65764
65765             var photoOverlayLayers = {
65766               streetside: 'Bing Streetside',
65767               mapillary: 'Mapillary Images',
65768               'mapillary-map-features': 'Mapillary Map Features',
65769               'mapillary-signs': 'Mapillary Signs',
65770               openstreetcam: 'OpenStreetCam Images'
65771             };
65772
65773             for (var layerID in photoOverlayLayers) {
65774               var layer = context.layers().layer(layerID);
65775
65776               if (layer && layer.enabled()) {
65777                 photoOverlaysUsed.push(layerID);
65778                 imageryUsed.push(photoOverlayLayers[layerID]);
65779               }
65780             }
65781
65782             context.history().imageryUsed(imageryUsed);
65783             context.history().photoOverlaysUsed(photoOverlaysUsed);
65784           };
65785
65786           var _checkedBlocklists;
65787
65788           background.sources = function (extent, zoom, includeCurrent) {
65789             if (!_imageryIndex) return []; // called before init()?
65790
65791             var visible = {};
65792             (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach(function (d) {
65793               return visible[d.id] = true;
65794             });
65795             var currSource = baseLayer.source();
65796             var osm = context.connection();
65797             var blocklists = osm && osm.imageryBlocklists();
65798
65799             if (blocklists && blocklists !== _checkedBlocklists) {
65800               _imageryIndex.backgrounds.forEach(function (source) {
65801                 source.isBlocked = blocklists.some(function (blocklist) {
65802                   return blocklist.test(source.template());
65803                 });
65804               });
65805
65806               _checkedBlocklists = blocklists;
65807             }
65808
65809             return _imageryIndex.backgrounds.filter(function (source) {
65810               if (includeCurrent && currSource === source) return true; // optionally always include the current imagery
65811
65812               if (source.isBlocked) return false; // even bundled sources may be blocked - #7905
65813
65814               if (!source.polygon) return true; // always include imagery with worldwide coverage
65815
65816               if (zoom && zoom < 6) return false; // optionally exclude local imagery at low zooms
65817
65818               return visible[source.id]; // include imagery visible in given extent
65819             });
65820           };
65821
65822           background.dimensions = function (val) {
65823             if (!val) return;
65824             baseLayer.dimensions(val);
65825
65826             _overlayLayers.forEach(function (layer) {
65827               return layer.dimensions(val);
65828             });
65829           };
65830
65831           background.baseLayerSource = function (d) {
65832             if (!arguments.length) return baseLayer.source(); // test source against OSM imagery blocklists..
65833
65834             var osm = context.connection();
65835             if (!osm) return background;
65836             var blocklists = osm.imageryBlocklists();
65837             var template = d.template();
65838             var fail = false;
65839             var tested = 0;
65840             var regex;
65841
65842             for (var i = 0; i < blocklists.length; i++) {
65843               regex = blocklists[i];
65844               fail = regex.test(template);
65845               tested++;
65846               if (fail) break;
65847             } // ensure at least one test was run.
65848
65849
65850             if (!tested) {
65851               regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
65852               fail = regex.test(template);
65853             }
65854
65855             baseLayer.source(!fail ? d : background.findSource('none'));
65856             dispatch$1.call('change');
65857             background.updateImagery();
65858             return background;
65859           };
65860
65861           background.findSource = function (id) {
65862             if (!id || !_imageryIndex) return null; // called before init()?
65863
65864             return _imageryIndex.backgrounds.find(function (d) {
65865               return d.id && d.id === id;
65866             });
65867           };
65868
65869           background.bing = function () {
65870             background.baseLayerSource(background.findSource('Bing'));
65871           };
65872
65873           background.showsLayer = function (d) {
65874             var currSource = baseLayer.source();
65875             if (!d || !currSource) return false;
65876             return d.id === currSource.id || _overlayLayers.some(function (layer) {
65877               return d.id === layer.source().id;
65878             });
65879           };
65880
65881           background.overlayLayerSources = function () {
65882             return _overlayLayers.map(function (layer) {
65883               return layer.source();
65884             });
65885           };
65886
65887           background.toggleOverlayLayer = function (d) {
65888             var layer;
65889
65890             for (var i = 0; i < _overlayLayers.length; i++) {
65891               layer = _overlayLayers[i];
65892
65893               if (layer.source() === d) {
65894                 _overlayLayers.splice(i, 1);
65895
65896                 dispatch$1.call('change');
65897                 background.updateImagery();
65898                 return;
65899               }
65900             }
65901
65902             layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(baseLayer.dimensions());
65903
65904             _overlayLayers.push(layer);
65905
65906             dispatch$1.call('change');
65907             background.updateImagery();
65908           };
65909
65910           background.nudge = function (d, zoom) {
65911             var currSource = baseLayer.source();
65912
65913             if (currSource) {
65914               currSource.nudge(d, zoom);
65915               dispatch$1.call('change');
65916               background.updateImagery();
65917             }
65918
65919             return background;
65920           };
65921
65922           background.offset = function (d) {
65923             var currSource = baseLayer.source();
65924
65925             if (!arguments.length) {
65926               return currSource && currSource.offset() || [0, 0];
65927             }
65928
65929             if (currSource) {
65930               currSource.offset(d);
65931               dispatch$1.call('change');
65932               background.updateImagery();
65933             }
65934
65935             return background;
65936           };
65937
65938           background.brightness = function (d) {
65939             if (!arguments.length) return _brightness;
65940             _brightness = d;
65941             if (context.mode()) dispatch$1.call('change');
65942             return background;
65943           };
65944
65945           background.contrast = function (d) {
65946             if (!arguments.length) return _contrast;
65947             _contrast = d;
65948             if (context.mode()) dispatch$1.call('change');
65949             return background;
65950           };
65951
65952           background.saturation = function (d) {
65953             if (!arguments.length) return _saturation;
65954             _saturation = d;
65955             if (context.mode()) dispatch$1.call('change');
65956             return background;
65957           };
65958
65959           background.sharpness = function (d) {
65960             if (!arguments.length) return _sharpness;
65961             _sharpness = d;
65962             if (context.mode()) dispatch$1.call('change');
65963             return background;
65964           };
65965
65966           var _loadPromise;
65967
65968           background.ensureLoaded = function () {
65969             if (_loadPromise) return _loadPromise;
65970
65971             function parseMapParams(qmap) {
65972               if (!qmap) return false;
65973               var params = qmap.split('/').map(Number);
65974               if (params.length < 3 || params.some(isNaN)) return false;
65975               return geoExtent([params[2], params[1]]); // lon,lat
65976             }
65977
65978             var hash = utilStringQs(window.location.hash);
65979             var requested = hash.background || hash.layer;
65980             var extent = parseMapParams(hash.map);
65981             return _loadPromise = ensureImageryIndex().then(function (imageryIndex) {
65982               var first = imageryIndex.backgrounds.length && imageryIndex.backgrounds[0];
65983               var best;
65984
65985               if (!requested && extent) {
65986                 best = background.sources(extent).find(function (s) {
65987                   return s.best();
65988                 });
65989               } // Decide which background layer to display
65990
65991
65992               if (requested && requested.indexOf('custom:') === 0) {
65993                 var template = requested.replace(/^custom:/, '');
65994                 var custom = background.findSource('custom');
65995                 background.baseLayerSource(custom.template(template));
65996                 corePreferences('background-custom-template', template);
65997               } else {
65998                 background.baseLayerSource(background.findSource(requested) || best || background.findSource(corePreferences('background-last-used')) || background.findSource('Bing') || first || background.findSource('none'));
65999               }
66000
66001               var locator = imageryIndex.backgrounds.find(function (d) {
66002                 return d.overlay && d["default"];
66003               });
66004
66005               if (locator) {
66006                 background.toggleOverlayLayer(locator);
66007               }
66008
66009               var overlays = (hash.overlays || '').split(',');
66010               overlays.forEach(function (overlay) {
66011                 overlay = background.findSource(overlay);
66012
66013                 if (overlay) {
66014                   background.toggleOverlayLayer(overlay);
66015                 }
66016               });
66017
66018               if (hash.gpx) {
66019                 var gpx = context.layers().layer('data');
66020
66021                 if (gpx) {
66022                   gpx.url(hash.gpx, '.gpx');
66023                 }
66024               }
66025
66026               if (hash.offset) {
66027                 var offset = hash.offset.replace(/;/g, ',').split(',').map(function (n) {
66028                   return !isNaN(n) && n;
66029                 });
66030
66031                 if (offset.length === 2) {
66032                   background.offset(geoMetersToOffset(offset));
66033                 }
66034               }
66035             })["catch"](function () {
66036               /* ignore */
66037             });
66038           };
66039
66040           return utilRebind(background, dispatch$1, 'on');
66041         }
66042
66043         function rendererFeatures(context) {
66044           var dispatch$1 = dispatch('change', 'redraw');
66045           var features = utilRebind({}, dispatch$1, 'on');
66046
66047           var _deferred = new Set();
66048
66049           var traffic_roads = {
66050             'motorway': true,
66051             'motorway_link': true,
66052             'trunk': true,
66053             'trunk_link': true,
66054             'primary': true,
66055             'primary_link': true,
66056             'secondary': true,
66057             'secondary_link': true,
66058             'tertiary': true,
66059             'tertiary_link': true,
66060             'residential': true,
66061             'unclassified': true,
66062             'living_street': true
66063           };
66064           var service_roads = {
66065             'service': true,
66066             'road': true,
66067             'track': true
66068           };
66069           var paths = {
66070             'path': true,
66071             'footway': true,
66072             'cycleway': true,
66073             'bridleway': true,
66074             'steps': true,
66075             'pedestrian': true
66076           };
66077           var past_futures = {
66078             'proposed': true,
66079             'construction': true,
66080             'abandoned': true,
66081             'dismantled': true,
66082             'disused': true,
66083             'razed': true,
66084             'demolished': true,
66085             'obliterated': true
66086           };
66087           var _cullFactor = 1;
66088           var _cache = {};
66089           var _rules = {};
66090           var _stats = {};
66091           var _keys = [];
66092           var _hidden = [];
66093           var _forceVisible = {};
66094
66095           function update() {
66096             if (!window.mocha) {
66097               var hash = utilStringQs(window.location.hash);
66098               var disabled = features.disabled();
66099
66100               if (disabled.length) {
66101                 hash.disable_features = disabled.join(',');
66102               } else {
66103                 delete hash.disable_features;
66104               }
66105
66106               window.location.replace('#' + utilQsString(hash, true));
66107               corePreferences('disabled-features', disabled.join(','));
66108             }
66109
66110             _hidden = features.hidden();
66111             dispatch$1.call('change');
66112             dispatch$1.call('redraw');
66113           }
66114
66115           function defineRule(k, filter, max) {
66116             var isEnabled = true;
66117
66118             _keys.push(k);
66119
66120             _rules[k] = {
66121               filter: filter,
66122               enabled: isEnabled,
66123               // whether the user wants it enabled..
66124               count: 0,
66125               currentMax: max || Infinity,
66126               defaultMax: max || Infinity,
66127               enable: function enable() {
66128                 this.enabled = true;
66129                 this.currentMax = this.defaultMax;
66130               },
66131               disable: function disable() {
66132                 this.enabled = false;
66133                 this.currentMax = 0;
66134               },
66135               hidden: function hidden() {
66136                 return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
66137               },
66138               autoHidden: function autoHidden() {
66139                 return this.hidden() && this.currentMax > 0;
66140               }
66141             };
66142           }
66143
66144           defineRule('points', function isPoint(tags, geometry) {
66145             return geometry === 'point';
66146           }, 200);
66147           defineRule('traffic_roads', function isTrafficRoad(tags) {
66148             return traffic_roads[tags.highway];
66149           });
66150           defineRule('service_roads', function isServiceRoad(tags) {
66151             return service_roads[tags.highway];
66152           });
66153           defineRule('paths', function isPath(tags) {
66154             return paths[tags.highway];
66155           });
66156           defineRule('buildings', function isBuilding(tags) {
66157             return !!tags.building && tags.building !== 'no' || tags.parking === 'multi-storey' || tags.parking === 'sheds' || tags.parking === 'carports' || tags.parking === 'garage_boxes';
66158           }, 250);
66159           defineRule('building_parts', function isBuildingPart(tags) {
66160             return tags['building:part'];
66161           });
66162           defineRule('indoor', function isIndoor(tags) {
66163             return tags.indoor;
66164           });
66165           defineRule('landuse', function isLanduse(tags, geometry) {
66166             return geometry === 'area' && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
66167           });
66168           defineRule('boundaries', function isBoundary(tags) {
66169             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);
66170           });
66171           defineRule('water', function isWater(tags) {
66172             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';
66173           });
66174           defineRule('rail', function isRail(tags) {
66175             return (!!tags.railway || tags.landuse === 'railway') && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
66176           });
66177           defineRule('pistes', function isPiste(tags) {
66178             return tags['piste:type'];
66179           });
66180           defineRule('aerialways', function isPiste(tags) {
66181             return tags.aerialway && tags.aerialway !== 'yes' && tags.aerialway !== 'station';
66182           });
66183           defineRule('power', function isPower(tags) {
66184             return !!tags.power;
66185           }); // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
66186
66187           defineRule('past_future', function isPastFuture(tags) {
66188             if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
66189               return false;
66190             }
66191
66192             var strings = Object.keys(tags);
66193
66194             for (var i = 0; i < strings.length; i++) {
66195               var s = strings[i];
66196
66197               if (past_futures[s] || past_futures[tags[s]]) {
66198                 return true;
66199               }
66200             }
66201
66202             return false;
66203           }); // Lines or areas that don't match another feature filter.
66204           // IMPORTANT: The 'others' feature must be the last one defined,
66205           //   so that code in getMatches can skip this test if `hasMatch = true`
66206
66207           defineRule('others', function isOther(tags, geometry) {
66208             return geometry === 'line' || geometry === 'area';
66209           });
66210
66211           features.features = function () {
66212             return _rules;
66213           };
66214
66215           features.keys = function () {
66216             return _keys;
66217           };
66218
66219           features.enabled = function (k) {
66220             if (!arguments.length) {
66221               return _keys.filter(function (k) {
66222                 return _rules[k].enabled;
66223               });
66224             }
66225
66226             return _rules[k] && _rules[k].enabled;
66227           };
66228
66229           features.disabled = function (k) {
66230             if (!arguments.length) {
66231               return _keys.filter(function (k) {
66232                 return !_rules[k].enabled;
66233               });
66234             }
66235
66236             return _rules[k] && !_rules[k].enabled;
66237           };
66238
66239           features.hidden = function (k) {
66240             if (!arguments.length) {
66241               return _keys.filter(function (k) {
66242                 return _rules[k].hidden();
66243               });
66244             }
66245
66246             return _rules[k] && _rules[k].hidden();
66247           };
66248
66249           features.autoHidden = function (k) {
66250             if (!arguments.length) {
66251               return _keys.filter(function (k) {
66252                 return _rules[k].autoHidden();
66253               });
66254             }
66255
66256             return _rules[k] && _rules[k].autoHidden();
66257           };
66258
66259           features.enable = function (k) {
66260             if (_rules[k] && !_rules[k].enabled) {
66261               _rules[k].enable();
66262
66263               update();
66264             }
66265           };
66266
66267           features.enableAll = function () {
66268             var didEnable = false;
66269
66270             for (var k in _rules) {
66271               if (!_rules[k].enabled) {
66272                 didEnable = true;
66273
66274                 _rules[k].enable();
66275               }
66276             }
66277
66278             if (didEnable) update();
66279           };
66280
66281           features.disable = function (k) {
66282             if (_rules[k] && _rules[k].enabled) {
66283               _rules[k].disable();
66284
66285               update();
66286             }
66287           };
66288
66289           features.disableAll = function () {
66290             var didDisable = false;
66291
66292             for (var k in _rules) {
66293               if (_rules[k].enabled) {
66294                 didDisable = true;
66295
66296                 _rules[k].disable();
66297               }
66298             }
66299
66300             if (didDisable) update();
66301           };
66302
66303           features.toggle = function (k) {
66304             if (_rules[k]) {
66305               (function (f) {
66306                 return f.enabled ? f.disable() : f.enable();
66307               })(_rules[k]);
66308
66309               update();
66310             }
66311           };
66312
66313           features.resetStats = function () {
66314             for (var i = 0; i < _keys.length; i++) {
66315               _rules[_keys[i]].count = 0;
66316             }
66317
66318             dispatch$1.call('change');
66319           };
66320
66321           features.gatherStats = function (d, resolver, dimensions) {
66322             var needsRedraw = false;
66323             var types = utilArrayGroupBy(d, 'type');
66324             var entities = [].concat(types.relation || [], types.way || [], types.node || []);
66325             var currHidden, geometry, matches, i, j;
66326
66327             for (i = 0; i < _keys.length; i++) {
66328               _rules[_keys[i]].count = 0;
66329             } // adjust the threshold for point/building culling based on viewport size..
66330             // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
66331
66332
66333             _cullFactor = dimensions[0] * dimensions[1] / 1000000;
66334
66335             for (i = 0; i < entities.length; i++) {
66336               geometry = entities[i].geometry(resolver);
66337               matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
66338
66339               for (j = 0; j < matches.length; j++) {
66340                 _rules[matches[j]].count++;
66341               }
66342             }
66343
66344             currHidden = features.hidden();
66345
66346             if (currHidden !== _hidden) {
66347               _hidden = currHidden;
66348               needsRedraw = true;
66349               dispatch$1.call('change');
66350             }
66351
66352             return needsRedraw;
66353           };
66354
66355           features.stats = function () {
66356             for (var i = 0; i < _keys.length; i++) {
66357               _stats[_keys[i]] = _rules[_keys[i]].count;
66358             }
66359
66360             return _stats;
66361           };
66362
66363           features.clear = function (d) {
66364             for (var i = 0; i < d.length; i++) {
66365               features.clearEntity(d[i]);
66366             }
66367           };
66368
66369           features.clearEntity = function (entity) {
66370             delete _cache[osmEntity.key(entity)];
66371           };
66372
66373           features.reset = function () {
66374             Array.from(_deferred).forEach(function (handle) {
66375               window.cancelIdleCallback(handle);
66376
66377               _deferred["delete"](handle);
66378             });
66379             _cache = {};
66380           }; // only certain relations are worth checking
66381
66382
66383           function relationShouldBeChecked(relation) {
66384             // multipolygon features have `area` geometry and aren't checked here
66385             return relation.tags.type === 'boundary';
66386           }
66387
66388           features.getMatches = function (entity, resolver, geometry) {
66389             if (geometry === 'vertex' || geometry === 'relation' && !relationShouldBeChecked(entity)) return {};
66390             var ent = osmEntity.key(entity);
66391
66392             if (!_cache[ent]) {
66393               _cache[ent] = {};
66394             }
66395
66396             if (!_cache[ent].matches) {
66397               var matches = {};
66398               var hasMatch = false;
66399
66400               for (var i = 0; i < _keys.length; i++) {
66401                 if (_keys[i] === 'others') {
66402                   if (hasMatch) continue; // If an entity...
66403                   //   1. is a way that hasn't matched other 'interesting' feature rules,
66404
66405                   if (entity.type === 'way') {
66406                     var parents = features.getParents(entity, resolver, geometry); //   2a. belongs only to a single multipolygon relation
66407
66408                     if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
66409                     parents.length > 0 && parents.every(function (parent) {
66410                       return parent.tags.type === 'boundary';
66411                     })) {
66412                       // ...then match whatever feature rules the parent relation has matched.
66413                       // see #2548, #2887
66414                       //
66415                       // IMPORTANT:
66416                       // For this to work, getMatches must be called on relations before ways.
66417                       //
66418                       var pkey = osmEntity.key(parents[0]);
66419
66420                       if (_cache[pkey] && _cache[pkey].matches) {
66421                         matches = Object.assign({}, _cache[pkey].matches); // shallow copy
66422
66423                         continue;
66424                       }
66425                     }
66426                   }
66427                 }
66428
66429                 if (_rules[_keys[i]].filter(entity.tags, geometry)) {
66430                   matches[_keys[i]] = hasMatch = true;
66431                 }
66432               }
66433
66434               _cache[ent].matches = matches;
66435             }
66436
66437             return _cache[ent].matches;
66438           };
66439
66440           features.getParents = function (entity, resolver, geometry) {
66441             if (geometry === 'point') return [];
66442             var ent = osmEntity.key(entity);
66443
66444             if (!_cache[ent]) {
66445               _cache[ent] = {};
66446             }
66447
66448             if (!_cache[ent].parents) {
66449               var parents = [];
66450
66451               if (geometry === 'vertex') {
66452                 parents = resolver.parentWays(entity);
66453               } else {
66454                 // 'line', 'area', 'relation'
66455                 parents = resolver.parentRelations(entity);
66456               }
66457
66458               _cache[ent].parents = parents;
66459             }
66460
66461             return _cache[ent].parents;
66462           };
66463
66464           features.isHiddenPreset = function (preset, geometry) {
66465             if (!_hidden.length) return false;
66466             if (!preset.tags) return false;
66467             var test = preset.setTags({}, geometry);
66468
66469             for (var key in _rules) {
66470               if (_rules[key].filter(test, geometry)) {
66471                 if (_hidden.indexOf(key) !== -1) {
66472                   return key;
66473                 }
66474
66475                 return false;
66476               }
66477             }
66478
66479             return false;
66480           };
66481
66482           features.isHiddenFeature = function (entity, resolver, geometry) {
66483             if (!_hidden.length) return false;
66484             if (!entity.version) return false;
66485             if (_forceVisible[entity.id]) return false;
66486             var matches = Object.keys(features.getMatches(entity, resolver, geometry));
66487             return matches.length && matches.every(function (k) {
66488               return features.hidden(k);
66489             });
66490           };
66491
66492           features.isHiddenChild = function (entity, resolver, geometry) {
66493             if (!_hidden.length) return false;
66494             if (!entity.version || geometry === 'point') return false;
66495             if (_forceVisible[entity.id]) return false;
66496             var parents = features.getParents(entity, resolver, geometry);
66497             if (!parents.length) return false;
66498
66499             for (var i = 0; i < parents.length; i++) {
66500               if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
66501                 return false;
66502               }
66503             }
66504
66505             return true;
66506           };
66507
66508           features.hasHiddenConnections = function (entity, resolver) {
66509             if (!_hidden.length) return false;
66510             var childNodes, connections;
66511
66512             if (entity.type === 'midpoint') {
66513               childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
66514               connections = [];
66515             } else {
66516               childNodes = entity.nodes ? resolver.childNodes(entity) : [];
66517               connections = features.getParents(entity, resolver, entity.geometry(resolver));
66518             } // gather ways connected to child nodes..
66519
66520
66521             connections = childNodes.reduce(function (result, e) {
66522               return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
66523             }, connections);
66524             return connections.some(function (e) {
66525               return features.isHidden(e, resolver, e.geometry(resolver));
66526             });
66527           };
66528
66529           features.isHidden = function (entity, resolver, geometry) {
66530             if (!_hidden.length) return false;
66531             if (!entity.version) return false;
66532             var fn = geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature;
66533             return fn(entity, resolver, geometry);
66534           };
66535
66536           features.filter = function (d, resolver) {
66537             if (!_hidden.length) return d;
66538             var result = [];
66539
66540             for (var i = 0; i < d.length; i++) {
66541               var entity = d[i];
66542
66543               if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
66544                 result.push(entity);
66545               }
66546             }
66547
66548             return result;
66549           };
66550
66551           features.forceVisible = function (entityIDs) {
66552             if (!arguments.length) return Object.keys(_forceVisible);
66553             _forceVisible = {};
66554
66555             for (var i = 0; i < entityIDs.length; i++) {
66556               _forceVisible[entityIDs[i]] = true;
66557               var entity = context.hasEntity(entityIDs[i]);
66558
66559               if (entity && entity.type === 'relation') {
66560                 // also show relation members (one level deep)
66561                 for (var j in entity.members) {
66562                   _forceVisible[entity.members[j].id] = true;
66563                 }
66564               }
66565             }
66566
66567             return features;
66568           };
66569
66570           features.init = function () {
66571             var storage = corePreferences('disabled-features');
66572
66573             if (storage) {
66574               var storageDisabled = storage.replace(/;/g, ',').split(',');
66575               storageDisabled.forEach(features.disable);
66576             }
66577
66578             var hash = utilStringQs(window.location.hash);
66579
66580             if (hash.disable_features) {
66581               var hashDisabled = hash.disable_features.replace(/;/g, ',').split(',');
66582               hashDisabled.forEach(features.disable);
66583             }
66584           }; // warm up the feature matching cache upon merging fetched data
66585
66586
66587           context.history().on('merge.features', function (newEntities) {
66588             if (!newEntities) return;
66589             var handle = window.requestIdleCallback(function () {
66590               var graph = context.graph();
66591               var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways
66592
66593               var entities = [].concat(types.relation || [], types.way || [], types.node || []);
66594
66595               for (var i = 0; i < entities.length; i++) {
66596                 var geometry = entities[i].geometry(graph);
66597                 features.getMatches(entities[i], graph, geometry);
66598               }
66599             });
66600
66601             _deferred.add(handle);
66602           });
66603           return features;
66604         }
66605
66606         //
66607         // - the activeID - nope
66608         // - 1 away (adjacent) to the activeID - yes (vertices will be merged)
66609         // - 2 away from the activeID - nope (would create a self intersecting segment)
66610         // - all others on a linear way - yes
66611         // - all others on a closed way - nope (would create a self intersecting polygon)
66612         //
66613         // returns
66614         // 0 = active vertex - no touch/connect
66615         // 1 = passive vertex - yes touch/connect
66616         // 2 = adjacent vertex - yes but pay attention segmenting a line here
66617         //
66618
66619         function svgPassiveVertex(node, graph, activeID) {
66620           if (!activeID) return 1;
66621           if (activeID === node.id) return 0;
66622           var parents = graph.parentWays(node);
66623           var i, j, nodes, isClosed, ix1, ix2, ix3, ix4, max;
66624
66625           for (i = 0; i < parents.length; i++) {
66626             nodes = parents[i].nodes;
66627             isClosed = parents[i].isClosed();
66628
66629             for (j = 0; j < nodes.length; j++) {
66630               // find this vertex, look nearby
66631               if (nodes[j] === node.id) {
66632                 ix1 = j - 2;
66633                 ix2 = j - 1;
66634                 ix3 = j + 1;
66635                 ix4 = j + 2;
66636
66637                 if (isClosed) {
66638                   // wraparound if needed
66639                   max = nodes.length - 1;
66640                   if (ix1 < 0) ix1 = max + ix1;
66641                   if (ix2 < 0) ix2 = max + ix2;
66642                   if (ix3 > max) ix3 = ix3 - max;
66643                   if (ix4 > max) ix4 = ix4 - max;
66644                 }
66645
66646                 if (nodes[ix1] === activeID) return 0; // no - prevent self intersect
66647                 else if (nodes[ix2] === activeID) return 2; // ok - adjacent
66648                   else if (nodes[ix3] === activeID) return 2; // ok - adjacent
66649                     else if (nodes[ix4] === activeID) return 0; // no - prevent self intersect
66650                       else if (isClosed && nodes.indexOf(activeID) !== -1) return 0; // no - prevent self intersect
66651               }
66652             }
66653           }
66654
66655           return 1; // ok
66656         }
66657         function svgMarkerSegments(projection, graph, dt, shouldReverse, bothDirections) {
66658           return function (entity) {
66659             var i = 0;
66660             var offset = dt;
66661             var segments = [];
66662             var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream;
66663             var coordinates = graph.childNodes(entity).map(function (n) {
66664               return n.loc;
66665             });
66666             var a, b;
66667
66668             if (shouldReverse(entity)) {
66669               coordinates.reverse();
66670             }
66671
66672             d3_geoStream({
66673               type: 'LineString',
66674               coordinates: coordinates
66675             }, projection.stream(clip({
66676               lineStart: function lineStart() {},
66677               lineEnd: function lineEnd() {
66678                 a = null;
66679               },
66680               point: function point(x, y) {
66681                 b = [x, y];
66682
66683                 if (a) {
66684                   var span = geoVecLength(a, b) - offset;
66685
66686                   if (span >= 0) {
66687                     var heading = geoVecAngle(a, b);
66688                     var dx = dt * Math.cos(heading);
66689                     var dy = dt * Math.sin(heading);
66690                     var p = [a[0] + offset * Math.cos(heading), a[1] + offset * Math.sin(heading)]; // gather coordinates
66691
66692                     var coord = [a, p];
66693
66694                     for (span -= dt; span >= 0; span -= dt) {
66695                       p = geoVecAdd(p, [dx, dy]);
66696                       coord.push(p);
66697                     }
66698
66699                     coord.push(b); // generate svg paths
66700
66701                     var segment = '';
66702                     var j;
66703
66704                     for (j = 0; j < coord.length; j++) {
66705                       segment += (j === 0 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
66706                     }
66707
66708                     segments.push({
66709                       id: entity.id,
66710                       index: i++,
66711                       d: segment
66712                     });
66713
66714                     if (bothDirections(entity)) {
66715                       segment = '';
66716
66717                       for (j = coord.length - 1; j >= 0; j--) {
66718                         segment += (j === coord.length - 1 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
66719                       }
66720
66721                       segments.push({
66722                         id: entity.id,
66723                         index: i++,
66724                         d: segment
66725                       });
66726                     }
66727                   }
66728
66729                   offset = -span;
66730                 }
66731
66732                 a = b;
66733               }
66734             })));
66735             return segments;
66736           };
66737         }
66738         function svgPath(projection, graph, isArea) {
66739           // Explanation of magic numbers:
66740           // "padding" here allows space for strokes to extend beyond the viewport,
66741           // so that the stroke isn't drawn along the edge of the viewport when
66742           // the shape is clipped.
66743           //
66744           // When drawing lines, pad viewport by 5px.
66745           // When drawing areas, pad viewport by 65px in each direction to allow
66746           // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
66747           var cache = {};
66748           var padding = isArea ? 65 : 5;
66749           var viewport = projection.clipExtent();
66750           var paddedExtent = [[viewport[0][0] - padding, viewport[0][1] - padding], [viewport[1][0] + padding, viewport[1][1] + padding]];
66751           var clip = d3_geoIdentity().clipExtent(paddedExtent).stream;
66752           var project = projection.stream;
66753           var path = d3_geoPath().projection({
66754             stream: function stream(output) {
66755               return project(clip(output));
66756             }
66757           });
66758
66759           var svgpath = function svgpath(entity) {
66760             if (entity.id in cache) {
66761               return cache[entity.id];
66762             } else {
66763               return cache[entity.id] = path(entity.asGeoJSON(graph));
66764             }
66765           };
66766
66767           svgpath.geojson = function (d) {
66768             if (d.__featurehash__ !== undefined) {
66769               if (d.__featurehash__ in cache) {
66770                 return cache[d.__featurehash__];
66771               } else {
66772                 return cache[d.__featurehash__] = path(d);
66773               }
66774             } else {
66775               return path(d);
66776             }
66777           };
66778
66779           return svgpath;
66780         }
66781         function svgPointTransform(projection) {
66782           var svgpoint = function svgpoint(entity) {
66783             // http://jsperf.com/short-array-join
66784             var pt = projection(entity.loc);
66785             return 'translate(' + pt[0] + ',' + pt[1] + ')';
66786           };
66787
66788           svgpoint.geojson = function (d) {
66789             return svgpoint(d.properties.entity);
66790           };
66791
66792           return svgpoint;
66793         }
66794         function svgRelationMemberTags(graph) {
66795           return function (entity) {
66796             var tags = entity.tags;
66797             var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
66798             graph.parentRelations(entity).forEach(function (relation) {
66799               var type = relation.tags.type;
66800
66801               if (type === 'multipolygon' && shouldCopyMultipolygonTags || type === 'boundary') {
66802                 tags = Object.assign({}, relation.tags, tags);
66803               }
66804             });
66805             return tags;
66806           };
66807         }
66808         function svgSegmentWay(way, graph, activeID) {
66809           // When there is no activeID, we can memoize this expensive computation
66810           if (activeID === undefined) {
66811             return graph["transient"](way, 'waySegments', getWaySegments);
66812           } else {
66813             return getWaySegments();
66814           }
66815
66816           function getWaySegments() {
66817             var isActiveWay = way.nodes.indexOf(activeID) !== -1;
66818             var features = {
66819               passive: [],
66820               active: []
66821             };
66822             var start = {};
66823             var end = {};
66824             var node, type;
66825
66826             for (var i = 0; i < way.nodes.length; i++) {
66827               node = graph.entity(way.nodes[i]);
66828               type = svgPassiveVertex(node, graph, activeID);
66829               end = {
66830                 node: node,
66831                 type: type
66832               };
66833
66834               if (start.type !== undefined) {
66835                 if (start.node.id === activeID || end.node.id === activeID) ; else if (isActiveWay && (start.type === 2 || end.type === 2)) {
66836                   // one adjacent vertex
66837                   pushActive(start, end, i);
66838                 } else if (start.type === 0 && end.type === 0) {
66839                   // both active vertices
66840                   pushActive(start, end, i);
66841                 } else {
66842                   pushPassive(start, end, i);
66843                 }
66844               }
66845
66846               start = end;
66847             }
66848
66849             return features;
66850
66851             function pushActive(start, end, index) {
66852               features.active.push({
66853                 type: 'Feature',
66854                 id: way.id + '-' + index + '-nope',
66855                 properties: {
66856                   nope: true,
66857                   target: true,
66858                   entity: way,
66859                   nodes: [start.node, end.node],
66860                   index: index
66861                 },
66862                 geometry: {
66863                   type: 'LineString',
66864                   coordinates: [start.node.loc, end.node.loc]
66865                 }
66866               });
66867             }
66868
66869             function pushPassive(start, end, index) {
66870               features.passive.push({
66871                 type: 'Feature',
66872                 id: way.id + '-' + index,
66873                 properties: {
66874                   target: true,
66875                   entity: way,
66876                   nodes: [start.node, end.node],
66877                   index: index
66878                 },
66879                 geometry: {
66880                   type: 'LineString',
66881                   coordinates: [start.node.loc, end.node.loc]
66882                 }
66883               });
66884             }
66885           }
66886         }
66887
66888         function svgTagClasses() {
66889           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'];
66890           var statuses = [// nonexistent, might be built
66891           'proposed', 'planned', // under maintentance or between groundbreaking and opening
66892           'construction', // existent but not functional
66893           'disused', // dilapidated to nonexistent
66894           'abandoned', // nonexistent, still may appear in imagery
66895           'dismantled', 'razed', 'demolished', 'obliterated', // existent occasionally, e.g. stormwater drainage basin
66896           'intermittent'];
66897           var secondaries = ['oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier', 'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport', 'public_transport', 'location', 'parking', 'golf', 'type', 'leisure', 'man_made', 'indoor'];
66898
66899           var _tags = function _tags(entity) {
66900             return entity.tags;
66901           };
66902
66903           var tagClasses = function tagClasses(selection) {
66904             selection.each(function tagClassesEach(entity) {
66905               var value = this.className;
66906
66907               if (value.baseVal !== undefined) {
66908                 value = value.baseVal;
66909               }
66910
66911               var t = _tags(entity);
66912
66913               var computed = tagClasses.getClassesString(t, value);
66914
66915               if (computed !== value) {
66916                 select(this).attr('class', computed);
66917               }
66918             });
66919           };
66920
66921           tagClasses.getClassesString = function (t, value) {
66922             var primary, status;
66923             var i, j, k, v; // in some situations we want to render perimeter strokes a certain way
66924
66925             var overrideGeometry;
66926
66927             if (/\bstroke\b/.test(value)) {
66928               if (!!t.barrier && t.barrier !== 'no') {
66929                 overrideGeometry = 'line';
66930               }
66931             } // preserve base classes (nothing with `tag-`)
66932
66933
66934             var classes = value.trim().split(/\s+/).filter(function (klass) {
66935               return klass.length && !/^tag-/.test(klass);
66936             }).map(function (klass) {
66937               // special overrides for some perimeter strokes
66938               return klass === 'line' || klass === 'area' ? overrideGeometry || klass : klass;
66939             }); // pick at most one primary classification tag..
66940
66941             for (i = 0; i < primaries.length; i++) {
66942               k = primaries[i];
66943               v = t[k];
66944               if (!v || v === 'no') continue;
66945
66946               if (k === 'piste:type') {
66947                 // avoid a ':' in the class name
66948                 k = 'piste';
66949               } else if (k === 'building:part') {
66950                 // avoid a ':' in the class name
66951                 k = 'building_part';
66952               }
66953
66954               primary = k;
66955
66956               if (statuses.indexOf(v) !== -1) {
66957                 // e.g. `railway=abandoned`
66958                 status = v;
66959                 classes.push('tag-' + k);
66960               } else {
66961                 classes.push('tag-' + k);
66962                 classes.push('tag-' + k + '-' + v);
66963               }
66964
66965               break;
66966             }
66967
66968             if (!primary) {
66969               for (i = 0; i < statuses.length; i++) {
66970                 for (j = 0; j < primaries.length; j++) {
66971                   k = statuses[i] + ':' + primaries[j]; // e.g. `demolished:building=yes`
66972
66973                   v = t[k];
66974                   if (!v || v === 'no') continue;
66975                   status = statuses[i];
66976                   break;
66977                 }
66978               }
66979             } // add at most one status tag, only if relates to primary tag..
66980
66981
66982             if (!status) {
66983               for (i = 0; i < statuses.length; i++) {
66984                 k = statuses[i];
66985                 v = t[k];
66986                 if (!v || v === 'no') continue;
66987
66988                 if (v === 'yes') {
66989                   // e.g. `railway=rail + abandoned=yes`
66990                   status = k;
66991                 } else if (primary && primary === v) {
66992                   // e.g. `railway=rail + abandoned=railway`
66993                   status = k;
66994                 } else if (!primary && primaries.indexOf(v) !== -1) {
66995                   // e.g. `abandoned=railway`
66996                   status = k;
66997                   primary = v;
66998                   classes.push('tag-' + v);
66999                 } // else ignore e.g.  `highway=path + abandoned=railway`
67000
67001
67002                 if (status) break;
67003               }
67004             }
67005
67006             if (status) {
67007               classes.push('tag-status');
67008               classes.push('tag-status-' + status);
67009             } // add any secondary tags
67010
67011
67012             for (i = 0; i < secondaries.length; i++) {
67013               k = secondaries[i];
67014               v = t[k];
67015               if (!v || v === 'no' || k === primary) continue;
67016               classes.push('tag-' + k);
67017               classes.push('tag-' + k + '-' + v);
67018             } // For highways, look for surface tagging..
67019
67020
67021             if (primary === 'highway' && !osmPathHighwayTagValues[t.highway] || primary === 'aeroway') {
67022               var surface = t.highway === 'track' ? 'unpaved' : 'paved';
67023
67024               for (k in t) {
67025                 v = t[k];
67026
67027                 if (k in osmPavedTags) {
67028                   surface = osmPavedTags[k][v] ? 'paved' : 'unpaved';
67029                 }
67030
67031                 if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
67032                   surface = 'semipaved';
67033                 }
67034               }
67035
67036               classes.push('tag-' + surface);
67037             } // If this is a wikidata-tagged item, add a class for that..
67038
67039
67040             if (t.wikidata || t['brand:wikidata']) {
67041               classes.push('tag-wikidata');
67042             }
67043
67044             return classes.join(' ').trim();
67045           };
67046
67047           tagClasses.tags = function (val) {
67048             if (!arguments.length) return _tags;
67049             _tags = val;
67050             return tagClasses;
67051           };
67052
67053           return tagClasses;
67054         }
67055
67056         // Patterns only work in Firefox when set directly on element.
67057         // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
67058         var patterns = {
67059           // tag - pattern name
67060           // -or-
67061           // tag - value - pattern name
67062           // -or-
67063           // tag - value - rules (optional tag-values, pattern name)
67064           // (matches earlier rules first, so fallback should be last entry)
67065           amenity: {
67066             grave_yard: 'cemetery',
67067             fountain: 'water_standing'
67068           },
67069           landuse: {
67070             cemetery: [{
67071               religion: 'christian',
67072               pattern: 'cemetery_christian'
67073             }, {
67074               religion: 'buddhist',
67075               pattern: 'cemetery_buddhist'
67076             }, {
67077               religion: 'muslim',
67078               pattern: 'cemetery_muslim'
67079             }, {
67080               religion: 'jewish',
67081               pattern: 'cemetery_jewish'
67082             }, {
67083               pattern: 'cemetery'
67084             }],
67085             construction: 'construction',
67086             farmland: 'farmland',
67087             farmyard: 'farmyard',
67088             forest: [{
67089               leaf_type: 'broadleaved',
67090               pattern: 'forest_broadleaved'
67091             }, {
67092               leaf_type: 'needleleaved',
67093               pattern: 'forest_needleleaved'
67094             }, {
67095               leaf_type: 'leafless',
67096               pattern: 'forest_leafless'
67097             }, {
67098               pattern: 'forest'
67099             } // same as 'leaf_type:mixed'
67100             ],
67101             grave_yard: 'cemetery',
67102             grass: [{
67103               golf: 'green',
67104               pattern: 'golf_green'
67105             }, {
67106               pattern: 'grass'
67107             }],
67108             landfill: 'landfill',
67109             meadow: 'meadow',
67110             military: 'construction',
67111             orchard: 'orchard',
67112             quarry: 'quarry',
67113             vineyard: 'vineyard'
67114           },
67115           natural: {
67116             beach: 'beach',
67117             grassland: 'grass',
67118             sand: 'beach',
67119             scrub: 'scrub',
67120             water: [{
67121               water: 'pond',
67122               pattern: 'pond'
67123             }, {
67124               water: 'reservoir',
67125               pattern: 'water_standing'
67126             }, {
67127               pattern: 'waves'
67128             }],
67129             wetland: [{
67130               wetland: 'marsh',
67131               pattern: 'wetland_marsh'
67132             }, {
67133               wetland: 'swamp',
67134               pattern: 'wetland_swamp'
67135             }, {
67136               wetland: 'bog',
67137               pattern: 'wetland_bog'
67138             }, {
67139               wetland: 'reedbed',
67140               pattern: 'wetland_reedbed'
67141             }, {
67142               pattern: 'wetland'
67143             }],
67144             wood: [{
67145               leaf_type: 'broadleaved',
67146               pattern: 'forest_broadleaved'
67147             }, {
67148               leaf_type: 'needleleaved',
67149               pattern: 'forest_needleleaved'
67150             }, {
67151               leaf_type: 'leafless',
67152               pattern: 'forest_leafless'
67153             }, {
67154               pattern: 'forest'
67155             } // same as 'leaf_type:mixed'
67156             ]
67157           },
67158           traffic_calming: {
67159             island: [{
67160               surface: 'grass',
67161               pattern: 'grass'
67162             }],
67163             chicane: [{
67164               surface: 'grass',
67165               pattern: 'grass'
67166             }],
67167             choker: [{
67168               surface: 'grass',
67169               pattern: 'grass'
67170             }]
67171           }
67172         };
67173         function svgTagPattern(tags) {
67174           // Skip pattern filling if this is a building (buildings don't get patterns applied)
67175           if (tags.building && tags.building !== 'no') {
67176             return null;
67177           }
67178
67179           for (var tag in patterns) {
67180             var entityValue = tags[tag];
67181             if (!entityValue) continue;
67182
67183             if (typeof patterns[tag] === 'string') {
67184               // extra short syntax (just tag) - pattern name
67185               return 'pattern-' + patterns[tag];
67186             } else {
67187               var values = patterns[tag];
67188
67189               for (var value in values) {
67190                 if (entityValue !== value) continue;
67191                 var rules = values[value];
67192
67193                 if (typeof rules === 'string') {
67194                   // short syntax - pattern name
67195                   return 'pattern-' + rules;
67196                 } // long syntax - rule array
67197
67198
67199                 for (var ruleKey in rules) {
67200                   var rule = rules[ruleKey];
67201                   var pass = true;
67202
67203                   for (var criterion in rule) {
67204                     if (criterion !== 'pattern') {
67205                       // reserved for pattern name
67206                       // The only rule is a required tag-value pair
67207                       var v = tags[criterion];
67208
67209                       if (!v || v !== rule[criterion]) {
67210                         pass = false;
67211                         break;
67212                       }
67213                     }
67214                   }
67215
67216                   if (pass) {
67217                     return 'pattern-' + rule.pattern;
67218                   }
67219                 }
67220               }
67221             }
67222           }
67223
67224           return null;
67225         }
67226
67227         function svgAreas(projection, context) {
67228           function getPatternStyle(tags) {
67229             var imageID = svgTagPattern(tags);
67230
67231             if (imageID) {
67232               return 'url("#ideditor-' + imageID + '")';
67233             }
67234
67235             return '';
67236           }
67237
67238           function drawTargets(selection, graph, entities, filter) {
67239             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67240             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
67241             var getPath = svgPath(projection).geojson;
67242             var activeID = context.activeID();
67243             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
67244
67245             var data = {
67246               targets: [],
67247               nopes: []
67248             };
67249             entities.forEach(function (way) {
67250               var features = svgSegmentWay(way, graph, activeID);
67251               data.targets.push.apply(data.targets, features.passive);
67252               data.nopes.push.apply(data.nopes, features.active);
67253             }); // Targets allow hover and vertex snapping
67254
67255             var targetData = data.targets.filter(getPath);
67256             var targets = selection.selectAll('.area.target-allowed').filter(function (d) {
67257               return filter(d.properties.entity);
67258             }).data(targetData, function key(d) {
67259               return d.id;
67260             }); // exit
67261
67262             targets.exit().remove();
67263
67264             var segmentWasEdited = function segmentWasEdited(d) {
67265               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
67266
67267               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
67268                 return false;
67269               }
67270
67271               return d.properties.nodes.some(function (n) {
67272                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
67273               });
67274             }; // enter/update
67275
67276
67277             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
67278               return 'way area target target-allowed ' + targetClass + d.id;
67279             }).classed('segment-edited', segmentWasEdited); // NOPE
67280
67281             var nopeData = data.nopes.filter(getPath);
67282             var nopes = selection.selectAll('.area.target-nope').filter(function (d) {
67283               return filter(d.properties.entity);
67284             }).data(nopeData, function key(d) {
67285               return d.id;
67286             }); // exit
67287
67288             nopes.exit().remove(); // enter/update
67289
67290             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
67291               return 'way area target target-nope ' + nopeClass + d.id;
67292             }).classed('segment-edited', segmentWasEdited);
67293           }
67294
67295           function drawAreas(selection, graph, entities, filter) {
67296             var path = svgPath(projection, graph, true);
67297             var areas = {};
67298             var multipolygon;
67299             var base = context.history().base();
67300
67301             for (var i = 0; i < entities.length; i++) {
67302               var entity = entities[i];
67303               if (entity.geometry(graph) !== 'area') continue;
67304               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
67305
67306               if (multipolygon) {
67307                 areas[multipolygon.id] = {
67308                   entity: multipolygon.mergeTags(entity.tags),
67309                   area: Math.abs(entity.area(graph))
67310                 };
67311               } else if (!areas[entity.id]) {
67312                 areas[entity.id] = {
67313                   entity: entity,
67314                   area: Math.abs(entity.area(graph))
67315                 };
67316               }
67317             }
67318
67319             var fills = Object.values(areas).filter(function hasPath(a) {
67320               return path(a.entity);
67321             });
67322             fills.sort(function areaSort(a, b) {
67323               return b.area - a.area;
67324             });
67325             fills = fills.map(function (a) {
67326               return a.entity;
67327             });
67328             var strokes = fills.filter(function (area) {
67329               return area.type === 'way';
67330             });
67331             var data = {
67332               clip: fills,
67333               shadow: strokes,
67334               stroke: strokes,
67335               fill: fills
67336             };
67337             var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath-osm').filter(filter).data(data.clip, osmEntity.key);
67338             clipPaths.exit().remove();
67339             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-osm').attr('id', function (entity) {
67340               return 'ideditor-' + entity.id + '-clippath';
67341             });
67342             clipPathsEnter.append('path');
67343             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', path);
67344             var drawLayer = selection.selectAll('.layer-osm.areas');
67345             var touchLayer = selection.selectAll('.layer-touch.areas'); // Draw areas..
67346
67347             var areagroup = drawLayer.selectAll('g.areagroup').data(['fill', 'shadow', 'stroke']);
67348             areagroup = areagroup.enter().append('g').attr('class', function (d) {
67349               return 'areagroup area-' + d;
67350             }).merge(areagroup);
67351             var paths = areagroup.selectAll('path').filter(filter).data(function (layer) {
67352               return data[layer];
67353             }, osmEntity.key);
67354             paths.exit().remove();
67355             var fillpaths = selection.selectAll('.area-fill path.area').nodes();
67356             var bisect = d3_bisector(function (node) {
67357               return -node.__data__.area(graph);
67358             }).left;
67359
67360             function sortedByArea(entity) {
67361               if (this._parent.__data__ === 'fill') {
67362                 return fillpaths[bisect(fillpaths, -entity.area(graph))];
67363               }
67364             }
67365
67366             paths = paths.enter().insert('path', sortedByArea).merge(paths).each(function (entity) {
67367               var layer = this.parentNode.__data__;
67368               this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
67369
67370               if (layer === 'fill') {
67371                 this.setAttribute('clip-path', 'url(#ideditor-' + entity.id + '-clippath)');
67372                 this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
67373               }
67374             }).classed('added', function (d) {
67375               return !base.entities[d.id];
67376             }).classed('geometry-edited', function (d) {
67377               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
67378             }).classed('retagged', function (d) {
67379               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
67380             }).call(svgTagClasses()).attr('d', path); // Draw touch targets..
67381
67382             touchLayer.call(drawTargets, graph, data.stroke, filter);
67383           }
67384
67385           return drawAreas;
67386         }
67387
67388         //[4]           NameStartChar      ::=          ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
67389         //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
67390         //[5]           Name       ::=          NameStartChar (NameChar)*
67391         var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/; //\u10000-\uEFFFF
67392
67393         var nameChar = new RegExp("[\\-\\.0-9" + nameStartChar.source.slice(1, -1) + "\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
67394         var tagNamePattern = new RegExp('^' + nameStartChar.source + nameChar.source + '*(?:\:' + nameStartChar.source + nameChar.source + '*)?$'); //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
67395         //var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
67396         //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
67397         //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
67398
67399         var S_TAG = 0; //tag name offerring
67400
67401         var S_ATTR = 1; //attr name offerring 
67402
67403         var S_ATTR_SPACE = 2; //attr name end and space offer
67404
67405         var S_EQ = 3; //=space?
67406
67407         var S_ATTR_NOQUOT_VALUE = 4; //attr value(no quot value only)
67408
67409         var S_ATTR_END = 5; //attr value end and no space(quot end)
67410
67411         var S_TAG_SPACE = 6; //(attr value end || tag end ) && (space offer)
67412
67413         var S_TAG_CLOSE = 7; //closed el<el />
67414
67415         function XMLReader() {}
67416
67417         XMLReader.prototype = {
67418           parse: function parse(source, defaultNSMap, entityMap) {
67419             var domBuilder = this.domBuilder;
67420             domBuilder.startDocument();
67421
67422             _copy(defaultNSMap, defaultNSMap = {});
67423
67424             _parse(source, defaultNSMap, entityMap, domBuilder, this.errorHandler);
67425
67426             domBuilder.endDocument();
67427           }
67428         };
67429
67430         function _parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
67431           function fixedFromCharCode(code) {
67432             // String.prototype.fromCharCode does not supports
67433             // > 2 bytes unicode chars directly
67434             if (code > 0xffff) {
67435               code -= 0x10000;
67436               var surrogate1 = 0xd800 + (code >> 10),
67437                   surrogate2 = 0xdc00 + (code & 0x3ff);
67438               return String.fromCharCode(surrogate1, surrogate2);
67439             } else {
67440               return String.fromCharCode(code);
67441             }
67442           }
67443
67444           function entityReplacer(a) {
67445             var k = a.slice(1, -1);
67446
67447             if (k in entityMap) {
67448               return entityMap[k];
67449             } else if (k.charAt(0) === '#') {
67450               return fixedFromCharCode(parseInt(k.substr(1).replace('x', '0x')));
67451             } else {
67452               errorHandler.error('entity not found:' + a);
67453               return a;
67454             }
67455           }
67456
67457           function appendText(end) {
67458             //has some bugs
67459             if (end > start) {
67460               var xt = source.substring(start, end).replace(/&#?\w+;/g, entityReplacer);
67461               locator && position(start);
67462               domBuilder.characters(xt, 0, end - start);
67463               start = end;
67464             }
67465           }
67466
67467           function position(p, m) {
67468             while (p >= lineEnd && (m = linePattern.exec(source))) {
67469               lineStart = m.index;
67470               lineEnd = lineStart + m[0].length;
67471               locator.lineNumber++; //console.log('line++:',locator,startPos,endPos)
67472             }
67473
67474             locator.columnNumber = p - lineStart + 1;
67475           }
67476
67477           var lineStart = 0;
67478           var lineEnd = 0;
67479           var linePattern = /.*(?:\r\n?|\n)|.*$/g;
67480           var locator = domBuilder.locator;
67481           var parseStack = [{
67482             currentNSMap: defaultNSMapCopy
67483           }];
67484           var closeMap = {};
67485           var start = 0;
67486
67487           while (true) {
67488             try {
67489               var tagStart = source.indexOf('<', start);
67490
67491               if (tagStart < 0) {
67492                 if (!source.substr(start).match(/^\s*$/)) {
67493                   var doc = domBuilder.doc;
67494                   var text = doc.createTextNode(source.substr(start));
67495                   doc.appendChild(text);
67496                   domBuilder.currentElement = text;
67497                 }
67498
67499                 return;
67500               }
67501
67502               if (tagStart > start) {
67503                 appendText(tagStart);
67504               }
67505
67506               switch (source.charAt(tagStart + 1)) {
67507                 case '/':
67508                   var end = source.indexOf('>', tagStart + 3);
67509                   var tagName = source.substring(tagStart + 2, end);
67510                   var config = parseStack.pop();
67511
67512                   if (end < 0) {
67513                     tagName = source.substring(tagStart + 2).replace(/[\s<].*/, ''); //console.error('#@@@@@@'+tagName)
67514
67515                     errorHandler.error("end tag name: " + tagName + ' is not complete:' + config.tagName);
67516                     end = tagStart + 1 + tagName.length;
67517                   } else if (tagName.match(/\s</)) {
67518                     tagName = tagName.replace(/[\s<].*/, '');
67519                     errorHandler.error("end tag name: " + tagName + ' maybe not complete');
67520                     end = tagStart + 1 + tagName.length;
67521                   } //console.error(parseStack.length,parseStack)
67522                   //console.error(config);
67523
67524
67525                   var localNSMap = config.localNSMap;
67526                   var endMatch = config.tagName == tagName;
67527                   var endIgnoreCaseMach = endMatch || config.tagName && config.tagName.toLowerCase() == tagName.toLowerCase();
67528
67529                   if (endIgnoreCaseMach) {
67530                     domBuilder.endElement(config.uri, config.localName, tagName);
67531
67532                     if (localNSMap) {
67533                       for (var prefix in localNSMap) {
67534                         domBuilder.endPrefixMapping(prefix);
67535                       }
67536                     }
67537
67538                     if (!endMatch) {
67539                       errorHandler.fatalError("end tag name: " + tagName + ' is not match the current start tagName:' + config.tagName);
67540                     }
67541                   } else {
67542                     parseStack.push(config);
67543                   }
67544
67545                   end++;
67546                   break;
67547                 // end elment
67548
67549                 case '?':
67550                   // <?...?>
67551                   locator && position(tagStart);
67552                   end = parseInstruction(source, tagStart, domBuilder);
67553                   break;
67554
67555                 case '!':
67556                   // <!doctype,<![CDATA,<!--
67557                   locator && position(tagStart);
67558                   end = parseDCC(source, tagStart, domBuilder, errorHandler);
67559                   break;
67560
67561                 default:
67562                   locator && position(tagStart);
67563                   var el = new ElementAttributes();
67564                   var currentNSMap = parseStack[parseStack.length - 1].currentNSMap; //elStartEnd
67565
67566                   var end = parseElementStartPart(source, tagStart, el, currentNSMap, entityReplacer, errorHandler);
67567                   var len = el.length;
67568
67569                   if (!el.closed && fixSelfClosed(source, end, el.tagName, closeMap)) {
67570                     el.closed = true;
67571
67572                     if (!entityMap.nbsp) {
67573                       errorHandler.warning('unclosed xml attribute');
67574                     }
67575                   }
67576
67577                   if (locator && len) {
67578                     var locator2 = copyLocator(locator, {}); //try{//attribute position fixed
67579
67580                     for (var i = 0; i < len; i++) {
67581                       var a = el[i];
67582                       position(a.offset);
67583                       a.locator = copyLocator(locator, {});
67584                     } //}catch(e){console.error('@@@@@'+e)}
67585
67586
67587                     domBuilder.locator = locator2;
67588
67589                     if (appendElement(el, domBuilder, currentNSMap)) {
67590                       parseStack.push(el);
67591                     }
67592
67593                     domBuilder.locator = locator;
67594                   } else {
67595                     if (appendElement(el, domBuilder, currentNSMap)) {
67596                       parseStack.push(el);
67597                     }
67598                   }
67599
67600                   if (el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed) {
67601                     end = parseHtmlSpecialContent(source, end, el.tagName, entityReplacer, domBuilder);
67602                   } else {
67603                     end++;
67604                   }
67605
67606               }
67607             } catch (e) {
67608               errorHandler.error('element parse error: ' + e); //errorHandler.error('element parse error: '+e);
67609
67610               end = -1; //throw e;
67611             }
67612
67613             if (end > start) {
67614               start = end;
67615             } else {
67616               //TODO: 这里有可能sax回退,有位置错误风险
67617               appendText(Math.max(tagStart, start) + 1);
67618             }
67619           }
67620         }
67621
67622         function copyLocator(f, t) {
67623           t.lineNumber = f.lineNumber;
67624           t.columnNumber = f.columnNumber;
67625           return t;
67626         }
67627         /**
67628          * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
67629          * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
67630          */
67631
67632
67633         function parseElementStartPart(source, start, el, currentNSMap, entityReplacer, errorHandler) {
67634           var attrName;
67635           var value;
67636           var p = ++start;
67637           var s = S_TAG; //status
67638
67639           while (true) {
67640             var c = source.charAt(p);
67641
67642             switch (c) {
67643               case '=':
67644                 if (s === S_ATTR) {
67645                   //attrName
67646                   attrName = source.slice(start, p);
67647                   s = S_EQ;
67648                 } else if (s === S_ATTR_SPACE) {
67649                   s = S_EQ;
67650                 } else {
67651                   //fatalError: equal must after attrName or space after attrName
67652                   throw new Error('attribute equal must after attrName');
67653                 }
67654
67655                 break;
67656
67657               case '\'':
67658               case '"':
67659                 if (s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
67660                 ) {
67661                     //equal
67662                     if (s === S_ATTR) {
67663                       errorHandler.warning('attribute value must after "="');
67664                       attrName = source.slice(start, p);
67665                     }
67666
67667                     start = p + 1;
67668                     p = source.indexOf(c, start);
67669
67670                     if (p > 0) {
67671                       value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
67672                       el.add(attrName, value, start - 1);
67673                       s = S_ATTR_END;
67674                     } else {
67675                       //fatalError: no end quot match
67676                       throw new Error('attribute value no end \'' + c + '\' match');
67677                     }
67678                   } else if (s == S_ATTR_NOQUOT_VALUE) {
67679                   value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer); //console.log(attrName,value,start,p)
67680
67681                   el.add(attrName, value, start); //console.dir(el)
67682
67683                   errorHandler.warning('attribute "' + attrName + '" missed start quot(' + c + ')!!');
67684                   start = p + 1;
67685                   s = S_ATTR_END;
67686                 } else {
67687                   //fatalError: no equal before
67688                   throw new Error('attribute value must after "="');
67689                 }
67690
67691                 break;
67692
67693               case '/':
67694                 switch (s) {
67695                   case S_TAG:
67696                     el.setTagName(source.slice(start, p));
67697
67698                   case S_ATTR_END:
67699                   case S_TAG_SPACE:
67700                   case S_TAG_CLOSE:
67701                     s = S_TAG_CLOSE;
67702                     el.closed = true;
67703
67704                   case S_ATTR_NOQUOT_VALUE:
67705                   case S_ATTR:
67706                   case S_ATTR_SPACE:
67707                     break;
67708                   //case S_EQ:
67709
67710                   default:
67711                     throw new Error("attribute invalid close char('/')");
67712                 }
67713
67714                 break;
67715
67716               case '':
67717                 //end document
67718                 //throw new Error('unexpected end of input')
67719                 errorHandler.error('unexpected end of input');
67720
67721                 if (s == S_TAG) {
67722                   el.setTagName(source.slice(start, p));
67723                 }
67724
67725                 return p;
67726
67727               case '>':
67728                 switch (s) {
67729                   case S_TAG:
67730                     el.setTagName(source.slice(start, p));
67731
67732                   case S_ATTR_END:
67733                   case S_TAG_SPACE:
67734                   case S_TAG_CLOSE:
67735                     break;
67736                   //normal
67737
67738                   case S_ATTR_NOQUOT_VALUE: //Compatible state
67739
67740                   case S_ATTR:
67741                     value = source.slice(start, p);
67742
67743                     if (value.slice(-1) === '/') {
67744                       el.closed = true;
67745                       value = value.slice(0, -1);
67746                     }
67747
67748                   case S_ATTR_SPACE:
67749                     if (s === S_ATTR_SPACE) {
67750                       value = attrName;
67751                     }
67752
67753                     if (s == S_ATTR_NOQUOT_VALUE) {
67754                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
67755                       el.add(attrName, value.replace(/&#?\w+;/g, entityReplacer), start);
67756                     } else {
67757                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)) {
67758                         errorHandler.warning('attribute "' + value + '" missed value!! "' + value + '" instead!!');
67759                       }
67760
67761                       el.add(value, value, start);
67762                     }
67763
67764                     break;
67765
67766                   case S_EQ:
67767                     throw new Error('attribute value missed!!');
67768                 } //                    console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
67769
67770
67771                 return p;
67772
67773               /*xml space '\x20' | #x9 | #xD | #xA; */
67774
67775               case "\x80":
67776                 c = ' ';
67777
67778               default:
67779                 if (c <= ' ') {
67780                   //space
67781                   switch (s) {
67782                     case S_TAG:
67783                       el.setTagName(source.slice(start, p)); //tagName
67784
67785                       s = S_TAG_SPACE;
67786                       break;
67787
67788                     case S_ATTR:
67789                       attrName = source.slice(start, p);
67790                       s = S_ATTR_SPACE;
67791                       break;
67792
67793                     case S_ATTR_NOQUOT_VALUE:
67794                       var value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
67795                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
67796                       el.add(attrName, value, start);
67797
67798                     case S_ATTR_END:
67799                       s = S_TAG_SPACE;
67800                       break;
67801                     //case S_TAG_SPACE:
67802                     //case S_EQ:
67803                     //case S_ATTR_SPACE:
67804                     //  void();break;
67805                     //case S_TAG_CLOSE:
67806                     //ignore warning
67807                   }
67808                 } else {
67809                   //not space
67810                   //S_TAG,      S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
67811                   //S_ATTR_SPACE,       S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
67812                   switch (s) {
67813                     //case S_TAG:void();break;
67814                     //case S_ATTR:void();break;
67815                     //case S_ATTR_NOQUOT_VALUE:void();break;
67816                     case S_ATTR_SPACE:
67817                       var tagName = el.tagName;
67818
67819                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
67820                         errorHandler.warning('attribute "' + attrName + '" missed value!! "' + attrName + '" instead2!!');
67821                       }
67822
67823                       el.add(attrName, attrName, start);
67824                       start = p;
67825                       s = S_ATTR;
67826                       break;
67827
67828                     case S_ATTR_END:
67829                       errorHandler.warning('attribute space is required"' + attrName + '"!!');
67830
67831                     case S_TAG_SPACE:
67832                       s = S_ATTR;
67833                       start = p;
67834                       break;
67835
67836                     case S_EQ:
67837                       s = S_ATTR_NOQUOT_VALUE;
67838                       start = p;
67839                       break;
67840
67841                     case S_TAG_CLOSE:
67842                       throw new Error("elements closed character '/' and '>' must be connected to");
67843                   }
67844                 }
67845
67846             } //end outer switch
67847             //console.log('p++',p)
67848
67849
67850             p++;
67851           }
67852         }
67853         /**
67854          * @return true if has new namespace define
67855          */
67856
67857
67858         function appendElement(el, domBuilder, currentNSMap) {
67859           var tagName = el.tagName;
67860           var localNSMap = null; //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
67861
67862           var i = el.length;
67863
67864           while (i--) {
67865             var a = el[i];
67866             var qName = a.qName;
67867             var value = a.value;
67868             var nsp = qName.indexOf(':');
67869
67870             if (nsp > 0) {
67871               var prefix = a.prefix = qName.slice(0, nsp);
67872               var localName = qName.slice(nsp + 1);
67873               var nsPrefix = prefix === 'xmlns' && localName;
67874             } else {
67875               localName = qName;
67876               prefix = null;
67877               nsPrefix = qName === 'xmlns' && '';
67878             } //can not set prefix,because prefix !== ''
67879
67880
67881             a.localName = localName; //prefix == null for no ns prefix attribute 
67882
67883             if (nsPrefix !== false) {
67884               //hack!!
67885               if (localNSMap == null) {
67886                 localNSMap = {}; //console.log(currentNSMap,0)
67887
67888                 _copy(currentNSMap, currentNSMap = {}); //console.log(currentNSMap,1)
67889
67890               }
67891
67892               currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
67893               a.uri = 'http://www.w3.org/2000/xmlns/';
67894               domBuilder.startPrefixMapping(nsPrefix, value);
67895             }
67896           }
67897
67898           var i = el.length;
67899
67900           while (i--) {
67901             a = el[i];
67902             var prefix = a.prefix;
67903
67904             if (prefix) {
67905               //no prefix attribute has no namespace
67906               if (prefix === 'xml') {
67907                 a.uri = 'http://www.w3.org/XML/1998/namespace';
67908               }
67909
67910               if (prefix !== 'xmlns') {
67911                 a.uri = currentNSMap[prefix || '']; //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
67912               }
67913             }
67914           }
67915
67916           var nsp = tagName.indexOf(':');
67917
67918           if (nsp > 0) {
67919             prefix = el.prefix = tagName.slice(0, nsp);
67920             localName = el.localName = tagName.slice(nsp + 1);
67921           } else {
67922             prefix = null; //important!!
67923
67924             localName = el.localName = tagName;
67925           } //no prefix element has default namespace
67926
67927
67928           var ns = el.uri = currentNSMap[prefix || ''];
67929           domBuilder.startElement(ns, localName, tagName, el); //endPrefixMapping and startPrefixMapping have not any help for dom builder
67930           //localNSMap = null
67931
67932           if (el.closed) {
67933             domBuilder.endElement(ns, localName, tagName);
67934
67935             if (localNSMap) {
67936               for (prefix in localNSMap) {
67937                 domBuilder.endPrefixMapping(prefix);
67938               }
67939             }
67940           } else {
67941             el.currentNSMap = currentNSMap;
67942             el.localNSMap = localNSMap; //parseStack.push(el);
67943
67944             return true;
67945           }
67946         }
67947
67948         function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, domBuilder) {
67949           if (/^(?:script|textarea)$/i.test(tagName)) {
67950             var elEndStart = source.indexOf('</' + tagName + '>', elStartEnd);
67951             var text = source.substring(elStartEnd + 1, elEndStart);
67952
67953             if (/[&<]/.test(text)) {
67954               if (/^script$/i.test(tagName)) {
67955                 //if(!/\]\]>/.test(text)){
67956                 //lexHandler.startCDATA();
67957                 domBuilder.characters(text, 0, text.length); //lexHandler.endCDATA();
67958
67959                 return elEndStart; //}
67960               } //}else{//text area
67961
67962
67963               text = text.replace(/&#?\w+;/g, entityReplacer);
67964               domBuilder.characters(text, 0, text.length);
67965               return elEndStart; //}
67966             }
67967           }
67968
67969           return elStartEnd + 1;
67970         }
67971
67972         function fixSelfClosed(source, elStartEnd, tagName, closeMap) {
67973           //if(tagName in closeMap){
67974           var pos = closeMap[tagName];
67975
67976           if (pos == null) {
67977             //console.log(tagName)
67978             pos = source.lastIndexOf('</' + tagName + '>');
67979
67980             if (pos < elStartEnd) {
67981               //忘记闭合
67982               pos = source.lastIndexOf('</' + tagName);
67983             }
67984
67985             closeMap[tagName] = pos;
67986           }
67987
67988           return pos < elStartEnd; //} 
67989         }
67990
67991         function _copy(source, target) {
67992           for (var n in source) {
67993             target[n] = source[n];
67994           }
67995         }
67996
67997         function parseDCC(source, start, domBuilder, errorHandler) {
67998           //sure start with '<!'
67999           var next = source.charAt(start + 2);
68000
68001           switch (next) {
68002             case '-':
68003               if (source.charAt(start + 3) === '-') {
68004                 var end = source.indexOf('-->', start + 4); //append comment source.substring(4,end)//<!--
68005
68006                 if (end > start) {
68007                   domBuilder.comment(source, start + 4, end - start - 4);
68008                   return end + 3;
68009                 } else {
68010                   errorHandler.error("Unclosed comment");
68011                   return -1;
68012                 }
68013               } else {
68014                 //error
68015                 return -1;
68016               }
68017
68018             default:
68019               if (source.substr(start + 3, 6) == 'CDATA[') {
68020                 var end = source.indexOf(']]>', start + 9);
68021                 domBuilder.startCDATA();
68022                 domBuilder.characters(source, start + 9, end - start - 9);
68023                 domBuilder.endCDATA();
68024                 return end + 3;
68025               } //<!DOCTYPE
68026               //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
68027
68028
68029               var matchs = split$1(source, start);
68030               var len = matchs.length;
68031
68032               if (len > 1 && /!doctype/i.test(matchs[0][0])) {
68033                 var name = matchs[1][0];
68034                 var pubid = len > 3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
68035                 var sysid = len > 4 && matchs[4][0];
68036                 var lastMatch = matchs[len - 1];
68037                 domBuilder.startDTD(name, pubid && pubid.replace(/^(['"])(.*?)\1$/, '$2'), sysid && sysid.replace(/^(['"])(.*?)\1$/, '$2'));
68038                 domBuilder.endDTD();
68039                 return lastMatch.index + lastMatch[0].length;
68040               }
68041
68042           }
68043
68044           return -1;
68045         }
68046
68047         function parseInstruction(source, start, domBuilder) {
68048           var end = source.indexOf('?>', start);
68049
68050           if (end) {
68051             var match = source.substring(start, end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
68052
68053             if (match) {
68054               var len = match[0].length;
68055               domBuilder.processingInstruction(match[1], match[2]);
68056               return end + 2;
68057             } else {
68058               //error
68059               return -1;
68060             }
68061           }
68062
68063           return -1;
68064         }
68065         /**
68066          * @param source
68067          */
68068
68069
68070         function ElementAttributes(source) {}
68071
68072         ElementAttributes.prototype = {
68073           setTagName: function setTagName(tagName) {
68074             if (!tagNamePattern.test(tagName)) {
68075               throw new Error('invalid tagName:' + tagName);
68076             }
68077
68078             this.tagName = tagName;
68079           },
68080           add: function add(qName, value, offset) {
68081             if (!tagNamePattern.test(qName)) {
68082               throw new Error('invalid attribute:' + qName);
68083             }
68084
68085             this[this.length++] = {
68086               qName: qName,
68087               value: value,
68088               offset: offset
68089             };
68090           },
68091           length: 0,
68092           getLocalName: function getLocalName(i) {
68093             return this[i].localName;
68094           },
68095           getLocator: function getLocator(i) {
68096             return this[i].locator;
68097           },
68098           getQName: function getQName(i) {
68099             return this[i].qName;
68100           },
68101           getURI: function getURI(i) {
68102             return this[i].uri;
68103           },
68104           getValue: function getValue(i) {
68105             return this[i].value;
68106           } //  ,getIndex:function(uri, localName)){
68107           //            if(localName){
68108           //                    
68109           //            }else{
68110           //                    var qName = uri
68111           //            }
68112           //    },
68113           //    getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
68114           //    getType:function(uri,localName){}
68115           //    getType:function(i){},
68116
68117         };
68118
68119         function _set_proto_(thiz, parent) {
68120           thiz.__proto__ = parent;
68121           return thiz;
68122         }
68123
68124         if (!(_set_proto_({}, _set_proto_.prototype) instanceof _set_proto_)) {
68125           _set_proto_ = function _set_proto_(thiz, parent) {
68126             function p() {}
68127             p.prototype = parent;
68128             p = new p();
68129
68130             for (parent in thiz) {
68131               p[parent] = thiz[parent];
68132             }
68133
68134             return p;
68135           };
68136         }
68137
68138         function split$1(source, start) {
68139           var match;
68140           var buf = [];
68141           var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
68142           reg.lastIndex = start;
68143           reg.exec(source); //skip <
68144
68145           while (match = reg.exec(source)) {
68146             buf.push(match);
68147             if (match[1]) return buf;
68148           }
68149         }
68150
68151         var XMLReader_1 = XMLReader;
68152         var sax = {
68153           XMLReader: XMLReader_1
68154         };
68155
68156         /*
68157          * DOM Level 2
68158          * Object DOMException
68159          * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
68160          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
68161          */
68162         function copy$1(src, dest) {
68163           for (var p in src) {
68164             dest[p] = src[p];
68165           }
68166         }
68167         /**
68168         ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
68169         ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
68170          */
68171
68172
68173         function _extends(Class, Super) {
68174           var pt = Class.prototype;
68175
68176           if (Object.create) {
68177             var ppt = Object.create(Super.prototype);
68178             pt.__proto__ = ppt;
68179           }
68180
68181           if (!(pt instanceof Super)) {
68182             var t = function t() {};
68183             t.prototype = Super.prototype;
68184             t = new t();
68185             copy$1(pt, t);
68186             Class.prototype = pt = t;
68187           }
68188
68189           if (pt.constructor != Class) {
68190             if (typeof Class != 'function') {
68191               console.error("unknow Class:" + Class);
68192             }
68193
68194             pt.constructor = Class;
68195           }
68196         }
68197
68198         var htmlns = 'http://www.w3.org/1999/xhtml'; // Node Types
68199
68200         var NodeType = {};
68201         var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;
68202         var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;
68203         var TEXT_NODE = NodeType.TEXT_NODE = 3;
68204         var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;
68205         var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;
68206         var ENTITY_NODE = NodeType.ENTITY_NODE = 6;
68207         var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
68208         var COMMENT_NODE = NodeType.COMMENT_NODE = 8;
68209         var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;
68210         var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;
68211         var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;
68212         var NOTATION_NODE = NodeType.NOTATION_NODE = 12; // ExceptionCode
68213
68214         var ExceptionCode = {};
68215         var ExceptionMessage = {};
68216         var INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = (ExceptionMessage[1] = "Index size error", 1);
68217         var DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = (ExceptionMessage[2] = "DOMString size error", 2);
68218         var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = (ExceptionMessage[3] = "Hierarchy request error", 3);
68219         var WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = (ExceptionMessage[4] = "Wrong document", 4);
68220         var INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = (ExceptionMessage[5] = "Invalid character", 5);
68221         var NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = (ExceptionMessage[6] = "No data allowed", 6);
68222         var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = (ExceptionMessage[7] = "No modification allowed", 7);
68223         var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = (ExceptionMessage[8] = "Not found", 8);
68224         var NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = (ExceptionMessage[9] = "Not supported", 9);
68225         var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = (ExceptionMessage[10] = "Attribute in use", 10); //level2
68226
68227         var INVALID_STATE_ERR = ExceptionCode.INVALID_STATE_ERR = (ExceptionMessage[11] = "Invalid state", 11);
68228         var SYNTAX_ERR = ExceptionCode.SYNTAX_ERR = (ExceptionMessage[12] = "Syntax error", 12);
68229         var INVALID_MODIFICATION_ERR = ExceptionCode.INVALID_MODIFICATION_ERR = (ExceptionMessage[13] = "Invalid modification", 13);
68230         var NAMESPACE_ERR = ExceptionCode.NAMESPACE_ERR = (ExceptionMessage[14] = "Invalid namespace", 14);
68231         var INVALID_ACCESS_ERR = ExceptionCode.INVALID_ACCESS_ERR = (ExceptionMessage[15] = "Invalid access", 15);
68232
68233         function DOMException$2(code, message) {
68234           if (message instanceof Error) {
68235             var error = message;
68236           } else {
68237             error = this;
68238             Error.call(this, ExceptionMessage[code]);
68239             this.message = ExceptionMessage[code];
68240             if (Error.captureStackTrace) Error.captureStackTrace(this, DOMException$2);
68241           }
68242
68243           error.code = code;
68244           if (message) this.message = this.message + ": " + message;
68245           return error;
68246         }
68247         DOMException$2.prototype = Error.prototype;
68248         copy$1(ExceptionCode, DOMException$2);
68249         /**
68250          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
68251          * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live.
68252          * The items in the NodeList are accessible via an integral index, starting from 0.
68253          */
68254
68255         function NodeList() {}
68256         NodeList.prototype = {
68257           /**
68258            * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
68259            * @standard level1
68260            */
68261           length: 0,
68262
68263           /**
68264            * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.
68265            * @standard level1
68266            * @param index  unsigned long 
68267            *   Index into the collection.
68268            * @return Node
68269            *    The node at the indexth position in the NodeList, or null if that is not a valid index. 
68270            */
68271           item: function item(index) {
68272             return this[index] || null;
68273           },
68274           toString: function toString(isHTML, nodeFilter) {
68275             for (var buf = [], i = 0; i < this.length; i++) {
68276               serializeToString(this[i], buf, isHTML, nodeFilter);
68277             }
68278
68279             return buf.join('');
68280           }
68281         };
68282
68283         function LiveNodeList(node, refresh) {
68284           this._node = node;
68285           this._refresh = refresh;
68286
68287           _updateLiveList(this);
68288         }
68289
68290         function _updateLiveList(list) {
68291           var inc = list._node._inc || list._node.ownerDocument._inc;
68292
68293           if (list._inc != inc) {
68294             var ls = list._refresh(list._node); //console.log(ls.length)
68295
68296
68297             __set__(list, 'length', ls.length);
68298
68299             copy$1(ls, list);
68300             list._inc = inc;
68301           }
68302         }
68303
68304         LiveNodeList.prototype.item = function (i) {
68305           _updateLiveList(this);
68306
68307           return this[i];
68308         };
68309
68310         _extends(LiveNodeList, NodeList);
68311         /**
68312          * 
68313          * Objects implementing the NamedNodeMap interface are used to represent collections of nodes that can be accessed by name. Note that NamedNodeMap does not inherit from NodeList; NamedNodeMaps are not maintained in any particular order. Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal index, but this is simply to allow convenient enumeration of the contents of a NamedNodeMap, and does not imply that the DOM specifies an order to these Nodes.
68314          * NamedNodeMap objects in the DOM are live.
68315          * used for attributes or DocumentType entities 
68316          */
68317
68318
68319         function NamedNodeMap() {}
68320
68321         function _findNodeIndex(list, node) {
68322           var i = list.length;
68323
68324           while (i--) {
68325             if (list[i] === node) {
68326               return i;
68327             }
68328           }
68329         }
68330
68331         function _addNamedNode(el, list, newAttr, oldAttr) {
68332           if (oldAttr) {
68333             list[_findNodeIndex(list, oldAttr)] = newAttr;
68334           } else {
68335             list[list.length++] = newAttr;
68336           }
68337
68338           if (el) {
68339             newAttr.ownerElement = el;
68340             var doc = el.ownerDocument;
68341
68342             if (doc) {
68343               oldAttr && _onRemoveAttribute(doc, el, oldAttr);
68344
68345               _onAddAttribute(doc, el, newAttr);
68346             }
68347           }
68348         }
68349
68350         function _removeNamedNode(el, list, attr) {
68351           //console.log('remove attr:'+attr)
68352           var i = _findNodeIndex(list, attr);
68353
68354           if (i >= 0) {
68355             var lastIndex = list.length - 1;
68356
68357             while (i < lastIndex) {
68358               list[i] = list[++i];
68359             }
68360
68361             list.length = lastIndex;
68362
68363             if (el) {
68364               var doc = el.ownerDocument;
68365
68366               if (doc) {
68367                 _onRemoveAttribute(doc, el, attr);
68368
68369                 attr.ownerElement = null;
68370               }
68371             }
68372           } else {
68373             throw DOMException$2(NOT_FOUND_ERR, new Error(el.tagName + '@' + attr));
68374           }
68375         }
68376
68377         NamedNodeMap.prototype = {
68378           length: 0,
68379           item: NodeList.prototype.item,
68380           getNamedItem: function getNamedItem(key) {
68381             //          if(key.indexOf(':')>0 || key == 'xmlns'){
68382             //                  return null;
68383             //          }
68384             //console.log()
68385             var i = this.length;
68386
68387             while (i--) {
68388               var attr = this[i]; //console.log(attr.nodeName,key)
68389
68390               if (attr.nodeName == key) {
68391                 return attr;
68392               }
68393             }
68394           },
68395           setNamedItem: function setNamedItem(attr) {
68396             var el = attr.ownerElement;
68397
68398             if (el && el != this._ownerElement) {
68399               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
68400             }
68401
68402             var oldAttr = this.getNamedItem(attr.nodeName);
68403
68404             _addNamedNode(this._ownerElement, this, attr, oldAttr);
68405
68406             return oldAttr;
68407           },
68408
68409           /* returns Node */
68410           setNamedItemNS: function setNamedItemNS(attr) {
68411             // raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
68412             var el = attr.ownerElement,
68413                 oldAttr;
68414
68415             if (el && el != this._ownerElement) {
68416               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
68417             }
68418
68419             oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName);
68420
68421             _addNamedNode(this._ownerElement, this, attr, oldAttr);
68422
68423             return oldAttr;
68424           },
68425
68426           /* returns Node */
68427           removeNamedItem: function removeNamedItem(key) {
68428             var attr = this.getNamedItem(key);
68429
68430             _removeNamedNode(this._ownerElement, this, attr);
68431
68432             return attr;
68433           },
68434           // raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
68435           //for level2
68436           removeNamedItemNS: function removeNamedItemNS(namespaceURI, localName) {
68437             var attr = this.getNamedItemNS(namespaceURI, localName);
68438
68439             _removeNamedNode(this._ownerElement, this, attr);
68440
68441             return attr;
68442           },
68443           getNamedItemNS: function getNamedItemNS(namespaceURI, localName) {
68444             var i = this.length;
68445
68446             while (i--) {
68447               var node = this[i];
68448
68449               if (node.localName == localName && node.namespaceURI == namespaceURI) {
68450                 return node;
68451               }
68452             }
68453
68454             return null;
68455           }
68456         };
68457         /**
68458          * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
68459          */
68460
68461         function DOMImplementation(
68462         /* Object */
68463         features) {
68464           this._features = {};
68465
68466           if (features) {
68467             for (var feature in features) {
68468               this._features = features[feature];
68469             }
68470           }
68471         }
68472         DOMImplementation.prototype = {
68473           hasFeature: function hasFeature(
68474           /* string */
68475           feature,
68476           /* string */
68477           version) {
68478             var versions = this._features[feature.toLowerCase()];
68479
68480             if (versions && (!version || version in versions)) {
68481               return true;
68482             } else {
68483               return false;
68484             }
68485           },
68486           // Introduced in DOM Level 2:
68487           createDocument: function createDocument(namespaceURI, qualifiedName, doctype) {
68488             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
68489             var doc = new Document();
68490             doc.implementation = this;
68491             doc.childNodes = new NodeList();
68492             doc.doctype = doctype;
68493
68494             if (doctype) {
68495               doc.appendChild(doctype);
68496             }
68497
68498             if (qualifiedName) {
68499               var root = doc.createElementNS(namespaceURI, qualifiedName);
68500               doc.appendChild(root);
68501             }
68502
68503             return doc;
68504           },
68505           // Introduced in DOM Level 2:
68506           createDocumentType: function createDocumentType(qualifiedName, publicId, systemId) {
68507             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
68508             var node = new DocumentType();
68509             node.name = qualifiedName;
68510             node.nodeName = qualifiedName;
68511             node.publicId = publicId;
68512             node.systemId = systemId; // Introduced in DOM Level 2:
68513             //readonly attribute DOMString        internalSubset;
68514             //TODO:..
68515             //  readonly attribute NamedNodeMap     entities;
68516             //  readonly attribute NamedNodeMap     notations;
68517
68518             return node;
68519           }
68520         };
68521         /**
68522          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
68523          */
68524
68525         function Node() {}
68526         Node.prototype = {
68527           firstChild: null,
68528           lastChild: null,
68529           previousSibling: null,
68530           nextSibling: null,
68531           attributes: null,
68532           parentNode: null,
68533           childNodes: null,
68534           ownerDocument: null,
68535           nodeValue: null,
68536           namespaceURI: null,
68537           prefix: null,
68538           localName: null,
68539           // Modified in DOM Level 2:
68540           insertBefore: function insertBefore(newChild, refChild) {
68541             //raises 
68542             return _insertBefore(this, newChild, refChild);
68543           },
68544           replaceChild: function replaceChild(newChild, oldChild) {
68545             //raises 
68546             this.insertBefore(newChild, oldChild);
68547
68548             if (oldChild) {
68549               this.removeChild(oldChild);
68550             }
68551           },
68552           removeChild: function removeChild(oldChild) {
68553             return _removeChild(this, oldChild);
68554           },
68555           appendChild: function appendChild(newChild) {
68556             return this.insertBefore(newChild, null);
68557           },
68558           hasChildNodes: function hasChildNodes() {
68559             return this.firstChild != null;
68560           },
68561           cloneNode: function cloneNode(deep) {
68562             return _cloneNode(this.ownerDocument || this, this, deep);
68563           },
68564           // Modified in DOM Level 2:
68565           normalize: function normalize() {
68566             var child = this.firstChild;
68567
68568             while (child) {
68569               var next = child.nextSibling;
68570
68571               if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {
68572                 this.removeChild(next);
68573                 child.appendData(next.data);
68574               } else {
68575                 child.normalize();
68576                 child = next;
68577               }
68578             }
68579           },
68580           // Introduced in DOM Level 2:
68581           isSupported: function isSupported(feature, version) {
68582             return this.ownerDocument.implementation.hasFeature(feature, version);
68583           },
68584           // Introduced in DOM Level 2:
68585           hasAttributes: function hasAttributes() {
68586             return this.attributes.length > 0;
68587           },
68588           lookupPrefix: function lookupPrefix(namespaceURI) {
68589             var el = this;
68590
68591             while (el) {
68592               var map = el._nsMap; //console.dir(map)
68593
68594               if (map) {
68595                 for (var n in map) {
68596                   if (map[n] == namespaceURI) {
68597                     return n;
68598                   }
68599                 }
68600               }
68601
68602               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
68603             }
68604
68605             return null;
68606           },
68607           // Introduced in DOM Level 3:
68608           lookupNamespaceURI: function lookupNamespaceURI(prefix) {
68609             var el = this;
68610
68611             while (el) {
68612               var map = el._nsMap; //console.dir(map)
68613
68614               if (map) {
68615                 if (prefix in map) {
68616                   return map[prefix];
68617                 }
68618               }
68619
68620               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
68621             }
68622
68623             return null;
68624           },
68625           // Introduced in DOM Level 3:
68626           isDefaultNamespace: function isDefaultNamespace(namespaceURI) {
68627             var prefix = this.lookupPrefix(namespaceURI);
68628             return prefix == null;
68629           }
68630         };
68631
68632         function _xmlEncoder(c) {
68633           return c == '<' && '&lt;' || c == '>' && '&gt;' || c == '&' && '&amp;' || c == '"' && '&quot;' || '&#' + c.charCodeAt() + ';';
68634         }
68635
68636         copy$1(NodeType, Node);
68637         copy$1(NodeType, Node.prototype);
68638         /**
68639          * @param callback return true for continue,false for break
68640          * @return boolean true: break visit;
68641          */
68642
68643         function _visitNode(node, callback) {
68644           if (callback(node)) {
68645             return true;
68646           }
68647
68648           if (node = node.firstChild) {
68649             do {
68650               if (_visitNode(node, callback)) {
68651                 return true;
68652               }
68653             } while (node = node.nextSibling);
68654           }
68655         }
68656
68657         function Document() {}
68658
68659         function _onAddAttribute(doc, el, newAttr) {
68660           doc && doc._inc++;
68661           var ns = newAttr.namespaceURI;
68662
68663           if (ns == 'http://www.w3.org/2000/xmlns/') {
68664             //update namespace
68665             el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value;
68666           }
68667         }
68668
68669         function _onRemoveAttribute(doc, el, newAttr, remove) {
68670           doc && doc._inc++;
68671           var ns = newAttr.namespaceURI;
68672
68673           if (ns == 'http://www.w3.org/2000/xmlns/') {
68674             //update namespace
68675             delete el._nsMap[newAttr.prefix ? newAttr.localName : ''];
68676           }
68677         }
68678
68679         function _onUpdateChild(doc, el, newChild) {
68680           if (doc && doc._inc) {
68681             doc._inc++; //update childNodes
68682
68683             var cs = el.childNodes;
68684
68685             if (newChild) {
68686               cs[cs.length++] = newChild;
68687             } else {
68688               //console.log(1)
68689               var child = el.firstChild;
68690               var i = 0;
68691
68692               while (child) {
68693                 cs[i++] = child;
68694                 child = child.nextSibling;
68695               }
68696
68697               cs.length = i;
68698             }
68699           }
68700         }
68701         /**
68702          * attributes;
68703          * children;
68704          * 
68705          * writeable properties:
68706          * nodeValue,Attr:value,CharacterData:data
68707          * prefix
68708          */
68709
68710
68711         function _removeChild(parentNode, child) {
68712           var previous = child.previousSibling;
68713           var next = child.nextSibling;
68714
68715           if (previous) {
68716             previous.nextSibling = next;
68717           } else {
68718             parentNode.firstChild = next;
68719           }
68720
68721           if (next) {
68722             next.previousSibling = previous;
68723           } else {
68724             parentNode.lastChild = previous;
68725           }
68726
68727           _onUpdateChild(parentNode.ownerDocument, parentNode);
68728
68729           return child;
68730         }
68731         /**
68732          * preformance key(refChild == null)
68733          */
68734
68735
68736         function _insertBefore(parentNode, newChild, nextChild) {
68737           var cp = newChild.parentNode;
68738
68739           if (cp) {
68740             cp.removeChild(newChild); //remove and update
68741           }
68742
68743           if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
68744             var newFirst = newChild.firstChild;
68745
68746             if (newFirst == null) {
68747               return newChild;
68748             }
68749
68750             var newLast = newChild.lastChild;
68751           } else {
68752             newFirst = newLast = newChild;
68753           }
68754
68755           var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
68756           newFirst.previousSibling = pre;
68757           newLast.nextSibling = nextChild;
68758
68759           if (pre) {
68760             pre.nextSibling = newFirst;
68761           } else {
68762             parentNode.firstChild = newFirst;
68763           }
68764
68765           if (nextChild == null) {
68766             parentNode.lastChild = newLast;
68767           } else {
68768             nextChild.previousSibling = newLast;
68769           }
68770
68771           do {
68772             newFirst.parentNode = parentNode;
68773           } while (newFirst !== newLast && (newFirst = newFirst.nextSibling));
68774
68775           _onUpdateChild(parentNode.ownerDocument || parentNode, parentNode); //console.log(parentNode.lastChild.nextSibling == null)
68776
68777
68778           if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
68779             newChild.firstChild = newChild.lastChild = null;
68780           }
68781
68782           return newChild;
68783         }
68784
68785         function _appendSingleChild(parentNode, newChild) {
68786           var cp = newChild.parentNode;
68787
68788           if (cp) {
68789             var pre = parentNode.lastChild;
68790             cp.removeChild(newChild); //remove and update
68791
68792             var pre = parentNode.lastChild;
68793           }
68794
68795           var pre = parentNode.lastChild;
68796           newChild.parentNode = parentNode;
68797           newChild.previousSibling = pre;
68798           newChild.nextSibling = null;
68799
68800           if (pre) {
68801             pre.nextSibling = newChild;
68802           } else {
68803             parentNode.firstChild = newChild;
68804           }
68805
68806           parentNode.lastChild = newChild;
68807
68808           _onUpdateChild(parentNode.ownerDocument, parentNode, newChild);
68809
68810           return newChild; //console.log("__aa",parentNode.lastChild.nextSibling == null)
68811         }
68812
68813         Document.prototype = {
68814           //implementation : null,
68815           nodeName: '#document',
68816           nodeType: DOCUMENT_NODE,
68817           doctype: null,
68818           documentElement: null,
68819           _inc: 1,
68820           insertBefore: function insertBefore(newChild, refChild) {
68821             //raises 
68822             if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
68823               var child = newChild.firstChild;
68824
68825               while (child) {
68826                 var next = child.nextSibling;
68827                 this.insertBefore(child, refChild);
68828                 child = next;
68829               }
68830
68831               return newChild;
68832             }
68833
68834             if (this.documentElement == null && newChild.nodeType == ELEMENT_NODE) {
68835               this.documentElement = newChild;
68836             }
68837
68838             return _insertBefore(this, newChild, refChild), newChild.ownerDocument = this, newChild;
68839           },
68840           removeChild: function removeChild(oldChild) {
68841             if (this.documentElement == oldChild) {
68842               this.documentElement = null;
68843             }
68844
68845             return _removeChild(this, oldChild);
68846           },
68847           // Introduced in DOM Level 2:
68848           importNode: function importNode(importedNode, deep) {
68849             return _importNode(this, importedNode, deep);
68850           },
68851           // Introduced in DOM Level 2:
68852           getElementById: function getElementById(id) {
68853             var rtv = null;
68854
68855             _visitNode(this.documentElement, function (node) {
68856               if (node.nodeType == ELEMENT_NODE) {
68857                 if (node.getAttribute('id') == id) {
68858                   rtv = node;
68859                   return true;
68860                 }
68861               }
68862             });
68863
68864             return rtv;
68865           },
68866           //document factory method:
68867           createElement: function createElement(tagName) {
68868             var node = new Element();
68869             node.ownerDocument = this;
68870             node.nodeName = tagName;
68871             node.tagName = tagName;
68872             node.childNodes = new NodeList();
68873             var attrs = node.attributes = new NamedNodeMap();
68874             attrs._ownerElement = node;
68875             return node;
68876           },
68877           createDocumentFragment: function createDocumentFragment() {
68878             var node = new DocumentFragment();
68879             node.ownerDocument = this;
68880             node.childNodes = new NodeList();
68881             return node;
68882           },
68883           createTextNode: function createTextNode(data) {
68884             var node = new Text();
68885             node.ownerDocument = this;
68886             node.appendData(data);
68887             return node;
68888           },
68889           createComment: function createComment(data) {
68890             var node = new Comment();
68891             node.ownerDocument = this;
68892             node.appendData(data);
68893             return node;
68894           },
68895           createCDATASection: function createCDATASection(data) {
68896             var node = new CDATASection();
68897             node.ownerDocument = this;
68898             node.appendData(data);
68899             return node;
68900           },
68901           createProcessingInstruction: function createProcessingInstruction(target, data) {
68902             var node = new ProcessingInstruction();
68903             node.ownerDocument = this;
68904             node.tagName = node.target = target;
68905             node.nodeValue = node.data = data;
68906             return node;
68907           },
68908           createAttribute: function createAttribute(name) {
68909             var node = new Attr();
68910             node.ownerDocument = this;
68911             node.name = name;
68912             node.nodeName = name;
68913             node.localName = name;
68914             node.specified = true;
68915             return node;
68916           },
68917           createEntityReference: function createEntityReference(name) {
68918             var node = new EntityReference();
68919             node.ownerDocument = this;
68920             node.nodeName = name;
68921             return node;
68922           },
68923           // Introduced in DOM Level 2:
68924           createElementNS: function createElementNS(namespaceURI, qualifiedName) {
68925             var node = new Element();
68926             var pl = qualifiedName.split(':');
68927             var attrs = node.attributes = new NamedNodeMap();
68928             node.childNodes = new NodeList();
68929             node.ownerDocument = this;
68930             node.nodeName = qualifiedName;
68931             node.tagName = qualifiedName;
68932             node.namespaceURI = namespaceURI;
68933
68934             if (pl.length == 2) {
68935               node.prefix = pl[0];
68936               node.localName = pl[1];
68937             } else {
68938               //el.prefix = null;
68939               node.localName = qualifiedName;
68940             }
68941
68942             attrs._ownerElement = node;
68943             return node;
68944           },
68945           // Introduced in DOM Level 2:
68946           createAttributeNS: function createAttributeNS(namespaceURI, qualifiedName) {
68947             var node = new Attr();
68948             var pl = qualifiedName.split(':');
68949             node.ownerDocument = this;
68950             node.nodeName = qualifiedName;
68951             node.name = qualifiedName;
68952             node.namespaceURI = namespaceURI;
68953             node.specified = true;
68954
68955             if (pl.length == 2) {
68956               node.prefix = pl[0];
68957               node.localName = pl[1];
68958             } else {
68959               //el.prefix = null;
68960               node.localName = qualifiedName;
68961             }
68962
68963             return node;
68964           }
68965         };
68966
68967         _extends(Document, Node);
68968
68969         function Element() {
68970           this._nsMap = {};
68971         }
68972         Element.prototype = {
68973           nodeType: ELEMENT_NODE,
68974           hasAttribute: function hasAttribute(name) {
68975             return this.getAttributeNode(name) != null;
68976           },
68977           getAttribute: function getAttribute(name) {
68978             var attr = this.getAttributeNode(name);
68979             return attr && attr.value || '';
68980           },
68981           getAttributeNode: function getAttributeNode(name) {
68982             return this.attributes.getNamedItem(name);
68983           },
68984           setAttribute: function setAttribute(name, value) {
68985             var attr = this.ownerDocument.createAttribute(name);
68986             attr.value = attr.nodeValue = "" + value;
68987             this.setAttributeNode(attr);
68988           },
68989           removeAttribute: function removeAttribute(name) {
68990             var attr = this.getAttributeNode(name);
68991             attr && this.removeAttributeNode(attr);
68992           },
68993           //four real opeartion method
68994           appendChild: function appendChild(newChild) {
68995             if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
68996               return this.insertBefore(newChild, null);
68997             } else {
68998               return _appendSingleChild(this, newChild);
68999             }
69000           },
69001           setAttributeNode: function setAttributeNode(newAttr) {
69002             return this.attributes.setNamedItem(newAttr);
69003           },
69004           setAttributeNodeNS: function setAttributeNodeNS(newAttr) {
69005             return this.attributes.setNamedItemNS(newAttr);
69006           },
69007           removeAttributeNode: function removeAttributeNode(oldAttr) {
69008             //console.log(this == oldAttr.ownerElement)
69009             return this.attributes.removeNamedItem(oldAttr.nodeName);
69010           },
69011           //get real attribute name,and remove it by removeAttributeNode
69012           removeAttributeNS: function removeAttributeNS(namespaceURI, localName) {
69013             var old = this.getAttributeNodeNS(namespaceURI, localName);
69014             old && this.removeAttributeNode(old);
69015           },
69016           hasAttributeNS: function hasAttributeNS(namespaceURI, localName) {
69017             return this.getAttributeNodeNS(namespaceURI, localName) != null;
69018           },
69019           getAttributeNS: function getAttributeNS(namespaceURI, localName) {
69020             var attr = this.getAttributeNodeNS(namespaceURI, localName);
69021             return attr && attr.value || '';
69022           },
69023           setAttributeNS: function setAttributeNS(namespaceURI, qualifiedName, value) {
69024             var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
69025             attr.value = attr.nodeValue = "" + value;
69026             this.setAttributeNode(attr);
69027           },
69028           getAttributeNodeNS: function getAttributeNodeNS(namespaceURI, localName) {
69029             return this.attributes.getNamedItemNS(namespaceURI, localName);
69030           },
69031           getElementsByTagName: function getElementsByTagName(tagName) {
69032             return new LiveNodeList(this, function (base) {
69033               var ls = [];
69034
69035               _visitNode(base, function (node) {
69036                 if (node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)) {
69037                   ls.push(node);
69038                 }
69039               });
69040
69041               return ls;
69042             });
69043           },
69044           getElementsByTagNameNS: function getElementsByTagNameNS(namespaceURI, localName) {
69045             return new LiveNodeList(this, function (base) {
69046               var ls = [];
69047
69048               _visitNode(base, function (node) {
69049                 if (node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)) {
69050                   ls.push(node);
69051                 }
69052               });
69053
69054               return ls;
69055             });
69056           }
69057         };
69058         Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
69059         Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
69060
69061         _extends(Element, Node);
69062
69063         function Attr() {}
69064         Attr.prototype.nodeType = ATTRIBUTE_NODE;
69065
69066         _extends(Attr, Node);
69067
69068         function CharacterData() {}
69069         CharacterData.prototype = {
69070           data: '',
69071           substringData: function substringData(offset, count) {
69072             return this.data.substring(offset, offset + count);
69073           },
69074           appendData: function appendData(text) {
69075             text = this.data + text;
69076             this.nodeValue = this.data = text;
69077             this.length = text.length;
69078           },
69079           insertData: function insertData(offset, text) {
69080             this.replaceData(offset, 0, text);
69081           },
69082           appendChild: function appendChild(newChild) {
69083             throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR]);
69084           },
69085           deleteData: function deleteData(offset, count) {
69086             this.replaceData(offset, count, "");
69087           },
69088           replaceData: function replaceData(offset, count, text) {
69089             var start = this.data.substring(0, offset);
69090             var end = this.data.substring(offset + count);
69091             text = start + text + end;
69092             this.nodeValue = this.data = text;
69093             this.length = text.length;
69094           }
69095         };
69096
69097         _extends(CharacterData, Node);
69098
69099         function Text() {}
69100         Text.prototype = {
69101           nodeName: "#text",
69102           nodeType: TEXT_NODE,
69103           splitText: function splitText(offset) {
69104             var text = this.data;
69105             var newText = text.substring(offset);
69106             text = text.substring(0, offset);
69107             this.data = this.nodeValue = text;
69108             this.length = text.length;
69109             var newNode = this.ownerDocument.createTextNode(newText);
69110
69111             if (this.parentNode) {
69112               this.parentNode.insertBefore(newNode, this.nextSibling);
69113             }
69114
69115             return newNode;
69116           }
69117         };
69118
69119         _extends(Text, CharacterData);
69120
69121         function Comment() {}
69122         Comment.prototype = {
69123           nodeName: "#comment",
69124           nodeType: COMMENT_NODE
69125         };
69126
69127         _extends(Comment, CharacterData);
69128
69129         function CDATASection() {}
69130         CDATASection.prototype = {
69131           nodeName: "#cdata-section",
69132           nodeType: CDATA_SECTION_NODE
69133         };
69134
69135         _extends(CDATASection, CharacterData);
69136
69137         function DocumentType() {}
69138         DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
69139
69140         _extends(DocumentType, Node);
69141
69142         function Notation() {}
69143         Notation.prototype.nodeType = NOTATION_NODE;
69144
69145         _extends(Notation, Node);
69146
69147         function Entity() {}
69148         Entity.prototype.nodeType = ENTITY_NODE;
69149
69150         _extends(Entity, Node);
69151
69152         function EntityReference() {}
69153         EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
69154
69155         _extends(EntityReference, Node);
69156
69157         function DocumentFragment() {}
69158         DocumentFragment.prototype.nodeName = "#document-fragment";
69159         DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
69160
69161         _extends(DocumentFragment, Node);
69162
69163         function ProcessingInstruction() {}
69164
69165         ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
69166
69167         _extends(ProcessingInstruction, Node);
69168
69169         function XMLSerializer$1() {}
69170
69171         XMLSerializer$1.prototype.serializeToString = function (node, isHtml, nodeFilter) {
69172           return nodeSerializeToString.call(node, isHtml, nodeFilter);
69173         };
69174
69175         Node.prototype.toString = nodeSerializeToString;
69176
69177         function nodeSerializeToString(isHtml, nodeFilter) {
69178           var buf = [];
69179           var refNode = this.nodeType == 9 ? this.documentElement : this;
69180           var prefix = refNode.prefix;
69181           var uri = refNode.namespaceURI;
69182
69183           if (uri && prefix == null) {
69184             //console.log(prefix)
69185             var prefix = refNode.lookupPrefix(uri);
69186
69187             if (prefix == null) {
69188               //isHTML = true;
69189               var visibleNamespaces = [{
69190                 namespace: uri,
69191                 prefix: null
69192               } //{namespace:uri,prefix:''}
69193               ];
69194             }
69195           }
69196
69197           serializeToString(this, buf, isHtml, nodeFilter, visibleNamespaces); //console.log('###',this.nodeType,uri,prefix,buf.join(''))
69198
69199           return buf.join('');
69200         }
69201
69202         function needNamespaceDefine(node, isHTML, visibleNamespaces) {
69203           var prefix = node.prefix || '';
69204           var uri = node.namespaceURI;
69205
69206           if (!prefix && !uri) {
69207             return false;
69208           }
69209
69210           if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" || uri == 'http://www.w3.org/2000/xmlns/') {
69211             return false;
69212           }
69213
69214           var i = visibleNamespaces.length; //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
69215
69216           while (i--) {
69217             var ns = visibleNamespaces[i]; // get namespace prefix
69218             //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
69219
69220             if (ns.prefix == prefix) {
69221               return ns.namespace != uri;
69222             }
69223           } //console.log(isHTML,uri,prefix=='')
69224           //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
69225           //    return false;
69226           //}
69227           //node.flag = '11111'
69228           //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
69229
69230
69231           return true;
69232         }
69233
69234         function serializeToString(node, buf, isHTML, nodeFilter, visibleNamespaces) {
69235           if (nodeFilter) {
69236             node = nodeFilter(node);
69237
69238             if (node) {
69239               if (typeof node == 'string') {
69240                 buf.push(node);
69241                 return;
69242               }
69243             } else {
69244               return;
69245             } //buf.sort.apply(attrs, attributeSorter);
69246
69247           }
69248
69249           switch (node.nodeType) {
69250             case ELEMENT_NODE:
69251               if (!visibleNamespaces) visibleNamespaces = [];
69252               var startVisibleNamespaces = visibleNamespaces.length;
69253               var attrs = node.attributes;
69254               var len = attrs.length;
69255               var child = node.firstChild;
69256               var nodeName = node.tagName;
69257               isHTML = htmlns === node.namespaceURI || isHTML;
69258               buf.push('<', nodeName);
69259
69260               for (var i = 0; i < len; i++) {
69261                 // add namespaces for attributes
69262                 var attr = attrs.item(i);
69263
69264                 if (attr.prefix == 'xmlns') {
69265                   visibleNamespaces.push({
69266                     prefix: attr.localName,
69267                     namespace: attr.value
69268                   });
69269                 } else if (attr.nodeName == 'xmlns') {
69270                   visibleNamespaces.push({
69271                     prefix: '',
69272                     namespace: attr.value
69273                   });
69274                 }
69275               }
69276
69277               for (var i = 0; i < len; i++) {
69278                 var attr = attrs.item(i);
69279
69280                 if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) {
69281                   var prefix = attr.prefix || '';
69282                   var uri = attr.namespaceURI;
69283                   var ns = prefix ? ' xmlns:' + prefix : " xmlns";
69284                   buf.push(ns, '="', uri, '"');
69285                   visibleNamespaces.push({
69286                     prefix: prefix,
69287                     namespace: uri
69288                   });
69289                 }
69290
69291                 serializeToString(attr, buf, isHTML, nodeFilter, visibleNamespaces);
69292               } // add namespace for current node               
69293
69294
69295               if (needNamespaceDefine(node, isHTML, visibleNamespaces)) {
69296                 var prefix = node.prefix || '';
69297                 var uri = node.namespaceURI;
69298                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
69299                 buf.push(ns, '="', uri, '"');
69300                 visibleNamespaces.push({
69301                   prefix: prefix,
69302                   namespace: uri
69303                 });
69304               }
69305
69306               if (child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)) {
69307                 buf.push('>'); //if is cdata child node
69308
69309                 if (isHTML && /^script$/i.test(nodeName)) {
69310                   while (child) {
69311                     if (child.data) {
69312                       buf.push(child.data);
69313                     } else {
69314                       serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69315                     }
69316
69317                     child = child.nextSibling;
69318                   }
69319                 } else {
69320                   while (child) {
69321                     serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69322                     child = child.nextSibling;
69323                   }
69324                 }
69325
69326                 buf.push('</', nodeName, '>');
69327               } else {
69328                 buf.push('/>');
69329               } // remove added visible namespaces
69330               //visibleNamespaces.length = startVisibleNamespaces;
69331
69332
69333               return;
69334
69335             case DOCUMENT_NODE:
69336             case DOCUMENT_FRAGMENT_NODE:
69337               var child = node.firstChild;
69338
69339               while (child) {
69340                 serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69341                 child = child.nextSibling;
69342               }
69343
69344               return;
69345
69346             case ATTRIBUTE_NODE:
69347               return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g, _xmlEncoder), '"');
69348
69349             case TEXT_NODE:
69350               return buf.push(node.data.replace(/[<&]/g, _xmlEncoder));
69351
69352             case CDATA_SECTION_NODE:
69353               return buf.push('<![CDATA[', node.data, ']]>');
69354
69355             case COMMENT_NODE:
69356               return buf.push("<!--", node.data, "-->");
69357
69358             case DOCUMENT_TYPE_NODE:
69359               var pubid = node.publicId;
69360               var sysid = node.systemId;
69361               buf.push('<!DOCTYPE ', node.name);
69362
69363               if (pubid) {
69364                 buf.push(' PUBLIC "', pubid);
69365
69366                 if (sysid && sysid != '.') {
69367                   buf.push('" "', sysid);
69368                 }
69369
69370                 buf.push('">');
69371               } else if (sysid && sysid != '.') {
69372                 buf.push(' SYSTEM "', sysid, '">');
69373               } else {
69374                 var sub = node.internalSubset;
69375
69376                 if (sub) {
69377                   buf.push(" [", sub, "]");
69378                 }
69379
69380                 buf.push(">");
69381               }
69382
69383               return;
69384
69385             case PROCESSING_INSTRUCTION_NODE:
69386               return buf.push("<?", node.target, " ", node.data, "?>");
69387
69388             case ENTITY_REFERENCE_NODE:
69389               return buf.push('&', node.nodeName, ';');
69390             //case ENTITY_NODE:
69391             //case NOTATION_NODE:
69392
69393             default:
69394               buf.push('??', node.nodeName);
69395           }
69396         }
69397
69398         function _importNode(doc, node, deep) {
69399           var node2;
69400
69401           switch (node.nodeType) {
69402             case ELEMENT_NODE:
69403               node2 = node.cloneNode(false);
69404               node2.ownerDocument = doc;
69405             //var attrs = node2.attributes;
69406             //var len = attrs.length;
69407             //for(var i=0;i<len;i++){
69408             //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
69409             //}
69410
69411             case DOCUMENT_FRAGMENT_NODE:
69412               break;
69413
69414             case ATTRIBUTE_NODE:
69415               deep = true;
69416               break;
69417             //case ENTITY_REFERENCE_NODE:
69418             //case PROCESSING_INSTRUCTION_NODE:
69419             ////case TEXT_NODE:
69420             //case CDATA_SECTION_NODE:
69421             //case COMMENT_NODE:
69422             //  deep = false;
69423             //  break;
69424             //case DOCUMENT_NODE:
69425             //case DOCUMENT_TYPE_NODE:
69426             //cannot be imported.
69427             //case ENTITY_NODE:
69428             //case NOTATION_NODE:
69429             //can not hit in level3
69430             //default:throw e;
69431           }
69432
69433           if (!node2) {
69434             node2 = node.cloneNode(false); //false
69435           }
69436
69437           node2.ownerDocument = doc;
69438           node2.parentNode = null;
69439
69440           if (deep) {
69441             var child = node.firstChild;
69442
69443             while (child) {
69444               node2.appendChild(_importNode(doc, child, deep));
69445               child = child.nextSibling;
69446             }
69447           }
69448
69449           return node2;
69450         } //
69451         //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
69452         //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
69453
69454
69455         function _cloneNode(doc, node, deep) {
69456           var node2 = new node.constructor();
69457
69458           for (var n in node) {
69459             var v = node[n];
69460
69461             if (_typeof(v) != 'object') {
69462               if (v != node2[n]) {
69463                 node2[n] = v;
69464               }
69465             }
69466           }
69467
69468           if (node.childNodes) {
69469             node2.childNodes = new NodeList();
69470           }
69471
69472           node2.ownerDocument = doc;
69473
69474           switch (node2.nodeType) {
69475             case ELEMENT_NODE:
69476               var attrs = node.attributes;
69477               var attrs2 = node2.attributes = new NamedNodeMap();
69478               var len = attrs.length;
69479               attrs2._ownerElement = node2;
69480
69481               for (var i = 0; i < len; i++) {
69482                 node2.setAttributeNode(_cloneNode(doc, attrs.item(i), true));
69483               }
69484
69485               break;
69486
69487             case ATTRIBUTE_NODE:
69488               deep = true;
69489           }
69490
69491           if (deep) {
69492             var child = node.firstChild;
69493
69494             while (child) {
69495               node2.appendChild(_cloneNode(doc, child, deep));
69496               child = child.nextSibling;
69497             }
69498           }
69499
69500           return node2;
69501         }
69502
69503         function __set__(object, key, value) {
69504           object[key] = value;
69505         } //do dynamic
69506
69507
69508         try {
69509           if (Object.defineProperty) {
69510             var getTextContent = function getTextContent(node) {
69511               switch (node.nodeType) {
69512                 case ELEMENT_NODE:
69513                 case DOCUMENT_FRAGMENT_NODE:
69514                   var buf = [];
69515                   node = node.firstChild;
69516
69517                   while (node) {
69518                     if (node.nodeType !== 7 && node.nodeType !== 8) {
69519                       buf.push(getTextContent(node));
69520                     }
69521
69522                     node = node.nextSibling;
69523                   }
69524
69525                   return buf.join('');
69526
69527                 default:
69528                   return node.nodeValue;
69529               }
69530             };
69531
69532             Object.defineProperty(LiveNodeList.prototype, 'length', {
69533               get: function get() {
69534                 _updateLiveList(this);
69535
69536                 return this.$$length;
69537               }
69538             });
69539             Object.defineProperty(Node.prototype, 'textContent', {
69540               get: function get() {
69541                 return getTextContent(this);
69542               },
69543               set: function set(data) {
69544                 switch (this.nodeType) {
69545                   case ELEMENT_NODE:
69546                   case DOCUMENT_FRAGMENT_NODE:
69547                     while (this.firstChild) {
69548                       this.removeChild(this.firstChild);
69549                     }
69550
69551                     if (data || String(data)) {
69552                       this.appendChild(this.ownerDocument.createTextNode(data));
69553                     }
69554
69555                     break;
69556
69557                   default:
69558                     //TODO:
69559                     this.data = data;
69560                     this.value = data;
69561                     this.nodeValue = data;
69562                 }
69563               }
69564             });
69565
69566             __set__ = function __set__(object, key, value) {
69567               //console.log(value)
69568               object['$$' + key] = value;
69569             };
69570           }
69571         } catch (e) {//ie8
69572         } //if(typeof require == 'function'){
69573
69574
69575         var DOMImplementation_1 = DOMImplementation;
69576         var XMLSerializer_1 = XMLSerializer$1; //}
69577
69578         var dom = {
69579           DOMImplementation: DOMImplementation_1,
69580           XMLSerializer: XMLSerializer_1
69581         };
69582
69583         var domParser = createCommonjsModule(function (module, exports) {
69584           function DOMParser(options) {
69585             this.options = options || {
69586               locator: {}
69587             };
69588           }
69589
69590           DOMParser.prototype.parseFromString = function (source, mimeType) {
69591             var options = this.options;
69592             var sax = new XMLReader();
69593             var domBuilder = options.domBuilder || new DOMHandler(); //contentHandler and LexicalHandler
69594
69595             var errorHandler = options.errorHandler;
69596             var locator = options.locator;
69597             var defaultNSMap = options.xmlns || {};
69598             var entityMap = {
69599               'lt': '<',
69600               'gt': '>',
69601               'amp': '&',
69602               'quot': '"',
69603               'apos': "'"
69604             };
69605
69606             if (locator) {
69607               domBuilder.setDocumentLocator(locator);
69608             }
69609
69610             sax.errorHandler = buildErrorHandler(errorHandler, domBuilder, locator);
69611             sax.domBuilder = options.domBuilder || domBuilder;
69612
69613             if (/\/x?html?$/.test(mimeType)) {
69614               entityMap.nbsp = '\xa0';
69615               entityMap.copy = '\xa9';
69616               defaultNSMap[''] = 'http://www.w3.org/1999/xhtml';
69617             }
69618
69619             defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
69620
69621             if (source) {
69622               sax.parse(source, defaultNSMap, entityMap);
69623             } else {
69624               sax.errorHandler.error("invalid doc source");
69625             }
69626
69627             return domBuilder.doc;
69628           };
69629
69630           function buildErrorHandler(errorImpl, domBuilder, locator) {
69631             if (!errorImpl) {
69632               if (domBuilder instanceof DOMHandler) {
69633                 return domBuilder;
69634               }
69635
69636               errorImpl = domBuilder;
69637             }
69638
69639             var errorHandler = {};
69640             var isCallback = errorImpl instanceof Function;
69641             locator = locator || {};
69642
69643             function build(key) {
69644               var fn = errorImpl[key];
69645
69646               if (!fn && isCallback) {
69647                 fn = errorImpl.length == 2 ? function (msg) {
69648                   errorImpl(key, msg);
69649                 } : errorImpl;
69650               }
69651
69652               errorHandler[key] = fn && function (msg) {
69653                 fn('[xmldom ' + key + ']\t' + msg + _locator(locator));
69654               } || function () {};
69655             }
69656
69657             build('warning');
69658             build('error');
69659             build('fatalError');
69660             return errorHandler;
69661           } //console.log('#\n\n\n\n\n\n\n####')
69662
69663           /**
69664            * +ContentHandler+ErrorHandler
69665            * +LexicalHandler+EntityResolver2
69666            * -DeclHandler-DTDHandler 
69667            * 
69668            * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
69669            * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
69670            * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
69671            */
69672
69673
69674           function DOMHandler() {
69675             this.cdata = false;
69676           }
69677
69678           function position(locator, node) {
69679             node.lineNumber = locator.lineNumber;
69680             node.columnNumber = locator.columnNumber;
69681           }
69682           /**
69683            * @see org.xml.sax.ContentHandler#startDocument
69684            * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
69685            */
69686
69687
69688           DOMHandler.prototype = {
69689             startDocument: function startDocument() {
69690               this.doc = new DOMImplementation().createDocument(null, null, null);
69691
69692               if (this.locator) {
69693                 this.doc.documentURI = this.locator.systemId;
69694               }
69695             },
69696             startElement: function startElement(namespaceURI, localName, qName, attrs) {
69697               var doc = this.doc;
69698               var el = doc.createElementNS(namespaceURI, qName || localName);
69699               var len = attrs.length;
69700               appendElement(this, el);
69701               this.currentElement = el;
69702               this.locator && position(this.locator, el);
69703
69704               for (var i = 0; i < len; i++) {
69705                 var namespaceURI = attrs.getURI(i);
69706                 var value = attrs.getValue(i);
69707                 var qName = attrs.getQName(i);
69708                 var attr = doc.createAttributeNS(namespaceURI, qName);
69709                 this.locator && position(attrs.getLocator(i), attr);
69710                 attr.value = attr.nodeValue = value;
69711                 el.setAttributeNode(attr);
69712               }
69713             },
69714             endElement: function endElement(namespaceURI, localName, qName) {
69715               var current = this.currentElement;
69716               var tagName = current.tagName;
69717               this.currentElement = current.parentNode;
69718             },
69719             startPrefixMapping: function startPrefixMapping(prefix, uri) {},
69720             endPrefixMapping: function endPrefixMapping(prefix) {},
69721             processingInstruction: function processingInstruction(target, data) {
69722               var ins = this.doc.createProcessingInstruction(target, data);
69723               this.locator && position(this.locator, ins);
69724               appendElement(this, ins);
69725             },
69726             ignorableWhitespace: function ignorableWhitespace(ch, start, length) {},
69727             characters: function characters(chars, start, length) {
69728               chars = _toString.apply(this, arguments); //console.log(chars)
69729
69730               if (chars) {
69731                 if (this.cdata) {
69732                   var charNode = this.doc.createCDATASection(chars);
69733                 } else {
69734                   var charNode = this.doc.createTextNode(chars);
69735                 }
69736
69737                 if (this.currentElement) {
69738                   this.currentElement.appendChild(charNode);
69739                 } else if (/^\s*$/.test(chars)) {
69740                   this.doc.appendChild(charNode); //process xml
69741                 }
69742
69743                 this.locator && position(this.locator, charNode);
69744               }
69745             },
69746             skippedEntity: function skippedEntity(name) {},
69747             endDocument: function endDocument() {
69748               this.doc.normalize();
69749             },
69750             setDocumentLocator: function setDocumentLocator(locator) {
69751               if (this.locator = locator) {
69752                 // && !('lineNumber' in locator)){
69753                 locator.lineNumber = 0;
69754               }
69755             },
69756             //LexicalHandler
69757             comment: function comment(chars, start, length) {
69758               chars = _toString.apply(this, arguments);
69759               var comm = this.doc.createComment(chars);
69760               this.locator && position(this.locator, comm);
69761               appendElement(this, comm);
69762             },
69763             startCDATA: function startCDATA() {
69764               //used in characters() methods
69765               this.cdata = true;
69766             },
69767             endCDATA: function endCDATA() {
69768               this.cdata = false;
69769             },
69770             startDTD: function startDTD(name, publicId, systemId) {
69771               var impl = this.doc.implementation;
69772
69773               if (impl && impl.createDocumentType) {
69774                 var dt = impl.createDocumentType(name, publicId, systemId);
69775                 this.locator && position(this.locator, dt);
69776                 appendElement(this, dt);
69777               }
69778             },
69779
69780             /**
69781              * @see org.xml.sax.ErrorHandler
69782              * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
69783              */
69784             warning: function warning(error) {
69785               console.warn('[xmldom warning]\t' + error, _locator(this.locator));
69786             },
69787             error: function error(_error) {
69788               console.error('[xmldom error]\t' + _error, _locator(this.locator));
69789             },
69790             fatalError: function fatalError(error) {
69791               console.error('[xmldom fatalError]\t' + error, _locator(this.locator));
69792               throw error;
69793             }
69794           };
69795
69796           function _locator(l) {
69797             if (l) {
69798               return '\n@' + (l.systemId || '') + '#[line:' + l.lineNumber + ',col:' + l.columnNumber + ']';
69799             }
69800           }
69801
69802           function _toString(chars, start, length) {
69803             if (typeof chars == 'string') {
69804               return chars.substr(start, length);
69805             } else {
69806               //java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
69807               if (chars.length >= start + length || start) {
69808                 return new java.lang.String(chars, start, length) + '';
69809               }
69810
69811               return chars;
69812             }
69813           }
69814           /*
69815            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
69816            * used method of org.xml.sax.ext.LexicalHandler:
69817            *  #comment(chars, start, length)
69818            *  #startCDATA()
69819            *  #endCDATA()
69820            *  #startDTD(name, publicId, systemId)
69821            *
69822            *
69823            * IGNORED method of org.xml.sax.ext.LexicalHandler:
69824            *  #endDTD()
69825            *  #startEntity(name)
69826            *  #endEntity(name)
69827            *
69828            *
69829            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
69830            * IGNORED method of org.xml.sax.ext.DeclHandler
69831            *    #attributeDecl(eName, aName, type, mode, value)
69832            *  #elementDecl(name, model)
69833            *  #externalEntityDecl(name, publicId, systemId)
69834            *  #internalEntityDecl(name, value)
69835            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
69836            * IGNORED method of org.xml.sax.EntityResolver2
69837            *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
69838            *  #resolveEntity(publicId, systemId)
69839            *  #getExternalSubset(name, baseURI)
69840            * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
69841            * IGNORED method of org.xml.sax.DTDHandler
69842            *  #notationDecl(name, publicId, systemId) {};
69843            *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
69844            */
69845
69846
69847           "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g, function (key) {
69848             DOMHandler.prototype[key] = function () {
69849               return null;
69850             };
69851           });
69852           /* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
69853
69854           function appendElement(hander, node) {
69855             if (!hander.currentElement) {
69856               hander.doc.appendChild(node);
69857             } else {
69858               hander.currentElement.appendChild(node);
69859             }
69860           } //appendChild and setAttributeNS are preformance key
69861           //if(typeof require == 'function'){
69862
69863
69864           var XMLReader = sax.XMLReader;
69865           var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
69866           exports.XMLSerializer = dom.XMLSerializer;
69867           exports.DOMParser = DOMParser; //}
69868         });
69869
69870         var togeojson = createCommonjsModule(function (module, exports) {
69871           var toGeoJSON = function () {
69872
69873             var removeSpace = /\s*/g,
69874                 trimSpace = /^\s*|\s*$/g,
69875                 splitSpace = /\s+/; // generate a short, numeric hash of a string
69876
69877             function okhash(x) {
69878               if (!x || !x.length) return 0;
69879
69880               for (var i = 0, h = 0; i < x.length; i++) {
69881                 h = (h << 5) - h + x.charCodeAt(i) | 0;
69882               }
69883
69884               return h;
69885             } // all Y children of X
69886
69887
69888             function get(x, y) {
69889               return x.getElementsByTagName(y);
69890             }
69891
69892             function attr(x, y) {
69893               return x.getAttribute(y);
69894             }
69895
69896             function attrf(x, y) {
69897               return parseFloat(attr(x, y));
69898             } // one Y child of X, if any, otherwise null
69899
69900
69901             function get1(x, y) {
69902               var n = get(x, y);
69903               return n.length ? n[0] : null;
69904             } // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
69905
69906
69907             function norm(el) {
69908               if (el.normalize) {
69909                 el.normalize();
69910               }
69911
69912               return el;
69913             } // cast array x into numbers
69914
69915
69916             function numarray(x) {
69917               for (var j = 0, o = []; j < x.length; j++) {
69918                 o[j] = parseFloat(x[j]);
69919               }
69920
69921               return o;
69922             } // get the content of a text node, if any
69923
69924
69925             function nodeVal(x) {
69926               if (x) {
69927                 norm(x);
69928               }
69929
69930               return x && x.textContent || '';
69931             } // get the contents of multiple text nodes, if present
69932
69933
69934             function getMulti(x, ys) {
69935               var o = {},
69936                   n,
69937                   k;
69938
69939               for (k = 0; k < ys.length; k++) {
69940                 n = get1(x, ys[k]);
69941                 if (n) o[ys[k]] = nodeVal(n);
69942               }
69943
69944               return o;
69945             } // add properties of Y to X, overwriting if present in both
69946
69947
69948             function extend(x, y) {
69949               for (var k in y) {
69950                 x[k] = y[k];
69951               }
69952             } // get one coordinate from a coordinate array, if any
69953
69954
69955             function coord1(v) {
69956               return numarray(v.replace(removeSpace, '').split(','));
69957             } // get all coordinates from a coordinate array as [[],[]]
69958
69959
69960             function coord(v) {
69961               var coords = v.replace(trimSpace, '').split(splitSpace),
69962                   o = [];
69963
69964               for (var i = 0; i < coords.length; i++) {
69965                 o.push(coord1(coords[i]));
69966               }
69967
69968               return o;
69969             }
69970
69971             function coordPair(x) {
69972               var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
69973                   ele = get1(x, 'ele'),
69974                   // handle namespaced attribute in browser
69975               heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
69976                   time = get1(x, 'time'),
69977                   e;
69978
69979               if (ele) {
69980                 e = parseFloat(nodeVal(ele));
69981
69982                 if (!isNaN(e)) {
69983                   ll.push(e);
69984                 }
69985               }
69986
69987               return {
69988                 coordinates: ll,
69989                 time: time ? nodeVal(time) : null,
69990                 heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
69991               };
69992             } // create a new feature collection parent object
69993
69994
69995             function fc() {
69996               return {
69997                 type: 'FeatureCollection',
69998                 features: []
69999               };
70000             }
70001
70002             var serializer;
70003
70004             if (typeof XMLSerializer !== 'undefined') {
70005               /* istanbul ignore next */
70006               serializer = new XMLSerializer(); // only require xmldom in a node environment
70007             } else if ( (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && !process.browser) {
70008               serializer = new domParser.XMLSerializer();
70009             }
70010
70011             function xml2str(str) {
70012               // IE9 will create a new XMLSerializer but it'll crash immediately.
70013               // This line is ignored because we don't run coverage tests in IE9
70014
70015               /* istanbul ignore next */
70016               if (str.xml !== undefined) return str.xml;
70017               return serializer.serializeToString(str);
70018             }
70019
70020             var t = {
70021               kml: function kml(doc) {
70022                 var gj = fc(),
70023                     // styleindex keeps track of hashed styles in order to match features
70024                 styleIndex = {},
70025                     styleByHash = {},
70026                     // stylemapindex keeps track of style maps to expose in properties
70027                 styleMapIndex = {},
70028                     // atomic geospatial types supported by KML - MultiGeometry is
70029                 // handled separately
70030                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
70031                     // all root placemarks in the file
70032                 placemarks = get(doc, 'Placemark'),
70033                     styles = get(doc, 'Style'),
70034                     styleMaps = get(doc, 'StyleMap');
70035
70036                 for (var k = 0; k < styles.length; k++) {
70037                   var hash = okhash(xml2str(styles[k])).toString(16);
70038                   styleIndex['#' + attr(styles[k], 'id')] = hash;
70039                   styleByHash[hash] = styles[k];
70040                 }
70041
70042                 for (var l = 0; l < styleMaps.length; l++) {
70043                   styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
70044                   var pairs = get(styleMaps[l], 'Pair');
70045                   var pairsMap = {};
70046
70047                   for (var m = 0; m < pairs.length; m++) {
70048                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
70049                   }
70050
70051                   styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
70052                 }
70053
70054                 for (var j = 0; j < placemarks.length; j++) {
70055                   gj.features = gj.features.concat(getPlacemark(placemarks[j]));
70056                 }
70057
70058                 function kmlColor(v) {
70059                   var color, opacity;
70060                   v = v || '';
70061
70062                   if (v.substr(0, 1) === '#') {
70063                     v = v.substr(1);
70064                   }
70065
70066                   if (v.length === 6 || v.length === 3) {
70067                     color = v;
70068                   }
70069
70070                   if (v.length === 8) {
70071                     opacity = parseInt(v.substr(0, 2), 16) / 255;
70072                     color = '#' + v.substr(6, 2) + v.substr(4, 2) + v.substr(2, 2);
70073                   }
70074
70075                   return [color, isNaN(opacity) ? undefined : opacity];
70076                 }
70077
70078                 function gxCoord(v) {
70079                   return numarray(v.split(' '));
70080                 }
70081
70082                 function gxCoords(root) {
70083                   var elems = get(root, 'coord'),
70084                       coords = [],
70085                       times = [];
70086                   if (elems.length === 0) elems = get(root, 'gx:coord');
70087
70088                   for (var i = 0; i < elems.length; i++) {
70089                     coords.push(gxCoord(nodeVal(elems[i])));
70090                   }
70091
70092                   var timeElems = get(root, 'when');
70093
70094                   for (var j = 0; j < timeElems.length; j++) {
70095                     times.push(nodeVal(timeElems[j]));
70096                   }
70097
70098                   return {
70099                     coords: coords,
70100                     times: times
70101                   };
70102                 }
70103
70104                 function getGeometry(root) {
70105                   var geomNode,
70106                       geomNodes,
70107                       i,
70108                       j,
70109                       k,
70110                       geoms = [],
70111                       coordTimes = [];
70112
70113                   if (get1(root, 'MultiGeometry')) {
70114                     return getGeometry(get1(root, 'MultiGeometry'));
70115                   }
70116
70117                   if (get1(root, 'MultiTrack')) {
70118                     return getGeometry(get1(root, 'MultiTrack'));
70119                   }
70120
70121                   if (get1(root, 'gx:MultiTrack')) {
70122                     return getGeometry(get1(root, 'gx:MultiTrack'));
70123                   }
70124
70125                   for (i = 0; i < geotypes.length; i++) {
70126                     geomNodes = get(root, geotypes[i]);
70127
70128                     if (geomNodes) {
70129                       for (j = 0; j < geomNodes.length; j++) {
70130                         geomNode = geomNodes[j];
70131
70132                         if (geotypes[i] === 'Point') {
70133                           geoms.push({
70134                             type: 'Point',
70135                             coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
70136                           });
70137                         } else if (geotypes[i] === 'LineString') {
70138                           geoms.push({
70139                             type: 'LineString',
70140                             coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
70141                           });
70142                         } else if (geotypes[i] === 'Polygon') {
70143                           var rings = get(geomNode, 'LinearRing'),
70144                               coords = [];
70145
70146                           for (k = 0; k < rings.length; k++) {
70147                             coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
70148                           }
70149
70150                           geoms.push({
70151                             type: 'Polygon',
70152                             coordinates: coords
70153                           });
70154                         } else if (geotypes[i] === 'Track' || geotypes[i] === 'gx:Track') {
70155                           var track = gxCoords(geomNode);
70156                           geoms.push({
70157                             type: 'LineString',
70158                             coordinates: track.coords
70159                           });
70160                           if (track.times.length) coordTimes.push(track.times);
70161                         }
70162                       }
70163                     }
70164                   }
70165
70166                   return {
70167                     geoms: geoms,
70168                     coordTimes: coordTimes
70169                   };
70170                 }
70171
70172                 function getPlacemark(root) {
70173                   var geomsAndTimes = getGeometry(root),
70174                       i,
70175                       properties = {},
70176                       name = nodeVal(get1(root, 'name')),
70177                       address = nodeVal(get1(root, 'address')),
70178                       styleUrl = nodeVal(get1(root, 'styleUrl')),
70179                       description = nodeVal(get1(root, 'description')),
70180                       timeSpan = get1(root, 'TimeSpan'),
70181                       timeStamp = get1(root, 'TimeStamp'),
70182                       extendedData = get1(root, 'ExtendedData'),
70183                       lineStyle = get1(root, 'LineStyle'),
70184                       polyStyle = get1(root, 'PolyStyle'),
70185                       visibility = get1(root, 'visibility');
70186                   if (!geomsAndTimes.geoms.length) return [];
70187                   if (name) properties.name = name;
70188                   if (address) properties.address = address;
70189
70190                   if (styleUrl) {
70191                     if (styleUrl[0] !== '#') {
70192                       styleUrl = '#' + styleUrl;
70193                     }
70194
70195                     properties.styleUrl = styleUrl;
70196
70197                     if (styleIndex[styleUrl]) {
70198                       properties.styleHash = styleIndex[styleUrl];
70199                     }
70200
70201                     if (styleMapIndex[styleUrl]) {
70202                       properties.styleMapHash = styleMapIndex[styleUrl];
70203                       properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
70204                     } // Try to populate the lineStyle or polyStyle since we got the style hash
70205
70206
70207                     var style = styleByHash[properties.styleHash];
70208
70209                     if (style) {
70210                       if (!lineStyle) lineStyle = get1(style, 'LineStyle');
70211                       if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
70212                     }
70213                   }
70214
70215                   if (description) properties.description = description;
70216
70217                   if (timeSpan) {
70218                     var begin = nodeVal(get1(timeSpan, 'begin'));
70219                     var end = nodeVal(get1(timeSpan, 'end'));
70220                     properties.timespan = {
70221                       begin: begin,
70222                       end: end
70223                     };
70224                   }
70225
70226                   if (timeStamp) {
70227                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
70228                   }
70229
70230                   if (lineStyle) {
70231                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
70232                         color = linestyles[0],
70233                         opacity = linestyles[1],
70234                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
70235                     if (color) properties.stroke = color;
70236                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
70237                     if (!isNaN(width)) properties['stroke-width'] = width;
70238                   }
70239
70240                   if (polyStyle) {
70241                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
70242                         pcolor = polystyles[0],
70243                         popacity = polystyles[1],
70244                         fill = nodeVal(get1(polyStyle, 'fill')),
70245                         outline = nodeVal(get1(polyStyle, 'outline'));
70246                     if (pcolor) properties.fill = pcolor;
70247                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
70248                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
70249                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
70250                   }
70251
70252                   if (extendedData) {
70253                     var datas = get(extendedData, 'Data'),
70254                         simpleDatas = get(extendedData, 'SimpleData');
70255
70256                     for (i = 0; i < datas.length; i++) {
70257                       properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
70258                     }
70259
70260                     for (i = 0; i < simpleDatas.length; i++) {
70261                       properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
70262                     }
70263                   }
70264
70265                   if (visibility) {
70266                     properties.visibility = nodeVal(visibility);
70267                   }
70268
70269                   if (geomsAndTimes.coordTimes.length) {
70270                     properties.coordTimes = geomsAndTimes.coordTimes.length === 1 ? geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
70271                   }
70272
70273                   var feature = {
70274                     type: 'Feature',
70275                     geometry: geomsAndTimes.geoms.length === 1 ? geomsAndTimes.geoms[0] : {
70276                       type: 'GeometryCollection',
70277                       geometries: geomsAndTimes.geoms
70278                     },
70279                     properties: properties
70280                   };
70281                   if (attr(root, 'id')) feature.id = attr(root, 'id');
70282                   return [feature];
70283                 }
70284
70285                 return gj;
70286               },
70287               gpx: function gpx(doc) {
70288                 var i,
70289                     tracks = get(doc, 'trk'),
70290                     routes = get(doc, 'rte'),
70291                     waypoints = get(doc, 'wpt'),
70292                     // a feature collection
70293                 gj = fc(),
70294                     feature;
70295
70296                 for (i = 0; i < tracks.length; i++) {
70297                   feature = getTrack(tracks[i]);
70298                   if (feature) gj.features.push(feature);
70299                 }
70300
70301                 for (i = 0; i < routes.length; i++) {
70302                   feature = getRoute(routes[i]);
70303                   if (feature) gj.features.push(feature);
70304                 }
70305
70306                 for (i = 0; i < waypoints.length; i++) {
70307                   gj.features.push(getPoint(waypoints[i]));
70308                 }
70309
70310                 function getPoints(node, pointname) {
70311                   var pts = get(node, pointname),
70312                       line = [],
70313                       times = [],
70314                       heartRates = [],
70315                       l = pts.length;
70316                   if (l < 2) return {}; // Invalid line in GeoJSON
70317
70318                   for (var i = 0; i < l; i++) {
70319                     var c = coordPair(pts[i]);
70320                     line.push(c.coordinates);
70321                     if (c.time) times.push(c.time);
70322                     if (c.heartRate) heartRates.push(c.heartRate);
70323                   }
70324
70325                   return {
70326                     line: line,
70327                     times: times,
70328                     heartRates: heartRates
70329                   };
70330                 }
70331
70332                 function getTrack(node) {
70333                   var segments = get(node, 'trkseg'),
70334                       track = [],
70335                       times = [],
70336                       heartRates = [],
70337                       line;
70338
70339                   for (var i = 0; i < segments.length; i++) {
70340                     line = getPoints(segments[i], 'trkpt');
70341
70342                     if (line) {
70343                       if (line.line) track.push(line.line);
70344                       if (line.times && line.times.length) times.push(line.times);
70345                       if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
70346                     }
70347                   }
70348
70349                   if (track.length === 0) return;
70350                   var properties = getProperties(node);
70351                   extend(properties, getLineStyle(get1(node, 'extensions')));
70352                   if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
70353                   if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
70354                   return {
70355                     type: 'Feature',
70356                     properties: properties,
70357                     geometry: {
70358                       type: track.length === 1 ? 'LineString' : 'MultiLineString',
70359                       coordinates: track.length === 1 ? track[0] : track
70360                     }
70361                   };
70362                 }
70363
70364                 function getRoute(node) {
70365                   var line = getPoints(node, 'rtept');
70366                   if (!line.line) return;
70367                   var prop = getProperties(node);
70368                   extend(prop, getLineStyle(get1(node, 'extensions')));
70369                   var routeObj = {
70370                     type: 'Feature',
70371                     properties: prop,
70372                     geometry: {
70373                       type: 'LineString',
70374                       coordinates: line.line
70375                     }
70376                   };
70377                   return routeObj;
70378                 }
70379
70380                 function getPoint(node) {
70381                   var prop = getProperties(node);
70382                   extend(prop, getMulti(node, ['sym']));
70383                   return {
70384                     type: 'Feature',
70385                     properties: prop,
70386                     geometry: {
70387                       type: 'Point',
70388                       coordinates: coordPair(node).coordinates
70389                     }
70390                   };
70391                 }
70392
70393                 function getLineStyle(extensions) {
70394                   var style = {};
70395
70396                   if (extensions) {
70397                     var lineStyle = get1(extensions, 'line');
70398
70399                     if (lineStyle) {
70400                       var color = nodeVal(get1(lineStyle, 'color')),
70401                           opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
70402                           width = parseFloat(nodeVal(get1(lineStyle, 'width')));
70403                       if (color) style.stroke = color;
70404                       if (!isNaN(opacity)) style['stroke-opacity'] = opacity; // GPX width is in mm, convert to px with 96 px per inch
70405
70406                       if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
70407                     }
70408                   }
70409
70410                   return style;
70411                 }
70412
70413                 function getProperties(node) {
70414                   var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
70415                       links = get(node, 'link');
70416                   if (links.length) prop.links = [];
70417
70418                   for (var i = 0, link; i < links.length; i++) {
70419                     link = {
70420                       href: attr(links[i], 'href')
70421                     };
70422                     extend(link, getMulti(links[i], ['text', 'type']));
70423                     prop.links.push(link);
70424                   }
70425
70426                   return prop;
70427                 }
70428
70429                 return gj;
70430               }
70431             };
70432             return t;
70433           }();
70434
70435           module.exports = toGeoJSON;
70436         });
70437
70438         var _initialized = false;
70439         var _enabled = false;
70440
70441         var _geojson;
70442
70443         function svgData(projection, context, dispatch) {
70444           var throttledRedraw = throttle(function () {
70445             dispatch.call('change');
70446           }, 1000);
70447
70448           var _showLabels = true;
70449           var detected = utilDetect();
70450           var layer = select(null);
70451
70452           var _vtService;
70453
70454           var _fileList;
70455
70456           var _template;
70457
70458           var _src;
70459
70460           function init() {
70461             if (_initialized) return; // run once
70462
70463             _geojson = {};
70464             _enabled = true;
70465
70466             function over(d3_event) {
70467               d3_event.stopPropagation();
70468               d3_event.preventDefault();
70469               d3_event.dataTransfer.dropEffect = 'copy';
70470             }
70471
70472             context.container().attr('dropzone', 'copy').on('drop.svgData', function (d3_event) {
70473               d3_event.stopPropagation();
70474               d3_event.preventDefault();
70475               if (!detected.filedrop) return;
70476               drawData.fileList(d3_event.dataTransfer.files);
70477             }).on('dragenter.svgData', over).on('dragexit.svgData', over).on('dragover.svgData', over);
70478             _initialized = true;
70479           }
70480
70481           function getService() {
70482             if (services.vectorTile && !_vtService) {
70483               _vtService = services.vectorTile;
70484
70485               _vtService.event.on('loadedData', throttledRedraw);
70486             } else if (!services.vectorTile && _vtService) {
70487               _vtService = null;
70488             }
70489
70490             return _vtService;
70491           }
70492
70493           function showLayer() {
70494             layerOn();
70495             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
70496               dispatch.call('change');
70497             });
70498           }
70499
70500           function hideLayer() {
70501             throttledRedraw.cancel();
70502             layer.transition().duration(250).style('opacity', 0).on('end', layerOff);
70503           }
70504
70505           function layerOn() {
70506             layer.style('display', 'block');
70507           }
70508
70509           function layerOff() {
70510             layer.selectAll('.viewfield-group').remove();
70511             layer.style('display', 'none');
70512           } // ensure that all geojson features in a collection have IDs
70513
70514
70515           function ensureIDs(gj) {
70516             if (!gj) return null;
70517
70518             if (gj.type === 'FeatureCollection') {
70519               for (var i = 0; i < gj.features.length; i++) {
70520                 ensureFeatureID(gj.features[i]);
70521               }
70522             } else {
70523               ensureFeatureID(gj);
70524             }
70525
70526             return gj;
70527           } // ensure that each single Feature object has a unique ID
70528
70529
70530           function ensureFeatureID(feature) {
70531             if (!feature) return;
70532             feature.__featurehash__ = utilHashcode(fastJsonStableStringify(feature));
70533             return feature;
70534           } // Prefer an array of Features instead of a FeatureCollection
70535
70536
70537           function getFeatures(gj) {
70538             if (!gj) return [];
70539
70540             if (gj.type === 'FeatureCollection') {
70541               return gj.features;
70542             } else {
70543               return [gj];
70544             }
70545           }
70546
70547           function featureKey(d) {
70548             return d.__featurehash__;
70549           }
70550
70551           function isPolygon(d) {
70552             return d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon';
70553           }
70554
70555           function clipPathID(d) {
70556             return 'ideditor-data-' + d.__featurehash__ + '-clippath';
70557           }
70558
70559           function featureClasses(d) {
70560             return ['data' + d.__featurehash__, d.geometry.type, isPolygon(d) ? 'area' : '', d.__layerID__ || ''].filter(Boolean).join(' ');
70561           }
70562
70563           function drawData(selection) {
70564             var vtService = getService();
70565             var getPath = svgPath(projection).geojson;
70566             var getAreaPath = svgPath(projection, null, true).geojson;
70567             var hasData = drawData.hasData();
70568             layer = selection.selectAll('.layer-mapdata').data(_enabled && hasData ? [0] : []);
70569             layer.exit().remove();
70570             layer = layer.enter().append('g').attr('class', 'layer-mapdata').merge(layer);
70571             var surface = context.surface();
70572             if (!surface || surface.empty()) return; // not ready to draw yet, starting up
70573             // Gather data
70574
70575             var geoData, polygonData;
70576
70577             if (_template && vtService) {
70578               // fetch data from vector tile service
70579               var sourceID = _template;
70580               vtService.loadTiles(sourceID, _template, projection);
70581               geoData = vtService.data(sourceID, projection);
70582             } else {
70583               geoData = getFeatures(_geojson);
70584             }
70585
70586             geoData = geoData.filter(getPath);
70587             polygonData = geoData.filter(isPolygon); // Draw clip paths for polygons
70588
70589             var clipPaths = surface.selectAll('defs').selectAll('.clipPath-data').data(polygonData, featureKey);
70590             clipPaths.exit().remove();
70591             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-data').attr('id', clipPathID);
70592             clipPathsEnter.append('path');
70593             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', getAreaPath); // Draw fill, shadow, stroke layers
70594
70595             var datagroups = layer.selectAll('g.datagroup').data(['fill', 'shadow', 'stroke']);
70596             datagroups = datagroups.enter().append('g').attr('class', function (d) {
70597               return 'datagroup datagroup-' + d;
70598             }).merge(datagroups); // Draw paths
70599
70600             var pathData = {
70601               fill: polygonData,
70602               shadow: geoData,
70603               stroke: geoData
70604             };
70605             var paths = datagroups.selectAll('path').data(function (layer) {
70606               return pathData[layer];
70607             }, featureKey); // exit
70608
70609             paths.exit().remove(); // enter/update
70610
70611             paths = paths.enter().append('path').attr('class', function (d) {
70612               var datagroup = this.parentNode.__data__;
70613               return 'pathdata ' + datagroup + ' ' + featureClasses(d);
70614             }).attr('clip-path', function (d) {
70615               var datagroup = this.parentNode.__data__;
70616               return datagroup === 'fill' ? 'url(#' + clipPathID(d) + ')' : null;
70617             }).merge(paths).attr('d', function (d) {
70618               var datagroup = this.parentNode.__data__;
70619               return datagroup === 'fill' ? getAreaPath(d) : getPath(d);
70620             }); // Draw labels
70621
70622             layer.call(drawLabels, 'label-halo', geoData).call(drawLabels, 'label', geoData);
70623
70624             function drawLabels(selection, textClass, data) {
70625               var labelPath = d3_geoPath(projection);
70626               var labelData = data.filter(function (d) {
70627                 return _showLabels && d.properties && (d.properties.desc || d.properties.name);
70628               });
70629               var labels = selection.selectAll('text.' + textClass).data(labelData, featureKey); // exit
70630
70631               labels.exit().remove(); // enter/update
70632
70633               labels = labels.enter().append('text').attr('class', function (d) {
70634                 return textClass + ' ' + featureClasses(d);
70635               }).merge(labels).text(function (d) {
70636                 return d.properties.desc || d.properties.name;
70637               }).attr('x', function (d) {
70638                 var centroid = labelPath.centroid(d);
70639                 return centroid[0] + 11;
70640               }).attr('y', function (d) {
70641                 var centroid = labelPath.centroid(d);
70642                 return centroid[1];
70643               });
70644             }
70645           }
70646
70647           function getExtension(fileName) {
70648             if (!fileName) return;
70649             var re = /\.(gpx|kml|(geo)?json)$/i;
70650             var match = fileName.toLowerCase().match(re);
70651             return match && match.length && match[0];
70652           }
70653
70654           function xmlToDom(textdata) {
70655             return new DOMParser().parseFromString(textdata, 'text/xml');
70656           }
70657
70658           drawData.setFile = function (extension, data) {
70659             _template = null;
70660             _fileList = null;
70661             _geojson = null;
70662             _src = null;
70663             var gj;
70664
70665             switch (extension) {
70666               case '.gpx':
70667                 gj = togeojson.gpx(xmlToDom(data));
70668                 break;
70669
70670               case '.kml':
70671                 gj = togeojson.kml(xmlToDom(data));
70672                 break;
70673
70674               case '.geojson':
70675               case '.json':
70676                 gj = JSON.parse(data);
70677                 break;
70678             }
70679
70680             gj = gj || {};
70681
70682             if (Object.keys(gj).length) {
70683               _geojson = ensureIDs(gj);
70684               _src = extension + ' data file';
70685               this.fitZoom();
70686             }
70687
70688             dispatch.call('change');
70689             return this;
70690           };
70691
70692           drawData.showLabels = function (val) {
70693             if (!arguments.length) return _showLabels;
70694             _showLabels = val;
70695             return this;
70696           };
70697
70698           drawData.enabled = function (val) {
70699             if (!arguments.length) return _enabled;
70700             _enabled = val;
70701
70702             if (_enabled) {
70703               showLayer();
70704             } else {
70705               hideLayer();
70706             }
70707
70708             dispatch.call('change');
70709             return this;
70710           };
70711
70712           drawData.hasData = function () {
70713             var gj = _geojson || {};
70714             return !!(_template || Object.keys(gj).length);
70715           };
70716
70717           drawData.template = function (val, src) {
70718             if (!arguments.length) return _template; // test source against OSM imagery blocklists..
70719
70720             var osm = context.connection();
70721
70722             if (osm) {
70723               var blocklists = osm.imageryBlocklists();
70724               var fail = false;
70725               var tested = 0;
70726               var regex;
70727
70728               for (var i = 0; i < blocklists.length; i++) {
70729                 regex = blocklists[i];
70730                 fail = regex.test(val);
70731                 tested++;
70732                 if (fail) break;
70733               } // ensure at least one test was run.
70734
70735
70736               if (!tested) {
70737                 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
70738                 fail = regex.test(val);
70739               }
70740             }
70741
70742             _template = val;
70743             _fileList = null;
70744             _geojson = null; // strip off the querystring/hash from the template,
70745             // it often includes the access token
70746
70747             _src = src || 'vectortile:' + val.split(/[?#]/)[0];
70748             dispatch.call('change');
70749             return this;
70750           };
70751
70752           drawData.geojson = function (gj, src) {
70753             if (!arguments.length) return _geojson;
70754             _template = null;
70755             _fileList = null;
70756             _geojson = null;
70757             _src = null;
70758             gj = gj || {};
70759
70760             if (Object.keys(gj).length) {
70761               _geojson = ensureIDs(gj);
70762               _src = src || 'unknown.geojson';
70763             }
70764
70765             dispatch.call('change');
70766             return this;
70767           };
70768
70769           drawData.fileList = function (fileList) {
70770             if (!arguments.length) return _fileList;
70771             _template = null;
70772             _fileList = fileList;
70773             _geojson = null;
70774             _src = null;
70775             if (!fileList || !fileList.length) return this;
70776             var f = fileList[0];
70777             var extension = getExtension(f.name);
70778             var reader = new FileReader();
70779
70780             reader.onload = function () {
70781               return function (e) {
70782                 drawData.setFile(extension, e.target.result);
70783               };
70784             }();
70785
70786             reader.readAsText(f);
70787             return this;
70788           };
70789
70790           drawData.url = function (url, defaultExtension) {
70791             _template = null;
70792             _fileList = null;
70793             _geojson = null;
70794             _src = null; // strip off any querystring/hash from the url before checking extension
70795
70796             var testUrl = url.split(/[?#]/)[0];
70797             var extension = getExtension(testUrl) || defaultExtension;
70798
70799             if (extension) {
70800               _template = null;
70801               d3_text(url).then(function (data) {
70802                 drawData.setFile(extension, data);
70803               })["catch"](function () {
70804                 /* ignore */
70805               });
70806             } else {
70807               drawData.template(url);
70808             }
70809
70810             return this;
70811           };
70812
70813           drawData.getSrc = function () {
70814             return _src || '';
70815           };
70816
70817           drawData.fitZoom = function () {
70818             var features = getFeatures(_geojson);
70819             if (!features.length) return;
70820             var map = context.map();
70821             var viewport = map.trimmedExtent().polygon();
70822             var coords = features.reduce(function (coords, feature) {
70823               var geom = feature.geometry;
70824               if (!geom) return coords;
70825               var c = geom.coordinates;
70826               /* eslint-disable no-fallthrough */
70827
70828               switch (geom.type) {
70829                 case 'Point':
70830                   c = [c];
70831
70832                 case 'MultiPoint':
70833                 case 'LineString':
70834                   break;
70835
70836                 case 'MultiPolygon':
70837                   c = utilArrayFlatten(c);
70838
70839                 case 'Polygon':
70840                 case 'MultiLineString':
70841                   c = utilArrayFlatten(c);
70842                   break;
70843               }
70844               /* eslint-enable no-fallthrough */
70845
70846
70847               return utilArrayUnion(coords, c);
70848             }, []);
70849
70850             if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
70851               var extent = geoExtent(d3_geoBounds({
70852                 type: 'LineString',
70853                 coordinates: coords
70854               }));
70855               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
70856             }
70857
70858             return this;
70859           };
70860
70861           init();
70862           return drawData;
70863         }
70864
70865         function svgDebug(projection, context) {
70866           function drawDebug(selection) {
70867             var showTile = context.getDebug('tile');
70868             var showCollision = context.getDebug('collision');
70869             var showImagery = context.getDebug('imagery');
70870             var showTouchTargets = context.getDebug('target');
70871             var showDownloaded = context.getDebug('downloaded');
70872             var debugData = [];
70873
70874             if (showTile) {
70875               debugData.push({
70876                 "class": 'red',
70877                 label: 'tile'
70878               });
70879             }
70880
70881             if (showCollision) {
70882               debugData.push({
70883                 "class": 'yellow',
70884                 label: 'collision'
70885               });
70886             }
70887
70888             if (showImagery) {
70889               debugData.push({
70890                 "class": 'orange',
70891                 label: 'imagery'
70892               });
70893             }
70894
70895             if (showTouchTargets) {
70896               debugData.push({
70897                 "class": 'pink',
70898                 label: 'touchTargets'
70899               });
70900             }
70901
70902             if (showDownloaded) {
70903               debugData.push({
70904                 "class": 'purple',
70905                 label: 'downloaded'
70906               });
70907             }
70908
70909             var legend = context.container().select('.main-content').selectAll('.debug-legend').data(debugData.length ? [0] : []);
70910             legend.exit().remove();
70911             legend = legend.enter().append('div').attr('class', 'fillD debug-legend').merge(legend);
70912             var legendItems = legend.selectAll('.debug-legend-item').data(debugData, function (d) {
70913               return d.label;
70914             });
70915             legendItems.exit().remove();
70916             legendItems.enter().append('span').attr('class', function (d) {
70917               return "debug-legend-item ".concat(d["class"]);
70918             }).text(function (d) {
70919               return d.label;
70920             });
70921             var layer = selection.selectAll('.layer-debug').data(showImagery || showDownloaded ? [0] : []);
70922             layer.exit().remove();
70923             layer = layer.enter().append('g').attr('class', 'layer-debug').merge(layer); // imagery
70924
70925             var extent = context.map().extent();
70926             _mainFileFetcher.get('imagery').then(function (d) {
70927               var hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
70928               var features = hits.map(function (d) {
70929                 return d.features[d.id];
70930               });
70931               var imagery = layer.selectAll('path.debug-imagery').data(features);
70932               imagery.exit().remove();
70933               imagery.enter().append('path').attr('class', 'debug-imagery debug orange');
70934             })["catch"](function () {
70935               /* ignore */
70936             }); // downloaded
70937
70938             var osm = context.connection();
70939             var dataDownloaded = [];
70940
70941             if (osm && showDownloaded) {
70942               var rtree = osm.caches('get').tile.rtree;
70943               dataDownloaded = rtree.all().map(function (bbox) {
70944                 return {
70945                   type: 'Feature',
70946                   properties: {
70947                     id: bbox.id
70948                   },
70949                   geometry: {
70950                     type: 'Polygon',
70951                     coordinates: [[[bbox.minX, bbox.minY], [bbox.minX, bbox.maxY], [bbox.maxX, bbox.maxY], [bbox.maxX, bbox.minY], [bbox.minX, bbox.minY]]]
70952                   }
70953                 };
70954               });
70955             }
70956
70957             var downloaded = layer.selectAll('path.debug-downloaded').data(showDownloaded ? dataDownloaded : []);
70958             downloaded.exit().remove();
70959             downloaded.enter().append('path').attr('class', 'debug-downloaded debug purple'); // update
70960
70961             layer.selectAll('path').attr('d', svgPath(projection).geojson);
70962           } // This looks strange because `enabled` methods on other layers are
70963           // chainable getter/setters, and this one is just a getter.
70964
70965
70966           drawDebug.enabled = function () {
70967             if (!arguments.length) {
70968               return context.getDebug('tile') || context.getDebug('collision') || context.getDebug('imagery') || context.getDebug('target') || context.getDebug('downloaded');
70969             } else {
70970               return this;
70971             }
70972           };
70973
70974           return drawDebug;
70975         }
70976
70977         /*
70978             A standalone SVG element that contains only a `defs` sub-element. To be
70979             used once globally, since defs IDs must be unique within a document.
70980         */
70981
70982         function svgDefs(context) {
70983           var _defsSelection = select(null);
70984
70985           var _spritesheetIds = ['iD-sprite', 'maki-sprite', 'temaki-sprite', 'fa-sprite', 'community-sprite'];
70986
70987           function drawDefs(selection) {
70988             _defsSelection = selection.append('defs'); // add markers
70989
70990             _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
70991             // (they can't inherit it from the line they're attached to),
70992             // so we need to manually define markers for each color of tag
70993             // (also, it's slightly nicer if we can control the
70994             // positioning for different tags)
70995
70996
70997             function addSidedMarker(name, color, offset) {
70998               _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);
70999             }
71000
71001             addSidedMarker('natural', 'rgb(170, 170, 170)', 0); // for a coastline, the arrows are (somewhat unintuitively) on
71002             // the water side, so let's color them blue (with a gap) to
71003             // give a stronger indication
71004
71005             addSidedMarker('coastline', '#77dede', 1);
71006             addSidedMarker('waterway', '#77dede', 1); // barriers have a dashed line, and separating the triangle
71007             // from the line visually suits that
71008
71009             addSidedMarker('barrier', '#ddd', 1);
71010             addSidedMarker('man_made', '#fff', 0);
71011
71012             _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');
71013
71014             _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
71015
71016
71017             var patterns = _defsSelection.selectAll('pattern').data([// pattern name, pattern image name
71018             ['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) {
71019               return 'ideditor-pattern-' + d[0];
71020             }).attr('width', 32).attr('height', 32).attr('patternUnits', 'userSpaceOnUse');
71021
71022             patterns.append('rect').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('class', function (d) {
71023               return 'pattern-color-' + d[0];
71024             });
71025             patterns.append('image').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('xlink:href', function (d) {
71026               return context.imagePath('pattern/' + d[1] + '.png');
71027             }); // add clip paths
71028
71029             _defsSelection.selectAll('clipPath').data([12, 18, 20, 32, 45]).enter().append('clipPath').attr('id', function (d) {
71030               return 'ideditor-clip-square-' + d;
71031             }).append('rect').attr('x', 0).attr('y', 0).attr('width', function (d) {
71032               return d;
71033             }).attr('height', function (d) {
71034               return d;
71035             }); // add symbol spritesheets
71036
71037
71038             addSprites(_spritesheetIds, true);
71039           }
71040
71041           function addSprites(ids, overrideColors) {
71042             _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
71043
71044             var spritesheets = _defsSelection.selectAll('.spritesheet').data(_spritesheetIds);
71045
71046             spritesheets.enter().append('g').attr('class', function (d) {
71047               return 'spritesheet spritesheet-' + d;
71048             }).each(function (d) {
71049               var url = context.imagePath(d + '.svg');
71050               var node = select(this).node();
71051               svg(url).then(function (svg) {
71052                 node.appendChild(select(svg.documentElement).attr('id', 'ideditor-' + d).node());
71053
71054                 if (overrideColors && d !== 'iD-sprite') {
71055                   // allow icon colors to be overridden..
71056                   select(node).selectAll('path').attr('fill', 'currentColor');
71057                 }
71058               })["catch"](function () {
71059                 /* ignore */
71060               });
71061             });
71062             spritesheets.exit().remove();
71063           }
71064
71065           drawDefs.addSprites = addSprites;
71066           return drawDefs;
71067         }
71068
71069         var _layerEnabled = false;
71070
71071         var _qaService;
71072
71073         function svgKeepRight(projection, context, dispatch) {
71074           var throttledRedraw = throttle(function () {
71075             return dispatch.call('change');
71076           }, 1000);
71077
71078           var minZoom = 12;
71079           var touchLayer = select(null);
71080           var drawLayer = select(null);
71081           var layerVisible = false;
71082
71083           function markerPath(selection, klass) {
71084             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');
71085           } // Loosely-coupled keepRight service for fetching issues.
71086
71087
71088           function getService() {
71089             if (services.keepRight && !_qaService) {
71090               _qaService = services.keepRight;
71091
71092               _qaService.on('loaded', throttledRedraw);
71093             } else if (!services.keepRight && _qaService) {
71094               _qaService = null;
71095             }
71096
71097             return _qaService;
71098           } // Show the markers
71099
71100
71101           function editOn() {
71102             if (!layerVisible) {
71103               layerVisible = true;
71104               drawLayer.style('display', 'block');
71105             }
71106           } // Immediately remove the markers and their touch targets
71107
71108
71109           function editOff() {
71110             if (layerVisible) {
71111               layerVisible = false;
71112               drawLayer.style('display', 'none');
71113               drawLayer.selectAll('.qaItem.keepRight').remove();
71114               touchLayer.selectAll('.qaItem.keepRight').remove();
71115             }
71116           } // Enable the layer.  This shows the markers and transitions them to visible.
71117
71118
71119           function layerOn() {
71120             editOn();
71121             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
71122               return dispatch.call('change');
71123             });
71124           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
71125
71126
71127           function layerOff() {
71128             throttledRedraw.cancel();
71129             drawLayer.interrupt();
71130             touchLayer.selectAll('.qaItem.keepRight').remove();
71131             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
71132               editOff();
71133               dispatch.call('change');
71134             });
71135           } // Update the issue markers
71136
71137
71138           function updateMarkers() {
71139             if (!layerVisible || !_layerEnabled) return;
71140             var service = getService();
71141             var selectedID = context.selectedErrorID();
71142             var data = service ? service.getItems(projection) : [];
71143             var getTransform = svgPointTransform(projection); // Draw markers..
71144
71145             var markers = drawLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
71146               return d.id;
71147             }); // exit
71148
71149             markers.exit().remove(); // enter
71150
71151             var markersEnter = markers.enter().append('g').attr('class', function (d) {
71152               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
71153             });
71154             markersEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
71155             markersEnter.append('path').call(markerPath, 'shadow');
71156             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
71157
71158             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
71159               return d.id === selectedID;
71160             }).attr('transform', getTransform); // Draw targets..
71161
71162             if (touchLayer.empty()) return;
71163             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
71164             var targets = touchLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
71165               return d.id;
71166             }); // exit
71167
71168             targets.exit().remove(); // enter/update
71169
71170             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
71171               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
71172             }).attr('transform', getTransform);
71173
71174             function sortY(a, b) {
71175               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];
71176             }
71177           } // Draw the keepRight layer and schedule loading issues and updating markers.
71178
71179
71180           function drawKeepRight(selection) {
71181             var service = getService();
71182             var surface = context.surface();
71183
71184             if (surface && !surface.empty()) {
71185               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
71186             }
71187
71188             drawLayer = selection.selectAll('.layer-keepRight').data(service ? [0] : []);
71189             drawLayer.exit().remove();
71190             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-keepRight').style('display', _layerEnabled ? 'block' : 'none').merge(drawLayer);
71191
71192             if (_layerEnabled) {
71193               if (service && ~~context.map().zoom() >= minZoom) {
71194                 editOn();
71195                 service.loadIssues(projection);
71196                 updateMarkers();
71197               } else {
71198                 editOff();
71199               }
71200             }
71201           } // Toggles the layer on and off
71202
71203
71204           drawKeepRight.enabled = function (val) {
71205             if (!arguments.length) return _layerEnabled;
71206             _layerEnabled = val;
71207
71208             if (_layerEnabled) {
71209               layerOn();
71210             } else {
71211               layerOff();
71212
71213               if (context.selectedErrorID()) {
71214                 context.enter(modeBrowse(context));
71215               }
71216             }
71217
71218             dispatch.call('change');
71219             return this;
71220           };
71221
71222           drawKeepRight.supported = function () {
71223             return !!getService();
71224           };
71225
71226           return drawKeepRight;
71227         }
71228
71229         function svgGeolocate(projection) {
71230           var layer = select(null);
71231
71232           var _position;
71233
71234           function init() {
71235             if (svgGeolocate.initialized) return; // run once
71236
71237             svgGeolocate.enabled = false;
71238             svgGeolocate.initialized = true;
71239           }
71240
71241           function showLayer() {
71242             layer.style('display', 'block');
71243           }
71244
71245           function hideLayer() {
71246             layer.transition().duration(250).style('opacity', 0);
71247           }
71248
71249           function layerOn() {
71250             layer.style('opacity', 0).transition().duration(250).style('opacity', 1);
71251           }
71252
71253           function layerOff() {
71254             layer.style('display', 'none');
71255           }
71256
71257           function transform(d) {
71258             return svgPointTransform(projection)(d);
71259           }
71260
71261           function accuracy(accuracy, loc) {
71262             // converts accuracy to pixels...
71263             var degreesRadius = geoMetersToLat(accuracy),
71264                 tangentLoc = [loc[0], loc[1] + degreesRadius],
71265                 projectedTangent = projection(tangentLoc),
71266                 projectedLoc = projection([loc[0], loc[1]]); // southern most point will have higher pixel value...
71267
71268             return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
71269           }
71270
71271           function update() {
71272             var geolocation = {
71273               loc: [_position.coords.longitude, _position.coords.latitude]
71274             };
71275             var groups = layer.selectAll('.geolocations').selectAll('.geolocation').data([geolocation]);
71276             groups.exit().remove();
71277             var pointsEnter = groups.enter().append('g').attr('class', 'geolocation');
71278             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');
71279             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');
71280             groups.merge(pointsEnter).attr('transform', transform);
71281             layer.select('.geolocate-radius').attr('r', accuracy(_position.coords.accuracy, geolocation.loc));
71282           }
71283
71284           function drawLocation(selection) {
71285             var enabled = svgGeolocate.enabled;
71286             layer = selection.selectAll('.layer-geolocate').data([0]);
71287             layer.exit().remove();
71288             var layerEnter = layer.enter().append('g').attr('class', 'layer-geolocate').style('display', enabled ? 'block' : 'none');
71289             layerEnter.append('g').attr('class', 'geolocations');
71290             layer = layerEnter.merge(layer);
71291
71292             if (enabled) {
71293               update();
71294             } else {
71295               layerOff();
71296             }
71297           }
71298
71299           drawLocation.enabled = function (position, enabled) {
71300             if (!arguments.length) return svgGeolocate.enabled;
71301             _position = position;
71302             svgGeolocate.enabled = enabled;
71303
71304             if (svgGeolocate.enabled) {
71305               showLayer();
71306               layerOn();
71307             } else {
71308               hideLayer();
71309             }
71310
71311             return this;
71312           };
71313
71314           init();
71315           return drawLocation;
71316         }
71317
71318         function svgLabels(projection, context) {
71319           var path = d3_geoPath(projection);
71320           var detected = utilDetect();
71321           var baselineHack = detected.ie || detected.browser.toLowerCase() === 'edge' || detected.browser.toLowerCase() === 'firefox' && detected.version >= 70;
71322
71323           var _rdrawn = new RBush();
71324
71325           var _rskipped = new RBush();
71326
71327           var _textWidthCache = {};
71328           var _entitybboxes = {}; // Listed from highest to lowest priority
71329
71330           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]];
71331
71332           function shouldSkipIcon(preset) {
71333             var noIcons = ['building', 'landuse', 'natural'];
71334             return noIcons.some(function (s) {
71335               return preset.id.indexOf(s) >= 0;
71336             });
71337           }
71338
71339           function get(array, prop) {
71340             return function (d, i) {
71341               return array[i][prop];
71342             };
71343           }
71344
71345           function textWidth(text, size, elem) {
71346             var c = _textWidthCache[size];
71347             if (!c) c = _textWidthCache[size] = {};
71348
71349             if (c[text]) {
71350               return c[text];
71351             } else if (elem) {
71352               c[text] = elem.getComputedTextLength();
71353               return c[text];
71354             } else {
71355               var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
71356
71357               if (str === null) {
71358                 return size / 3 * 2 * text.length;
71359               } else {
71360                 return size / 3 * (2 * text.length + str.length);
71361               }
71362             }
71363           }
71364
71365           function drawLinePaths(selection, entities, filter, classes, labels) {
71366             var paths = selection.selectAll('path').filter(filter).data(entities, osmEntity.key); // exit
71367
71368             paths.exit().remove(); // enter/update
71369
71370             paths.enter().append('path').style('stroke-width', get(labels, 'font-size')).attr('id', function (d) {
71371               return 'ideditor-labelpath-' + d.id;
71372             }).attr('class', classes).merge(paths).attr('d', get(labels, 'lineString'));
71373           }
71374
71375           function drawLineLabels(selection, entities, filter, classes, labels) {
71376             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71377
71378             texts.exit().remove(); // enter
71379
71380             texts.enter().append('text').attr('class', function (d, i) {
71381               return classes + ' ' + labels[i].classes + ' ' + d.id;
71382             }).attr('dy', baselineHack ? '0.35em' : null).append('textPath').attr('class', 'textpath'); // update
71383
71384             selection.selectAll('text.' + classes).selectAll('.textpath').filter(filter).data(entities, osmEntity.key).attr('startOffset', '50%').attr('xlink:href', function (d) {
71385               return '#ideditor-labelpath-' + d.id;
71386             }).text(utilDisplayNameForPath);
71387           }
71388
71389           function drawPointLabels(selection, entities, filter, classes, labels) {
71390             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71391
71392             texts.exit().remove(); // enter/update
71393
71394             texts.enter().append('text').attr('class', function (d, i) {
71395               return classes + ' ' + labels[i].classes + ' ' + d.id;
71396             }).merge(texts).attr('x', get(labels, 'x')).attr('y', get(labels, 'y')).style('text-anchor', get(labels, 'textAnchor')).text(utilDisplayName).each(function (d, i) {
71397               textWidth(utilDisplayName(d), labels[i].height, this);
71398             });
71399           }
71400
71401           function drawAreaLabels(selection, entities, filter, classes, labels) {
71402             entities = entities.filter(hasText);
71403             labels = labels.filter(hasText);
71404             drawPointLabels(selection, entities, filter, classes, labels);
71405
71406             function hasText(d, i) {
71407               return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
71408             }
71409           }
71410
71411           function drawAreaIcons(selection, entities, filter, classes, labels) {
71412             var icons = selection.selectAll('use.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71413
71414             icons.exit().remove(); // enter/update
71415
71416             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) {
71417               var preset = _mainPresetIndex.match(d, context.graph());
71418               var picon = preset && preset.icon;
71419
71420               if (!picon) {
71421                 return '';
71422               } else {
71423                 var isMaki = /^maki-/.test(picon);
71424                 return '#' + picon + (isMaki ? '-15' : '');
71425               }
71426             });
71427           }
71428
71429           function drawCollisionBoxes(selection, rtree, which) {
71430             var classes = 'debug ' + which + ' ' + (which === 'debug-skipped' ? 'orange' : 'yellow');
71431             var gj = [];
71432
71433             if (context.getDebug('collision')) {
71434               gj = rtree.all().map(function (d) {
71435                 return {
71436                   type: 'Polygon',
71437                   coordinates: [[[d.minX, d.minY], [d.maxX, d.minY], [d.maxX, d.maxY], [d.minX, d.maxY], [d.minX, d.minY]]]
71438                 };
71439               });
71440             }
71441
71442             var boxes = selection.selectAll('.' + which).data(gj); // exit
71443
71444             boxes.exit().remove(); // enter/update
71445
71446             boxes.enter().append('path').attr('class', classes).merge(boxes).attr('d', d3_geoPath());
71447           }
71448
71449           function drawLabels(selection, graph, entities, filter, dimensions, fullRedraw) {
71450             var wireframe = context.surface().classed('fill-wireframe');
71451             var zoom = geoScaleToZoom(projection.scale());
71452             var labelable = [];
71453             var renderNodeAs = {};
71454             var i, j, k, entity, geometry;
71455
71456             for (i = 0; i < labelStack.length; i++) {
71457               labelable.push([]);
71458             }
71459
71460             if (fullRedraw) {
71461               _rdrawn.clear();
71462
71463               _rskipped.clear();
71464
71465               _entitybboxes = {};
71466             } else {
71467               for (i = 0; i < entities.length; i++) {
71468                 entity = entities[i];
71469                 var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + 'I'] || []);
71470
71471                 for (j = 0; j < toRemove.length; j++) {
71472                   _rdrawn.remove(toRemove[j]);
71473
71474                   _rskipped.remove(toRemove[j]);
71475                 }
71476               }
71477             } // Loop through all the entities to do some preprocessing
71478
71479
71480             for (i = 0; i < entities.length; i++) {
71481               entity = entities[i];
71482               geometry = entity.geometry(graph); // Insert collision boxes around interesting points/vertices
71483
71484               if (geometry === 'point' || geometry === 'vertex' && isInterestingVertex(entity)) {
71485                 var hasDirections = entity.directions(graph, projection).length;
71486                 var markerPadding;
71487
71488                 if (!wireframe && geometry === 'point' && !(zoom >= 18 && hasDirections)) {
71489                   renderNodeAs[entity.id] = 'point';
71490                   markerPadding = 20; // extra y for marker height
71491                 } else {
71492                   renderNodeAs[entity.id] = 'vertex';
71493                   markerPadding = 0;
71494                 }
71495
71496                 var coord = projection(entity.loc);
71497                 var nodePadding = 10;
71498                 var bbox = {
71499                   minX: coord[0] - nodePadding,
71500                   minY: coord[1] - nodePadding - markerPadding,
71501                   maxX: coord[0] + nodePadding,
71502                   maxY: coord[1] + nodePadding
71503                 };
71504                 doInsert(bbox, entity.id + 'P');
71505               } // From here on, treat vertices like points
71506
71507
71508               if (geometry === 'vertex') {
71509                 geometry = 'point';
71510               } // Determine which entities are label-able
71511
71512
71513               var preset = geometry === 'area' && _mainPresetIndex.match(entity, graph);
71514               var icon = preset && !shouldSkipIcon(preset) && preset.icon;
71515               if (!icon && !utilDisplayName(entity)) continue;
71516
71517               for (k = 0; k < labelStack.length; k++) {
71518                 var matchGeom = labelStack[k][0];
71519                 var matchKey = labelStack[k][1];
71520                 var matchVal = labelStack[k][2];
71521                 var hasVal = entity.tags[matchKey];
71522
71523                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
71524                   labelable[k].push(entity);
71525                   break;
71526                 }
71527               }
71528             }
71529
71530             var positions = {
71531               point: [],
71532               line: [],
71533               area: []
71534             };
71535             var labelled = {
71536               point: [],
71537               line: [],
71538               area: []
71539             }; // Try and find a valid label for labellable entities
71540
71541             for (k = 0; k < labelable.length; k++) {
71542               var fontSize = labelStack[k][3];
71543
71544               for (i = 0; i < labelable[k].length; i++) {
71545                 entity = labelable[k][i];
71546                 geometry = entity.geometry(graph);
71547                 var getName = geometry === 'line' ? utilDisplayNameForPath : utilDisplayName;
71548                 var name = getName(entity);
71549                 var width = name && textWidth(name, fontSize);
71550                 var p = null;
71551
71552                 if (geometry === 'point' || geometry === 'vertex') {
71553                   // no point or vertex labels in wireframe mode
71554                   // no vertex labels at low zooms (vertices have no icons)
71555                   if (wireframe) continue;
71556                   var renderAs = renderNodeAs[entity.id];
71557                   if (renderAs === 'vertex' && zoom < 17) continue;
71558                   p = getPointLabel(entity, width, fontSize, renderAs);
71559                 } else if (geometry === 'line') {
71560                   p = getLineLabel(entity, width, fontSize);
71561                 } else if (geometry === 'area') {
71562                   p = getAreaLabel(entity, width, fontSize);
71563                 }
71564
71565                 if (p) {
71566                   if (geometry === 'vertex') {
71567                     geometry = 'point';
71568                   } // treat vertex like point
71569
71570
71571                   p.classes = geometry + ' tag-' + labelStack[k][1];
71572                   positions[geometry].push(p);
71573                   labelled[geometry].push(entity);
71574                 }
71575               }
71576             }
71577
71578             function isInterestingVertex(entity) {
71579               var selectedIDs = context.selectedIDs();
71580               return entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || selectedIDs.indexOf(entity.id) !== -1 || graph.parentWays(entity).some(function (parent) {
71581                 return selectedIDs.indexOf(parent.id) !== -1;
71582               });
71583             }
71584
71585             function getPointLabel(entity, width, height, geometry) {
71586               var y = geometry === 'point' ? -12 : 0;
71587               var pointOffsets = {
71588                 ltr: [15, y, 'start'],
71589                 rtl: [-15, y, 'end']
71590               };
71591               var textDirection = _mainLocalizer.textDirection();
71592               var coord = projection(entity.loc);
71593               var textPadding = 2;
71594               var offset = pointOffsets[textDirection];
71595               var p = {
71596                 height: height,
71597                 width: width,
71598                 x: coord[0] + offset[0],
71599                 y: coord[1] + offset[1],
71600                 textAnchor: offset[2]
71601               }; // insert a collision box for the text label..
71602
71603               var bbox;
71604
71605               if (textDirection === 'rtl') {
71606                 bbox = {
71607                   minX: p.x - width - textPadding,
71608                   minY: p.y - height / 2 - textPadding,
71609                   maxX: p.x + textPadding,
71610                   maxY: p.y + height / 2 + textPadding
71611                 };
71612               } else {
71613                 bbox = {
71614                   minX: p.x - textPadding,
71615                   minY: p.y - height / 2 - textPadding,
71616                   maxX: p.x + width + textPadding,
71617                   maxY: p.y + height / 2 + textPadding
71618                 };
71619               }
71620
71621               if (tryInsert([bbox], entity.id, true)) {
71622                 return p;
71623               }
71624             }
71625
71626             function getLineLabel(entity, width, height) {
71627               var viewport = geoExtent(context.projection.clipExtent()).polygon();
71628               var points = graph.childNodes(entity).map(function (node) {
71629                 return projection(node.loc);
71630               });
71631               var length = geoPathLength(points);
71632               if (length < width + 20) return; // % along the line to attempt to place the label
71633
71634               var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
71635               var padding = 3;
71636
71637               for (var i = 0; i < lineOffsets.length; i++) {
71638                 var offset = lineOffsets[i];
71639                 var middle = offset / 100 * length;
71640                 var start = middle - width / 2;
71641                 if (start < 0 || start + width > length) continue; // generate subpath and ignore paths that are invalid or don't cross viewport.
71642
71643                 var sub = subpath(points, start, start + width);
71644
71645                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
71646                   continue;
71647                 }
71648
71649                 var isReverse = reverse(sub);
71650
71651                 if (isReverse) {
71652                   sub = sub.reverse();
71653                 }
71654
71655                 var bboxes = [];
71656                 var boxsize = (height + 2) / 2;
71657
71658                 for (var j = 0; j < sub.length - 1; j++) {
71659                   var a = sub[j];
71660                   var b = sub[j + 1]; // split up the text into small collision boxes
71661
71662                   var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
71663
71664                   for (var box = 0; box < num; box++) {
71665                     var p = geoVecInterp(a, b, box / num);
71666                     var x0 = p[0] - boxsize - padding;
71667                     var y0 = p[1] - boxsize - padding;
71668                     var x1 = p[0] + boxsize + padding;
71669                     var y1 = p[1] + boxsize + padding;
71670                     bboxes.push({
71671                       minX: Math.min(x0, x1),
71672                       minY: Math.min(y0, y1),
71673                       maxX: Math.max(x0, x1),
71674                       maxY: Math.max(y0, y1)
71675                     });
71676                   }
71677                 }
71678
71679                 if (tryInsert(bboxes, entity.id, false)) {
71680                   // accept this one
71681                   return {
71682                     'font-size': height + 2,
71683                     lineString: lineString(sub),
71684                     startOffset: offset + '%'
71685                   };
71686                 }
71687               }
71688
71689               function reverse(p) {
71690                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
71691                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI / 2 && angle > -Math.PI / 2);
71692               }
71693
71694               function lineString(points) {
71695                 return 'M' + points.join('L');
71696               }
71697
71698               function subpath(points, from, to) {
71699                 var sofar = 0;
71700                 var start, end, i0, i1;
71701
71702                 for (var i = 0; i < points.length - 1; i++) {
71703                   var a = points[i];
71704                   var b = points[i + 1];
71705                   var current = geoVecLength(a, b);
71706                   var portion;
71707
71708                   if (!start && sofar + current >= from) {
71709                     portion = (from - sofar) / current;
71710                     start = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
71711                     i0 = i + 1;
71712                   }
71713
71714                   if (!end && sofar + current >= to) {
71715                     portion = (to - sofar) / current;
71716                     end = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
71717                     i1 = i + 1;
71718                   }
71719
71720                   sofar += current;
71721                 }
71722
71723                 var result = points.slice(i0, i1);
71724                 result.unshift(start);
71725                 result.push(end);
71726                 return result;
71727               }
71728             }
71729
71730             function getAreaLabel(entity, width, height) {
71731               var centroid = path.centroid(entity.asGeoJSON(graph, true));
71732               var extent = entity.extent(graph);
71733               var areaWidth = projection(extent[1])[0] - projection(extent[0])[0];
71734               if (isNaN(centroid[0]) || areaWidth < 20) return;
71735               var preset = _mainPresetIndex.match(entity, context.graph());
71736               var picon = preset && preset.icon;
71737               var iconSize = 17;
71738               var padding = 2;
71739               var p = {};
71740
71741               if (picon) {
71742                 // icon and label..
71743                 if (addIcon()) {
71744                   addLabel(iconSize + padding);
71745                   return p;
71746                 }
71747               } else {
71748                 // label only..
71749                 if (addLabel(0)) {
71750                   return p;
71751                 }
71752               }
71753
71754               function addIcon() {
71755                 var iconX = centroid[0] - iconSize / 2;
71756                 var iconY = centroid[1] - iconSize / 2;
71757                 var bbox = {
71758                   minX: iconX,
71759                   minY: iconY,
71760                   maxX: iconX + iconSize,
71761                   maxY: iconY + iconSize
71762                 };
71763
71764                 if (tryInsert([bbox], entity.id + 'I', true)) {
71765                   p.transform = 'translate(' + iconX + ',' + iconY + ')';
71766                   return true;
71767                 }
71768
71769                 return false;
71770               }
71771
71772               function addLabel(yOffset) {
71773                 if (width && areaWidth >= width + 20) {
71774                   var labelX = centroid[0];
71775                   var labelY = centroid[1] + yOffset;
71776                   var bbox = {
71777                     minX: labelX - width / 2 - padding,
71778                     minY: labelY - height / 2 - padding,
71779                     maxX: labelX + width / 2 + padding,
71780                     maxY: labelY + height / 2 + padding
71781                   };
71782
71783                   if (tryInsert([bbox], entity.id, true)) {
71784                     p.x = labelX;
71785                     p.y = labelY;
71786                     p.textAnchor = 'middle';
71787                     p.height = height;
71788                     return true;
71789                   }
71790                 }
71791
71792                 return false;
71793               }
71794             } // force insert a singular bounding box
71795             // singular box only, no array, id better be unique
71796
71797
71798             function doInsert(bbox, id) {
71799               bbox.id = id;
71800               var oldbox = _entitybboxes[id];
71801
71802               if (oldbox) {
71803                 _rdrawn.remove(oldbox);
71804               }
71805
71806               _entitybboxes[id] = bbox;
71807
71808               _rdrawn.insert(bbox);
71809             }
71810
71811             function tryInsert(bboxes, id, saveSkipped) {
71812               var skipped = false;
71813
71814               for (var i = 0; i < bboxes.length; i++) {
71815                 var bbox = bboxes[i];
71816                 bbox.id = id; // Check that label is visible
71817
71818                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
71819                   skipped = true;
71820                   break;
71821                 }
71822
71823                 if (_rdrawn.collides(bbox)) {
71824                   skipped = true;
71825                   break;
71826                 }
71827               }
71828
71829               _entitybboxes[id] = bboxes;
71830
71831               if (skipped) {
71832                 if (saveSkipped) {
71833                   _rskipped.load(bboxes);
71834                 }
71835               } else {
71836                 _rdrawn.load(bboxes);
71837               }
71838
71839               return !skipped;
71840             }
71841
71842             var layer = selection.selectAll('.layer-osm.labels');
71843             layer.selectAll('.labels-group').data(['halo', 'label', 'debug']).enter().append('g').attr('class', function (d) {
71844               return 'labels-group ' + d;
71845             });
71846             var halo = layer.selectAll('.labels-group.halo');
71847             var label = layer.selectAll('.labels-group.label');
71848             var debug = layer.selectAll('.labels-group.debug'); // points
71849
71850             drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
71851             drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point); // lines
71852
71853             drawLinePaths(layer, labelled.line, filter, '', positions.line);
71854             drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
71855             drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line); // areas
71856
71857             drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
71858             drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
71859             drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
71860             drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area); // debug
71861
71862             drawCollisionBoxes(debug, _rskipped, 'debug-skipped');
71863             drawCollisionBoxes(debug, _rdrawn, 'debug-drawn');
71864             layer.call(filterLabels);
71865           }
71866
71867           function filterLabels(selection) {
71868             var drawLayer = selection.selectAll('.layer-osm.labels');
71869             var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
71870             layers.selectAll('.nolabel').classed('nolabel', false);
71871             var mouse = context.map().mouse();
71872             var graph = context.graph();
71873             var selectedIDs = context.selectedIDs();
71874             var ids = [];
71875             var pad, bbox; // hide labels near the mouse
71876
71877             if (mouse) {
71878               pad = 20;
71879               bbox = {
71880                 minX: mouse[0] - pad,
71881                 minY: mouse[1] - pad,
71882                 maxX: mouse[0] + pad,
71883                 maxY: mouse[1] + pad
71884               };
71885
71886               var nearMouse = _rdrawn.search(bbox).map(function (entity) {
71887                 return entity.id;
71888               });
71889
71890               ids.push.apply(ids, nearMouse);
71891             } // hide labels on selected nodes (they look weird when dragging / haloed)
71892
71893
71894             for (var i = 0; i < selectedIDs.length; i++) {
71895               var entity = graph.hasEntity(selectedIDs[i]);
71896
71897               if (entity && entity.type === 'node') {
71898                 ids.push(selectedIDs[i]);
71899               }
71900             }
71901
71902             layers.selectAll(utilEntitySelector(ids)).classed('nolabel', true); // draw the mouse bbox if debugging is on..
71903
71904             var debug = selection.selectAll('.labels-group.debug');
71905             var gj = [];
71906
71907             if (context.getDebug('collision')) {
71908               gj = bbox ? [{
71909                 type: 'Polygon',
71910                 coordinates: [[[bbox.minX, bbox.minY], [bbox.maxX, bbox.minY], [bbox.maxX, bbox.maxY], [bbox.minX, bbox.maxY], [bbox.minX, bbox.minY]]]
71911               }] : [];
71912             }
71913
71914             var box = debug.selectAll('.debug-mouse').data(gj); // exit
71915
71916             box.exit().remove(); // enter/update
71917
71918             box.enter().append('path').attr('class', 'debug debug-mouse yellow').merge(box).attr('d', d3_geoPath());
71919           }
71920
71921           var throttleFilterLabels = throttle(filterLabels, 100);
71922
71923           drawLabels.observe = function (selection) {
71924             var listener = function listener() {
71925               throttleFilterLabels(selection);
71926             };
71927
71928             selection.on('mousemove.hidelabels', listener);
71929             context.on('enter.hidelabels', listener);
71930           };
71931
71932           drawLabels.off = function (selection) {
71933             throttleFilterLabels.cancel();
71934             selection.on('mousemove.hidelabels', null);
71935             context.on('enter.hidelabels', null);
71936           };
71937
71938           return drawLabels;
71939         }
71940
71941         var _layerEnabled$1 = false;
71942
71943         var _qaService$1;
71944
71945         function svgImproveOSM(projection, context, dispatch) {
71946           var throttledRedraw = throttle(function () {
71947             return dispatch.call('change');
71948           }, 1000);
71949
71950           var minZoom = 12;
71951           var touchLayer = select(null);
71952           var drawLayer = select(null);
71953           var layerVisible = false;
71954
71955           function markerPath(selection, klass) {
71956             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');
71957           } // Loosely-coupled improveOSM service for fetching issues
71958
71959
71960           function getService() {
71961             if (services.improveOSM && !_qaService$1) {
71962               _qaService$1 = services.improveOSM;
71963
71964               _qaService$1.on('loaded', throttledRedraw);
71965             } else if (!services.improveOSM && _qaService$1) {
71966               _qaService$1 = null;
71967             }
71968
71969             return _qaService$1;
71970           } // Show the markers
71971
71972
71973           function editOn() {
71974             if (!layerVisible) {
71975               layerVisible = true;
71976               drawLayer.style('display', 'block');
71977             }
71978           } // Immediately remove the markers and their touch targets
71979
71980
71981           function editOff() {
71982             if (layerVisible) {
71983               layerVisible = false;
71984               drawLayer.style('display', 'none');
71985               drawLayer.selectAll('.qaItem.improveOSM').remove();
71986               touchLayer.selectAll('.qaItem.improveOSM').remove();
71987             }
71988           } // Enable the layer.  This shows the markers and transitions them to visible.
71989
71990
71991           function layerOn() {
71992             editOn();
71993             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
71994               return dispatch.call('change');
71995             });
71996           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
71997
71998
71999           function layerOff() {
72000             throttledRedraw.cancel();
72001             drawLayer.interrupt();
72002             touchLayer.selectAll('.qaItem.improveOSM').remove();
72003             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72004               editOff();
72005               dispatch.call('change');
72006             });
72007           } // Update the issue markers
72008
72009
72010           function updateMarkers() {
72011             if (!layerVisible || !_layerEnabled$1) return;
72012             var service = getService();
72013             var selectedID = context.selectedErrorID();
72014             var data = service ? service.getItems(projection) : [];
72015             var getTransform = svgPointTransform(projection); // Draw markers..
72016
72017             var markers = drawLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
72018               return d.id;
72019             }); // exit
72020
72021             markers.exit().remove(); // enter
72022
72023             var markersEnter = markers.enter().append('g').attr('class', function (d) {
72024               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
72025             });
72026             markersEnter.append('polygon').call(markerPath, 'shadow');
72027             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
72028             markersEnter.append('polygon').attr('fill', 'currentColor').call(markerPath, 'qaItem-fill');
72029             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
72030               var picon = d.icon;
72031
72032               if (!picon) {
72033                 return '';
72034               } else {
72035                 var isMaki = /^maki-/.test(picon);
72036                 return "#".concat(picon).concat(isMaki ? '-11' : '');
72037               }
72038             }); // update
72039
72040             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
72041               return d.id === selectedID;
72042             }).attr('transform', getTransform); // Draw targets..
72043
72044             if (touchLayer.empty()) return;
72045             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
72046             var targets = touchLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
72047               return d.id;
72048             }); // exit
72049
72050             targets.exit().remove(); // enter/update
72051
72052             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
72053               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
72054             }).attr('transform', getTransform);
72055
72056             function sortY(a, b) {
72057               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
72058             }
72059           } // Draw the ImproveOSM layer and schedule loading issues and updating markers.
72060
72061
72062           function drawImproveOSM(selection) {
72063             var service = getService();
72064             var surface = context.surface();
72065
72066             if (surface && !surface.empty()) {
72067               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
72068             }
72069
72070             drawLayer = selection.selectAll('.layer-improveOSM').data(service ? [0] : []);
72071             drawLayer.exit().remove();
72072             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-improveOSM').style('display', _layerEnabled$1 ? 'block' : 'none').merge(drawLayer);
72073
72074             if (_layerEnabled$1) {
72075               if (service && ~~context.map().zoom() >= minZoom) {
72076                 editOn();
72077                 service.loadIssues(projection);
72078                 updateMarkers();
72079               } else {
72080                 editOff();
72081               }
72082             }
72083           } // Toggles the layer on and off
72084
72085
72086           drawImproveOSM.enabled = function (val) {
72087             if (!arguments.length) return _layerEnabled$1;
72088             _layerEnabled$1 = val;
72089
72090             if (_layerEnabled$1) {
72091               layerOn();
72092             } else {
72093               layerOff();
72094
72095               if (context.selectedErrorID()) {
72096                 context.enter(modeBrowse(context));
72097               }
72098             }
72099
72100             dispatch.call('change');
72101             return this;
72102           };
72103
72104           drawImproveOSM.supported = function () {
72105             return !!getService();
72106           };
72107
72108           return drawImproveOSM;
72109         }
72110
72111         var _layerEnabled$2 = false;
72112
72113         var _qaService$2;
72114
72115         function svgOsmose(projection, context, dispatch) {
72116           var throttledRedraw = throttle(function () {
72117             return dispatch.call('change');
72118           }, 1000);
72119
72120           var minZoom = 12;
72121           var touchLayer = select(null);
72122           var drawLayer = select(null);
72123           var layerVisible = false;
72124
72125           function markerPath(selection, klass) {
72126             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');
72127           } // Loosely-coupled osmose service for fetching issues
72128
72129
72130           function getService() {
72131             if (services.osmose && !_qaService$2) {
72132               _qaService$2 = services.osmose;
72133
72134               _qaService$2.on('loaded', throttledRedraw);
72135             } else if (!services.osmose && _qaService$2) {
72136               _qaService$2 = null;
72137             }
72138
72139             return _qaService$2;
72140           } // Show the markers
72141
72142
72143           function editOn() {
72144             if (!layerVisible) {
72145               layerVisible = true;
72146               drawLayer.style('display', 'block');
72147             }
72148           } // Immediately remove the markers and their touch targets
72149
72150
72151           function editOff() {
72152             if (layerVisible) {
72153               layerVisible = false;
72154               drawLayer.style('display', 'none');
72155               drawLayer.selectAll('.qaItem.osmose').remove();
72156               touchLayer.selectAll('.qaItem.osmose').remove();
72157             }
72158           } // Enable the layer.  This shows the markers and transitions them to visible.
72159
72160
72161           function layerOn() {
72162             editOn();
72163             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
72164               return dispatch.call('change');
72165             });
72166           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
72167
72168
72169           function layerOff() {
72170             throttledRedraw.cancel();
72171             drawLayer.interrupt();
72172             touchLayer.selectAll('.qaItem.osmose').remove();
72173             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72174               editOff();
72175               dispatch.call('change');
72176             });
72177           } // Update the issue markers
72178
72179
72180           function updateMarkers() {
72181             if (!layerVisible || !_layerEnabled$2) return;
72182             var service = getService();
72183             var selectedID = context.selectedErrorID();
72184             var data = service ? service.getItems(projection) : [];
72185             var getTransform = svgPointTransform(projection); // Draw markers..
72186
72187             var markers = drawLayer.selectAll('.qaItem.osmose').data(data, function (d) {
72188               return d.id;
72189             }); // exit
72190
72191             markers.exit().remove(); // enter
72192
72193             var markersEnter = markers.enter().append('g').attr('class', function (d) {
72194               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
72195             });
72196             markersEnter.append('polygon').call(markerPath, 'shadow');
72197             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
72198             markersEnter.append('polygon').attr('fill', function (d) {
72199               return service.getColor(d.item);
72200             }).call(markerPath, 'qaItem-fill');
72201             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
72202               var picon = d.icon;
72203
72204               if (!picon) {
72205                 return '';
72206               } else {
72207                 var isMaki = /^maki-/.test(picon);
72208                 return "#".concat(picon).concat(isMaki ? '-11' : '');
72209               }
72210             }); // update
72211
72212             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
72213               return d.id === selectedID;
72214             }).attr('transform', getTransform); // Draw targets..
72215
72216             if (touchLayer.empty()) return;
72217             var fillClass = context.getDebug('target') ? 'pink' : 'nocolor';
72218             var targets = touchLayer.selectAll('.qaItem.osmose').data(data, function (d) {
72219               return d.id;
72220             }); // exit
72221
72222             targets.exit().remove(); // enter/update
72223
72224             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
72225               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
72226             }).attr('transform', getTransform);
72227
72228             function sortY(a, b) {
72229               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
72230             }
72231           } // Draw the Osmose layer and schedule loading issues and updating markers.
72232
72233
72234           function drawOsmose(selection) {
72235             var service = getService();
72236             var surface = context.surface();
72237
72238             if (surface && !surface.empty()) {
72239               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
72240             }
72241
72242             drawLayer = selection.selectAll('.layer-osmose').data(service ? [0] : []);
72243             drawLayer.exit().remove();
72244             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-osmose').style('display', _layerEnabled$2 ? 'block' : 'none').merge(drawLayer);
72245
72246             if (_layerEnabled$2) {
72247               if (service && ~~context.map().zoom() >= minZoom) {
72248                 editOn();
72249                 service.loadIssues(projection);
72250                 updateMarkers();
72251               } else {
72252                 editOff();
72253               }
72254             }
72255           } // Toggles the layer on and off
72256
72257
72258           drawOsmose.enabled = function (val) {
72259             if (!arguments.length) return _layerEnabled$2;
72260             _layerEnabled$2 = val;
72261
72262             if (_layerEnabled$2) {
72263               // Strings supplied by Osmose fetched before showing layer for first time
72264               // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented
72265               // Also, If layer is toggled quickly multiple requests are sent
72266               getService().loadStrings().then(layerOn)["catch"](function (err) {
72267                 console.log(err); // eslint-disable-line no-console
72268               });
72269             } else {
72270               layerOff();
72271
72272               if (context.selectedErrorID()) {
72273                 context.enter(modeBrowse(context));
72274               }
72275             }
72276
72277             dispatch.call('change');
72278             return this;
72279           };
72280
72281           drawOsmose.supported = function () {
72282             return !!getService();
72283           };
72284
72285           return drawOsmose;
72286         }
72287
72288         function svgStreetside(projection, context, dispatch) {
72289           var throttledRedraw = throttle(function () {
72290             dispatch.call('change');
72291           }, 1000);
72292
72293           var minZoom = 14;
72294           var minMarkerZoom = 16;
72295           var minViewfieldZoom = 18;
72296           var layer = select(null);
72297           var _viewerYaw = 0;
72298           var _selectedSequence = null;
72299
72300           var _streetside;
72301           /**
72302            * init().
72303            */
72304
72305
72306           function init() {
72307             if (svgStreetside.initialized) return; // run once
72308
72309             svgStreetside.enabled = false;
72310             svgStreetside.initialized = true;
72311           }
72312           /**
72313            * getService().
72314            */
72315
72316
72317           function getService() {
72318             if (services.streetside && !_streetside) {
72319               _streetside = services.streetside;
72320
72321               _streetside.event.on('viewerChanged.svgStreetside', viewerChanged).on('loadedImages.svgStreetside', throttledRedraw);
72322             } else if (!services.streetside && _streetside) {
72323               _streetside = null;
72324             }
72325
72326             return _streetside;
72327           }
72328           /**
72329            * showLayer().
72330            */
72331
72332
72333           function showLayer() {
72334             var service = getService();
72335             if (!service) return;
72336             editOn();
72337             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
72338               dispatch.call('change');
72339             });
72340           }
72341           /**
72342            * hideLayer().
72343            */
72344
72345
72346           function hideLayer() {
72347             throttledRedraw.cancel();
72348             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
72349           }
72350           /**
72351            * editOn().
72352            */
72353
72354
72355           function editOn() {
72356             layer.style('display', 'block');
72357           }
72358           /**
72359            * editOff().
72360            */
72361
72362
72363           function editOff() {
72364             layer.selectAll('.viewfield-group').remove();
72365             layer.style('display', 'none');
72366           }
72367           /**
72368            * click() Handles 'bubble' point click event.
72369            */
72370
72371
72372           function click(d3_event, d) {
72373             var service = getService();
72374             if (!service) return; // try to preserve the viewer rotation when staying on the same sequence
72375
72376             if (d.sequenceKey !== _selectedSequence) {
72377               _viewerYaw = 0; // reset
72378             }
72379
72380             _selectedSequence = d.sequenceKey;
72381             service.ensureViewerLoaded(context).then(function () {
72382               service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
72383             });
72384             context.map().centerEase(d.loc);
72385           }
72386           /**
72387            * mouseover().
72388            */
72389
72390
72391           function mouseover(d3_event, d) {
72392             var service = getService();
72393             if (service) service.setStyles(context, d);
72394           }
72395           /**
72396            * mouseout().
72397            */
72398
72399
72400           function mouseout() {
72401             var service = getService();
72402             if (service) service.setStyles(context, null);
72403           }
72404           /**
72405            * transform().
72406            */
72407
72408
72409           function transform(d) {
72410             var t = svgPointTransform(projection)(d);
72411             var rot = d.ca + _viewerYaw;
72412
72413             if (rot) {
72414               t += ' rotate(' + Math.floor(rot) + ',0,0)';
72415             }
72416
72417             return t;
72418           }
72419
72420           function viewerChanged() {
72421             var service = getService();
72422             if (!service) return;
72423             var viewer = service.viewer();
72424             if (!viewer) return; // update viewfield rotation
72425
72426             _viewerYaw = viewer.getYaw(); // avoid updating if the map is currently transformed
72427             // e.g. during drags or easing.
72428
72429             if (context.map().isTransformed()) return;
72430             layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
72431           }
72432
72433           context.photos().on('change.streetside', update);
72434
72435           function filterBubbles(bubbles) {
72436             var fromDate = context.photos().fromDate();
72437             var toDate = context.photos().toDate();
72438             var usernames = context.photos().usernames();
72439
72440             if (fromDate) {
72441               var fromTimestamp = new Date(fromDate).getTime();
72442               bubbles = bubbles.filter(function (bubble) {
72443                 return new Date(bubble.captured_at).getTime() >= fromTimestamp;
72444               });
72445             }
72446
72447             if (toDate) {
72448               var toTimestamp = new Date(toDate).getTime();
72449               bubbles = bubbles.filter(function (bubble) {
72450                 return new Date(bubble.captured_at).getTime() <= toTimestamp;
72451               });
72452             }
72453
72454             if (usernames) {
72455               bubbles = bubbles.filter(function (bubble) {
72456                 return usernames.indexOf(bubble.captured_by) !== -1;
72457               });
72458             }
72459
72460             return bubbles;
72461           }
72462
72463           function filterSequences(sequences) {
72464             var fromDate = context.photos().fromDate();
72465             var toDate = context.photos().toDate();
72466             var usernames = context.photos().usernames();
72467
72468             if (fromDate) {
72469               var fromTimestamp = new Date(fromDate).getTime();
72470               sequences = sequences.filter(function (sequences) {
72471                 return new Date(sequences.properties.captured_at).getTime() >= fromTimestamp;
72472               });
72473             }
72474
72475             if (toDate) {
72476               var toTimestamp = new Date(toDate).getTime();
72477               sequences = sequences.filter(function (sequences) {
72478                 return new Date(sequences.properties.captured_at).getTime() <= toTimestamp;
72479               });
72480             }
72481
72482             if (usernames) {
72483               sequences = sequences.filter(function (sequences) {
72484                 return usernames.indexOf(sequences.properties.captured_by) !== -1;
72485               });
72486             }
72487
72488             return sequences;
72489           }
72490           /**
72491            * update().
72492            */
72493
72494
72495           function update() {
72496             var viewer = context.container().select('.photoviewer');
72497             var selected = viewer.empty() ? undefined : viewer.datum();
72498             var z = ~~context.map().zoom();
72499             var showMarkers = z >= minMarkerZoom;
72500             var showViewfields = z >= minViewfieldZoom;
72501             var service = getService();
72502             var sequences = [];
72503             var bubbles = [];
72504
72505             if (context.photos().showsPanoramic()) {
72506               sequences = service ? service.sequences(projection) : [];
72507               bubbles = service && showMarkers ? service.bubbles(projection) : [];
72508               sequences = filterSequences(sequences);
72509               bubbles = filterBubbles(bubbles);
72510             }
72511
72512             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
72513               return d.properties.key;
72514             }); // exit
72515
72516             traces.exit().remove(); // enter/update
72517
72518             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
72519             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(bubbles, function (d) {
72520               // force reenter once bubbles are attached to a sequence
72521               return d.key + (d.sequenceKey ? 'v1' : 'v0');
72522             }); // exit
72523
72524             groups.exit().remove(); // enter
72525
72526             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
72527             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72528
72529             var markers = groups.merge(groupsEnter).sort(function (a, b) {
72530               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
72531             }).attr('transform', transform).select('.viewfield-scale');
72532             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72533             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72534             viewfields.exit().remove(); // viewfields may or may not be drawn...
72535             // but if they are, draw below the circles
72536
72537             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72538
72539             function viewfieldPath() {
72540               var d = this.parentNode.__data__;
72541
72542               if (d.pano) {
72543                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72544               } else {
72545                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72546               }
72547             }
72548           }
72549           /**
72550            * drawImages()
72551            * drawImages is the method that is returned (and that runs) every time 'svgStreetside()' is called.
72552            * 'svgStreetside()' is called from index.js
72553            */
72554
72555
72556           function drawImages(selection) {
72557             var enabled = svgStreetside.enabled;
72558             var service = getService();
72559             layer = selection.selectAll('.layer-streetside-images').data(service ? [0] : []);
72560             layer.exit().remove();
72561             var layerEnter = layer.enter().append('g').attr('class', 'layer-streetside-images').style('display', enabled ? 'block' : 'none');
72562             layerEnter.append('g').attr('class', 'sequences');
72563             layerEnter.append('g').attr('class', 'markers');
72564             layer = layerEnter.merge(layer);
72565
72566             if (enabled) {
72567               if (service && ~~context.map().zoom() >= minZoom) {
72568                 editOn();
72569                 update();
72570                 service.loadBubbles(projection);
72571               } else {
72572                 editOff();
72573               }
72574             }
72575           }
72576           /**
72577            * drawImages.enabled().
72578            */
72579
72580
72581           drawImages.enabled = function (_) {
72582             if (!arguments.length) return svgStreetside.enabled;
72583             svgStreetside.enabled = _;
72584
72585             if (svgStreetside.enabled) {
72586               showLayer();
72587             } else {
72588               hideLayer();
72589             }
72590
72591             dispatch.call('change');
72592             return this;
72593           };
72594           /**
72595            * drawImages.supported().
72596            */
72597
72598
72599           drawImages.supported = function () {
72600             return !!getService();
72601           };
72602
72603           init();
72604           return drawImages;
72605         }
72606
72607         function svgMapillaryImages(projection, context, dispatch) {
72608           var throttledRedraw = throttle(function () {
72609             dispatch.call('change');
72610           }, 1000);
72611
72612           var minZoom = 12;
72613           var minMarkerZoom = 16;
72614           var minViewfieldZoom = 18;
72615           var layer = select(null);
72616
72617           var _mapillary;
72618
72619           var viewerCompassAngle;
72620
72621           function init() {
72622             if (svgMapillaryImages.initialized) return; // run once
72623
72624             svgMapillaryImages.enabled = false;
72625             svgMapillaryImages.initialized = true;
72626           }
72627
72628           function getService() {
72629             if (services.mapillary && !_mapillary) {
72630               _mapillary = services.mapillary;
72631
72632               _mapillary.event.on('loadedImages', throttledRedraw);
72633             } else if (!services.mapillary && _mapillary) {
72634               _mapillary = null;
72635             }
72636
72637             return _mapillary;
72638           }
72639
72640           function showLayer() {
72641             var service = getService();
72642             if (!service) return;
72643             editOn();
72644             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
72645               dispatch.call('change');
72646             });
72647           }
72648
72649           function hideLayer() {
72650             throttledRedraw.cancel();
72651             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
72652           }
72653
72654           function editOn() {
72655             layer.style('display', 'block');
72656           }
72657
72658           function editOff() {
72659             layer.selectAll('.viewfield-group').remove();
72660             layer.style('display', 'none');
72661           }
72662
72663           function click(d3_event, d) {
72664             var service = getService();
72665             if (!service) return;
72666             service.ensureViewerLoaded(context).then(function () {
72667               service.selectImage(context, d.key).showViewer(context);
72668             });
72669             context.map().centerEase(d.loc);
72670           }
72671
72672           function mouseover(d) {
72673             var service = getService();
72674             if (service) service.setStyles(context, d);
72675           }
72676
72677           function mouseout() {
72678             var service = getService();
72679             if (service) service.setStyles(context, null);
72680           }
72681
72682           function transform(d) {
72683             var t = svgPointTransform(projection)(d);
72684
72685             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
72686               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
72687             } else if (d.ca) {
72688               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
72689             }
72690
72691             return t;
72692           }
72693
72694           context.photos().on('change.mapillary_images', update);
72695
72696           function filterImages(images) {
72697             var showsPano = context.photos().showsPanoramic();
72698             var showsFlat = context.photos().showsFlat();
72699             var fromDate = context.photos().fromDate();
72700             var toDate = context.photos().toDate();
72701             var usernames = context.photos().usernames();
72702
72703             if (!showsPano || !showsFlat) {
72704               images = images.filter(function (image) {
72705                 if (image.pano) return showsPano;
72706                 return showsFlat;
72707               });
72708             }
72709
72710             if (fromDate) {
72711               var fromTimestamp = new Date(fromDate).getTime();
72712               images = images.filter(function (image) {
72713                 return new Date(image.captured_at).getTime() >= fromTimestamp;
72714               });
72715             }
72716
72717             if (toDate) {
72718               var toTimestamp = new Date(toDate).getTime();
72719               images = images.filter(function (image) {
72720                 return new Date(image.captured_at).getTime() <= toTimestamp;
72721               });
72722             }
72723
72724             if (usernames) {
72725               images = images.filter(function (image) {
72726                 return usernames.indexOf(image.captured_by) !== -1;
72727               });
72728             }
72729
72730             return images;
72731           }
72732
72733           function filterSequences(sequences, service) {
72734             var showsPano = context.photos().showsPanoramic();
72735             var showsFlat = context.photos().showsFlat();
72736             var fromDate = context.photos().fromDate();
72737             var toDate = context.photos().toDate();
72738             var usernames = context.photos().usernames();
72739
72740             if (!showsPano || !showsFlat) {
72741               sequences = sequences.filter(function (sequence) {
72742                 if (sequence.properties.hasOwnProperty('pano')) {
72743                   if (sequence.properties.pano) return showsPano;
72744                   return showsFlat;
72745                 } else {
72746                   // if the sequence doesn't specify pano or not, search its images
72747                   var cProps = sequence.properties.coordinateProperties;
72748
72749                   if (cProps && cProps.image_keys && cProps.image_keys.length > 0) {
72750                     for (var index in cProps.image_keys) {
72751                       var imageKey = cProps.image_keys[index];
72752                       var image = service.cachedImage(imageKey);
72753
72754                       if (image && image.hasOwnProperty('pano')) {
72755                         if (image.pano) return showsPano;
72756                         return showsFlat;
72757                       }
72758                     }
72759                   }
72760                 }
72761
72762                 return false;
72763               });
72764             }
72765
72766             if (fromDate) {
72767               var fromTimestamp = new Date(fromDate).getTime();
72768               sequences = sequences.filter(function (sequence) {
72769                 return new Date(sequence.properties.captured_at).getTime() >= fromTimestamp;
72770               });
72771             }
72772
72773             if (toDate) {
72774               var toTimestamp = new Date(toDate).getTime();
72775               sequences = sequences.filter(function (sequence) {
72776                 return new Date(sequence.properties.captured_at).getTime() <= toTimestamp;
72777               });
72778             }
72779
72780             if (usernames) {
72781               sequences = sequences.filter(function (sequence) {
72782                 return usernames.indexOf(sequence.properties.username) !== -1;
72783               });
72784             }
72785
72786             return sequences;
72787           }
72788
72789           function update() {
72790             var z = ~~context.map().zoom();
72791             var showMarkers = z >= minMarkerZoom;
72792             var showViewfields = z >= minViewfieldZoom;
72793             var service = getService();
72794             var sequences = service ? service.sequences(projection) : [];
72795             var images = service && showMarkers ? service.images(projection) : [];
72796             images = filterImages(images);
72797             sequences = filterSequences(sequences, service);
72798             service.filterViewer(context);
72799             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
72800               return d.properties.key;
72801             }); // exit
72802
72803             traces.exit().remove(); // enter/update
72804
72805             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
72806             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
72807               return d.key;
72808             }); // exit
72809
72810             groups.exit().remove(); // enter
72811
72812             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
72813             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72814
72815             var markers = groups.merge(groupsEnter).sort(function (a, b) {
72816               return b.loc[1] - a.loc[1]; // sort Y
72817             }).attr('transform', transform).select('.viewfield-scale');
72818             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72819             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72820             viewfields.exit().remove();
72821             viewfields.enter() // viewfields may or may not be drawn...
72822             .insert('path', 'circle') // but if they are, draw below the circles
72823             .attr('class', 'viewfield').classed('pano', function () {
72824               return this.parentNode.__data__.pano;
72825             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72826
72827             function viewfieldPath() {
72828               var d = this.parentNode.__data__;
72829
72830               if (d.pano) {
72831                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72832               } else {
72833                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72834               }
72835             }
72836           }
72837
72838           function drawImages(selection) {
72839             var enabled = svgMapillaryImages.enabled;
72840             var service = getService();
72841             layer = selection.selectAll('.layer-mapillary').data(service ? [0] : []);
72842             layer.exit().remove();
72843             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary').style('display', enabled ? 'block' : 'none');
72844             layerEnter.append('g').attr('class', 'sequences');
72845             layerEnter.append('g').attr('class', 'markers');
72846             layer = layerEnter.merge(layer);
72847
72848             if (enabled) {
72849               if (service && ~~context.map().zoom() >= minZoom) {
72850                 editOn();
72851                 update();
72852                 service.loadImages(projection);
72853               } else {
72854                 editOff();
72855               }
72856             }
72857           }
72858
72859           drawImages.enabled = function (_) {
72860             if (!arguments.length) return svgMapillaryImages.enabled;
72861             svgMapillaryImages.enabled = _;
72862
72863             if (svgMapillaryImages.enabled) {
72864               showLayer();
72865             } else {
72866               hideLayer();
72867             }
72868
72869             dispatch.call('change');
72870             return this;
72871           };
72872
72873           drawImages.supported = function () {
72874             return !!getService();
72875           };
72876
72877           init();
72878           return drawImages;
72879         }
72880
72881         function svgMapillaryPosition(projection, context) {
72882           var throttledRedraw = throttle(function () {
72883             update();
72884           }, 1000);
72885
72886           var minZoom = 12;
72887           var minViewfieldZoom = 18;
72888           var layer = select(null);
72889
72890           var _mapillary;
72891
72892           var viewerCompassAngle;
72893
72894           function init() {
72895             if (svgMapillaryPosition.initialized) return; // run once
72896
72897             svgMapillaryPosition.initialized = true;
72898           }
72899
72900           function getService() {
72901             if (services.mapillary && !_mapillary) {
72902               _mapillary = services.mapillary;
72903
72904               _mapillary.event.on('nodeChanged', throttledRedraw);
72905
72906               _mapillary.event.on('bearingChanged', function (e) {
72907                 viewerCompassAngle = e;
72908                 if (context.map().isTransformed()) return;
72909                 layer.selectAll('.viewfield-group.currentView').filter(function (d) {
72910                   return d.pano;
72911                 }).attr('transform', transform);
72912               });
72913             } else if (!services.mapillary && _mapillary) {
72914               _mapillary = null;
72915             }
72916
72917             return _mapillary;
72918           }
72919
72920           function editOn() {
72921             layer.style('display', 'block');
72922           }
72923
72924           function editOff() {
72925             layer.selectAll('.viewfield-group').remove();
72926             layer.style('display', 'none');
72927           }
72928
72929           function transform(d) {
72930             var t = svgPointTransform(projection)(d);
72931
72932             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
72933               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
72934             } else if (d.ca) {
72935               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
72936             }
72937
72938             return t;
72939           }
72940
72941           function update() {
72942             var z = ~~context.map().zoom();
72943             var showViewfields = z >= minViewfieldZoom;
72944             var service = getService();
72945             var node = service && service.getActiveImage();
72946             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(node ? [node] : [], function (d) {
72947               return d.key;
72948             }); // exit
72949
72950             groups.exit().remove(); // enter
72951
72952             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group currentView highlighted');
72953             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72954
72955             var markers = groups.merge(groupsEnter).attr('transform', transform).select('.viewfield-scale');
72956             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72957             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72958             viewfields.exit().remove();
72959             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').classed('pano', function () {
72960               return this.parentNode.__data__.pano;
72961             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72962
72963             function viewfieldPath() {
72964               var d = this.parentNode.__data__;
72965
72966               if (d.pano) {
72967                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72968               } else {
72969                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72970               }
72971             }
72972           }
72973
72974           function drawImages(selection) {
72975             var service = getService();
72976             layer = selection.selectAll('.layer-mapillary-position').data(service ? [0] : []);
72977             layer.exit().remove();
72978             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary-position');
72979             layerEnter.append('g').attr('class', 'markers');
72980             layer = layerEnter.merge(layer);
72981
72982             if (service && ~~context.map().zoom() >= minZoom) {
72983               editOn();
72984               update();
72985             } else {
72986               editOff();
72987             }
72988           }
72989
72990           drawImages.enabled = function () {
72991             update();
72992             return this;
72993           };
72994
72995           drawImages.supported = function () {
72996             return !!getService();
72997           };
72998
72999           init();
73000           return drawImages;
73001         }
73002
73003         function svgMapillarySigns(projection, context, dispatch) {
73004           var throttledRedraw = throttle(function () {
73005             dispatch.call('change');
73006           }, 1000);
73007
73008           var minZoom = 12;
73009           var layer = select(null);
73010
73011           var _mapillary;
73012
73013           function init() {
73014             if (svgMapillarySigns.initialized) return; // run once
73015
73016             svgMapillarySigns.enabled = false;
73017             svgMapillarySigns.initialized = true;
73018           }
73019
73020           function getService() {
73021             if (services.mapillary && !_mapillary) {
73022               _mapillary = services.mapillary;
73023
73024               _mapillary.event.on('loadedSigns', throttledRedraw);
73025             } else if (!services.mapillary && _mapillary) {
73026               _mapillary = null;
73027             }
73028
73029             return _mapillary;
73030           }
73031
73032           function showLayer() {
73033             var service = getService();
73034             if (!service) return;
73035             service.loadSignResources(context);
73036             editOn();
73037           }
73038
73039           function hideLayer() {
73040             throttledRedraw.cancel();
73041             editOff();
73042           }
73043
73044           function editOn() {
73045             layer.style('display', 'block');
73046           }
73047
73048           function editOff() {
73049             layer.selectAll('.icon-sign').remove();
73050             layer.style('display', 'none');
73051           }
73052
73053           function click(d3_event, d) {
73054             var service = getService();
73055             if (!service) return;
73056             context.map().centerEase(d.loc);
73057             var selectedImageKey = service.getSelectedImageKey();
73058             var imageKey;
73059             var highlightedDetection; // Pick one of the images the sign was detected in,
73060             // preference given to an image already selected.
73061
73062             d.detections.forEach(function (detection) {
73063               if (!imageKey || selectedImageKey === detection.image_key) {
73064                 imageKey = detection.image_key;
73065                 highlightedDetection = detection;
73066               }
73067             });
73068
73069             if (imageKey === selectedImageKey) {
73070               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
73071             } else {
73072               service.ensureViewerLoaded(context).then(function () {
73073                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
73074               });
73075             }
73076           }
73077
73078           function update() {
73079             var service = getService();
73080             var data = service ? service.signs(projection) : [];
73081             var selectedImageKey = service.getSelectedImageKey();
73082             var transform = svgPointTransform(projection);
73083             var signs = layer.selectAll('.icon-sign').data(data, function (d) {
73084               return d.key;
73085             }); // exit
73086
73087             signs.exit().remove(); // enter
73088
73089             var enter = signs.enter().append('g').attr('class', 'icon-sign icon-detected').on('click', click);
73090             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
73091               return '#' + d.value;
73092             });
73093             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
73094
73095             signs.merge(enter).attr('transform', transform).classed('currentView', function (d) {
73096               return d.detections.some(function (detection) {
73097                 return detection.image_key === selectedImageKey;
73098               });
73099             }).sort(function (a, b) {
73100               var aSelected = a.detections.some(function (detection) {
73101                 return detection.image_key === selectedImageKey;
73102               });
73103               var bSelected = b.detections.some(function (detection) {
73104                 return detection.image_key === selectedImageKey;
73105               });
73106
73107               if (aSelected === bSelected) {
73108                 return b.loc[1] - a.loc[1]; // sort Y
73109               } else if (aSelected) {
73110                 return 1;
73111               }
73112
73113               return -1;
73114             });
73115           }
73116
73117           function drawSigns(selection) {
73118             var enabled = svgMapillarySigns.enabled;
73119             var service = getService();
73120             layer = selection.selectAll('.layer-mapillary-signs').data(service ? [0] : []);
73121             layer.exit().remove();
73122             layer = layer.enter().append('g').attr('class', 'layer-mapillary-signs layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
73123
73124             if (enabled) {
73125               if (service && ~~context.map().zoom() >= minZoom) {
73126                 editOn();
73127                 update();
73128                 service.loadSigns(projection);
73129                 service.showSignDetections(true);
73130               } else {
73131                 editOff();
73132               }
73133             } else if (service) {
73134               service.showSignDetections(false);
73135             }
73136           }
73137
73138           drawSigns.enabled = function (_) {
73139             if (!arguments.length) return svgMapillarySigns.enabled;
73140             svgMapillarySigns.enabled = _;
73141
73142             if (svgMapillarySigns.enabled) {
73143               showLayer();
73144             } else {
73145               hideLayer();
73146             }
73147
73148             dispatch.call('change');
73149             return this;
73150           };
73151
73152           drawSigns.supported = function () {
73153             return !!getService();
73154           };
73155
73156           init();
73157           return drawSigns;
73158         }
73159
73160         function svgMapillaryMapFeatures(projection, context, dispatch) {
73161           var throttledRedraw = throttle(function () {
73162             dispatch.call('change');
73163           }, 1000);
73164
73165           var minZoom = 12;
73166           var layer = select(null);
73167
73168           var _mapillary;
73169
73170           function init() {
73171             if (svgMapillaryMapFeatures.initialized) return; // run once
73172
73173             svgMapillaryMapFeatures.enabled = false;
73174             svgMapillaryMapFeatures.initialized = true;
73175           }
73176
73177           function getService() {
73178             if (services.mapillary && !_mapillary) {
73179               _mapillary = services.mapillary;
73180
73181               _mapillary.event.on('loadedMapFeatures', throttledRedraw);
73182             } else if (!services.mapillary && _mapillary) {
73183               _mapillary = null;
73184             }
73185
73186             return _mapillary;
73187           }
73188
73189           function showLayer() {
73190             var service = getService();
73191             if (!service) return;
73192             service.loadObjectResources(context);
73193             editOn();
73194           }
73195
73196           function hideLayer() {
73197             throttledRedraw.cancel();
73198             editOff();
73199           }
73200
73201           function editOn() {
73202             layer.style('display', 'block');
73203           }
73204
73205           function editOff() {
73206             layer.selectAll('.icon-map-feature').remove();
73207             layer.style('display', 'none');
73208           }
73209
73210           function click(d3_event, d) {
73211             var service = getService();
73212             if (!service) return;
73213             context.map().centerEase(d.loc);
73214             var selectedImageKey = service.getSelectedImageKey();
73215             var imageKey;
73216             var highlightedDetection; // Pick one of the images the map feature was detected in,
73217             // preference given to an image already selected.
73218
73219             d.detections.forEach(function (detection) {
73220               if (!imageKey || selectedImageKey === detection.image_key) {
73221                 imageKey = detection.image_key;
73222                 highlightedDetection = detection;
73223               }
73224             });
73225
73226             if (imageKey === selectedImageKey) {
73227               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
73228             } else {
73229               service.ensureViewerLoaded(context).then(function () {
73230                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
73231               });
73232             }
73233           }
73234
73235           function update() {
73236             var service = getService();
73237             var data = service ? service.mapFeatures(projection) : [];
73238             var selectedImageKey = service && service.getSelectedImageKey();
73239             var transform = svgPointTransform(projection);
73240             var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
73241               return d.key;
73242             }); // exit
73243
73244             mapFeatures.exit().remove(); // enter
73245
73246             var enter = mapFeatures.enter().append('g').attr('class', 'icon-map-feature icon-detected').on('click', click);
73247             enter.append('title').text(function (d) {
73248               var id = d.value.replace(/--/g, '.').replace(/-/g, '_');
73249               return _t('mapillary_map_features.' + id);
73250             });
73251             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
73252               if (d.value === 'object--billboard') {
73253                 // no billboard icon right now, so use the advertisement icon
73254                 return '#object--sign--advertisement';
73255               }
73256
73257               return '#' + d.value;
73258             });
73259             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
73260
73261             mapFeatures.merge(enter).attr('transform', transform).classed('currentView', function (d) {
73262               return d.detections.some(function (detection) {
73263                 return detection.image_key === selectedImageKey;
73264               });
73265             }).sort(function (a, b) {
73266               var aSelected = a.detections.some(function (detection) {
73267                 return detection.image_key === selectedImageKey;
73268               });
73269               var bSelected = b.detections.some(function (detection) {
73270                 return detection.image_key === selectedImageKey;
73271               });
73272
73273               if (aSelected === bSelected) {
73274                 return b.loc[1] - a.loc[1]; // sort Y
73275               } else if (aSelected) {
73276                 return 1;
73277               }
73278
73279               return -1;
73280             });
73281           }
73282
73283           function drawMapFeatures(selection) {
73284             var enabled = svgMapillaryMapFeatures.enabled;
73285             var service = getService();
73286             layer = selection.selectAll('.layer-mapillary-map-features').data(service ? [0] : []);
73287             layer.exit().remove();
73288             layer = layer.enter().append('g').attr('class', 'layer-mapillary-map-features layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
73289
73290             if (enabled) {
73291               if (service && ~~context.map().zoom() >= minZoom) {
73292                 editOn();
73293                 update();
73294                 service.loadMapFeatures(projection);
73295                 service.showFeatureDetections(true);
73296               } else {
73297                 editOff();
73298               }
73299             } else if (service) {
73300               service.showFeatureDetections(false);
73301             }
73302           }
73303
73304           drawMapFeatures.enabled = function (_) {
73305             if (!arguments.length) return svgMapillaryMapFeatures.enabled;
73306             svgMapillaryMapFeatures.enabled = _;
73307
73308             if (svgMapillaryMapFeatures.enabled) {
73309               showLayer();
73310             } else {
73311               hideLayer();
73312             }
73313
73314             dispatch.call('change');
73315             return this;
73316           };
73317
73318           drawMapFeatures.supported = function () {
73319             return !!getService();
73320           };
73321
73322           init();
73323           return drawMapFeatures;
73324         }
73325
73326         function svgOpenstreetcamImages(projection, context, dispatch) {
73327           var throttledRedraw = throttle(function () {
73328             dispatch.call('change');
73329           }, 1000);
73330
73331           var minZoom = 12;
73332           var minMarkerZoom = 16;
73333           var minViewfieldZoom = 18;
73334           var layer = select(null);
73335
73336           var _openstreetcam;
73337
73338           function init() {
73339             if (svgOpenstreetcamImages.initialized) return; // run once
73340
73341             svgOpenstreetcamImages.enabled = false;
73342             svgOpenstreetcamImages.initialized = true;
73343           }
73344
73345           function getService() {
73346             if (services.openstreetcam && !_openstreetcam) {
73347               _openstreetcam = services.openstreetcam;
73348
73349               _openstreetcam.event.on('loadedImages', throttledRedraw);
73350             } else if (!services.openstreetcam && _openstreetcam) {
73351               _openstreetcam = null;
73352             }
73353
73354             return _openstreetcam;
73355           }
73356
73357           function showLayer() {
73358             var service = getService();
73359             if (!service) return;
73360             editOn();
73361             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
73362               dispatch.call('change');
73363             });
73364           }
73365
73366           function hideLayer() {
73367             throttledRedraw.cancel();
73368             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
73369           }
73370
73371           function editOn() {
73372             layer.style('display', 'block');
73373           }
73374
73375           function editOff() {
73376             layer.selectAll('.viewfield-group').remove();
73377             layer.style('display', 'none');
73378           }
73379
73380           function click(d3_event, d) {
73381             var service = getService();
73382             if (!service) return;
73383             service.ensureViewerLoaded(context).then(function () {
73384               service.selectImage(context, d.key).showViewer(context);
73385             });
73386             context.map().centerEase(d.loc);
73387           }
73388
73389           function mouseover(d3_event, d) {
73390             var service = getService();
73391             if (service) service.setStyles(context, d);
73392           }
73393
73394           function mouseout() {
73395             var service = getService();
73396             if (service) service.setStyles(context, null);
73397           }
73398
73399           function transform(d) {
73400             var t = svgPointTransform(projection)(d);
73401
73402             if (d.ca) {
73403               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
73404             }
73405
73406             return t;
73407           }
73408
73409           context.photos().on('change.openstreetcam_images', update);
73410
73411           function filterImages(images) {
73412             var fromDate = context.photos().fromDate();
73413             var toDate = context.photos().toDate();
73414             var usernames = context.photos().usernames();
73415
73416             if (fromDate) {
73417               var fromTimestamp = new Date(fromDate).getTime();
73418               images = images.filter(function (item) {
73419                 return new Date(item.captured_at).getTime() >= fromTimestamp;
73420               });
73421             }
73422
73423             if (toDate) {
73424               var toTimestamp = new Date(toDate).getTime();
73425               images = images.filter(function (item) {
73426                 return new Date(item.captured_at).getTime() <= toTimestamp;
73427               });
73428             }
73429
73430             if (usernames) {
73431               images = images.filter(function (item) {
73432                 return usernames.indexOf(item.captured_by) !== -1;
73433               });
73434             }
73435
73436             return images;
73437           }
73438
73439           function filterSequences(sequences) {
73440             var fromDate = context.photos().fromDate();
73441             var toDate = context.photos().toDate();
73442             var usernames = context.photos().usernames();
73443
73444             if (fromDate) {
73445               var fromTimestamp = new Date(fromDate).getTime();
73446               sequences = sequences.filter(function (image) {
73447                 return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
73448               });
73449             }
73450
73451             if (toDate) {
73452               var toTimestamp = new Date(toDate).getTime();
73453               sequences = sequences.filter(function (image) {
73454                 return new Date(image.properties.captured_at).getTime() <= toTimestamp;
73455               });
73456             }
73457
73458             if (usernames) {
73459               sequences = sequences.filter(function (image) {
73460                 return usernames.indexOf(image.properties.captured_by) !== -1;
73461               });
73462             }
73463
73464             return sequences;
73465           }
73466
73467           function update() {
73468             var viewer = context.container().select('.photoviewer');
73469             var selected = viewer.empty() ? undefined : viewer.datum();
73470             var z = ~~context.map().zoom();
73471             var showMarkers = z >= minMarkerZoom;
73472             var showViewfields = z >= minViewfieldZoom;
73473             var service = getService();
73474             var sequences = [];
73475             var images = [];
73476
73477             if (context.photos().showsFlat()) {
73478               sequences = service ? service.sequences(projection) : [];
73479               images = service && showMarkers ? service.images(projection) : [];
73480               sequences = filterSequences(sequences);
73481               images = filterImages(images);
73482             }
73483
73484             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
73485               return d.properties.key;
73486             }); // exit
73487
73488             traces.exit().remove(); // enter/update
73489
73490             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
73491             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
73492               return d.key;
73493             }); // exit
73494
73495             groups.exit().remove(); // enter
73496
73497             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
73498             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
73499
73500             var markers = groups.merge(groupsEnter).sort(function (a, b) {
73501               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1]; // sort Y
73502             }).attr('transform', transform).select('.viewfield-scale');
73503             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
73504             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
73505             viewfields.exit().remove();
73506             viewfields.enter() // viewfields may or may not be drawn...
73507             .insert('path', 'circle') // but if they are, draw below the circles
73508             .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');
73509           }
73510
73511           function drawImages(selection) {
73512             var enabled = svgOpenstreetcamImages.enabled,
73513                 service = getService();
73514             layer = selection.selectAll('.layer-openstreetcam').data(service ? [0] : []);
73515             layer.exit().remove();
73516             var layerEnter = layer.enter().append('g').attr('class', 'layer-openstreetcam').style('display', enabled ? 'block' : 'none');
73517             layerEnter.append('g').attr('class', 'sequences');
73518             layerEnter.append('g').attr('class', 'markers');
73519             layer = layerEnter.merge(layer);
73520
73521             if (enabled) {
73522               if (service && ~~context.map().zoom() >= minZoom) {
73523                 editOn();
73524                 update();
73525                 service.loadImages(projection);
73526               } else {
73527                 editOff();
73528               }
73529             }
73530           }
73531
73532           drawImages.enabled = function (_) {
73533             if (!arguments.length) return svgOpenstreetcamImages.enabled;
73534             svgOpenstreetcamImages.enabled = _;
73535
73536             if (svgOpenstreetcamImages.enabled) {
73537               showLayer();
73538             } else {
73539               hideLayer();
73540             }
73541
73542             dispatch.call('change');
73543             return this;
73544           };
73545
73546           drawImages.supported = function () {
73547             return !!getService();
73548           };
73549
73550           init();
73551           return drawImages;
73552         }
73553
73554         function svgOsm(projection, context, dispatch) {
73555           var enabled = true;
73556
73557           function drawOsm(selection) {
73558             selection.selectAll('.layer-osm').data(['covered', 'areas', 'lines', 'points', 'labels']).enter().append('g').attr('class', function (d) {
73559               return 'layer-osm ' + d;
73560             });
73561             selection.selectAll('.layer-osm.points').selectAll('.points-group').data(['points', 'midpoints', 'vertices', 'turns']).enter().append('g').attr('class', function (d) {
73562               return 'points-group ' + d;
73563             });
73564           }
73565
73566           function showLayer() {
73567             var layer = context.surface().selectAll('.data-layer.osm');
73568             layer.interrupt();
73569             layer.classed('disabled', false).style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
73570               dispatch.call('change');
73571             });
73572           }
73573
73574           function hideLayer() {
73575             var layer = context.surface().selectAll('.data-layer.osm');
73576             layer.interrupt();
73577             layer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
73578               layer.classed('disabled', true);
73579               dispatch.call('change');
73580             });
73581           }
73582
73583           drawOsm.enabled = function (val) {
73584             if (!arguments.length) return enabled;
73585             enabled = val;
73586
73587             if (enabled) {
73588               showLayer();
73589             } else {
73590               hideLayer();
73591             }
73592
73593             dispatch.call('change');
73594             return this;
73595           };
73596
73597           return drawOsm;
73598         }
73599
73600         var _notesEnabled = false;
73601
73602         var _osmService;
73603
73604         function svgNotes(projection, context, dispatch$1) {
73605           if (!dispatch$1) {
73606             dispatch$1 = dispatch('change');
73607           }
73608
73609           var throttledRedraw = throttle(function () {
73610             dispatch$1.call('change');
73611           }, 1000);
73612
73613           var minZoom = 12;
73614           var touchLayer = select(null);
73615           var drawLayer = select(null);
73616           var _notesVisible = false;
73617
73618           function markerPath(selection, klass) {
73619             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');
73620           } // Loosely-coupled osm service for fetching notes.
73621
73622
73623           function getService() {
73624             if (services.osm && !_osmService) {
73625               _osmService = services.osm;
73626
73627               _osmService.on('loadedNotes', throttledRedraw);
73628             } else if (!services.osm && _osmService) {
73629               _osmService = null;
73630             }
73631
73632             return _osmService;
73633           } // Show the notes
73634
73635
73636           function editOn() {
73637             if (!_notesVisible) {
73638               _notesVisible = true;
73639               drawLayer.style('display', 'block');
73640             }
73641           } // Immediately remove the notes and their touch targets
73642
73643
73644           function editOff() {
73645             if (_notesVisible) {
73646               _notesVisible = false;
73647               drawLayer.style('display', 'none');
73648               drawLayer.selectAll('.note').remove();
73649               touchLayer.selectAll('.note').remove();
73650             }
73651           } // Enable the layer.  This shows the notes and transitions them to visible.
73652
73653
73654           function layerOn() {
73655             editOn();
73656             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
73657               dispatch$1.call('change');
73658             });
73659           } // Disable the layer.  This transitions the layer invisible and then hides the notes.
73660
73661
73662           function layerOff() {
73663             throttledRedraw.cancel();
73664             drawLayer.interrupt();
73665             touchLayer.selectAll('.note').remove();
73666             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
73667               editOff();
73668               dispatch$1.call('change');
73669             });
73670           } // Update the note markers
73671
73672
73673           function updateMarkers() {
73674             if (!_notesVisible || !_notesEnabled) return;
73675             var service = getService();
73676             var selectedID = context.selectedNoteID();
73677             var data = service ? service.notes(projection) : [];
73678             var getTransform = svgPointTransform(projection); // Draw markers..
73679
73680             var notes = drawLayer.selectAll('.note').data(data, function (d) {
73681               return d.status + d.id;
73682             }); // exit
73683
73684             notes.exit().remove(); // enter
73685
73686             var notesEnter = notes.enter().append('g').attr('class', function (d) {
73687               return 'note note-' + d.id + ' ' + d.status;
73688             }).classed('new', function (d) {
73689               return d.id < 0;
73690             });
73691             notesEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
73692             notesEnter.append('path').call(markerPath, 'shadow');
73693             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');
73694             notesEnter.selectAll('.icon-annotation').data(function (d) {
73695               return [d];
73696             }).enter().append('use').attr('class', 'icon-annotation').attr('width', '10px').attr('height', '10px').attr('x', '-3px').attr('y', '-19px').attr('xlink:href', function (d) {
73697               return '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
73698             }); // update
73699
73700             notes.merge(notesEnter).sort(sortY).classed('selected', function (d) {
73701               var mode = context.mode();
73702               var isMoving = mode && mode.id === 'drag-note'; // no shadows when dragging
73703
73704               return !isMoving && d.id === selectedID;
73705             }).attr('transform', getTransform); // Draw targets..
73706
73707             if (touchLayer.empty()) return;
73708             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73709             var targets = touchLayer.selectAll('.note').data(data, function (d) {
73710               return d.id;
73711             }); // exit
73712
73713             targets.exit().remove(); // enter/update
73714
73715             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
73716               var newClass = d.id < 0 ? 'new' : '';
73717               return 'note target note-' + d.id + ' ' + fillClass + newClass;
73718             }).attr('transform', getTransform);
73719
73720             function sortY(a, b) {
73721               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
73722             }
73723           } // Draw the notes layer and schedule loading notes and updating markers.
73724
73725
73726           function drawNotes(selection) {
73727             var service = getService();
73728             var surface = context.surface();
73729
73730             if (surface && !surface.empty()) {
73731               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
73732             }
73733
73734             drawLayer = selection.selectAll('.layer-notes').data(service ? [0] : []);
73735             drawLayer.exit().remove();
73736             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-notes').style('display', _notesEnabled ? 'block' : 'none').merge(drawLayer);
73737
73738             if (_notesEnabled) {
73739               if (service && ~~context.map().zoom() >= minZoom) {
73740                 editOn();
73741                 service.loadNotes(projection);
73742                 updateMarkers();
73743               } else {
73744                 editOff();
73745               }
73746             }
73747           } // Toggles the layer on and off
73748
73749
73750           drawNotes.enabled = function (val) {
73751             if (!arguments.length) return _notesEnabled;
73752             _notesEnabled = val;
73753
73754             if (_notesEnabled) {
73755               layerOn();
73756             } else {
73757               layerOff();
73758
73759               if (context.selectedNoteID()) {
73760                 context.enter(modeBrowse(context));
73761               }
73762             }
73763
73764             dispatch$1.call('change');
73765             return this;
73766           };
73767
73768           return drawNotes;
73769         }
73770
73771         function svgTouch() {
73772           function drawTouch(selection) {
73773             selection.selectAll('.layer-touch').data(['areas', 'lines', 'points', 'turns', 'markers']).enter().append('g').attr('class', function (d) {
73774               return 'layer-touch ' + d;
73775             });
73776           }
73777
73778           return drawTouch;
73779         }
73780
73781         function refresh(selection, node) {
73782           var cr = node.getBoundingClientRect();
73783           var prop = [cr.width, cr.height];
73784           selection.property('__dimensions__', prop);
73785           return prop;
73786         }
73787
73788         function utilGetDimensions(selection, force) {
73789           if (!selection || selection.empty()) {
73790             return [0, 0];
73791           }
73792
73793           var node = selection.node(),
73794               cached = selection.property('__dimensions__');
73795           return !cached || force ? refresh(selection, node) : cached;
73796         }
73797         function utilSetDimensions(selection, dimensions) {
73798           if (!selection || selection.empty()) {
73799             return selection;
73800           }
73801
73802           var node = selection.node();
73803
73804           if (dimensions === null) {
73805             refresh(selection, node);
73806             return selection;
73807           }
73808
73809           return selection.property('__dimensions__', [dimensions[0], dimensions[1]]).attr('width', dimensions[0]).attr('height', dimensions[1]);
73810         }
73811
73812         function svgLayers(projection, context) {
73813           var dispatch$1 = dispatch('change');
73814           var svg = select(null);
73815           var _layers = [{
73816             id: 'osm',
73817             layer: svgOsm(projection, context, dispatch$1)
73818           }, {
73819             id: 'notes',
73820             layer: svgNotes(projection, context, dispatch$1)
73821           }, {
73822             id: 'data',
73823             layer: svgData(projection, context, dispatch$1)
73824           }, {
73825             id: 'keepRight',
73826             layer: svgKeepRight(projection, context, dispatch$1)
73827           }, {
73828             id: 'improveOSM',
73829             layer: svgImproveOSM(projection, context, dispatch$1)
73830           }, {
73831             id: 'osmose',
73832             layer: svgOsmose(projection, context, dispatch$1)
73833           }, {
73834             id: 'streetside',
73835             layer: svgStreetside(projection, context, dispatch$1)
73836           }, {
73837             id: 'mapillary',
73838             layer: svgMapillaryImages(projection, context, dispatch$1)
73839           }, {
73840             id: 'mapillary-position',
73841             layer: svgMapillaryPosition(projection, context)
73842           }, {
73843             id: 'mapillary-map-features',
73844             layer: svgMapillaryMapFeatures(projection, context, dispatch$1)
73845           }, {
73846             id: 'mapillary-signs',
73847             layer: svgMapillarySigns(projection, context, dispatch$1)
73848           }, {
73849             id: 'openstreetcam',
73850             layer: svgOpenstreetcamImages(projection, context, dispatch$1)
73851           }, {
73852             id: 'debug',
73853             layer: svgDebug(projection, context)
73854           }, {
73855             id: 'geolocate',
73856             layer: svgGeolocate(projection)
73857           }, {
73858             id: 'touch',
73859             layer: svgTouch()
73860           }];
73861
73862           function drawLayers(selection) {
73863             svg = selection.selectAll('.surface').data([0]);
73864             svg = svg.enter().append('svg').attr('class', 'surface').merge(svg);
73865             var defs = svg.selectAll('.surface-defs').data([0]);
73866             defs.enter().append('defs').attr('class', 'surface-defs');
73867             var groups = svg.selectAll('.data-layer').data(_layers);
73868             groups.exit().remove();
73869             groups.enter().append('g').attr('class', function (d) {
73870               return 'data-layer ' + d.id;
73871             }).merge(groups).each(function (d) {
73872               select(this).call(d.layer);
73873             });
73874           }
73875
73876           drawLayers.all = function () {
73877             return _layers;
73878           };
73879
73880           drawLayers.layer = function (id) {
73881             var obj = _layers.find(function (o) {
73882               return o.id === id;
73883             });
73884
73885             return obj && obj.layer;
73886           };
73887
73888           drawLayers.only = function (what) {
73889             var arr = [].concat(what);
73890
73891             var all = _layers.map(function (layer) {
73892               return layer.id;
73893             });
73894
73895             return drawLayers.remove(utilArrayDifference(all, arr));
73896           };
73897
73898           drawLayers.remove = function (what) {
73899             var arr = [].concat(what);
73900             arr.forEach(function (id) {
73901               _layers = _layers.filter(function (o) {
73902                 return o.id !== id;
73903               });
73904             });
73905             dispatch$1.call('change');
73906             return this;
73907           };
73908
73909           drawLayers.add = function (what) {
73910             var arr = [].concat(what);
73911             arr.forEach(function (obj) {
73912               if ('id' in obj && 'layer' in obj) {
73913                 _layers.push(obj);
73914               }
73915             });
73916             dispatch$1.call('change');
73917             return this;
73918           };
73919
73920           drawLayers.dimensions = function (val) {
73921             if (!arguments.length) return utilGetDimensions(svg);
73922             utilSetDimensions(svg, val);
73923             return this;
73924           };
73925
73926           return utilRebind(drawLayers, dispatch$1, 'on');
73927         }
73928
73929         function svgLines(projection, context) {
73930           var detected = utilDetect();
73931           var highway_stack = {
73932             motorway: 0,
73933             motorway_link: 1,
73934             trunk: 2,
73935             trunk_link: 3,
73936             primary: 4,
73937             primary_link: 5,
73938             secondary: 6,
73939             tertiary: 7,
73940             unclassified: 8,
73941             residential: 9,
73942             service: 10,
73943             footway: 11
73944           };
73945
73946           function drawTargets(selection, graph, entities, filter) {
73947             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73948             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
73949             var getPath = svgPath(projection).geojson;
73950             var activeID = context.activeID();
73951             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
73952
73953             var data = {
73954               targets: [],
73955               nopes: []
73956             };
73957             entities.forEach(function (way) {
73958               var features = svgSegmentWay(way, graph, activeID);
73959               data.targets.push.apply(data.targets, features.passive);
73960               data.nopes.push.apply(data.nopes, features.active);
73961             }); // Targets allow hover and vertex snapping
73962
73963             var targetData = data.targets.filter(getPath);
73964             var targets = selection.selectAll('.line.target-allowed').filter(function (d) {
73965               return filter(d.properties.entity);
73966             }).data(targetData, function key(d) {
73967               return d.id;
73968             }); // exit
73969
73970             targets.exit().remove();
73971
73972             var segmentWasEdited = function segmentWasEdited(d) {
73973               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
73974
73975               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
73976                 return false;
73977               }
73978
73979               return d.properties.nodes.some(function (n) {
73980                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
73981               });
73982             }; // enter/update
73983
73984
73985             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
73986               return 'way line target target-allowed ' + targetClass + d.id;
73987             }).classed('segment-edited', segmentWasEdited); // NOPE
73988
73989             var nopeData = data.nopes.filter(getPath);
73990             var nopes = selection.selectAll('.line.target-nope').filter(function (d) {
73991               return filter(d.properties.entity);
73992             }).data(nopeData, function key(d) {
73993               return d.id;
73994             }); // exit
73995
73996             nopes.exit().remove(); // enter/update
73997
73998             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
73999               return 'way line target target-nope ' + nopeClass + d.id;
74000             }).classed('segment-edited', segmentWasEdited);
74001           }
74002
74003           function drawLines(selection, graph, entities, filter) {
74004             var base = context.history().base();
74005
74006             function waystack(a, b) {
74007               var selected = context.selectedIDs();
74008               var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
74009               var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
74010
74011               if (a.tags.highway) {
74012                 scoreA -= highway_stack[a.tags.highway];
74013               }
74014
74015               if (b.tags.highway) {
74016                 scoreB -= highway_stack[b.tags.highway];
74017               }
74018
74019               return scoreA - scoreB;
74020             }
74021
74022             function drawLineGroup(selection, klass, isSelected) {
74023               // Note: Don't add `.selected` class in draw modes
74024               var mode = context.mode();
74025               var isDrawing = mode && /^draw/.test(mode.id);
74026               var selectedClass = !isDrawing && isSelected ? 'selected ' : '';
74027               var lines = selection.selectAll('path').filter(filter).data(getPathData(isSelected), osmEntity.key);
74028               lines.exit().remove(); // Optimization: Call expensive TagClasses only on enter selection. This
74029               // works because osmEntity.key is defined to include the entity v attribute.
74030
74031               lines.enter().append('path').attr('class', function (d) {
74032                 var prefix = 'way line'; // if this line isn't styled by its own tags
74033
74034                 if (!d.hasInterestingTags()) {
74035                   var parentRelations = graph.parentRelations(d);
74036                   var parentMultipolygons = parentRelations.filter(function (relation) {
74037                     return relation.isMultipolygon();
74038                   }); // and if it's a member of at least one multipolygon relation
74039
74040                   if (parentMultipolygons.length > 0 && // and only multipolygon relations
74041                   parentRelations.length === parentMultipolygons.length) {
74042                     // then fudge the classes to style this as an area edge
74043                     prefix = 'relation area';
74044                   }
74045                 }
74046
74047                 var oldMPClass = oldMultiPolygonOuters[d.id] ? 'old-multipolygon ' : '';
74048                 return prefix + ' ' + klass + ' ' + selectedClass + oldMPClass + d.id;
74049               }).classed('added', function (d) {
74050                 return !base.entities[d.id];
74051               }).classed('geometry-edited', function (d) {
74052                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
74053               }).classed('retagged', function (d) {
74054                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74055               }).call(svgTagClasses()).merge(lines).sort(waystack).attr('d', getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
74056               return selection;
74057             }
74058
74059             function getPathData(isSelected) {
74060               return function () {
74061                 var layer = this.parentNode.__data__;
74062                 var data = pathdata[layer] || [];
74063                 return data.filter(function (d) {
74064                   if (isSelected) return context.selectedIDs().indexOf(d.id) !== -1;else return context.selectedIDs().indexOf(d.id) === -1;
74065                 });
74066               };
74067             }
74068
74069             function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
74070               var markergroup = layergroup.selectAll('g.' + groupclass).data([pathclass]);
74071               markergroup = markergroup.enter().append('g').attr('class', groupclass).merge(markergroup);
74072               var markers = markergroup.selectAll('path').filter(filter).data(function data() {
74073                 return groupdata[this.parentNode.__data__] || [];
74074               }, function key(d) {
74075                 return [d.id, d.index];
74076               });
74077               markers.exit().remove();
74078               markers = markers.enter().append('path').attr('class', pathclass).merge(markers).attr('marker-mid', marker).attr('d', function (d) {
74079                 return d.d;
74080               });
74081
74082               if (detected.ie) {
74083                 markers.each(function () {
74084                   this.parentNode.insertBefore(this, this);
74085                 });
74086               }
74087             }
74088
74089             var getPath = svgPath(projection, graph);
74090             var ways = [];
74091             var onewaydata = {};
74092             var sideddata = {};
74093             var oldMultiPolygonOuters = {};
74094
74095             for (var i = 0; i < entities.length; i++) {
74096               var entity = entities[i];
74097               var outer = osmOldMultipolygonOuterMember(entity, graph);
74098
74099               if (outer) {
74100                 ways.push(entity.mergeTags(outer.tags));
74101                 oldMultiPolygonOuters[outer.id] = true;
74102               } else if (entity.geometry(graph) === 'line') {
74103                 ways.push(entity);
74104               }
74105             }
74106
74107             ways = ways.filter(getPath);
74108             var pathdata = utilArrayGroupBy(ways, function (way) {
74109               return way.layer();
74110             });
74111             Object.keys(pathdata).forEach(function (k) {
74112               var v = pathdata[k];
74113               var onewayArr = v.filter(function (d) {
74114                 return d.isOneWay();
74115               });
74116               var onewaySegments = svgMarkerSegments(projection, graph, 35, function shouldReverse(entity) {
74117                 return entity.tags.oneway === '-1';
74118               }, function bothDirections(entity) {
74119                 return entity.tags.oneway === 'reversible' || entity.tags.oneway === 'alternating';
74120               });
74121               onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
74122               var sidedArr = v.filter(function (d) {
74123                 return d.isSided();
74124               });
74125               var sidedSegments = svgMarkerSegments(projection, graph, 30, function shouldReverse() {
74126                 return false;
74127               }, function bothDirections() {
74128                 return false;
74129               });
74130               sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
74131             });
74132             var covered = selection.selectAll('.layer-osm.covered'); // under areas
74133
74134             var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
74135
74136             var touchLayer = selection.selectAll('.layer-touch.lines'); // Draw lines..
74137
74138             [covered, uncovered].forEach(function (selection) {
74139               var range$1 = selection === covered ? range(-10, 0) : range(0, 11);
74140               var layergroup = selection.selectAll('g.layergroup').data(range$1);
74141               layergroup = layergroup.enter().append('g').attr('class', function (d) {
74142                 return 'layergroup layer' + String(d);
74143               }).merge(layergroup);
74144               layergroup.selectAll('g.linegroup').data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted']).enter().append('g').attr('class', function (d) {
74145                 return 'linegroup line-' + d;
74146               });
74147               layergroup.selectAll('g.line-shadow').call(drawLineGroup, 'shadow', false);
74148               layergroup.selectAll('g.line-casing').call(drawLineGroup, 'casing', false);
74149               layergroup.selectAll('g.line-stroke').call(drawLineGroup, 'stroke', false);
74150               layergroup.selectAll('g.line-shadow-highlighted').call(drawLineGroup, 'shadow', true);
74151               layergroup.selectAll('g.line-casing-highlighted').call(drawLineGroup, 'casing', true);
74152               layergroup.selectAll('g.line-stroke-highlighted').call(drawLineGroup, 'stroke', true);
74153               addMarkers(layergroup, 'oneway', 'onewaygroup', onewaydata, 'url(#ideditor-oneway-marker)');
74154               addMarkers(layergroup, 'sided', 'sidedgroup', sideddata, function marker(d) {
74155                 var category = graph.entity(d.id).sidednessIdentifier();
74156                 return 'url(#ideditor-sided-marker-' + category + ')';
74157               });
74158             }); // Draw touch targets..
74159
74160             touchLayer.call(drawTargets, graph, ways, filter);
74161           }
74162
74163           return drawLines;
74164         }
74165
74166         function svgMidpoints(projection, context) {
74167           var targetRadius = 8;
74168
74169           function drawTargets(selection, graph, entities, filter) {
74170             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74171             var getTransform = svgPointTransform(projection).geojson;
74172             var data = entities.map(function (midpoint) {
74173               return {
74174                 type: 'Feature',
74175                 id: midpoint.id,
74176                 properties: {
74177                   target: true,
74178                   entity: midpoint
74179                 },
74180                 geometry: {
74181                   type: 'Point',
74182                   coordinates: midpoint.loc
74183                 }
74184               };
74185             });
74186             var targets = selection.selectAll('.midpoint.target').filter(function (d) {
74187               return filter(d.properties.entity);
74188             }).data(data, function key(d) {
74189               return d.id;
74190             }); // exit
74191
74192             targets.exit().remove(); // enter/update
74193
74194             targets.enter().append('circle').attr('r', targetRadius).merge(targets).attr('class', function (d) {
74195               return 'node midpoint target ' + fillClass + d.id;
74196             }).attr('transform', getTransform);
74197           }
74198
74199           function drawMidpoints(selection, graph, entities, filter, extent) {
74200             var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
74201             var touchLayer = selection.selectAll('.layer-touch.points');
74202             var mode = context.mode();
74203
74204             if (mode && mode.id !== 'select' || !context.map().withinEditableZoom()) {
74205               drawLayer.selectAll('.midpoint').remove();
74206               touchLayer.selectAll('.midpoint.target').remove();
74207               return;
74208             }
74209
74210             var poly = extent.polygon();
74211             var midpoints = {};
74212
74213             for (var i = 0; i < entities.length; i++) {
74214               var entity = entities[i];
74215               if (entity.type !== 'way') continue;
74216               if (!filter(entity)) continue;
74217               if (context.selectedIDs().indexOf(entity.id) < 0) continue;
74218               var nodes = graph.childNodes(entity);
74219
74220               for (var j = 0; j < nodes.length - 1; j++) {
74221                 var a = nodes[j];
74222                 var b = nodes[j + 1];
74223                 var id = [a.id, b.id].sort().join('-');
74224
74225                 if (midpoints[id]) {
74226                   midpoints[id].parents.push(entity);
74227                 } else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
74228                   var point = geoVecInterp(a.loc, b.loc, 0.5);
74229                   var loc = null;
74230
74231                   if (extent.intersects(point)) {
74232                     loc = point;
74233                   } else {
74234                     for (var k = 0; k < 4; k++) {
74235                       point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
74236
74237                       if (point && geoVecLength(projection(a.loc), projection(point)) > 20 && geoVecLength(projection(b.loc), projection(point)) > 20) {
74238                         loc = point;
74239                         break;
74240                       }
74241                     }
74242                   }
74243
74244                   if (loc) {
74245                     midpoints[id] = {
74246                       type: 'midpoint',
74247                       id: id,
74248                       loc: loc,
74249                       edge: [a.id, b.id],
74250                       parents: [entity]
74251                     };
74252                   }
74253                 }
74254               }
74255             }
74256
74257             function midpointFilter(d) {
74258               if (midpoints[d.id]) return true;
74259
74260               for (var i = 0; i < d.parents.length; i++) {
74261                 if (filter(d.parents[i])) {
74262                   return true;
74263                 }
74264               }
74265
74266               return false;
74267             }
74268
74269             var groups = drawLayer.selectAll('.midpoint').filter(midpointFilter).data(Object.values(midpoints), function (d) {
74270               return d.id;
74271             });
74272             groups.exit().remove();
74273             var enter = groups.enter().insert('g', ':first-child').attr('class', 'midpoint');
74274             enter.append('polygon').attr('points', '-6,8 10,0 -6,-8').attr('class', 'shadow');
74275             enter.append('polygon').attr('points', '-3,4 5,0 -3,-4').attr('class', 'fill');
74276             groups = groups.merge(enter).attr('transform', function (d) {
74277               var translate = svgPointTransform(projection);
74278               var a = graph.entity(d.edge[0]);
74279               var b = graph.entity(d.edge[1]);
74280               var angle = geoAngle(a, b, projection) * (180 / Math.PI);
74281               return translate(d) + ' rotate(' + angle + ')';
74282             }).call(svgTagClasses().tags(function (d) {
74283               return d.parents[0].tags;
74284             })); // Propagate data bindings.
74285
74286             groups.select('polygon.shadow');
74287             groups.select('polygon.fill'); // Draw touch targets..
74288
74289             touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
74290           }
74291
74292           return drawMidpoints;
74293         }
74294
74295         function svgPoints(projection, context) {
74296           function markerPath(selection, klass) {
74297             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');
74298           }
74299
74300           function sortY(a, b) {
74301             return b.loc[1] - a.loc[1];
74302           } // Avoid exit/enter if we're just moving stuff around.
74303           // The node will get a new version but we only need to run the update selection.
74304
74305
74306           function fastEntityKey(d) {
74307             var mode = context.mode();
74308             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74309             return isMoving ? d.id : osmEntity.key(d);
74310           }
74311
74312           function drawTargets(selection, graph, entities, filter) {
74313             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74314             var getTransform = svgPointTransform(projection).geojson;
74315             var activeID = context.activeID();
74316             var data = [];
74317             entities.forEach(function (node) {
74318               if (activeID === node.id) return; // draw no target on the activeID
74319
74320               data.push({
74321                 type: 'Feature',
74322                 id: node.id,
74323                 properties: {
74324                   target: true,
74325                   entity: node
74326                 },
74327                 geometry: node.asGeoJSON()
74328               });
74329             });
74330             var targets = selection.selectAll('.point.target').filter(function (d) {
74331               return filter(d.properties.entity);
74332             }).data(data, function key(d) {
74333               return d.id;
74334             }); // exit
74335
74336             targets.exit().remove(); // enter/update
74337
74338             targets.enter().append('rect').attr('x', -10).attr('y', -26).attr('width', 20).attr('height', 30).merge(targets).attr('class', function (d) {
74339               return 'node point target ' + fillClass + d.id;
74340             }).attr('transform', getTransform);
74341           }
74342
74343           function drawPoints(selection, graph, entities, filter) {
74344             var wireframe = context.surface().classed('fill-wireframe');
74345             var zoom = geoScaleToZoom(projection.scale());
74346             var base = context.history().base(); // Points with a direction will render as vertices at higher zooms..
74347
74348             function renderAsPoint(entity) {
74349               return entity.geometry(graph) === 'point' && !(zoom >= 18 && entity.directions(graph, projection).length);
74350             } // All points will render as vertices in wireframe mode too..
74351
74352
74353             var points = wireframe ? [] : entities.filter(renderAsPoint);
74354             points.sort(sortY);
74355             var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
74356             var touchLayer = selection.selectAll('.layer-touch.points'); // Draw points..
74357
74358             var groups = drawLayer.selectAll('g.point').filter(filter).data(points, fastEntityKey);
74359             groups.exit().remove();
74360             var enter = groups.enter().append('g').attr('class', function (d) {
74361               return 'node point ' + d.id;
74362             }).order();
74363             enter.append('path').call(markerPath, 'shadow');
74364             enter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
74365             enter.append('path').call(markerPath, 'stroke');
74366             enter.append('use').attr('transform', 'translate(-5, -19)').attr('class', 'icon').attr('width', '11px').attr('height', '11px');
74367             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('added', function (d) {
74368               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
74369             }).classed('moved', function (d) {
74370               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
74371             }).classed('retagged', function (d) {
74372               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74373             }).call(svgTagClasses());
74374             groups.select('.shadow'); // propagate bound data
74375
74376             groups.select('.stroke'); // propagate bound data
74377
74378             groups.select('.icon') // propagate bound data
74379             .attr('xlink:href', function (entity) {
74380               var preset = _mainPresetIndex.match(entity, graph);
74381               var picon = preset && preset.icon;
74382
74383               if (!picon) {
74384                 return '';
74385               } else {
74386                 var isMaki = /^maki-/.test(picon);
74387                 return '#' + picon + (isMaki ? '-11' : '');
74388               }
74389             }); // Draw touch targets..
74390
74391             touchLayer.call(drawTargets, graph, points, filter);
74392           }
74393
74394           return drawPoints;
74395         }
74396
74397         function svgTurns(projection, context) {
74398           function icon(turn) {
74399             var u = turn.u ? '-u' : '';
74400             if (turn.no) return '#iD-turn-no' + u;
74401             if (turn.only) return '#iD-turn-only' + u;
74402             return '#iD-turn-yes' + u;
74403           }
74404
74405           function drawTurns(selection, graph, turns) {
74406             function turnTransform(d) {
74407               var pxRadius = 50;
74408               var toWay = graph.entity(d.to.way);
74409               var toPoints = graph.childNodes(toWay).map(function (n) {
74410                 return n.loc;
74411               }).map(projection);
74412               var toLength = geoPathLength(toPoints);
74413               var mid = toLength / 2; // midpoint of destination way
74414
74415               var toNode = graph.entity(d.to.node);
74416               var toVertex = graph.entity(d.to.vertex);
74417               var a = geoAngle(toVertex, toNode, projection);
74418               var o = projection(toVertex.loc);
74419               var r = d.u ? 0 // u-turn: no radius
74420               : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius
74421               : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways
74422
74423               return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')';
74424             }
74425
74426             var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
74427             var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns..
74428
74429             var groups = drawLayer.selectAll('g.turn').data(turns, function (d) {
74430               return d.key;
74431             }); // exit
74432
74433             groups.exit().remove(); // enter
74434
74435             var groupsEnter = groups.enter().append('g').attr('class', function (d) {
74436               return 'turn ' + d.key;
74437             });
74438             var turnsEnter = groupsEnter.filter(function (d) {
74439               return !d.u;
74440             });
74441             turnsEnter.append('rect').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74442             turnsEnter.append('use').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74443             var uEnter = groupsEnter.filter(function (d) {
74444               return d.u;
74445             });
74446             uEnter.append('circle').attr('r', '16');
74447             uEnter.append('use').attr('transform', 'translate(-16, -16)').attr('width', '32').attr('height', '32'); // update
74448
74449             groups = groups.merge(groupsEnter).attr('opacity', function (d) {
74450               return d.direct === false ? '0.7' : null;
74451             }).attr('transform', turnTransform);
74452             groups.select('use').attr('xlink:href', icon);
74453             groups.select('rect'); // propagate bound data
74454
74455             groups.select('circle'); // propagate bound data
74456             // Draw touch targets..
74457
74458             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74459             groups = touchLayer.selectAll('g.turn').data(turns, function (d) {
74460               return d.key;
74461             }); // exit
74462
74463             groups.exit().remove(); // enter
74464
74465             groupsEnter = groups.enter().append('g').attr('class', function (d) {
74466               return 'turn ' + d.key;
74467             });
74468             turnsEnter = groupsEnter.filter(function (d) {
74469               return !d.u;
74470             });
74471             turnsEnter.append('rect').attr('class', 'target ' + fillClass).attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74472             uEnter = groupsEnter.filter(function (d) {
74473               return d.u;
74474             });
74475             uEnter.append('circle').attr('class', 'target ' + fillClass).attr('r', '16'); // update
74476
74477             groups = groups.merge(groupsEnter).attr('transform', turnTransform);
74478             groups.select('rect'); // propagate bound data
74479
74480             groups.select('circle'); // propagate bound data
74481
74482             return this;
74483           }
74484
74485           return drawTurns;
74486         }
74487
74488         function svgVertices(projection, context) {
74489           var radiuses = {
74490             //       z16-, z17,   z18+,  w/icon
74491             shadow: [6, 7.5, 7.5, 12],
74492             stroke: [2.5, 3.5, 3.5, 8],
74493             fill: [1, 1.5, 1.5, 1.5]
74494           };
74495
74496           var _currHoverTarget;
74497
74498           var _currPersistent = {};
74499           var _currHover = {};
74500           var _prevHover = {};
74501           var _currSelected = {};
74502           var _prevSelected = {};
74503           var _radii = {};
74504
74505           function sortY(a, b) {
74506             return b.loc[1] - a.loc[1];
74507           } // Avoid exit/enter if we're just moving stuff around.
74508           // The node will get a new version but we only need to run the update selection.
74509
74510
74511           function fastEntityKey(d) {
74512             var mode = context.mode();
74513             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74514             return isMoving ? d.id : osmEntity.key(d);
74515           }
74516
74517           function draw(selection, graph, vertices, sets, filter) {
74518             sets = sets || {
74519               selected: {},
74520               important: {},
74521               hovered: {}
74522             };
74523             var icons = {};
74524             var directions = {};
74525             var wireframe = context.surface().classed('fill-wireframe');
74526             var zoom = geoScaleToZoom(projection.scale());
74527             var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
74528             var activeID = context.activeID();
74529             var base = context.history().base();
74530
74531             function getIcon(d) {
74532               // always check latest entity, as fastEntityKey avoids enter/exit now
74533               var entity = graph.entity(d.id);
74534               if (entity.id in icons) return icons[entity.id];
74535               icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
74536               return icons[entity.id];
74537             } // memoize directions results, return false for empty arrays (for use in filter)
74538
74539
74540             function getDirections(entity) {
74541               if (entity.id in directions) return directions[entity.id];
74542               var angles = entity.directions(graph, projection);
74543               directions[entity.id] = angles.length ? angles : false;
74544               return angles;
74545             }
74546
74547             function updateAttributes(selection) {
74548               ['shadow', 'stroke', 'fill'].forEach(function (klass) {
74549                 var rads = radiuses[klass];
74550                 selection.selectAll('.' + klass).each(function (entity) {
74551                   var i = z && getIcon(entity);
74552                   var r = rads[i ? 3 : z]; // slightly increase the size of unconnected endpoints #3775
74553
74554                   if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
74555                     r += 1.5;
74556                   }
74557
74558                   if (klass === 'shadow') {
74559                     // remember this value, so we don't need to
74560                     _radii[entity.id] = r; // recompute it when we draw the touch targets
74561                   }
74562
74563                   select(this).attr('r', r).attr('visibility', i && klass === 'fill' ? 'hidden' : null);
74564                 });
74565               });
74566             }
74567
74568             vertices.sort(sortY);
74569             var groups = selection.selectAll('g.vertex').filter(filter).data(vertices, fastEntityKey); // exit
74570
74571             groups.exit().remove(); // enter
74572
74573             var enter = groups.enter().append('g').attr('class', function (d) {
74574               return 'node vertex ' + d.id;
74575             }).order();
74576             enter.append('circle').attr('class', 'shadow');
74577             enter.append('circle').attr('class', 'stroke'); // Vertices with tags get a fill.
74578
74579             enter.filter(function (d) {
74580               return d.hasInterestingTags();
74581             }).append('circle').attr('class', 'fill'); // update
74582
74583             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('sibling', function (d) {
74584               return d.id in sets.selected;
74585             }).classed('shared', function (d) {
74586               return graph.isShared(d);
74587             }).classed('endpoint', function (d) {
74588               return d.isEndpoint(graph);
74589             }).classed('added', function (d) {
74590               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
74591             }).classed('moved', function (d) {
74592               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
74593             }).classed('retagged', function (d) {
74594               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74595             }).call(updateAttributes); // Vertices with icons get a `use`.
74596
74597             var iconUse = groups.selectAll('.icon').data(function data(d) {
74598               return zoom >= 17 && getIcon(d) ? [d] : [];
74599             }, fastEntityKey); // exit
74600
74601             iconUse.exit().remove(); // enter
74602
74603             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) {
74604               var picon = getIcon(d);
74605               var isMaki = /^maki-/.test(picon);
74606               return '#' + picon + (isMaki ? '-11' : '');
74607             }); // Vertices with directions get viewfields
74608
74609             var dgroups = groups.selectAll('.viewfieldgroup').data(function data(d) {
74610               return zoom >= 18 && getDirections(d) ? [d] : [];
74611             }, fastEntityKey); // exit
74612
74613             dgroups.exit().remove(); // enter/update
74614
74615             dgroups = dgroups.enter().insert('g', '.shadow').attr('class', 'viewfieldgroup').merge(dgroups);
74616             var viewfields = dgroups.selectAll('.viewfield').data(getDirections, function key(d) {
74617               return osmEntity.key(d);
74618             }); // exit
74619
74620             viewfields.exit().remove(); // enter/update
74621
74622             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) {
74623               return 'rotate(' + d + ')';
74624             });
74625           }
74626
74627           function drawTargets(selection, graph, entities, filter) {
74628             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74629             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
74630             var getTransform = svgPointTransform(projection).geojson;
74631             var activeID = context.activeID();
74632             var data = {
74633               targets: [],
74634               nopes: []
74635             };
74636             entities.forEach(function (node) {
74637               if (activeID === node.id) return; // draw no target on the activeID
74638
74639               var vertexType = svgPassiveVertex(node, graph, activeID);
74640
74641               if (vertexType !== 0) {
74642                 // passive or adjacent - allow to connect
74643                 data.targets.push({
74644                   type: 'Feature',
74645                   id: node.id,
74646                   properties: {
74647                     target: true,
74648                     entity: node
74649                   },
74650                   geometry: node.asGeoJSON()
74651                 });
74652               } else {
74653                 data.nopes.push({
74654                   type: 'Feature',
74655                   id: node.id + '-nope',
74656                   properties: {
74657                     nope: true,
74658                     target: true,
74659                     entity: node
74660                   },
74661                   geometry: node.asGeoJSON()
74662                 });
74663               }
74664             }); // Targets allow hover and vertex snapping
74665
74666             var targets = selection.selectAll('.vertex.target-allowed').filter(function (d) {
74667               return filter(d.properties.entity);
74668             }).data(data.targets, function key(d) {
74669               return d.id;
74670             }); // exit
74671
74672             targets.exit().remove(); // enter/update
74673
74674             targets.enter().append('circle').attr('r', function (d) {
74675               return _radii[d.id] || radiuses.shadow[3];
74676             }).merge(targets).attr('class', function (d) {
74677               return 'node vertex target target-allowed ' + targetClass + d.id;
74678             }).attr('transform', getTransform); // NOPE
74679
74680             var nopes = selection.selectAll('.vertex.target-nope').filter(function (d) {
74681               return filter(d.properties.entity);
74682             }).data(data.nopes, function key(d) {
74683               return d.id;
74684             }); // exit
74685
74686             nopes.exit().remove(); // enter/update
74687
74688             nopes.enter().append('circle').attr('r', function (d) {
74689               return _radii[d.properties.entity.id] || radiuses.shadow[3];
74690             }).merge(nopes).attr('class', function (d) {
74691               return 'node vertex target target-nope ' + nopeClass + d.id;
74692             }).attr('transform', getTransform);
74693           } // Points can also render as vertices:
74694           // 1. in wireframe mode or
74695           // 2. at higher zooms if they have a direction
74696
74697
74698           function renderAsVertex(entity, graph, wireframe, zoom) {
74699             var geometry = entity.geometry(graph);
74700             return geometry === 'vertex' || geometry === 'point' && (wireframe || zoom >= 18 && entity.directions(graph, projection).length);
74701           }
74702
74703           function isEditedNode(node, base, head) {
74704             var baseNode = base.entities[node.id];
74705             var headNode = head.entities[node.id];
74706             return !headNode || !baseNode || !fastDeepEqual(headNode.tags, baseNode.tags) || !fastDeepEqual(headNode.loc, baseNode.loc);
74707           }
74708
74709           function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
74710             var results = {};
74711             var seenIds = {};
74712
74713             function addChildVertices(entity) {
74714               // avoid redundant work and infinite recursion of circular relations
74715               if (seenIds[entity.id]) return;
74716               seenIds[entity.id] = true;
74717               var geometry = entity.geometry(graph);
74718
74719               if (!context.features().isHiddenFeature(entity, graph, geometry)) {
74720                 var i;
74721
74722                 if (entity.type === 'way') {
74723                   for (i = 0; i < entity.nodes.length; i++) {
74724                     var child = graph.hasEntity(entity.nodes[i]);
74725
74726                     if (child) {
74727                       addChildVertices(child);
74728                     }
74729                   }
74730                 } else if (entity.type === 'relation') {
74731                   for (i = 0; i < entity.members.length; i++) {
74732                     var member = graph.hasEntity(entity.members[i].id);
74733
74734                     if (member) {
74735                       addChildVertices(member);
74736                     }
74737                   }
74738                 } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
74739                   results[entity.id] = entity;
74740                 }
74741               }
74742             }
74743
74744             ids.forEach(function (id) {
74745               var entity = graph.hasEntity(id);
74746               if (!entity) return;
74747
74748               if (entity.type === 'node') {
74749                 if (renderAsVertex(entity, graph, wireframe, zoom)) {
74750                   results[entity.id] = entity;
74751                   graph.parentWays(entity).forEach(function (entity) {
74752                     addChildVertices(entity);
74753                   });
74754                 }
74755               } else {
74756                 // way, relation
74757                 addChildVertices(entity);
74758               }
74759             });
74760             return results;
74761           }
74762
74763           function drawVertices(selection, graph, entities, filter, extent, fullRedraw) {
74764             var wireframe = context.surface().classed('fill-wireframe');
74765             var visualDiff = context.surface().classed('highlight-edited');
74766             var zoom = geoScaleToZoom(projection.scale());
74767             var mode = context.mode();
74768             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74769             var base = context.history().base();
74770             var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
74771             var touchLayer = selection.selectAll('.layer-touch.points');
74772
74773             if (fullRedraw) {
74774               _currPersistent = {};
74775               _radii = {};
74776             } // Collect important vertices from the `entities` list..
74777             // (during a partial redraw, it will not contain everything)
74778
74779
74780             for (var i = 0; i < entities.length; i++) {
74781               var entity = entities[i];
74782               var geometry = entity.geometry(graph);
74783               var keep = false; // a point that looks like a vertex..
74784
74785               if (geometry === 'point' && renderAsVertex(entity, graph, wireframe, zoom)) {
74786                 _currPersistent[entity.id] = entity;
74787                 keep = true; // a vertex of some importance..
74788               } else if (geometry === 'vertex' && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
74789                 _currPersistent[entity.id] = entity;
74790                 keep = true;
74791               } // whatever this is, it's not a persistent vertex..
74792
74793
74794               if (!keep && !fullRedraw) {
74795                 delete _currPersistent[entity.id];
74796               }
74797             } // 3 sets of vertices to consider:
74798
74799
74800             var sets = {
74801               persistent: _currPersistent,
74802               // persistent = important vertices (render always)
74803               selected: _currSelected,
74804               // selected + siblings of selected (render always)
74805               hovered: _currHover // hovered + siblings of hovered (render only in draw modes)
74806
74807             };
74808             var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent); // Draw the vertices..
74809             // The filter function controls the scope of what objects d3 will touch (exit/enter/update)
74810             // Adjust the filter function to expand the scope beyond whatever entities were passed in.
74811
74812             var filterRendered = function filterRendered(d) {
74813               return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
74814             };
74815
74816             drawLayer.call(draw, graph, currentVisible(all), sets, filterRendered); // Draw touch targets..
74817             // When drawing, render all targets (not just those affected by a partial redraw)
74818
74819             var filterTouch = function filterTouch(d) {
74820               return isMoving ? true : filterRendered(d);
74821             };
74822
74823             touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
74824
74825             function currentVisible(which) {
74826               return Object.keys(which).map(graph.hasEntity, graph) // the current version of this entity
74827               .filter(function (entity) {
74828                 return entity && entity.intersects(extent, graph);
74829               });
74830             }
74831           } // partial redraw - only update the selected items..
74832
74833
74834           drawVertices.drawSelected = function (selection, graph, extent) {
74835             var wireframe = context.surface().classed('fill-wireframe');
74836             var zoom = geoScaleToZoom(projection.scale());
74837             _prevSelected = _currSelected || {};
74838
74839             if (context.map().isInWideSelection()) {
74840               _currSelected = {};
74841               context.selectedIDs().forEach(function (id) {
74842                 var entity = graph.hasEntity(id);
74843                 if (!entity) return;
74844
74845                 if (entity.type === 'node') {
74846                   if (renderAsVertex(entity, graph, wireframe, zoom)) {
74847                     _currSelected[entity.id] = entity;
74848                   }
74849                 }
74850               });
74851             } else {
74852               _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
74853             } // note that drawVertices will add `_currSelected` automatically if needed..
74854
74855
74856             var filter = function filter(d) {
74857               return d.id in _prevSelected;
74858             };
74859
74860             drawVertices(selection, graph, Object.values(_prevSelected), filter, extent, false);
74861           }; // partial redraw - only update the hovered items..
74862
74863
74864           drawVertices.drawHover = function (selection, graph, target, extent) {
74865             if (target === _currHoverTarget) return; // continue only if something changed
74866
74867             var wireframe = context.surface().classed('fill-wireframe');
74868             var zoom = geoScaleToZoom(projection.scale());
74869             _prevHover = _currHover || {};
74870             _currHoverTarget = target;
74871             var entity = target && target.properties && target.properties.entity;
74872
74873             if (entity) {
74874               _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
74875             } else {
74876               _currHover = {};
74877             } // note that drawVertices will add `_currHover` automatically if needed..
74878
74879
74880             var filter = function filter(d) {
74881               return d.id in _prevHover;
74882             };
74883
74884             drawVertices(selection, graph, Object.values(_prevHover), filter, extent, false);
74885           };
74886
74887           return drawVertices;
74888         }
74889
74890         function utilBindOnce(target, type, listener, capture) {
74891           var typeOnce = type + '.once';
74892
74893           function one() {
74894             target.on(typeOnce, null);
74895             listener.apply(this, arguments);
74896           }
74897
74898           target.on(typeOnce, one, capture);
74899           return this;
74900         }
74901
74902         function defaultFilter$2(d3_event) {
74903           return !d3_event.ctrlKey && !d3_event.button;
74904         }
74905
74906         function defaultExtent$1() {
74907           var e = this;
74908
74909           if (e instanceof SVGElement) {
74910             e = e.ownerSVGElement || e;
74911
74912             if (e.hasAttribute('viewBox')) {
74913               e = e.viewBox.baseVal;
74914               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
74915             }
74916
74917             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
74918           }
74919
74920           return [[0, 0], [e.clientWidth, e.clientHeight]];
74921         }
74922
74923         function defaultWheelDelta$1(d3_event) {
74924           return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 0.002);
74925         }
74926
74927         function defaultConstrain$1(transform, extent, translateExtent) {
74928           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
74929               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
74930               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
74931               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
74932           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));
74933         }
74934
74935         function utilZoomPan() {
74936           var filter = defaultFilter$2,
74937               extent = defaultExtent$1,
74938               constrain = defaultConstrain$1,
74939               wheelDelta = defaultWheelDelta$1,
74940               scaleExtent = [0, Infinity],
74941               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
74942               interpolate = interpolateZoom,
74943               dispatch$1 = dispatch('start', 'zoom', 'end'),
74944               _wheelDelay = 150,
74945               _transform = identity$2,
74946               _activeGesture;
74947
74948           function zoom(selection) {
74949             selection.on('pointerdown.zoom', pointerdown).on('wheel.zoom', wheeled).style('touch-action', 'none').style('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
74950             select(window).on('pointermove.zoompan', pointermove).on('pointerup.zoompan pointercancel.zoompan', pointerup);
74951           }
74952
74953           zoom.transform = function (collection, transform, point) {
74954             var selection = collection.selection ? collection.selection() : collection;
74955
74956             if (collection !== selection) {
74957               schedule(collection, transform, point);
74958             } else {
74959               selection.interrupt().each(function () {
74960                 gesture(this, arguments).start(null).zoom(null, null, typeof transform === 'function' ? transform.apply(this, arguments) : transform).end(null);
74961               });
74962             }
74963           };
74964
74965           zoom.scaleBy = function (selection, k, p) {
74966             zoom.scaleTo(selection, function () {
74967               var k0 = _transform.k,
74968                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
74969               return k0 * k1;
74970             }, p);
74971           };
74972
74973           zoom.scaleTo = function (selection, k, p) {
74974             zoom.transform(selection, function () {
74975               var e = extent.apply(this, arguments),
74976                   t0 = _transform,
74977                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p,
74978                   p1 = t0.invert(p0),
74979                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
74980               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
74981             }, p);
74982           };
74983
74984           zoom.translateBy = function (selection, x, y) {
74985             zoom.transform(selection, function () {
74986               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);
74987             });
74988           };
74989
74990           zoom.translateTo = function (selection, x, y, p) {
74991             zoom.transform(selection, function () {
74992               var e = extent.apply(this, arguments),
74993                   t = _transform,
74994                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p;
74995               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);
74996             }, p);
74997           };
74998
74999           function scale(transform, k) {
75000             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
75001             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
75002           }
75003
75004           function translate(transform, p0, p1) {
75005             var x = p0[0] - p1[0] * transform.k,
75006                 y = p0[1] - p1[1] * transform.k;
75007             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
75008           }
75009
75010           function centroid(extent) {
75011             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
75012           }
75013
75014           function schedule(transition, transform, point) {
75015             transition.on('start.zoom', function () {
75016               gesture(this, arguments).start(null);
75017             }).on('interrupt.zoom end.zoom', function () {
75018               gesture(this, arguments).end(null);
75019             }).tween('zoom', function () {
75020               var that = this,
75021                   args = arguments,
75022                   g = gesture(that, args),
75023                   e = extent.apply(that, args),
75024                   p = !point ? centroid(e) : typeof point === 'function' ? point.apply(that, args) : point,
75025                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
75026                   a = _transform,
75027                   b = typeof transform === 'function' ? transform.apply(that, args) : transform,
75028                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
75029               return function (t) {
75030                 if (t === 1) t = b; // Avoid rounding error on end.
75031                 else {
75032                     var l = i(t),
75033                         k = w / l[2];
75034                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
75035                   }
75036                 g.zoom(null, null, t);
75037               };
75038             });
75039           }
75040
75041           function gesture(that, args, clean) {
75042             return !clean && _activeGesture || new Gesture(that, args);
75043           }
75044
75045           function Gesture(that, args) {
75046             this.that = that;
75047             this.args = args;
75048             this.active = 0;
75049             this.extent = extent.apply(that, args);
75050           }
75051
75052           Gesture.prototype = {
75053             start: function start(d3_event) {
75054               if (++this.active === 1) {
75055                 _activeGesture = this;
75056                 dispatch$1.call('start', this, d3_event);
75057               }
75058
75059               return this;
75060             },
75061             zoom: function zoom(d3_event, key, transform) {
75062               if (this.mouse && key !== 'mouse') this.mouse[1] = transform.invert(this.mouse[0]);
75063               if (this.pointer0 && key !== 'touch') this.pointer0[1] = transform.invert(this.pointer0[0]);
75064               if (this.pointer1 && key !== 'touch') this.pointer1[1] = transform.invert(this.pointer1[0]);
75065               _transform = transform;
75066               dispatch$1.call('zoom', this, d3_event, key, transform);
75067               return this;
75068             },
75069             end: function end(d3_event) {
75070               if (--this.active === 0) {
75071                 _activeGesture = null;
75072                 dispatch$1.call('end', this, d3_event);
75073               }
75074
75075               return this;
75076             }
75077           };
75078
75079           function wheeled(d3_event) {
75080             if (!filter.apply(this, arguments)) return;
75081             var g = gesture(this, arguments),
75082                 t = _transform,
75083                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
75084                 p = utilFastMouse(this)(d3_event); // If the mouse is in the same location as before, reuse it.
75085             // If there were recent wheel events, reset the wheel idle timeout.
75086
75087             if (g.wheel) {
75088               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
75089                 g.mouse[1] = t.invert(g.mouse[0] = p);
75090               }
75091
75092               clearTimeout(g.wheel); // Otherwise, capture the mouse point and location at the start.
75093             } else {
75094               g.mouse = [p, t.invert(p)];
75095               interrupt(this);
75096               g.start(d3_event);
75097             }
75098
75099             d3_event.preventDefault();
75100             d3_event.stopImmediatePropagation();
75101             g.wheel = setTimeout(wheelidled, _wheelDelay);
75102             g.zoom(d3_event, 'mouse', constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
75103
75104             function wheelidled() {
75105               g.wheel = null;
75106               g.end(d3_event);
75107             }
75108           }
75109
75110           var _downPointerIDs = new Set();
75111
75112           var _pointerLocGetter;
75113
75114           function pointerdown(d3_event) {
75115             _downPointerIDs.add(d3_event.pointerId);
75116
75117             if (!filter.apply(this, arguments)) return;
75118             var g = gesture(this, arguments, _downPointerIDs.size === 1);
75119             var started;
75120             d3_event.stopImmediatePropagation();
75121             _pointerLocGetter = utilFastMouse(this);
75122
75123             var loc = _pointerLocGetter(d3_event);
75124
75125             var p = [loc, _transform.invert(loc), d3_event.pointerId];
75126
75127             if (!g.pointer0) {
75128               g.pointer0 = p;
75129               started = true;
75130             } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
75131               g.pointer1 = p;
75132             }
75133
75134             if (started) {
75135               interrupt(this);
75136               g.start(d3_event);
75137             }
75138           }
75139
75140           function pointermove(d3_event) {
75141             if (!_downPointerIDs.has(d3_event.pointerId)) return;
75142             if (!_activeGesture || !_pointerLocGetter) return;
75143             var g = gesture(this, arguments);
75144             var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
75145             var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
75146
75147             if ((isPointer0 || isPointer1) && 'buttons' in d3_event && !d3_event.buttons) {
75148               // The pointer went up without ending the gesture somehow, e.g.
75149               // a down mouse was moved off the map and released. End it here.
75150               if (g.pointer0) _downPointerIDs["delete"](g.pointer0[2]);
75151               if (g.pointer1) _downPointerIDs["delete"](g.pointer1[2]);
75152               g.end(d3_event);
75153               return;
75154             }
75155
75156             d3_event.preventDefault();
75157             d3_event.stopImmediatePropagation();
75158
75159             var loc = _pointerLocGetter(d3_event);
75160
75161             var t, p, l;
75162             if (isPointer0) g.pointer0[0] = loc;else if (isPointer1) g.pointer1[0] = loc;
75163             t = _transform;
75164
75165             if (g.pointer1) {
75166               var p0 = g.pointer0[0],
75167                   l0 = g.pointer0[1],
75168                   p1 = g.pointer1[0],
75169                   l1 = g.pointer1[1],
75170                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
75171                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
75172               t = scale(t, Math.sqrt(dp / dl));
75173               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
75174               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
75175             } else if (g.pointer0) {
75176               p = g.pointer0[0];
75177               l = g.pointer0[1];
75178             } else return;
75179
75180             g.zoom(d3_event, 'touch', constrain(translate(t, p, l), g.extent, translateExtent));
75181           }
75182
75183           function pointerup(d3_event) {
75184             if (!_downPointerIDs.has(d3_event.pointerId)) return;
75185
75186             _downPointerIDs["delete"](d3_event.pointerId);
75187
75188             if (!_activeGesture) return;
75189             var g = gesture(this, arguments);
75190             d3_event.stopImmediatePropagation();
75191             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;
75192
75193             if (g.pointer1 && !g.pointer0) {
75194               g.pointer0 = g.pointer1;
75195               delete g.pointer1;
75196             }
75197
75198             if (g.pointer0) g.pointer0[1] = _transform.invert(g.pointer0[0]);else {
75199               g.end(d3_event);
75200             }
75201           }
75202
75203           zoom.wheelDelta = function (_) {
75204             return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
75205           };
75206
75207           zoom.filter = function (_) {
75208             return arguments.length ? (filter = utilFunctor(!!_), zoom) : filter;
75209           };
75210
75211           zoom.extent = function (_) {
75212             return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
75213           };
75214
75215           zoom.scaleExtent = function (_) {
75216             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
75217           };
75218
75219           zoom.translateExtent = function (_) {
75220             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]]];
75221           };
75222
75223           zoom.constrain = function (_) {
75224             return arguments.length ? (constrain = _, zoom) : constrain;
75225           };
75226
75227           zoom.interpolate = function (_) {
75228             return arguments.length ? (interpolate = _, zoom) : interpolate;
75229           };
75230
75231           zoom._transform = function (_) {
75232             return arguments.length ? (_transform = _, zoom) : _transform;
75233           };
75234
75235           return utilRebind(zoom, dispatch$1, 'on');
75236         }
75237
75238         // if pointer events are supported. Falls back to default `dblclick` event.
75239
75240         function utilDoubleUp() {
75241           var dispatch$1 = dispatch('doubleUp');
75242           var _maxTimespan = 500; // milliseconds
75243
75244           var _maxDistance = 20; // web pixels; be somewhat generous to account for touch devices
75245
75246           var _pointer; // object representing the pointer that could trigger double up
75247
75248
75249           function pointerIsValidFor(loc) {
75250             // second pointerup must occur within a small timeframe after the first pointerdown
75251             return new Date().getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
75252             geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
75253           }
75254
75255           function pointerdown(d3_event) {
75256             // ignore right-click
75257             if (d3_event.ctrlKey || d3_event.button === 2) return;
75258             var loc = [d3_event.clientX, d3_event.clientY]; // Don't rely on pointerId here since it can change between pointerdown
75259             // events on touch devices
75260
75261             if (_pointer && !pointerIsValidFor(loc)) {
75262               // if this pointer is no longer valid, clear it so another can be started
75263               _pointer = undefined;
75264             }
75265
75266             if (!_pointer) {
75267               _pointer = {
75268                 startLoc: loc,
75269                 startTime: new Date().getTime(),
75270                 upCount: 0,
75271                 pointerId: d3_event.pointerId
75272               };
75273             } else {
75274               // double down
75275               _pointer.pointerId = d3_event.pointerId;
75276             }
75277           }
75278
75279           function pointerup(d3_event) {
75280             // ignore right-click
75281             if (d3_event.ctrlKey || d3_event.button === 2) return;
75282             if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
75283             _pointer.upCount += 1;
75284
75285             if (_pointer.upCount === 2) {
75286               // double up!
75287               var loc = [d3_event.clientX, d3_event.clientY];
75288
75289               if (pointerIsValidFor(loc)) {
75290                 var locInThis = utilFastMouse(this)(d3_event);
75291                 dispatch$1.call('doubleUp', this, d3_event, locInThis);
75292               } // clear the pointer info in any case
75293
75294
75295               _pointer = undefined;
75296             }
75297           }
75298
75299           function doubleUp(selection) {
75300             if ('PointerEvent' in window) {
75301               // dblclick isn't well supported on touch devices so manually use
75302               // pointer events if they're available
75303               selection.on('pointerdown.doubleUp', pointerdown).on('pointerup.doubleUp', pointerup);
75304             } else {
75305               // fallback to dblclick
75306               selection.on('dblclick.doubleUp', function (d3_event) {
75307                 dispatch$1.call('doubleUp', this, d3_event, utilFastMouse(this)(d3_event));
75308               });
75309             }
75310           }
75311
75312           doubleUp.off = function (selection) {
75313             selection.on('pointerdown.doubleUp', null).on('pointerup.doubleUp', null).on('dblclick.doubleUp', null);
75314           };
75315
75316           return utilRebind(doubleUp, dispatch$1, 'on');
75317         }
75318
75319         var TILESIZE = 256;
75320         var minZoom = 2;
75321         var maxZoom = 24;
75322         var kMin = geoZoomToScale(minZoom, TILESIZE);
75323         var kMax = geoZoomToScale(maxZoom, TILESIZE);
75324
75325         function clamp(num, min, max) {
75326           return Math.max(min, Math.min(num, max));
75327         }
75328
75329         function rendererMap(context) {
75330           var dispatch$1 = dispatch('move', 'drawn', 'crossEditableZoom', 'hitMinZoom', 'changeHighlighting', 'changeAreaFill');
75331           var projection = context.projection;
75332           var curtainProjection = context.curtainProjection;
75333           var drawLayers;
75334           var drawPoints;
75335           var drawVertices;
75336           var drawLines;
75337           var drawAreas;
75338           var drawMidpoints;
75339           var drawLabels;
75340
75341           var _selection = select(null);
75342
75343           var supersurface = select(null);
75344           var wrapper = select(null);
75345           var surface = select(null);
75346           var _dimensions = [1, 1];
75347           var _dblClickZoomEnabled = true;
75348           var _redrawEnabled = true;
75349
75350           var _gestureTransformStart;
75351
75352           var _transformStart = projection.transform();
75353
75354           var _transformLast;
75355
75356           var _isTransformed = false;
75357           var _minzoom = 0;
75358
75359           var _getMouseCoords;
75360
75361           var _lastPointerEvent;
75362
75363           var _lastWithinEditableZoom; // whether a pointerdown event started the zoom
75364
75365
75366           var _pointerDown = false; // use pointer events on supported platforms; fallback to mouse events
75367
75368           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom
75369
75370
75371           var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom;
75372
75373           var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(interpolate).filter(zoomEventFilter).on('zoom.map', zoomPan).on('start.map', function (d3_event) {
75374             _pointerDown = d3_event && (d3_event.type === 'pointerdown' || d3_event.sourceEvent && d3_event.sourceEvent.type === 'pointerdown');
75375           }).on('end.map', function () {
75376             _pointerDown = false;
75377           });
75378
75379           var _doubleUpHandler = utilDoubleUp();
75380
75381           var scheduleRedraw = throttle(redraw, 750); // var isRedrawScheduled = false;
75382           // var pendingRedrawCall;
75383           // function scheduleRedraw() {
75384           //     // Only schedule the redraw if one has not already been set.
75385           //     if (isRedrawScheduled) return;
75386           //     isRedrawScheduled = true;
75387           //     var that = this;
75388           //     var args = arguments;
75389           //     pendingRedrawCall = window.requestIdleCallback(function () {
75390           //         // Reset the boolean so future redraws can be set.
75391           //         isRedrawScheduled = false;
75392           //         redraw.apply(that, args);
75393           //     }, { timeout: 1400 });
75394           // }
75395
75396
75397           function cancelPendingRedraw() {
75398             scheduleRedraw.cancel(); // isRedrawScheduled = false;
75399             // window.cancelIdleCallback(pendingRedrawCall);
75400           }
75401
75402           function map(selection) {
75403             _selection = selection;
75404             context.on('change.map', immediateRedraw);
75405             var osm = context.connection();
75406
75407             if (osm) {
75408               osm.on('change.map', immediateRedraw);
75409             }
75410
75411             function didUndoOrRedo(targetTransform) {
75412               var mode = context.mode().id;
75413               if (mode !== 'browse' && mode !== 'select') return;
75414
75415               if (targetTransform) {
75416                 map.transformEase(targetTransform);
75417               }
75418             }
75419
75420             context.history().on('merge.map', function () {
75421               scheduleRedraw();
75422             }).on('change.map', immediateRedraw).on('undone.map', function (stack, fromStack) {
75423               didUndoOrRedo(fromStack.transform);
75424             }).on('redone.map', function (stack) {
75425               didUndoOrRedo(stack.transform);
75426             });
75427             context.background().on('change.map', immediateRedraw);
75428             context.features().on('redraw.map', immediateRedraw);
75429             drawLayers.on('change.map', function () {
75430               context.background().updateImagery();
75431               immediateRedraw();
75432             });
75433             selection.on('wheel.map mousewheel.map', function (d3_event) {
75434               // disable swipe-to-navigate browser pages on trackpad/magic mouse – #5552
75435               d3_event.preventDefault();
75436             }).call(_zoomerPanner).call(_zoomerPanner.transform, projection.transform()).on('dblclick.zoom', null); // override d3-zoom dblclick handling
75437
75438             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
75439             // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
75440
75441             wrapper = supersurface.append('div').attr('class', 'layer layer-data');
75442             map.surface = surface = wrapper.call(drawLayers).selectAll('.surface');
75443             surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + 'down.zoom', function (d3_event) {
75444               _lastPointerEvent = d3_event;
75445
75446               if (d3_event.button === 2) {
75447                 d3_event.stopPropagation();
75448               }
75449             }, true).on(_pointerPrefix + 'up.zoom', function (d3_event) {
75450               _lastPointerEvent = d3_event;
75451
75452               if (resetTransform()) {
75453                 immediateRedraw();
75454               }
75455             }).on(_pointerPrefix + 'move.map', function (d3_event) {
75456               _lastPointerEvent = d3_event;
75457             }).on(_pointerPrefix + 'over.vertices', function (d3_event) {
75458               if (map.editableDataEnabled() && !_isTransformed) {
75459                 var hover = d3_event.target.__data__;
75460                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
75461                 dispatch$1.call('drawn', this, {
75462                   full: false
75463                 });
75464               }
75465             }).on(_pointerPrefix + 'out.vertices', function (d3_event) {
75466               if (map.editableDataEnabled() && !_isTransformed) {
75467                 var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
75468                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
75469                 dispatch$1.call('drawn', this, {
75470                   full: false
75471                 });
75472               }
75473             });
75474             var detected = utilDetect(); // only WebKit supports gesture events
75475
75476             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
75477             // but we only need to do this on desktop Safari anyway. – #7694
75478             !detected.isMobileWebKit) {
75479               // Desktop Safari sends gesture events for multitouch trackpad pinches.
75480               // We can listen for these and translate them into map zooms.
75481               surface.on('gesturestart.surface', function (d3_event) {
75482                 d3_event.preventDefault();
75483                 _gestureTransformStart = projection.transform();
75484               }).on('gesturechange.surface', gestureChange);
75485             } // must call after surface init
75486
75487
75488             updateAreaFill();
75489
75490             _doubleUpHandler.on('doubleUp.map', function (d3_event, p0) {
75491               if (!_dblClickZoomEnabled) return; // don't zoom if targeting something other than the map itself
75492
75493               if (_typeof(d3_event.target.__data__) === 'object' && // or area fills
75494               !select(d3_event.target).classed('fill')) return;
75495               var zoomOut = d3_event.shiftKey;
75496               var t = projection.transform();
75497               var p1 = t.invert(p0);
75498               t = t.scale(zoomOut ? 0.5 : 2);
75499               t.x = p0[0] - p1[0] * t.k;
75500               t.y = p0[1] - p1[1] * t.k;
75501               map.transformEase(t);
75502             });
75503
75504             context.on('enter.map', function () {
75505               if (!map.editableDataEnabled(true
75506               /* skip zoom check */
75507               )) return; // redraw immediately any objects affected by a change in selectedIDs.
75508
75509               var graph = context.graph();
75510               var selectedAndParents = {};
75511               context.selectedIDs().forEach(function (id) {
75512                 var entity = graph.hasEntity(id);
75513
75514                 if (entity) {
75515                   selectedAndParents[entity.id] = entity;
75516
75517                   if (entity.type === 'node') {
75518                     graph.parentWays(entity).forEach(function (parent) {
75519                       selectedAndParents[parent.id] = parent;
75520                     });
75521                   }
75522                 }
75523               });
75524               var data = Object.values(selectedAndParents);
75525
75526               var filter = function filter(d) {
75527                 return d.id in selectedAndParents;
75528               };
75529
75530               data = context.features().filter(data, graph);
75531               surface.call(drawVertices.drawSelected, graph, map.extent()).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent());
75532               dispatch$1.call('drawn', this, {
75533                 full: false
75534               }); // redraw everything else later
75535
75536               scheduleRedraw();
75537             });
75538             map.dimensions(utilGetDimensions(selection));
75539           }
75540
75541           function zoomEventFilter(d3_event) {
75542             // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
75543             // Intercept `mousedown` and check if there is an orphaned zoom gesture.
75544             // This can happen if a previous `mousedown` occurred without a `mouseup`.
75545             // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
75546             // so that d3-zoom won't stop propagation of new `mousedown` events.
75547             if (d3_event.type === 'mousedown') {
75548               var hasOrphan = false;
75549               var listeners = window.__on;
75550
75551               for (var i = 0; i < listeners.length; i++) {
75552                 var listener = listeners[i];
75553
75554                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
75555                   hasOrphan = true;
75556                   break;
75557                 }
75558               }
75559
75560               if (hasOrphan) {
75561                 var event = window.CustomEvent;
75562
75563                 if (event) {
75564                   event = new event('mouseup');
75565                 } else {
75566                   event = window.document.createEvent('Event');
75567                   event.initEvent('mouseup', false, false);
75568                 } // Event needs to be dispatched with an event.view property.
75569
75570
75571                 event.view = window;
75572                 window.dispatchEvent(event);
75573               }
75574             }
75575
75576             return d3_event.button !== 2; // ignore right clicks
75577           }
75578
75579           function pxCenter() {
75580             return [_dimensions[0] / 2, _dimensions[1] / 2];
75581           }
75582
75583           function drawEditable(difference, extent) {
75584             var mode = context.mode();
75585             var graph = context.graph();
75586             var features = context.features();
75587             var all = context.history().intersects(map.extent());
75588             var fullRedraw = false;
75589             var data;
75590             var set;
75591             var filter;
75592             var applyFeatureLayerFilters = true;
75593
75594             if (map.isInWideSelection()) {
75595               data = [];
75596               utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function (id) {
75597                 var entity = context.hasEntity(id);
75598                 if (entity) data.push(entity);
75599               });
75600               fullRedraw = true;
75601               filter = utilFunctor(true); // selected features should always be visible, so we can skip filtering
75602
75603               applyFeatureLayerFilters = false;
75604             } else if (difference) {
75605               var complete = difference.complete(map.extent());
75606               data = Object.values(complete).filter(Boolean);
75607               set = new Set(Object.keys(complete));
75608
75609               filter = function filter(d) {
75610                 return set.has(d.id);
75611               };
75612
75613               features.clear(data);
75614             } else {
75615               // force a full redraw if gatherStats detects that a feature
75616               // should be auto-hidden (e.g. points or buildings)..
75617               if (features.gatherStats(all, graph, _dimensions)) {
75618                 extent = undefined;
75619               }
75620
75621               if (extent) {
75622                 data = context.history().intersects(map.extent().intersection(extent));
75623                 set = new Set(data.map(function (entity) {
75624                   return entity.id;
75625                 }));
75626
75627                 filter = function filter(d) {
75628                   return set.has(d.id);
75629                 };
75630               } else {
75631                 data = all;
75632                 fullRedraw = true;
75633                 filter = utilFunctor(true);
75634               }
75635             }
75636
75637             if (applyFeatureLayerFilters) {
75638               data = features.filter(data, graph);
75639             } else {
75640               context.features().resetStats();
75641             }
75642
75643             if (mode && mode.id === 'select') {
75644               // update selected vertices - the user might have just double-clicked a way,
75645               // creating a new vertex, triggering a partial redraw without a mode change
75646               surface.call(drawVertices.drawSelected, graph, map.extent());
75647             }
75648
75649             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);
75650             dispatch$1.call('drawn', this, {
75651               full: true
75652             });
75653           }
75654
75655           map.init = function () {
75656             drawLayers = svgLayers(projection, context);
75657             drawPoints = svgPoints(projection, context);
75658             drawVertices = svgVertices(projection, context);
75659             drawLines = svgLines(projection, context);
75660             drawAreas = svgAreas(projection, context);
75661             drawMidpoints = svgMidpoints(projection, context);
75662             drawLabels = svgLabels(projection, context);
75663           };
75664
75665           function editOff() {
75666             context.features().resetStats();
75667             surface.selectAll('.layer-osm *').remove();
75668             surface.selectAll('.layer-touch:not(.markers) *').remove();
75669             var allowed = {
75670               'browse': true,
75671               'save': true,
75672               'select-note': true,
75673               'select-data': true,
75674               'select-error': true
75675             };
75676             var mode = context.mode();
75677
75678             if (mode && !allowed[mode.id]) {
75679               context.enter(modeBrowse(context));
75680             }
75681
75682             dispatch$1.call('drawn', this, {
75683               full: true
75684             });
75685           }
75686
75687           function gestureChange(d3_event) {
75688             // Remap Safari gesture events to wheel events - #5492
75689             // We want these disabled most places, but enabled for zoom/unzoom on map surface
75690             // https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
75691             var e = d3_event;
75692             e.preventDefault();
75693             var props = {
75694               deltaMode: 0,
75695               // dummy values to ignore in zoomPan
75696               deltaY: 1,
75697               // dummy values to ignore in zoomPan
75698               clientX: e.clientX,
75699               clientY: e.clientY,
75700               screenX: e.screenX,
75701               screenY: e.screenY,
75702               x: e.x,
75703               y: e.y
75704             };
75705             var e2 = new WheelEvent('wheel', props);
75706             e2._scale = e.scale; // preserve the original scale
75707
75708             e2._rotation = e.rotation; // preserve the original rotation
75709
75710             _selection.node().dispatchEvent(e2);
75711           }
75712
75713           function zoomPan(event, key, transform) {
75714             var source = event && event.sourceEvent || event;
75715             var eventTransform = transform || event && event.transform;
75716             var x = eventTransform.x;
75717             var y = eventTransform.y;
75718             var k = eventTransform.k; // Special handling of 'wheel' events:
75719             // They might be triggered by the user scrolling the mouse wheel,
75720             // or 2-finger pinch/zoom gestures, the transform may need adjustment.
75721
75722             if (source && source.type === 'wheel') {
75723               // assume that the gesture is already handled by pointer events
75724               if (_pointerDown) return;
75725               var detected = utilDetect();
75726               var dX = source.deltaX;
75727               var dY = source.deltaY;
75728               var x2 = x;
75729               var y2 = y;
75730               var k2 = k;
75731               var t0, p0, p1; // Normalize mousewheel scroll speed (Firefox) - #3029
75732               // If wheel delta is provided in LINE units, recalculate it in PIXEL units
75733               // We are essentially redoing the calculations that occur here:
75734               //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
75735               // See this for more info:
75736               //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
75737
75738               if (source.deltaMode === 1
75739               /* LINE */
75740               ) {
75741                   // Convert from lines to pixels, more if the user is scrolling fast.
75742                   // (I made up the exp function to roughly match Firefox to what Chrome does)
75743                   // These numbers should be floats, because integers are treated as pan gesture below.
75744                   var lines = Math.abs(source.deltaY);
75745                   var sign = source.deltaY > 0 ? 1 : -1;
75746                   dY = sign * clamp(Math.exp((lines - 1) * 0.75) * 4.000244140625, 4.000244140625, // min
75747                   350.000244140625 // max
75748                   ); // On Firefox Windows and Linux we always get +/- the scroll line amount (default 3)
75749                   // There doesn't seem to be any scroll acceleration.
75750                   // This multiplier increases the speed a little bit - #5512
75751
75752                   if (detected.os !== 'mac') {
75753                     dY *= 5;
75754                   } // recalculate x2,y2,k2
75755
75756
75757                   t0 = _isTransformed ? _transformLast : _transformStart;
75758                   p0 = _getMouseCoords(source);
75759                   p1 = t0.invert(p0);
75760                   k2 = t0.k * Math.pow(2, -dY / 500);
75761                   k2 = clamp(k2, kMin, kMax);
75762                   x2 = p0[0] - p1[0] * k2;
75763                   y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (Safari) - #5492
75764                   // These are fake `wheel` events we made from Safari `gesturechange` events..
75765                 } else if (source._scale) {
75766                 // recalculate x2,y2,k2
75767                 t0 = _gestureTransformStart;
75768                 p0 = _getMouseCoords(source);
75769                 p1 = t0.invert(p0);
75770                 k2 = t0.k * source._scale;
75771                 k2 = clamp(k2, kMin, kMax);
75772                 x2 = p0[0] - p1[0] * k2;
75773                 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (all browsers except Safari) - #5492
75774                 // Pinch zooming via the `wheel` event will always have:
75775                 // - `ctrlKey = true`
75776                 // - `deltaY` is not round integer pixels (ignore `deltaX`)
75777               } else if (source.ctrlKey && !isInteger(dY)) {
75778                 dY *= 6; // slightly scale up whatever the browser gave us
75779                 // recalculate x2,y2,k2
75780
75781                 t0 = _isTransformed ? _transformLast : _transformStart;
75782                 p0 = _getMouseCoords(source);
75783                 p1 = t0.invert(p0);
75784                 k2 = t0.k * Math.pow(2, -dY / 500);
75785                 k2 = clamp(k2, kMin, kMax);
75786                 x2 = p0[0] - p1[0] * k2;
75787                 y2 = p0[1] - p1[1] * k2; // Trackpad scroll zooming with shift or alt/option key down
75788               } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
75789                 // recalculate x2,y2,k2
75790                 t0 = _isTransformed ? _transformLast : _transformStart;
75791                 p0 = _getMouseCoords(source);
75792                 p1 = t0.invert(p0);
75793                 k2 = t0.k * Math.pow(2, -dY / 500);
75794                 k2 = clamp(k2, kMin, kMax);
75795                 x2 = p0[0] - p1[0] * k2;
75796                 y2 = p0[1] - p1[1] * k2; // 2 finger map panning (Mac only, all browsers) - #5492, #5512
75797                 // Panning via the `wheel` event will always have:
75798                 // - `ctrlKey = false`
75799                 // - `deltaX`,`deltaY` are round integer pixels
75800               } else if (detected.os === 'mac' && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
75801                 p1 = projection.translate();
75802                 x2 = p1[0] - dX;
75803                 y2 = p1[1] - dY;
75804                 k2 = projection.scale();
75805                 k2 = clamp(k2, kMin, kMax);
75806               } // something changed - replace the event transform
75807
75808
75809               if (x2 !== x || y2 !== y || k2 !== k) {
75810                 x = x2;
75811                 y = y2;
75812                 k = k2;
75813                 eventTransform = identity$2.translate(x2, y2).scale(k2);
75814
75815                 if (_zoomerPanner._transform) {
75816                   // utilZoomPan interface
75817                   _zoomerPanner._transform(eventTransform);
75818                 } else {
75819                   // d3_zoom interface
75820                   _selection.node().__zoom = eventTransform;
75821                 }
75822               }
75823             }
75824
75825             if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
75826               return; // no change
75827             }
75828
75829             var withinEditableZoom = map.withinEditableZoom();
75830
75831             if (_lastWithinEditableZoom !== withinEditableZoom) {
75832               if (_lastWithinEditableZoom !== undefined) {
75833                 // notify that the map zoomed in or out over the editable zoom threshold
75834                 dispatch$1.call('crossEditableZoom', this, withinEditableZoom);
75835               }
75836
75837               _lastWithinEditableZoom = withinEditableZoom;
75838             }
75839
75840             if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
75841               surface.interrupt();
75842               dispatch$1.call('hitMinZoom', this, map);
75843               setCenterZoom(map.center(), context.minEditableZoom(), 0, true);
75844               scheduleRedraw();
75845               dispatch$1.call('move', this, map);
75846               return;
75847             }
75848
75849             projection.transform(eventTransform);
75850             var scale = k / _transformStart.k;
75851             var tX = (x / scale - _transformStart.x) * scale;
75852             var tY = (y / scale - _transformStart.y) * scale;
75853
75854             if (context.inIntro()) {
75855               curtainProjection.transform({
75856                 x: x - tX,
75857                 y: y - tY,
75858                 k: k
75859               });
75860             }
75861
75862             if (source) {
75863               _lastPointerEvent = event;
75864             }
75865
75866             _isTransformed = true;
75867             _transformLast = eventTransform;
75868             utilSetTransform(supersurface, tX, tY, scale);
75869             scheduleRedraw();
75870             dispatch$1.call('move', this, map);
75871
75872             function isInteger(val) {
75873               return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
75874             }
75875           }
75876
75877           function resetTransform() {
75878             if (!_isTransformed) return false;
75879             utilSetTransform(supersurface, 0, 0);
75880             _isTransformed = false;
75881
75882             if (context.inIntro()) {
75883               curtainProjection.transform(projection.transform());
75884             }
75885
75886             return true;
75887           }
75888
75889           function redraw(difference, extent) {
75890             if (surface.empty() || !_redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws.
75891             // It would result in artifacts where differenced entities are redrawn with
75892             // one transform and unchanged entities with another.
75893
75894             if (resetTransform()) {
75895               difference = extent = undefined;
75896             }
75897
75898             var zoom = map.zoom();
75899             var z = String(~~zoom);
75900
75901             if (surface.attr('data-zoom') !== z) {
75902               surface.attr('data-zoom', z);
75903             } // class surface as `lowzoom` around z17-z18.5 (based on latitude)
75904
75905
75906             var lat = map.center()[1];
75907             var lowzoom = linear$2().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
75908             surface.classed('low-zoom', zoom <= lowzoom(lat));
75909
75910             if (!difference) {
75911               supersurface.call(context.background());
75912               wrapper.call(drawLayers);
75913             } // OSM
75914
75915
75916             if (map.editableDataEnabled() || map.isInWideSelection()) {
75917               context.loadTiles(projection);
75918               drawEditable(difference, extent);
75919             } else {
75920               editOff();
75921             }
75922
75923             _transformStart = projection.transform();
75924             return map;
75925           }
75926
75927           var immediateRedraw = function immediateRedraw(difference, extent) {
75928             if (!difference && !extent) cancelPendingRedraw();
75929             redraw(difference, extent);
75930           };
75931
75932           map.lastPointerEvent = function () {
75933             return _lastPointerEvent;
75934           };
75935
75936           map.mouse = function (d3_event) {
75937             var event = _lastPointerEvent || d3_event;
75938
75939             if (event) {
75940               var s;
75941
75942               while (s = event.sourceEvent) {
75943                 event = s;
75944               }
75945
75946               return _getMouseCoords(event);
75947             }
75948
75949             return null;
75950           }; // returns Lng/Lat
75951
75952
75953           map.mouseCoordinates = function () {
75954             var coord = map.mouse() || pxCenter();
75955             return projection.invert(coord);
75956           };
75957
75958           map.dblclickZoomEnable = function (val) {
75959             if (!arguments.length) return _dblClickZoomEnabled;
75960             _dblClickZoomEnabled = val;
75961             return map;
75962           };
75963
75964           map.redrawEnable = function (val) {
75965             if (!arguments.length) return _redrawEnabled;
75966             _redrawEnabled = val;
75967             return map;
75968           };
75969
75970           map.isTransformed = function () {
75971             return _isTransformed;
75972           };
75973
75974           function setTransform(t2, duration, force) {
75975             var t = projection.transform();
75976             if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) return false;
75977
75978             if (duration) {
75979               _selection.transition().duration(duration).on('start', function () {
75980                 map.startEase();
75981               }).call(_zoomerPanner.transform, identity$2.translate(t2.x, t2.y).scale(t2.k));
75982             } else {
75983               projection.transform(t2);
75984               _transformStart = t2;
75985
75986               _selection.call(_zoomerPanner.transform, _transformStart);
75987             }
75988
75989             return true;
75990           }
75991
75992           function setCenterZoom(loc2, z2, duration, force) {
75993             var c = map.center();
75994             var z = map.zoom();
75995             if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force) return false;
75996             var proj = geoRawMercator().transform(projection.transform()); // copy projection
75997
75998             var k2 = clamp(geoZoomToScale(z2, TILESIZE), kMin, kMax);
75999             proj.scale(k2);
76000             var t = proj.translate();
76001             var point = proj(loc2);
76002             var center = pxCenter();
76003             t[0] += center[0] - point[0];
76004             t[1] += center[1] - point[1];
76005             return setTransform(identity$2.translate(t[0], t[1]).scale(k2), duration, force);
76006           }
76007
76008           map.pan = function (delta, duration) {
76009             var t = projection.translate();
76010             var k = projection.scale();
76011             t[0] += delta[0];
76012             t[1] += delta[1];
76013
76014             if (duration) {
76015               _selection.transition().duration(duration).on('start', function () {
76016                 map.startEase();
76017               }).call(_zoomerPanner.transform, identity$2.translate(t[0], t[1]).scale(k));
76018             } else {
76019               projection.translate(t);
76020               _transformStart = projection.transform();
76021
76022               _selection.call(_zoomerPanner.transform, _transformStart);
76023
76024               dispatch$1.call('move', this, map);
76025               immediateRedraw();
76026             }
76027
76028             return map;
76029           };
76030
76031           map.dimensions = function (val) {
76032             if (!arguments.length) return _dimensions;
76033             _dimensions = val;
76034             drawLayers.dimensions(_dimensions);
76035             context.background().dimensions(_dimensions);
76036             projection.clipExtent([[0, 0], _dimensions]);
76037             _getMouseCoords = utilFastMouse(supersurface.node());
76038             scheduleRedraw();
76039             return map;
76040           };
76041
76042           function zoomIn(delta) {
76043             setCenterZoom(map.center(), ~~map.zoom() + delta, 250, true);
76044           }
76045
76046           function zoomOut(delta) {
76047             setCenterZoom(map.center(), ~~map.zoom() - delta, 250, true);
76048           }
76049
76050           map.zoomIn = function () {
76051             zoomIn(1);
76052           };
76053
76054           map.zoomInFurther = function () {
76055             zoomIn(4);
76056           };
76057
76058           map.canZoomIn = function () {
76059             return map.zoom() < maxZoom;
76060           };
76061
76062           map.zoomOut = function () {
76063             zoomOut(1);
76064           };
76065
76066           map.zoomOutFurther = function () {
76067             zoomOut(4);
76068           };
76069
76070           map.canZoomOut = function () {
76071             return map.zoom() > minZoom;
76072           };
76073
76074           map.center = function (loc2) {
76075             if (!arguments.length) {
76076               return projection.invert(pxCenter());
76077             }
76078
76079             if (setCenterZoom(loc2, map.zoom())) {
76080               dispatch$1.call('move', this, map);
76081             }
76082
76083             scheduleRedraw();
76084             return map;
76085           };
76086
76087           map.unobscuredCenterZoomEase = function (loc, zoom) {
76088             var offset = map.unobscuredOffsetPx();
76089             var proj = geoRawMercator().transform(projection.transform()); // copy projection
76090             // use the target zoom to calculate the offset center
76091
76092             proj.scale(geoZoomToScale(zoom, TILESIZE));
76093             var locPx = proj(loc);
76094             var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
76095             var offsetLoc = proj.invert(offsetLocPx);
76096             map.centerZoomEase(offsetLoc, zoom);
76097           };
76098
76099           map.unobscuredOffsetPx = function () {
76100             var openPane = context.container().select('.map-panes .map-pane.shown');
76101
76102             if (!openPane.empty()) {
76103               return [openPane.node().offsetWidth / 2, 0];
76104             }
76105
76106             return [0, 0];
76107           };
76108
76109           map.zoom = function (z2) {
76110             if (!arguments.length) {
76111               return Math.max(geoScaleToZoom(projection.scale(), TILESIZE), 0);
76112             }
76113
76114             if (z2 < _minzoom) {
76115               surface.interrupt();
76116               dispatch$1.call('hitMinZoom', this, map);
76117               z2 = context.minEditableZoom();
76118             }
76119
76120             if (setCenterZoom(map.center(), z2)) {
76121               dispatch$1.call('move', this, map);
76122             }
76123
76124             scheduleRedraw();
76125             return map;
76126           };
76127
76128           map.centerZoom = function (loc2, z2) {
76129             if (setCenterZoom(loc2, z2)) {
76130               dispatch$1.call('move', this, map);
76131             }
76132
76133             scheduleRedraw();
76134             return map;
76135           };
76136
76137           map.zoomTo = function (entity) {
76138             var extent = entity.extent(context.graph());
76139             if (!isFinite(extent.area())) return map;
76140             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
76141             return map.centerZoom(extent.center(), z2);
76142           };
76143
76144           map.centerEase = function (loc2, duration) {
76145             duration = duration || 250;
76146             setCenterZoom(loc2, map.zoom(), duration);
76147             return map;
76148           };
76149
76150           map.zoomEase = function (z2, duration) {
76151             duration = duration || 250;
76152             setCenterZoom(map.center(), z2, duration, false);
76153             return map;
76154           };
76155
76156           map.centerZoomEase = function (loc2, z2, duration) {
76157             duration = duration || 250;
76158             setCenterZoom(loc2, z2, duration, false);
76159             return map;
76160           };
76161
76162           map.transformEase = function (t2, duration) {
76163             duration = duration || 250;
76164             setTransform(t2, duration, false
76165             /* don't force */
76166             );
76167             return map;
76168           };
76169
76170           map.zoomToEase = function (obj, duration) {
76171             var extent;
76172
76173             if (Array.isArray(obj)) {
76174               obj.forEach(function (entity) {
76175                 var entityExtent = entity.extent(context.graph());
76176
76177                 if (!extent) {
76178                   extent = entityExtent;
76179                 } else {
76180                   extent = extent.extend(entityExtent);
76181                 }
76182               });
76183             } else {
76184               extent = obj.extent(context.graph());
76185             }
76186
76187             if (!isFinite(extent.area())) return map;
76188             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
76189             return map.centerZoomEase(extent.center(), z2, duration);
76190           };
76191
76192           map.startEase = function () {
76193             utilBindOnce(surface, _pointerPrefix + 'down.ease', function () {
76194               map.cancelEase();
76195             });
76196             return map;
76197           };
76198
76199           map.cancelEase = function () {
76200             _selection.interrupt();
76201
76202             return map;
76203           };
76204
76205           map.extent = function (val) {
76206             if (!arguments.length) {
76207               return new geoExtent(projection.invert([0, _dimensions[1]]), projection.invert([_dimensions[0], 0]));
76208             } else {
76209               var extent = geoExtent(val);
76210               map.centerZoom(extent.center(), map.extentZoom(extent));
76211             }
76212           };
76213
76214           map.trimmedExtent = function (val) {
76215             if (!arguments.length) {
76216               var headerY = 71;
76217               var footerY = 30;
76218               var pad = 10;
76219               return new geoExtent(projection.invert([pad, _dimensions[1] - footerY - pad]), projection.invert([_dimensions[0] - pad, headerY + pad]));
76220             } else {
76221               var extent = geoExtent(val);
76222               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
76223             }
76224           };
76225
76226           function calcExtentZoom(extent, dim) {
76227             var tl = projection([extent[0][0], extent[1][1]]);
76228             var br = projection([extent[1][0], extent[0][1]]); // Calculate maximum zoom that fits extent
76229
76230             var hFactor = (br[0] - tl[0]) / dim[0];
76231             var vFactor = (br[1] - tl[1]) / dim[1];
76232             var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
76233             var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
76234             var newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
76235             return newZoom;
76236           }
76237
76238           map.extentZoom = function (val) {
76239             return calcExtentZoom(geoExtent(val), _dimensions);
76240           };
76241
76242           map.trimmedExtentZoom = function (val) {
76243             var trimY = 120;
76244             var trimX = 40;
76245             var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
76246             return calcExtentZoom(geoExtent(val), trimmed);
76247           };
76248
76249           map.withinEditableZoom = function () {
76250             return map.zoom() >= context.minEditableZoom();
76251           };
76252
76253           map.isInWideSelection = function () {
76254             return !map.withinEditableZoom() && context.selectedIDs().length;
76255           };
76256
76257           map.editableDataEnabled = function (skipZoomCheck) {
76258             var layer = context.layers().layer('osm');
76259             if (!layer || !layer.enabled()) return false;
76260             return skipZoomCheck || map.withinEditableZoom();
76261           };
76262
76263           map.notesEditable = function () {
76264             var layer = context.layers().layer('notes');
76265             if (!layer || !layer.enabled()) return false;
76266             return map.withinEditableZoom();
76267           };
76268
76269           map.minzoom = function (val) {
76270             if (!arguments.length) return _minzoom;
76271             _minzoom = val;
76272             return map;
76273           };
76274
76275           map.toggleHighlightEdited = function () {
76276             surface.classed('highlight-edited', !surface.classed('highlight-edited'));
76277             map.pan([0, 0]); // trigger a redraw
76278
76279             dispatch$1.call('changeHighlighting', this);
76280           };
76281
76282           map.areaFillOptions = ['wireframe', 'partial', 'full'];
76283
76284           map.activeAreaFill = function (val) {
76285             if (!arguments.length) return corePreferences('area-fill') || 'partial';
76286             corePreferences('area-fill', val);
76287
76288             if (val !== 'wireframe') {
76289               corePreferences('area-fill-toggle', val);
76290             }
76291
76292             updateAreaFill();
76293             map.pan([0, 0]); // trigger a redraw
76294
76295             dispatch$1.call('changeAreaFill', this);
76296             return map;
76297           };
76298
76299           map.toggleWireframe = function () {
76300             var activeFill = map.activeAreaFill();
76301
76302             if (activeFill === 'wireframe') {
76303               activeFill = corePreferences('area-fill-toggle') || 'partial';
76304             } else {
76305               activeFill = 'wireframe';
76306             }
76307
76308             map.activeAreaFill(activeFill);
76309           };
76310
76311           function updateAreaFill() {
76312             var activeFill = map.activeAreaFill();
76313             map.areaFillOptions.forEach(function (opt) {
76314               surface.classed('fill-' + opt, Boolean(opt === activeFill));
76315             });
76316           }
76317
76318           map.layers = function () {
76319             return drawLayers;
76320           };
76321
76322           map.doubleUpHandler = function () {
76323             return _doubleUpHandler;
76324           };
76325
76326           return utilRebind(map, dispatch$1, 'on');
76327         }
76328
76329         function rendererPhotos(context) {
76330           var dispatch$1 = dispatch('change');
76331           var _layerIDs = ['streetside', 'mapillary', 'mapillary-map-features', 'mapillary-signs', 'openstreetcam'];
76332           var _allPhotoTypes = ['flat', 'panoramic'];
76333
76334           var _shownPhotoTypes = _allPhotoTypes.slice(); // shallow copy
76335
76336
76337           var _dateFilters = ['fromDate', 'toDate'];
76338
76339           var _fromDate;
76340
76341           var _toDate;
76342
76343           var _usernames;
76344
76345           function photos() {}
76346
76347           function updateStorage() {
76348             if (window.mocha) return;
76349             var hash = utilStringQs(window.location.hash);
76350             var enabled = context.layers().all().filter(function (d) {
76351               return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
76352             }).map(function (d) {
76353               return d.id;
76354             });
76355
76356             if (enabled.length) {
76357               hash.photo_overlay = enabled.join(',');
76358             } else {
76359               delete hash.photo_overlay;
76360             }
76361
76362             window.location.replace('#' + utilQsString(hash, true));
76363           }
76364
76365           photos.overlayLayerIDs = function () {
76366             return _layerIDs;
76367           };
76368
76369           photos.allPhotoTypes = function () {
76370             return _allPhotoTypes;
76371           };
76372
76373           photos.dateFilters = function () {
76374             return _dateFilters;
76375           };
76376
76377           photos.dateFilterValue = function (val) {
76378             return val === _dateFilters[0] ? _fromDate : _toDate;
76379           };
76380
76381           photos.setDateFilter = function (type, val, updateUrl) {
76382             // validate the date
76383             var date = val && new Date(val);
76384
76385             if (date && !isNaN(date)) {
76386               val = date.toISOString().substr(0, 10);
76387             } else {
76388               val = null;
76389             }
76390
76391             if (type === _dateFilters[0]) {
76392               _fromDate = val;
76393
76394               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
76395                 _toDate = _fromDate;
76396               }
76397             }
76398
76399             if (type === _dateFilters[1]) {
76400               _toDate = val;
76401
76402               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
76403                 _fromDate = _toDate;
76404               }
76405             }
76406
76407             dispatch$1.call('change', this);
76408
76409             if (updateUrl) {
76410               var rangeString;
76411
76412               if (_fromDate || _toDate) {
76413                 rangeString = (_fromDate || '') + '_' + (_toDate || '');
76414               }
76415
76416               setUrlFilterValue('photo_dates', rangeString);
76417             }
76418           };
76419
76420           photos.setUsernameFilter = function (val, updateUrl) {
76421             if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(',');
76422
76423             if (val) {
76424               val = val.map(function (d) {
76425                 return d.trim();
76426               }).filter(Boolean);
76427
76428               if (!val.length) {
76429                 val = null;
76430               }
76431             }
76432
76433             _usernames = val;
76434             dispatch$1.call('change', this);
76435
76436             if (updateUrl) {
76437               var hashString;
76438
76439               if (_usernames) {
76440                 hashString = _usernames.join(',');
76441               }
76442
76443               setUrlFilterValue('photo_username', hashString);
76444             }
76445           };
76446
76447           function setUrlFilterValue(property, val) {
76448             if (!window.mocha) {
76449               var hash = utilStringQs(window.location.hash);
76450
76451               if (val) {
76452                 if (hash[property] === val) return;
76453                 hash[property] = val;
76454               } else {
76455                 if (!(property in hash)) return;
76456                 delete hash[property];
76457               }
76458
76459               window.location.replace('#' + utilQsString(hash, true));
76460             }
76461           }
76462
76463           function showsLayer(id) {
76464             var layer = context.layers().layer(id);
76465             return layer && layer.supported() && layer.enabled();
76466           }
76467
76468           photos.shouldFilterByDate = function () {
76469             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
76470           };
76471
76472           photos.shouldFilterByPhotoType = function () {
76473             return showsLayer('mapillary') || showsLayer('streetside') && showsLayer('openstreetcam');
76474           };
76475
76476           photos.shouldFilterByUsername = function () {
76477             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
76478           };
76479
76480           photos.showsPhotoType = function (val) {
76481             if (!photos.shouldFilterByPhotoType()) return true;
76482             return _shownPhotoTypes.indexOf(val) !== -1;
76483           };
76484
76485           photos.showsFlat = function () {
76486             return photos.showsPhotoType('flat');
76487           };
76488
76489           photos.showsPanoramic = function () {
76490             return photos.showsPhotoType('panoramic');
76491           };
76492
76493           photos.fromDate = function () {
76494             return _fromDate;
76495           };
76496
76497           photos.toDate = function () {
76498             return _toDate;
76499           };
76500
76501           photos.togglePhotoType = function (val) {
76502             var index = _shownPhotoTypes.indexOf(val);
76503
76504             if (index !== -1) {
76505               _shownPhotoTypes.splice(index, 1);
76506             } else {
76507               _shownPhotoTypes.push(val);
76508             }
76509
76510             dispatch$1.call('change', this);
76511             return photos;
76512           };
76513
76514           photos.usernames = function () {
76515             return _usernames;
76516           };
76517
76518           photos.init = function () {
76519             var hash = utilStringQs(window.location.hash);
76520
76521             if (hash.photo_dates) {
76522               // expect format like `photo_dates=2019-01-01_2020-12-31`, but allow a couple different separators
76523               var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
76524               this.setDateFilter('fromDate', parts && parts.length >= 2 && parts[1], false);
76525               this.setDateFilter('toDate', parts && parts.length >= 3 && parts[2], false);
76526             }
76527
76528             if (hash.photo_username) {
76529               this.setUsernameFilter(hash.photo_username, false);
76530             }
76531
76532             if (hash.photo_overlay) {
76533               // support enabling photo layers by default via a URL parameter, e.g. `photo_overlay=openstreetcam;mapillary;streetside`
76534               var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ',').split(',');
76535               hashOverlayIDs.forEach(function (id) {
76536                 var layer = _layerIDs.indexOf(id) !== -1 && context.layers().layer(id);
76537                 if (layer && !layer.enabled()) layer.enabled(true);
76538               });
76539             }
76540
76541             if (hash.photo) {
76542               // support opening a photo via a URL parameter, e.g. `photo=mapillary-fztgSDtLpa08ohPZFZjeRQ`
76543               var photoIds = hash.photo.replace(/;/g, ',').split(',');
76544               var photoId = photoIds.length && photoIds[0].trim();
76545               var results = /(.*)\/(.*)/g.exec(photoId);
76546
76547               if (results && results.length >= 3) {
76548                 var serviceId = results[1];
76549                 var photoKey = results[2];
76550                 var service = services[serviceId];
76551
76552                 if (service && service.ensureViewerLoaded) {
76553                   // if we're showing a photo then make sure its layer is enabled too
76554                   var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
76555                   if (layer && !layer.enabled()) layer.enabled(true);
76556                   var baselineTime = Date.now();
76557                   service.on('loadedImages.rendererPhotos', function () {
76558                     // don't open the viewer if too much time has elapsed
76559                     if (Date.now() - baselineTime > 45000) {
76560                       service.on('loadedImages.rendererPhotos', null);
76561                       return;
76562                     }
76563
76564                     if (!service.cachedImage(photoKey)) return;
76565                     service.on('loadedImages.rendererPhotos', null);
76566                     service.ensureViewerLoaded(context).then(function () {
76567                       service.selectImage(context, photoKey).showViewer(context);
76568                     });
76569                   });
76570                 }
76571               }
76572             }
76573
76574             context.layers().on('change.rendererPhotos', updateStorage);
76575           };
76576
76577           return utilRebind(photos, dispatch$1, 'on');
76578         }
76579
76580         function uiAccount(context) {
76581           var osm = context.connection();
76582
76583           function update(selection) {
76584             if (!osm) return;
76585
76586             if (!osm.authenticated()) {
76587               selection.selectAll('.userLink, .logoutLink').classed('hide', true);
76588               return;
76589             }
76590
76591             osm.userDetails(function (err, details) {
76592               var userLink = selection.select('.userLink'),
76593                   logoutLink = selection.select('.logoutLink');
76594               userLink.html('');
76595               logoutLink.html('');
76596               if (err || !details) return;
76597               selection.selectAll('.userLink, .logoutLink').classed('hide', false); // Link
76598
76599               var userLinkA = userLink.append('a').attr('href', osm.userURL(details.display_name)).attr('target', '_blank'); // Add thumbnail or dont
76600
76601               if (details.image_url) {
76602                 userLinkA.append('img').attr('class', 'icon pre-text user-icon').attr('src', details.image_url);
76603               } else {
76604                 userLinkA.call(svgIcon('#iD-icon-avatar', 'pre-text light'));
76605               } // Add user name
76606
76607
76608               userLinkA.append('span').attr('class', 'label').html(details.display_name);
76609               logoutLink.append('a').attr('class', 'logout').attr('href', '#').html(_t.html('logout')).on('click.logout', function (d3_event) {
76610                 d3_event.preventDefault();
76611                 osm.logout();
76612               });
76613             });
76614           }
76615
76616           return function (selection) {
76617             selection.append('li').attr('class', 'userLink').classed('hide', true);
76618             selection.append('li').attr('class', 'logoutLink').classed('hide', true);
76619
76620             if (osm) {
76621               osm.on('change.account', function () {
76622                 update(selection);
76623               });
76624               update(selection);
76625             }
76626           };
76627         }
76628
76629         function uiAttribution(context) {
76630           var _selection = select(null);
76631
76632           function render(selection, data, klass) {
76633             var div = selection.selectAll(".".concat(klass)).data([0]);
76634             div = div.enter().append('div').attr('class', klass).merge(div);
76635             var attributions = div.selectAll('.attribution').data(data, function (d) {
76636               return d.id;
76637             });
76638             attributions.exit().remove();
76639             attributions = attributions.enter().append('span').attr('class', 'attribution').each(function (d, i, nodes) {
76640               var attribution = select(nodes[i]);
76641
76642               if (d.terms_html) {
76643                 attribution.html(d.terms_html);
76644                 return;
76645               }
76646
76647               if (d.terms_url) {
76648                 attribution = attribution.append('a').attr('href', d.terms_url).attr('target', '_blank');
76649               }
76650
76651               var sourceID = d.id.replace(/\./g, '<TX_DOT>');
76652               var terms_text = _t("imagery.".concat(sourceID, ".attribution.text"), {
76653                 "default": d.terms_text || d.id || d.name()
76654               });
76655
76656               if (d.icon && !d.overlay) {
76657                 attribution.append('img').attr('class', 'source-image').attr('src', d.icon);
76658               }
76659
76660               attribution.append('span').attr('class', 'attribution-text').html(terms_text);
76661             }).merge(attributions);
76662             var copyright = attributions.selectAll('.copyright-notice').data(function (d) {
76663               var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
76664               return notice ? [notice] : [];
76665             });
76666             copyright.exit().remove();
76667             copyright = copyright.enter().append('span').attr('class', 'copyright-notice').merge(copyright);
76668             copyright.html(String);
76669           }
76670
76671           function update() {
76672             var baselayer = context.background().baseLayerSource();
76673
76674             _selection.call(render, baselayer ? [baselayer] : [], 'base-layer-attribution');
76675
76676             var z = context.map().zoom();
76677             var overlays = context.background().overlayLayerSources() || [];
76678
76679             _selection.call(render, overlays.filter(function (s) {
76680               return s.validZoom(z);
76681             }), 'overlay-layer-attribution');
76682           }
76683
76684           return function (selection) {
76685             _selection = selection;
76686             context.background().on('change.attribution', update);
76687             context.map().on('move.attribution', throttle(update, 400, {
76688               leading: false
76689             }));
76690             update();
76691           };
76692         }
76693
76694         function uiContributors(context) {
76695           var osm = context.connection(),
76696               debouncedUpdate = debounce(function () {
76697             update();
76698           }, 1000),
76699               limit = 4,
76700               hidden = false,
76701               wrap = select(null);
76702
76703           function update() {
76704             if (!osm) return;
76705             var users = {},
76706                 entities = context.history().intersects(context.map().extent());
76707             entities.forEach(function (entity) {
76708               if (entity && entity.user) users[entity.user] = true;
76709             });
76710             var u = Object.keys(users),
76711                 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
76712             wrap.html('').call(svgIcon('#iD-icon-nearby', 'pre-text light'));
76713             var userList = select(document.createElement('span'));
76714             userList.selectAll().data(subset).enter().append('a').attr('class', 'user-link').attr('href', function (d) {
76715               return osm.userURL(d);
76716             }).attr('target', '_blank').html(String);
76717
76718             if (u.length > limit) {
76719               var count = select(document.createElement('span'));
76720               var othersNum = u.length - limit + 1;
76721               count.append('a').attr('target', '_blank').attr('href', function () {
76722                 return osm.changesetsURL(context.map().center(), context.map().zoom());
76723               }).html(othersNum);
76724               wrap.append('span').html(_t.html('contributors.truncated_list', {
76725                 n: othersNum,
76726                 users: userList.html(),
76727                 count: count.html()
76728               }));
76729             } else {
76730               wrap.append('span').html(_t.html('contributors.list', {
76731                 users: userList.html()
76732               }));
76733             }
76734
76735             if (!u.length) {
76736               hidden = true;
76737               wrap.transition().style('opacity', 0);
76738             } else if (hidden) {
76739               wrap.transition().style('opacity', 1);
76740             }
76741           }
76742
76743           return function (selection) {
76744             if (!osm) return;
76745             wrap = selection;
76746             update();
76747             osm.on('loaded.contributors', debouncedUpdate);
76748             context.map().on('move.contributors', debouncedUpdate);
76749           };
76750         }
76751
76752         var _popoverID = 0;
76753         function uiPopover(klass) {
76754           var _id = _popoverID++;
76755
76756           var _anchorSelection = select(null);
76757
76758           var popover = function popover(selection) {
76759             _anchorSelection = selection;
76760             selection.each(setup);
76761           };
76762
76763           var _animation = utilFunctor(false);
76764
76765           var _placement = utilFunctor('top'); // top, bottom, left, right
76766
76767
76768           var _alignment = utilFunctor('center'); // leading, center, trailing
76769
76770
76771           var _scrollContainer = utilFunctor(select(null));
76772
76773           var _content;
76774
76775           var _displayType = utilFunctor('');
76776
76777           var _hasArrow = utilFunctor(true); // use pointer events on supported platforms; fallback to mouse events
76778
76779
76780           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
76781
76782           popover.displayType = function (val) {
76783             if (arguments.length) {
76784               _displayType = utilFunctor(val);
76785               return popover;
76786             } else {
76787               return _displayType;
76788             }
76789           };
76790
76791           popover.hasArrow = function (val) {
76792             if (arguments.length) {
76793               _hasArrow = utilFunctor(val);
76794               return popover;
76795             } else {
76796               return _hasArrow;
76797             }
76798           };
76799
76800           popover.placement = function (val) {
76801             if (arguments.length) {
76802               _placement = utilFunctor(val);
76803               return popover;
76804             } else {
76805               return _placement;
76806             }
76807           };
76808
76809           popover.alignment = function (val) {
76810             if (arguments.length) {
76811               _alignment = utilFunctor(val);
76812               return popover;
76813             } else {
76814               return _alignment;
76815             }
76816           };
76817
76818           popover.scrollContainer = function (val) {
76819             if (arguments.length) {
76820               _scrollContainer = utilFunctor(val);
76821               return popover;
76822             } else {
76823               return _scrollContainer;
76824             }
76825           };
76826
76827           popover.content = function (val) {
76828             if (arguments.length) {
76829               _content = val;
76830               return popover;
76831             } else {
76832               return _content;
76833             }
76834           };
76835
76836           popover.isShown = function () {
76837             var popoverSelection = _anchorSelection.select('.popover-' + _id);
76838
76839             return !popoverSelection.empty() && popoverSelection.classed('in');
76840           };
76841
76842           popover.show = function () {
76843             _anchorSelection.each(show);
76844           };
76845
76846           popover.updateContent = function () {
76847             _anchorSelection.each(updateContent);
76848           };
76849
76850           popover.hide = function () {
76851             _anchorSelection.each(hide);
76852           };
76853
76854           popover.toggle = function () {
76855             _anchorSelection.each(toggle);
76856           };
76857
76858           popover.destroy = function (selection, selector) {
76859             // by default, just destroy the current popover
76860             selector = selector || '.popover-' + _id;
76861             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 () {
76862               return this.getAttribute('data-original-title') || this.getAttribute('title');
76863             }).attr('data-original-title', null).selectAll(selector).remove();
76864           };
76865
76866           popover.destroyAny = function (selection) {
76867             selection.call(popover.destroy, '.popover');
76868           };
76869
76870           function setup() {
76871             var anchor = select(this);
76872
76873             var animate = _animation.apply(this, arguments);
76874
76875             var popoverSelection = anchor.selectAll('.popover-' + _id).data([0]);
76876             var enter = popoverSelection.enter().append('div').attr('class', 'popover popover-' + _id + ' ' + (klass ? klass : '')).classed('arrowed', _hasArrow.apply(this, arguments));
76877             enter.append('div').attr('class', 'popover-arrow');
76878             enter.append('div').attr('class', 'popover-inner');
76879             popoverSelection = enter.merge(popoverSelection);
76880
76881             if (animate) {
76882               popoverSelection.classed('fade', true);
76883             }
76884
76885             var display = _displayType.apply(this, arguments);
76886
76887             if (display === 'hover') {
76888               var _lastNonMouseEnterTime;
76889
76890               anchor.on(_pointerPrefix + 'enter.popover', function (d3_event) {
76891                 if (d3_event.pointerType) {
76892                   if (d3_event.pointerType !== 'mouse') {
76893                     _lastNonMouseEnterTime = d3_event.timeStamp; // only allow hover behavior for mouse input
76894
76895                     return;
76896                   } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
76897                     // HACK: iOS 13.4 sends an erroneous `mouse` type pointerenter
76898                     // event for non-mouse interactions right after sending
76899                     // the correct type pointerenter event. Workaround by discarding
76900                     // any mouse event that occurs immediately after a non-mouse event.
76901                     return;
76902                   }
76903                 } // don't show if buttons are pressed, e.g. during click and drag of map
76904
76905
76906                 if (d3_event.buttons !== 0) return;
76907                 show.apply(this, arguments);
76908               }).on(_pointerPrefix + 'leave.popover', function () {
76909                 hide.apply(this, arguments);
76910               }) // show on focus too for better keyboard navigation support
76911               .on('focus.popover', function () {
76912                 show.apply(this, arguments);
76913               }).on('blur.popover', function () {
76914                 hide.apply(this, arguments);
76915               });
76916             } else if (display === 'clickFocus') {
76917               anchor.on(_pointerPrefix + 'down.popover', function (d3_event) {
76918                 d3_event.preventDefault();
76919                 d3_event.stopPropagation();
76920               }).on(_pointerPrefix + 'up.popover', function (d3_event) {
76921                 d3_event.preventDefault();
76922                 d3_event.stopPropagation();
76923               }).on('click.popover', toggle);
76924               popoverSelection // This attribute lets the popover take focus
76925               .attr('tabindex', 0).on('blur.popover', function () {
76926                 anchor.each(function () {
76927                   hide.apply(this, arguments);
76928                 });
76929               });
76930             }
76931           }
76932
76933           function show() {
76934             var anchor = select(this);
76935             var popoverSelection = anchor.selectAll('.popover-' + _id);
76936
76937             if (popoverSelection.empty()) {
76938               // popover was removed somehow, put it back
76939               anchor.call(popover.destroy);
76940               anchor.each(setup);
76941               popoverSelection = anchor.selectAll('.popover-' + _id);
76942             }
76943
76944             popoverSelection.classed('in', true);
76945
76946             var displayType = _displayType.apply(this, arguments);
76947
76948             if (displayType === 'clickFocus') {
76949               anchor.classed('active', true);
76950               popoverSelection.node().focus();
76951             }
76952
76953             anchor.each(updateContent);
76954           }
76955
76956           function updateContent() {
76957             var anchor = select(this);
76958
76959             if (_content) {
76960               anchor.selectAll('.popover-' + _id + ' > .popover-inner').call(_content.apply(this, arguments));
76961             }
76962
76963             updatePosition.apply(this, arguments); // hack: update multiple times to fix instances where the absolute offset is
76964             // set before the dynamic popover size is calculated by the browser
76965
76966             updatePosition.apply(this, arguments);
76967             updatePosition.apply(this, arguments);
76968           }
76969
76970           function updatePosition() {
76971             var anchor = select(this);
76972             var popoverSelection = anchor.selectAll('.popover-' + _id);
76973
76974             var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
76975
76976             var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
76977             var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
76978             var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
76979
76980             var placement = _placement.apply(this, arguments);
76981
76982             popoverSelection.classed('left', false).classed('right', false).classed('top', false).classed('bottom', false).classed(placement, true);
76983
76984             var alignment = _alignment.apply(this, arguments);
76985
76986             var alignFactor = 0.5;
76987
76988             if (alignment === 'leading') {
76989               alignFactor = 0;
76990             } else if (alignment === 'trailing') {
76991               alignFactor = 1;
76992             }
76993
76994             var anchorFrame = getFrame(anchor.node());
76995             var popoverFrame = getFrame(popoverSelection.node());
76996             var position;
76997
76998             switch (placement) {
76999               case 'top':
77000                 position = {
77001                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
77002                   y: anchorFrame.y - popoverFrame.h
77003                 };
77004                 break;
77005
77006               case 'bottom':
77007                 position = {
77008                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
77009                   y: anchorFrame.y + anchorFrame.h
77010                 };
77011                 break;
77012
77013               case 'left':
77014                 position = {
77015                   x: anchorFrame.x - popoverFrame.w,
77016                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
77017                 };
77018                 break;
77019
77020               case 'right':
77021                 position = {
77022                   x: anchorFrame.x + anchorFrame.w,
77023                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
77024                 };
77025                 break;
77026             }
77027
77028             if (position) {
77029               if (scrollNode && (placement === 'top' || placement === 'bottom')) {
77030                 var initialPosX = position.x;
77031
77032                 if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
77033                   position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
77034                 } else if (position.x < 10) {
77035                   position.x = 10;
77036                 }
77037
77038                 var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow'); // keep the arrow centered on the button, or as close as possible
77039
77040                 var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
77041                 arrow.style('left', ~~arrowPosX + 'px');
77042               }
77043
77044               popoverSelection.style('left', ~~position.x + 'px').style('top', ~~position.y + 'px');
77045             } else {
77046               popoverSelection.style('left', null).style('top', null);
77047             }
77048
77049             function getFrame(node) {
77050               var positionStyle = select(node).style('position');
77051
77052               if (positionStyle === 'absolute' || positionStyle === 'static') {
77053                 return {
77054                   x: node.offsetLeft - scrollLeft,
77055                   y: node.offsetTop - scrollTop,
77056                   w: node.offsetWidth,
77057                   h: node.offsetHeight
77058                 };
77059               } else {
77060                 return {
77061                   x: 0,
77062                   y: 0,
77063                   w: node.offsetWidth,
77064                   h: node.offsetHeight
77065                 };
77066               }
77067             }
77068           }
77069
77070           function hide() {
77071             var anchor = select(this);
77072
77073             if (_displayType.apply(this, arguments) === 'clickFocus') {
77074               anchor.classed('active', false);
77075             }
77076
77077             anchor.selectAll('.popover-' + _id).classed('in', false);
77078           }
77079
77080           function toggle() {
77081             if (select(this).select('.popover-' + _id).classed('in')) {
77082               hide.apply(this, arguments);
77083             } else {
77084               show.apply(this, arguments);
77085             }
77086           }
77087
77088           return popover;
77089         }
77090
77091         function uiTooltip(klass) {
77092           var tooltip = uiPopover((klass || '') + ' tooltip').displayType('hover');
77093
77094           var _title = function _title() {
77095             var title = this.getAttribute('data-original-title');
77096
77097             if (title) {
77098               return title;
77099             } else {
77100               title = this.getAttribute('title');
77101               this.removeAttribute('title');
77102               this.setAttribute('data-original-title', title);
77103             }
77104
77105             return title;
77106           };
77107
77108           var _heading = utilFunctor(null);
77109
77110           var _keys = utilFunctor(null);
77111
77112           tooltip.title = function (val) {
77113             if (!arguments.length) return _title;
77114             _title = utilFunctor(val);
77115             return tooltip;
77116           };
77117
77118           tooltip.heading = function (val) {
77119             if (!arguments.length) return _heading;
77120             _heading = utilFunctor(val);
77121             return tooltip;
77122           };
77123
77124           tooltip.keys = function (val) {
77125             if (!arguments.length) return _keys;
77126             _keys = utilFunctor(val);
77127             return tooltip;
77128           };
77129
77130           tooltip.content(function () {
77131             var heading = _heading.apply(this, arguments);
77132
77133             var text = _title.apply(this, arguments);
77134
77135             var keys = _keys.apply(this, arguments);
77136
77137             return function (selection) {
77138               var headingSelect = selection.selectAll('.tooltip-heading').data(heading ? [heading] : []);
77139               headingSelect.exit().remove();
77140               headingSelect.enter().append('div').attr('class', 'tooltip-heading').merge(headingSelect).html(heading);
77141               var textSelect = selection.selectAll('.tooltip-text').data(text ? [text] : []);
77142               textSelect.exit().remove();
77143               textSelect.enter().append('div').attr('class', 'tooltip-text').merge(textSelect).html(text);
77144               var keyhintWrap = selection.selectAll('.keyhint-wrap').data(keys && keys.length ? [0] : []);
77145               keyhintWrap.exit().remove();
77146               var keyhintWrapEnter = keyhintWrap.enter().append('div').attr('class', 'keyhint-wrap');
77147               keyhintWrapEnter.append('span').html(_t.html('tooltip_keyhint'));
77148               keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
77149               keyhintWrap.selectAll('kbd.shortcut').data(keys && keys.length ? keys : []).enter().append('kbd').attr('class', 'shortcut').html(function (d) {
77150                 return d;
77151               });
77152             };
77153           });
77154           return tooltip;
77155         }
77156
77157         function uiEditMenu(context) {
77158           var dispatch$1 = dispatch('toggled');
77159
77160           var _menu = select(null);
77161
77162           var _operations = []; // the position the menu should be displayed relative to
77163
77164           var _anchorLoc = [0, 0];
77165           var _anchorLocLonLat = [0, 0]; // a string indicating how the menu was opened
77166
77167           var _triggerType = '';
77168           var _vpTopMargin = 85; // viewport top margin
77169
77170           var _vpBottomMargin = 45; // viewport bottom margin
77171
77172           var _vpSideMargin = 35; // viewport side margin
77173
77174           var _menuTop = false;
77175
77176           var _menuHeight;
77177
77178           var _menuWidth; // hardcode these values to make menu positioning easier
77179
77180
77181           var _verticalPadding = 4; // see also `.edit-menu .tooltip` CSS; include margin
77182
77183           var _tooltipWidth = 210; // offset the menu slightly from the target location
77184
77185           var _menuSideMargin = 10;
77186           var _tooltips = [];
77187
77188           var editMenu = function editMenu(selection) {
77189             var isTouchMenu = _triggerType.includes('touch') || _triggerType.includes('pen');
77190
77191             var ops = _operations.filter(function (op) {
77192               return !isTouchMenu || !op.mouseOnly;
77193             });
77194
77195             if (!ops.length) return;
77196             _tooltips = []; // Position the menu above the anchor for stylus and finger input
77197             // since the mapper's hand likely obscures the screen below the anchor
77198
77199             _menuTop = isTouchMenu; // Show labels for touch input since there aren't hover tooltips
77200
77201             var showLabels = isTouchMenu;
77202             var buttonHeight = showLabels ? 32 : 34;
77203
77204             if (showLabels) {
77205               // Get a general idea of the width based on the length of the label
77206               _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function (op) {
77207                 return op.title.length;
77208               })));
77209             } else {
77210               _menuWidth = 44;
77211             }
77212
77213             _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
77214             _menu = selection.append('div').attr('class', 'edit-menu').classed('touch-menu', isTouchMenu).style('padding', _verticalPadding + 'px 0');
77215
77216             var buttons = _menu.selectAll('.edit-menu-item').data(ops); // enter
77217
77218
77219             var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
77220               return 'edit-menu-item edit-menu-item-' + d.id;
77221             }).style('height', buttonHeight + 'px').on('click', click) // don't listen for `mouseup` because we only care about non-mouse pointer types
77222             .on('pointerup', pointerup).on('pointerdown mousedown', function pointerdown(d3_event) {
77223               // don't let button presses also act as map input - #1869
77224               d3_event.stopPropagation();
77225             }).on('mouseenter.highlight', function (d3_event, d) {
77226               if (!d.relatedEntityIds || select(this).classed('disabled')) return;
77227               utilHighlightEntities(d.relatedEntityIds(), true, context);
77228             }).on('mouseleave.highlight', function (d3_event, d) {
77229               if (!d.relatedEntityIds) return;
77230               utilHighlightEntities(d.relatedEntityIds(), false, context);
77231             });
77232             buttonsEnter.each(function (d) {
77233               var tooltip = uiTooltip().heading(d.title).title(d.tooltip()).keys([d.keys[0]]);
77234
77235               _tooltips.push(tooltip);
77236
77237               select(this).call(tooltip).append('div').attr('class', 'icon-wrap').call(svgIcon('#iD-operation-' + d.id, 'operation'));
77238             });
77239
77240             if (showLabels) {
77241               buttonsEnter.append('span').attr('class', 'label').html(function (d) {
77242                 return d.title;
77243               });
77244             } // update
77245
77246
77247             buttonsEnter.merge(buttons).classed('disabled', function (d) {
77248               return d.disabled();
77249             });
77250             updatePosition();
77251             var initialScale = context.projection.scale();
77252             context.map().on('move.edit-menu', function () {
77253               if (initialScale !== context.projection.scale()) {
77254                 editMenu.close();
77255               }
77256             }).on('drawn.edit-menu', function (info) {
77257               if (info.full) updatePosition();
77258             });
77259             var lastPointerUpType; // `pointerup` is always called before `click`
77260
77261             function pointerup(d3_event) {
77262               lastPointerUpType = d3_event.pointerType;
77263             }
77264
77265             function click(d3_event, operation) {
77266               d3_event.stopPropagation();
77267
77268               if (operation.relatedEntityIds) {
77269                 utilHighlightEntities(operation.relatedEntityIds(), false, context);
77270               }
77271
77272               if (operation.disabled()) {
77273                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
77274                   // there are no tooltips for touch interactions so flash feedback instead
77275                   context.ui().flash.duration(4000).iconName('#iD-operation-' + operation.id).iconClass('operation disabled').label(operation.tooltip)();
77276                 }
77277               } else {
77278                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
77279                   context.ui().flash.duration(2000).iconName('#iD-operation-' + operation.id).iconClass('operation').label(operation.annotation() || operation.title)();
77280                 }
77281
77282                 operation();
77283                 editMenu.close();
77284               }
77285
77286               lastPointerUpType = null;
77287             }
77288
77289             dispatch$1.call('toggled', this, true);
77290           };
77291
77292           function updatePosition() {
77293             if (!_menu || _menu.empty()) return;
77294             var anchorLoc = context.projection(_anchorLocLonLat);
77295             var viewport = context.surfaceRect();
77296
77297             if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
77298               // close the menu if it's gone offscreen
77299               editMenu.close();
77300               return;
77301             }
77302
77303             var menuLeft = displayOnLeft(viewport);
77304             var offset = [0, 0];
77305             offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
77306
77307             if (_menuTop) {
77308               if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
77309                 // menu is near top viewport edge, shift downward
77310                 offset[1] = -anchorLoc[1] + _vpTopMargin;
77311               } else {
77312                 offset[1] = -_menuHeight;
77313               }
77314             } else {
77315               if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
77316                 // menu is near bottom viewport edge, shift upwards
77317                 offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
77318               } else {
77319                 offset[1] = 0;
77320               }
77321             }
77322
77323             var origin = geoVecAdd(anchorLoc, offset);
77324
77325             _menu.style('left', origin[0] + 'px').style('top', origin[1] + 'px');
77326
77327             var tooltipSide = tooltipPosition(viewport, menuLeft);
77328
77329             _tooltips.forEach(function (tooltip) {
77330               tooltip.placement(tooltipSide);
77331             });
77332
77333             function displayOnLeft(viewport) {
77334               if (_mainLocalizer.textDirection() === 'ltr') {
77335                 if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport.width - _vpSideMargin) {
77336                   // right menu would be too close to the right viewport edge, go left
77337                   return true;
77338                 } // prefer right menu
77339
77340
77341                 return false;
77342               } else {
77343                 // rtl
77344                 if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
77345                   // left menu would be too close to the left viewport edge, go right
77346                   return false;
77347                 } // prefer left menu
77348
77349
77350                 return true;
77351               }
77352             }
77353
77354             function tooltipPosition(viewport, menuLeft) {
77355               if (_mainLocalizer.textDirection() === 'ltr') {
77356                 if (menuLeft) {
77357                   // if there's not room for a right-side menu then there definitely
77358                   // isn't room for right-side tooltips
77359                   return 'left';
77360                 }
77361
77362                 if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport.width - _vpSideMargin) {
77363                   // right tooltips would be too close to the right viewport edge, go left
77364                   return 'left';
77365                 } // prefer right tooltips
77366
77367
77368                 return 'right';
77369               } else {
77370                 // rtl
77371                 if (!menuLeft) {
77372                   return 'right';
77373                 }
77374
77375                 if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
77376                   // left tooltips would be too close to the left viewport edge, go right
77377                   return 'right';
77378                 } // prefer left tooltips
77379
77380
77381                 return 'left';
77382               }
77383             }
77384           }
77385
77386           editMenu.close = function () {
77387             context.map().on('move.edit-menu', null).on('drawn.edit-menu', null);
77388
77389             _menu.remove();
77390
77391             _tooltips = [];
77392             dispatch$1.call('toggled', this, false);
77393           };
77394
77395           editMenu.anchorLoc = function (val) {
77396             if (!arguments.length) return _anchorLoc;
77397             _anchorLoc = val;
77398             _anchorLocLonLat = context.projection.invert(_anchorLoc);
77399             return editMenu;
77400           };
77401
77402           editMenu.triggerType = function (val) {
77403             if (!arguments.length) return _triggerType;
77404             _triggerType = val;
77405             return editMenu;
77406           };
77407
77408           editMenu.operations = function (val) {
77409             if (!arguments.length) return _operations;
77410             _operations = val;
77411             return editMenu;
77412           };
77413
77414           return utilRebind(editMenu, dispatch$1, 'on');
77415         }
77416
77417         function uiFeatureInfo(context) {
77418           function update(selection) {
77419             var features = context.features();
77420             var stats = features.stats();
77421             var count = 0;
77422             var hiddenList = features.hidden().map(function (k) {
77423               if (stats[k]) {
77424                 count += stats[k];
77425                 return _t('inspector.title_count', {
77426                   title: _t.html('feature.' + k + '.description'),
77427                   count: stats[k]
77428                 });
77429               }
77430
77431               return null;
77432             }).filter(Boolean);
77433             selection.html('');
77434
77435             if (hiddenList.length) {
77436               var tooltipBehavior = uiTooltip().placement('top').title(function () {
77437                 return hiddenList.join('<br/>');
77438               });
77439               selection.append('a').attr('class', 'chip').attr('href', '#').html(_t.html('feature_info.hidden_warning', {
77440                 count: count
77441               })).call(tooltipBehavior).on('click', function (d3_event) {
77442                 tooltipBehavior.hide();
77443                 d3_event.preventDefault(); // open the Map Data pane
77444
77445                 context.ui().togglePanes(context.container().select('.map-panes .map-data-pane'));
77446               });
77447             }
77448
77449             selection.classed('hide', !hiddenList.length);
77450           }
77451
77452           return function (selection) {
77453             update(selection);
77454             context.features().on('change.feature_info', function () {
77455               update(selection);
77456             });
77457           };
77458         }
77459
77460         function uiFlash(context) {
77461           var _flashTimer;
77462
77463           var _duration = 2000;
77464           var _iconName = '#iD-icon-no';
77465           var _iconClass = 'disabled';
77466           var _label = '';
77467
77468           function flash() {
77469             if (_flashTimer) {
77470               _flashTimer.stop();
77471             }
77472
77473             context.container().select('.main-footer-wrap').classed('footer-hide', true).classed('footer-show', false);
77474             context.container().select('.flash-wrap').classed('footer-hide', false).classed('footer-show', true);
77475             var content = context.container().select('.flash-wrap').selectAll('.flash-content').data([0]); // Enter
77476
77477             var contentEnter = content.enter().append('div').attr('class', 'flash-content');
77478             var iconEnter = contentEnter.append('svg').attr('class', 'flash-icon icon').append('g').attr('transform', 'translate(10,10)');
77479             iconEnter.append('circle').attr('r', 9);
77480             iconEnter.append('use').attr('transform', 'translate(-7,-7)').attr('width', '14').attr('height', '14');
77481             contentEnter.append('div').attr('class', 'flash-text'); // Update
77482
77483             content = content.merge(contentEnter);
77484             content.selectAll('.flash-icon').attr('class', 'icon flash-icon ' + (_iconClass || ''));
77485             content.selectAll('.flash-icon use').attr('xlink:href', _iconName);
77486             content.selectAll('.flash-text').attr('class', 'flash-text').html(_label);
77487             _flashTimer = d3_timeout(function () {
77488               _flashTimer = null;
77489               context.container().select('.main-footer-wrap').classed('footer-hide', false).classed('footer-show', true);
77490               context.container().select('.flash-wrap').classed('footer-hide', true).classed('footer-show', false);
77491             }, _duration);
77492             return content;
77493           }
77494
77495           flash.duration = function (_) {
77496             if (!arguments.length) return _duration;
77497             _duration = _;
77498             return flash;
77499           };
77500
77501           flash.label = function (_) {
77502             if (!arguments.length) return _label;
77503             _label = _;
77504             return flash;
77505           };
77506
77507           flash.iconName = function (_) {
77508             if (!arguments.length) return _iconName;
77509             _iconName = _;
77510             return flash;
77511           };
77512
77513           flash.iconClass = function (_) {
77514             if (!arguments.length) return _iconClass;
77515             _iconClass = _;
77516             return flash;
77517           };
77518
77519           return flash;
77520         }
77521
77522         function uiFullScreen(context) {
77523           var element = context.container().node(); // var button = d3_select(null);
77524
77525           function getFullScreenFn() {
77526             if (element.requestFullscreen) {
77527               return element.requestFullscreen;
77528             } else if (element.msRequestFullscreen) {
77529               return element.msRequestFullscreen;
77530             } else if (element.mozRequestFullScreen) {
77531               return element.mozRequestFullScreen;
77532             } else if (element.webkitRequestFullscreen) {
77533               return element.webkitRequestFullscreen;
77534             }
77535           }
77536
77537           function getExitFullScreenFn() {
77538             if (document.exitFullscreen) {
77539               return document.exitFullscreen;
77540             } else if (document.msExitFullscreen) {
77541               return document.msExitFullscreen;
77542             } else if (document.mozCancelFullScreen) {
77543               return document.mozCancelFullScreen;
77544             } else if (document.webkitExitFullscreen) {
77545               return document.webkitExitFullscreen;
77546             }
77547           }
77548
77549           function isFullScreen() {
77550             return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
77551           }
77552
77553           function isSupported() {
77554             return !!getFullScreenFn();
77555           }
77556
77557           function fullScreen(d3_event) {
77558             d3_event.preventDefault();
77559
77560             if (!isFullScreen()) {
77561               // button.classed('active', true);
77562               getFullScreenFn().apply(element);
77563             } else {
77564               // button.classed('active', false);
77565               getExitFullScreenFn().apply(document);
77566             }
77567           }
77568
77569           return function () {
77570             // selection) {
77571             if (!isSupported()) return; // button = selection.append('button')
77572             //     .attr('title', t('full_screen'))
77573             //     .on('click', fullScreen)
77574             //     .call(tooltip);
77575             // button.append('span')
77576             //     .attr('class', 'icon full-screen');
77577
77578             var detected = utilDetect();
77579             var keys = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
77580             context.keybinding().on(keys, fullScreen);
77581           };
77582         }
77583
77584         function uiGeolocate(context) {
77585           var _geolocationOptions = {
77586             // prioritize speed and power usage over precision
77587             enableHighAccuracy: false,
77588             // don't hang indefinitely getting the location
77589             timeout: 6000 // 6sec
77590
77591           };
77592
77593           var _locating = uiLoading(context).message(_t.html('geolocate.locating')).blocking(true);
77594
77595           var _layer = context.layers().layer('geolocate');
77596
77597           var _position;
77598
77599           var _extent;
77600
77601           var _timeoutID;
77602
77603           var _button = select(null);
77604
77605           function click() {
77606             if (context.inIntro()) return;
77607
77608             if (!_layer.enabled() && !_locating.isShown()) {
77609               // This timeout ensures that we still call finish() even if
77610               // the user declines to share their location in Firefox
77611               _timeoutID = setTimeout(error, 10000
77612               /* 10sec */
77613               );
77614               context.container().call(_locating); // get the latest position even if we already have one
77615
77616               navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
77617             } else {
77618               _locating.close();
77619
77620               _layer.enabled(null, false);
77621
77622               updateButtonState();
77623             }
77624           }
77625
77626           function zoomTo() {
77627             context.enter(modeBrowse(context));
77628             var map = context.map();
77629
77630             _layer.enabled(_position, true);
77631
77632             updateButtonState();
77633             map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
77634           }
77635
77636           function success(geolocation) {
77637             _position = geolocation;
77638             var coords = _position.coords;
77639             _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
77640             zoomTo();
77641             finish();
77642           }
77643
77644           function error() {
77645             if (_position) {
77646               // use the position from a previous call if we have one
77647               zoomTo();
77648             } else {
77649               context.ui().flash.label(_t.html('geolocate.location_unavailable')).iconName('#iD-icon-geolocate')();
77650             }
77651
77652             finish();
77653           }
77654
77655           function finish() {
77656             _locating.close(); // unblock ui
77657
77658
77659             if (_timeoutID) {
77660               clearTimeout(_timeoutID);
77661             }
77662
77663             _timeoutID = undefined;
77664           }
77665
77666           function updateButtonState() {
77667             _button.classed('active', _layer.enabled());
77668           }
77669
77670           return function (selection) {
77671             if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
77672             _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')]));
77673             context.keybinding().on(_t('geolocate.key'), click);
77674           };
77675         }
77676
77677         function uiPanelBackground(context) {
77678           var background = context.background();
77679           var _currSourceName = null;
77680           var _metadata = {};
77681           var _metadataKeys = ['zoom', 'vintage', 'source', 'description', 'resolution', 'accuracy'];
77682
77683           var debouncedRedraw = debounce(redraw, 250);
77684
77685           function redraw(selection) {
77686             var source = background.baseLayerSource();
77687             if (!source) return;
77688             var isDG = source.id.match(/^DigitalGlobe/i) !== null;
77689             var sourceLabel = source.label();
77690
77691             if (_currSourceName !== sourceLabel) {
77692               _currSourceName = sourceLabel;
77693               _metadata = {};
77694             }
77695
77696             selection.html('');
77697             var list = selection.append('ul').attr('class', 'background-info');
77698             list.append('li').html(_currSourceName);
77699
77700             _metadataKeys.forEach(function (k) {
77701               // DigitalGlobe vintage is available in raster layers for now.
77702               if (isDG && k === 'vintage') return;
77703               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]);
77704             });
77705
77706             debouncedGetMetadata(selection);
77707             var toggleTiles = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
77708             selection.append('a').html(_t.html('info_panels.background.' + toggleTiles)).attr('href', '#').attr('class', 'button button-toggle-tiles').on('click', function (d3_event) {
77709               d3_event.preventDefault();
77710               context.setDebug('tile', !context.getDebug('tile'));
77711               selection.call(redraw);
77712             });
77713
77714             if (isDG) {
77715               var key = source.id + '-vintage';
77716               var sourceVintage = context.background().findSource(key);
77717               var showsVintage = context.background().showsLayer(sourceVintage);
77718               var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
77719               selection.append('a').html(_t.html('info_panels.background.' + toggleVintage)).attr('href', '#').attr('class', 'button button-toggle-vintage').on('click', function (d3_event) {
77720                 d3_event.preventDefault();
77721                 context.background().toggleOverlayLayer(sourceVintage);
77722                 selection.call(redraw);
77723               });
77724             } // disable if necessary
77725
77726
77727             ['DigitalGlobe-Premium', 'DigitalGlobe-Standard'].forEach(function (layerId) {
77728               if (source.id !== layerId) {
77729                 var key = layerId + '-vintage';
77730                 var sourceVintage = context.background().findSource(key);
77731
77732                 if (context.background().showsLayer(sourceVintage)) {
77733                   context.background().toggleOverlayLayer(sourceVintage);
77734                 }
77735               }
77736             });
77737           }
77738
77739           var debouncedGetMetadata = debounce(getMetadata, 250);
77740
77741           function getMetadata(selection) {
77742             var tile = context.container().select('.layer-background img.tile-center'); // tile near viewport center
77743
77744             if (tile.empty()) return;
77745             var sourceName = _currSourceName;
77746             var d = tile.datum();
77747             var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
77748             var center = context.map().center(); // update zoom
77749
77750             _metadata.zoom = String(zoom);
77751             selection.selectAll('.background-info-list-zoom').classed('hide', false).selectAll('.background-info-span-zoom').html(_metadata.zoom);
77752             if (!d || !d.length >= 3) return;
77753             background.baseLayerSource().getMetadata(center, d, function (err, result) {
77754               if (err || _currSourceName !== sourceName) return; // update vintage
77755
77756               var vintage = result.vintage;
77757               _metadata.vintage = vintage && vintage.range || _t('info_panels.background.unknown');
77758               selection.selectAll('.background-info-list-vintage').classed('hide', false).selectAll('.background-info-span-vintage').html(_metadata.vintage); // update other _metadata
77759
77760               _metadataKeys.forEach(function (k) {
77761                 if (k === 'zoom' || k === 'vintage') return; // done already
77762
77763                 var val = result[k];
77764                 _metadata[k] = val;
77765                 selection.selectAll('.background-info-list-' + k).classed('hide', !val).selectAll('.background-info-span-' + k).html(val);
77766               });
77767             });
77768           }
77769
77770           var panel = function panel(selection) {
77771             selection.call(redraw);
77772             context.map().on('drawn.info-background', function () {
77773               selection.call(debouncedRedraw);
77774             }).on('move.info-background', function () {
77775               selection.call(debouncedGetMetadata);
77776             });
77777           };
77778
77779           panel.off = function () {
77780             context.map().on('drawn.info-background', null).on('move.info-background', null);
77781           };
77782
77783           panel.id = 'background';
77784           panel.label = _t.html('info_panels.background.title');
77785           panel.key = _t('info_panels.background.key');
77786           return panel;
77787         }
77788
77789         function uiPanelHistory(context) {
77790           var osm;
77791
77792           function displayTimestamp(timestamp) {
77793             if (!timestamp) return _t('info_panels.history.unknown');
77794             var options = {
77795               day: 'numeric',
77796               month: 'short',
77797               year: 'numeric',
77798               hour: 'numeric',
77799               minute: 'numeric',
77800               second: 'numeric'
77801             };
77802             var d = new Date(timestamp);
77803             if (isNaN(d.getTime())) return _t('info_panels.history.unknown');
77804             return d.toLocaleString(_mainLocalizer.localeCode(), options);
77805           }
77806
77807           function displayUser(selection, userName) {
77808             if (!userName) {
77809               selection.append('span').html(_t.html('info_panels.history.unknown'));
77810               return;
77811             }
77812
77813             selection.append('span').attr('class', 'user-name').html(userName);
77814             var links = selection.append('div').attr('class', 'links');
77815
77816             if (osm) {
77817               links.append('a').attr('class', 'user-osm-link').attr('href', osm.userURL(userName)).attr('target', '_blank').html('OSM');
77818             }
77819
77820             links.append('a').attr('class', 'user-hdyc-link').attr('href', 'https://hdyc.neis-one.org/?' + userName).attr('target', '_blank').attr('tabindex', -1).html('HDYC');
77821           }
77822
77823           function displayChangeset(selection, changeset) {
77824             if (!changeset) {
77825               selection.append('span').html(_t.html('info_panels.history.unknown'));
77826               return;
77827             }
77828
77829             selection.append('span').attr('class', 'changeset-id').html(changeset);
77830             var links = selection.append('div').attr('class', 'links');
77831
77832             if (osm) {
77833               links.append('a').attr('class', 'changeset-osm-link').attr('href', osm.changesetURL(changeset)).attr('target', '_blank').html('OSM');
77834             }
77835
77836             links.append('a').attr('class', 'changeset-osmcha-link').attr('href', 'https://osmcha.org/changesets/' + changeset).attr('target', '_blank').html('OSMCha');
77837             links.append('a').attr('class', 'changeset-achavi-link').attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset).attr('target', '_blank').html('Achavi');
77838           }
77839
77840           function redraw(selection) {
77841             var selectedNoteID = context.selectedNoteID();
77842             osm = context.connection();
77843             var selected, note, entity;
77844
77845             if (selectedNoteID && osm) {
77846               // selected 1 note
77847               selected = [_t('note.note') + ' ' + selectedNoteID];
77848               note = osm.getNote(selectedNoteID);
77849             } else {
77850               // selected 1..n entities
77851               selected = context.selectedIDs().filter(function (e) {
77852                 return context.hasEntity(e);
77853               });
77854
77855               if (selected.length) {
77856                 entity = context.entity(selected[0]);
77857               }
77858             }
77859
77860             var singular = selected.length === 1 ? selected[0] : null;
77861             selection.html('');
77862             selection.append('h4').attr('class', 'history-heading').html(singular || _t.html('info_panels.selected', {
77863               n: selected.length
77864             }));
77865             if (!singular) return;
77866
77867             if (entity) {
77868               selection.call(redrawEntity, entity);
77869             } else if (note) {
77870               selection.call(redrawNote, note);
77871             }
77872           }
77873
77874           function redrawNote(selection, note) {
77875             if (!note || note.isNew()) {
77876               selection.append('div').html(_t.html('info_panels.history.note_no_history'));
77877               return;
77878             }
77879
77880             var list = selection.append('ul');
77881             list.append('li').html(_t.html('info_panels.history.note_comments') + ':').append('span').html(note.comments.length);
77882
77883             if (note.comments.length) {
77884               list.append('li').html(_t.html('info_panels.history.note_created_date') + ':').append('span').html(displayTimestamp(note.comments[0].date));
77885               list.append('li').html(_t.html('info_panels.history.note_created_user') + ':').call(displayUser, note.comments[0].user);
77886             }
77887
77888             if (osm) {
77889               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'));
77890             }
77891           }
77892
77893           function redrawEntity(selection, entity) {
77894             if (!entity || entity.isNew()) {
77895               selection.append('div').html(_t.html('info_panels.history.no_history'));
77896               return;
77897             }
77898
77899             var links = selection.append('div').attr('class', 'links');
77900
77901             if (osm) {
77902               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');
77903             }
77904
77905             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');
77906             var list = selection.append('ul');
77907             list.append('li').html(_t.html('info_panels.history.version') + ':').append('span').html(entity.version);
77908             list.append('li').html(_t.html('info_panels.history.last_edit') + ':').append('span').html(displayTimestamp(entity.timestamp));
77909             list.append('li').html(_t.html('info_panels.history.edited_by') + ':').call(displayUser, entity.user);
77910             list.append('li').html(_t.html('info_panels.history.changeset') + ':').call(displayChangeset, entity.changeset);
77911           }
77912
77913           var panel = function panel(selection) {
77914             selection.call(redraw);
77915             context.map().on('drawn.info-history', function () {
77916               selection.call(redraw);
77917             });
77918             context.on('enter.info-history', function () {
77919               selection.call(redraw);
77920             });
77921           };
77922
77923           panel.off = function () {
77924             context.map().on('drawn.info-history', null);
77925             context.on('enter.info-history', null);
77926           };
77927
77928           panel.id = 'history';
77929           panel.label = _t.html('info_panels.history.title');
77930           panel.key = _t('info_panels.history.key');
77931           return panel;
77932         }
77933
77934         var OSM_PRECISION = 7;
77935         /**
77936          * Returns a localized representation of the given length measurement.
77937          *
77938          * @param {Number} m area in meters
77939          * @param {Boolean} isImperial true for U.S. customary units; false for metric
77940          */
77941
77942         function displayLength(m, isImperial) {
77943           var d = m * (isImperial ? 3.28084 : 1);
77944           var unit;
77945
77946           if (isImperial) {
77947             if (d >= 5280) {
77948               d /= 5280;
77949               unit = 'miles';
77950             } else {
77951               unit = 'feet';
77952             }
77953           } else {
77954             if (d >= 1000) {
77955               d /= 1000;
77956               unit = 'kilometers';
77957             } else {
77958               unit = 'meters';
77959             }
77960           }
77961
77962           return _t('units.' + unit, {
77963             quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
77964               maximumSignificantDigits: 4
77965             })
77966           });
77967         }
77968         /**
77969          * Returns a localized representation of the given area measurement.
77970          *
77971          * @param {Number} m2 area in square meters
77972          * @param {Boolean} isImperial true for U.S. customary units; false for metric
77973          */
77974
77975         function displayArea(m2, isImperial) {
77976           var locale = _mainLocalizer.localeCode();
77977           var d = m2 * (isImperial ? 10.7639111056 : 1);
77978           var d1, d2, area;
77979           var unit1 = '';
77980           var unit2 = '';
77981
77982           if (isImperial) {
77983             if (d >= 6969600) {
77984               // > 0.25mi² show mi²
77985               d1 = d / 27878400;
77986               unit1 = 'square_miles';
77987             } else {
77988               d1 = d;
77989               unit1 = 'square_feet';
77990             }
77991
77992             if (d > 4356 && d < 43560000) {
77993               // 0.1 - 1000 acres
77994               d2 = d / 43560;
77995               unit2 = 'acres';
77996             }
77997           } else {
77998             if (d >= 250000) {
77999               // > 0.25km² show km²
78000               d1 = d / 1000000;
78001               unit1 = 'square_kilometers';
78002             } else {
78003               d1 = d;
78004               unit1 = 'square_meters';
78005             }
78006
78007             if (d > 1000 && d < 10000000) {
78008               // 0.1 - 1000 hectares
78009               d2 = d / 10000;
78010               unit2 = 'hectares';
78011             }
78012           }
78013
78014           area = _t('units.' + unit1, {
78015             quantity: d1.toLocaleString(locale, {
78016               maximumSignificantDigits: 4
78017             })
78018           });
78019
78020           if (d2) {
78021             return _t('units.area_pair', {
78022               area1: area,
78023               area2: _t('units.' + unit2, {
78024                 quantity: d2.toLocaleString(locale, {
78025                   maximumSignificantDigits: 2
78026                 })
78027               })
78028             });
78029           } else {
78030             return area;
78031           }
78032         }
78033
78034         function wrap$2(x, min, max) {
78035           var d = max - min;
78036           return ((x - min) % d + d) % d + min;
78037         }
78038
78039         function clamp$1(x, min, max) {
78040           return Math.max(min, Math.min(x, max));
78041         }
78042
78043         function displayCoordinate(deg, pos, neg) {
78044           var locale = _mainLocalizer.localeCode();
78045           var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
78046           var sec = (min - Math.floor(min)) * 60;
78047           var displayDegrees = _t('units.arcdegrees', {
78048             quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
78049           });
78050           var displayCoordinate;
78051
78052           if (Math.floor(sec) > 0) {
78053             displayCoordinate = displayDegrees + _t('units.arcminutes', {
78054               quantity: Math.floor(min).toLocaleString(locale)
78055             }) + _t('units.arcseconds', {
78056               quantity: Math.round(sec).toLocaleString(locale)
78057             });
78058           } else if (Math.floor(min) > 0) {
78059             displayCoordinate = displayDegrees + _t('units.arcminutes', {
78060               quantity: Math.round(min).toLocaleString(locale)
78061             });
78062           } else {
78063             displayCoordinate = _t('units.arcdegrees', {
78064               quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
78065             });
78066           }
78067
78068           if (deg === 0) {
78069             return displayCoordinate;
78070           } else {
78071             return _t('units.coordinate', {
78072               coordinate: displayCoordinate,
78073               direction: _t('units.' + (deg > 0 ? pos : neg))
78074             });
78075           }
78076         }
78077         /**
78078          * Returns given coordinate pair in degree-minute-second format.
78079          *
78080          * @param {Array<Number>} coord longitude and latitude
78081          */
78082
78083
78084         function dmsCoordinatePair(coord) {
78085           return _t('units.coordinate_pair', {
78086             latitude: displayCoordinate(clamp$1(coord[1], -90, 90), 'north', 'south'),
78087             longitude: displayCoordinate(wrap$2(coord[0], -180, 180), 'east', 'west')
78088           });
78089         }
78090         /**
78091          * Returns the given coordinate pair in decimal format.
78092          * note: unlocalized to avoid comma ambiguity - see #4765
78093          *
78094          * @param {Array<Number>} coord longitude and latitude
78095          */
78096
78097         function decimalCoordinatePair(coord) {
78098           return _t('units.coordinate_pair', {
78099             latitude: clamp$1(coord[1], -90, 90).toFixed(OSM_PRECISION),
78100             longitude: wrap$2(coord[0], -180, 180).toFixed(OSM_PRECISION)
78101           });
78102         }
78103
78104         function uiPanelLocation(context) {
78105           var currLocation = '';
78106
78107           function redraw(selection) {
78108             selection.html('');
78109             var list = selection.append('ul'); // Mouse coordinates
78110
78111             var coord = context.map().mouseCoordinates();
78112
78113             if (coord.some(isNaN)) {
78114               coord = context.map().center();
78115             }
78116
78117             list.append('li').html(dmsCoordinatePair(coord)).append('li').html(decimalCoordinatePair(coord)); // Location Info
78118
78119             selection.append('div').attr('class', 'location-info').html(currLocation || ' ');
78120             debouncedGetLocation(selection, coord);
78121           }
78122
78123           var debouncedGetLocation = debounce(getLocation, 250);
78124
78125           function getLocation(selection, coord) {
78126             if (!services.geocoder) {
78127               currLocation = _t('info_panels.location.unknown_location');
78128               selection.selectAll('.location-info').html(currLocation);
78129             } else {
78130               services.geocoder.reverse(coord, function (err, result) {
78131                 currLocation = result ? result.display_name : _t('info_panels.location.unknown_location');
78132                 selection.selectAll('.location-info').html(currLocation);
78133               });
78134             }
78135           }
78136
78137           var panel = function panel(selection) {
78138             selection.call(redraw);
78139             context.surface().on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'move.info-location', function () {
78140               selection.call(redraw);
78141             });
78142           };
78143
78144           panel.off = function () {
78145             context.surface().on('.info-location', null);
78146           };
78147
78148           panel.id = 'location';
78149           panel.label = _t.html('info_panels.location.title');
78150           panel.key = _t('info_panels.location.key');
78151           return panel;
78152         }
78153
78154         function uiPanelMeasurement(context) {
78155           function radiansToMeters(r) {
78156             // using WGS84 authalic radius (6371007.1809 m)
78157             return r * 6371007.1809;
78158           }
78159
78160           function steradiansToSqmeters(r) {
78161             // http://gis.stackexchange.com/a/124857/40446
78162             return r / (4 * Math.PI) * 510065621724000;
78163           }
78164
78165           function toLineString(feature) {
78166             if (feature.type === 'LineString') return feature;
78167             var result = {
78168               type: 'LineString',
78169               coordinates: []
78170             };
78171
78172             if (feature.type === 'Polygon') {
78173               result.coordinates = feature.coordinates[0];
78174             } else if (feature.type === 'MultiPolygon') {
78175               result.coordinates = feature.coordinates[0][0];
78176             }
78177
78178             return result;
78179           }
78180
78181           function redraw(selection) {
78182             var graph = context.graph();
78183             var selectedNoteID = context.selectedNoteID();
78184             var osm = services.osm;
78185             var isImperial = !_mainLocalizer.usesMetric();
78186             var localeCode = _mainLocalizer.localeCode();
78187             var heading;
78188             var center, location, centroid;
78189             var closed, geometry;
78190             var totalNodeCount,
78191                 length = 0,
78192                 area = 0,
78193                 distance;
78194
78195             if (selectedNoteID && osm) {
78196               // selected 1 note
78197               var note = osm.getNote(selectedNoteID);
78198               heading = _t('note.note') + ' ' + selectedNoteID;
78199               location = note.loc;
78200               geometry = 'note';
78201             } else {
78202               // selected 1..n entities
78203               var selectedIDs = context.selectedIDs().filter(function (id) {
78204                 return context.hasEntity(id);
78205               });
78206               var selected = selectedIDs.map(function (id) {
78207                 return context.entity(id);
78208               });
78209               heading = selected.length === 1 ? selected[0].id : _t('info_panels.selected', {
78210                 n: selected.length
78211               });
78212
78213               if (selected.length) {
78214                 var extent = geoExtent();
78215
78216                 for (var i in selected) {
78217                   var entity = selected[i];
78218
78219                   extent._extend(entity.extent(graph));
78220
78221                   geometry = entity.geometry(graph);
78222
78223                   if (geometry === 'line' || geometry === 'area') {
78224                     closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
78225                     var feature = entity.asGeoJSON(graph);
78226                     length += radiansToMeters(d3_geoLength(toLineString(feature)));
78227                     centroid = d3_geoCentroid(feature);
78228
78229                     if (closed) {
78230                       area += steradiansToSqmeters(entity.area(graph));
78231                     }
78232                   }
78233                 }
78234
78235                 if (selected.length > 1) {
78236                   geometry = null;
78237                   closed = null;
78238                   centroid = null;
78239                 }
78240
78241                 if (selected.length === 2 && selected[0].type === 'node' && selected[1].type === 'node') {
78242                   distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
78243                 }
78244
78245                 if (selected.length === 1 && selected[0].type === 'node') {
78246                   location = selected[0].loc;
78247                 } else {
78248                   totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
78249                 }
78250
78251                 if (!location && !centroid) {
78252                   center = extent.center();
78253                 }
78254               }
78255             }
78256
78257             selection.html('');
78258
78259             if (heading) {
78260               selection.append('h4').attr('class', 'measurement-heading').html(heading);
78261             }
78262
78263             var list = selection.append('ul');
78264             var coordItem;
78265
78266             if (geometry) {
78267               list.append('li').html(_t.html('info_panels.measurement.geometry') + ':').append('span').html(closed ? _t('info_panels.measurement.closed_' + geometry) : _t('geometry.' + geometry));
78268             }
78269
78270             if (totalNodeCount) {
78271               list.append('li').html(_t.html('info_panels.measurement.node_count') + ':').append('span').html(totalNodeCount.toLocaleString(localeCode));
78272             }
78273
78274             if (area) {
78275               list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, isImperial));
78276             }
78277
78278             if (length) {
78279               list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, isImperial));
78280             }
78281
78282             if (typeof distance === 'number') {
78283               list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, isImperial));
78284             }
78285
78286             if (location) {
78287               coordItem = list.append('li').html(_t.html('info_panels.measurement.location') + ':');
78288               coordItem.append('span').html(dmsCoordinatePair(location));
78289               coordItem.append('span').html(decimalCoordinatePair(location));
78290             }
78291
78292             if (centroid) {
78293               coordItem = list.append('li').html(_t.html('info_panels.measurement.centroid') + ':');
78294               coordItem.append('span').html(dmsCoordinatePair(centroid));
78295               coordItem.append('span').html(decimalCoordinatePair(centroid));
78296             }
78297
78298             if (center) {
78299               coordItem = list.append('li').html(_t.html('info_panels.measurement.center') + ':');
78300               coordItem.append('span').html(dmsCoordinatePair(center));
78301               coordItem.append('span').html(decimalCoordinatePair(center));
78302             }
78303
78304             if (length || area || typeof distance === 'number') {
78305               var toggle = isImperial ? 'imperial' : 'metric';
78306               selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
78307                 d3_event.preventDefault();
78308                 isImperial = !isImperial;
78309                 selection.call(redraw);
78310               });
78311             }
78312           }
78313
78314           var panel = function panel(selection) {
78315             selection.call(redraw);
78316             context.map().on('drawn.info-measurement', function () {
78317               selection.call(redraw);
78318             });
78319             context.on('enter.info-measurement', function () {
78320               selection.call(redraw);
78321             });
78322           };
78323
78324           panel.off = function () {
78325             context.map().on('drawn.info-measurement', null);
78326             context.on('enter.info-measurement', null);
78327           };
78328
78329           panel.id = 'measurement';
78330           panel.label = _t.html('info_panels.measurement.title');
78331           panel.key = _t('info_panels.measurement.key');
78332           return panel;
78333         }
78334
78335         var uiInfoPanels = {
78336           background: uiPanelBackground,
78337           history: uiPanelHistory,
78338           location: uiPanelLocation,
78339           measurement: uiPanelMeasurement
78340         };
78341
78342         function uiInfo(context) {
78343           var ids = Object.keys(uiInfoPanels);
78344           var wasActive = ['measurement'];
78345           var panels = {};
78346           var active = {}; // create panels
78347
78348           ids.forEach(function (k) {
78349             if (!panels[k]) {
78350               panels[k] = uiInfoPanels[k](context);
78351               active[k] = false;
78352             }
78353           });
78354
78355           function info(selection) {
78356             function redraw() {
78357               var activeids = ids.filter(function (k) {
78358                 return active[k];
78359               }).sort();
78360               var containers = infoPanels.selectAll('.panel-container').data(activeids, function (k) {
78361                 return k;
78362               });
78363               containers.exit().style('opacity', 1).transition().duration(200).style('opacity', 0).on('end', function (d) {
78364                 select(this).call(panels[d].off).remove();
78365               });
78366               var enter = containers.enter().append('div').attr('class', function (d) {
78367                 return 'fillD2 panel-container panel-container-' + d;
78368               });
78369               enter.style('opacity', 0).transition().duration(200).style('opacity', 1);
78370               var title = enter.append('div').attr('class', 'panel-title fillD2');
78371               title.append('h3').html(function (d) {
78372                 return panels[d].label;
78373               });
78374               title.append('button').attr('class', 'close').on('click', function (d3_event, d) {
78375                 d3_event.stopImmediatePropagation();
78376                 d3_event.preventDefault();
78377                 info.toggle(d);
78378               }).call(svgIcon('#iD-icon-close'));
78379               enter.append('div').attr('class', function (d) {
78380                 return 'panel-content panel-content-' + d;
78381               }); // redraw the panels
78382
78383               infoPanels.selectAll('.panel-content').each(function (d) {
78384                 select(this).call(panels[d]);
78385               });
78386             }
78387
78388             info.toggle = function (which) {
78389               var activeids = ids.filter(function (k) {
78390                 return active[k];
78391               });
78392
78393               if (which) {
78394                 // toggle one
78395                 active[which] = !active[which];
78396
78397                 if (activeids.length === 1 && activeids[0] === which) {
78398                   // none active anymore
78399                   wasActive = [which];
78400                 }
78401
78402                 context.container().select('.' + which + '-panel-toggle-item').classed('active', active[which]).select('input').property('checked', active[which]);
78403               } else {
78404                 // toggle all
78405                 if (activeids.length) {
78406                   wasActive = activeids;
78407                   activeids.forEach(function (k) {
78408                     active[k] = false;
78409                   });
78410                 } else {
78411                   wasActive.forEach(function (k) {
78412                     active[k] = true;
78413                   });
78414                 }
78415               }
78416
78417               redraw();
78418             };
78419
78420             var infoPanels = selection.selectAll('.info-panels').data([0]);
78421             infoPanels = infoPanels.enter().append('div').attr('class', 'info-panels').merge(infoPanels);
78422             redraw();
78423             context.keybinding().on(uiCmd('⌘' + _t('info_panels.key')), function (d3_event) {
78424               d3_event.stopImmediatePropagation();
78425               d3_event.preventDefault();
78426               info.toggle();
78427             });
78428             ids.forEach(function (k) {
78429               var key = _t('info_panels.' + k + '.key', {
78430                 "default": null
78431               });
78432               if (!key) return;
78433               context.keybinding().on(uiCmd('⌘⇧' + key), function (d3_event) {
78434                 d3_event.stopImmediatePropagation();
78435                 d3_event.preventDefault();
78436                 info.toggle(k);
78437               });
78438             });
78439           }
78440
78441           return info;
78442         }
78443
78444         function pointBox(loc, context) {
78445           var rect = context.surfaceRect();
78446           var point = context.curtainProjection(loc);
78447           return {
78448             left: point[0] + rect.left - 40,
78449             top: point[1] + rect.top - 60,
78450             width: 80,
78451             height: 90
78452           };
78453         }
78454         function pad(locOrBox, padding, context) {
78455           var box;
78456
78457           if (locOrBox instanceof Array) {
78458             var rect = context.surfaceRect();
78459             var point = context.curtainProjection(locOrBox);
78460             box = {
78461               left: point[0] + rect.left,
78462               top: point[1] + rect.top
78463             };
78464           } else {
78465             box = locOrBox;
78466           }
78467
78468           return {
78469             left: box.left - padding,
78470             top: box.top - padding,
78471             width: (box.width || 0) + 2 * padding,
78472             height: (box.width || 0) + 2 * padding
78473           };
78474         }
78475         function icon(name, svgklass, useklass) {
78476           return '<svg class="icon ' + (svgklass || '') + '">' + '<use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : '') + '></use></svg>';
78477         }
78478         var helpStringReplacements; // Returns the localized HTML element for `id` with a standardized set of icon, key, and
78479         // label replacements suitable for tutorials and documentation. Optionally supplemented
78480         // with custom `replacements`
78481
78482         function helpHtml(id, replacements) {
78483           // only load these the first time
78484           if (!helpStringReplacements) helpStringReplacements = {
78485             // insert icons corresponding to various UI elements
78486             point_icon: icon('#iD-icon-point', 'inline'),
78487             line_icon: icon('#iD-icon-line', 'inline'),
78488             area_icon: icon('#iD-icon-area', 'inline'),
78489             note_icon: icon('#iD-icon-note', 'inline add-note'),
78490             plus: icon('#iD-icon-plus', 'inline'),
78491             minus: icon('#iD-icon-minus', 'inline'),
78492             layers_icon: icon('#iD-icon-layers', 'inline'),
78493             data_icon: icon('#iD-icon-data', 'inline'),
78494             inspect: icon('#iD-icon-inspect', 'inline'),
78495             help_icon: icon('#iD-icon-help', 'inline'),
78496             undo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo', 'inline'),
78497             redo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-undo' : '#iD-icon-redo', 'inline'),
78498             save_icon: icon('#iD-icon-save', 'inline'),
78499             // operation icons
78500             circularize_icon: icon('#iD-operation-circularize', 'inline operation'),
78501             continue_icon: icon('#iD-operation-continue', 'inline operation'),
78502             copy_icon: icon('#iD-operation-copy', 'inline operation'),
78503             delete_icon: icon('#iD-operation-delete', 'inline operation'),
78504             disconnect_icon: icon('#iD-operation-disconnect', 'inline operation'),
78505             downgrade_icon: icon('#iD-operation-downgrade', 'inline operation'),
78506             extract_icon: icon('#iD-operation-extract', 'inline operation'),
78507             merge_icon: icon('#iD-operation-merge', 'inline operation'),
78508             move_icon: icon('#iD-operation-move', 'inline operation'),
78509             orthogonalize_icon: icon('#iD-operation-orthogonalize', 'inline operation'),
78510             paste_icon: icon('#iD-operation-paste', 'inline operation'),
78511             reflect_long_icon: icon('#iD-operation-reflect-long', 'inline operation'),
78512             reflect_short_icon: icon('#iD-operation-reflect-short', 'inline operation'),
78513             reverse_icon: icon('#iD-operation-reverse', 'inline operation'),
78514             rotate_icon: icon('#iD-operation-rotate', 'inline operation'),
78515             split_icon: icon('#iD-operation-split', 'inline operation'),
78516             straighten_icon: icon('#iD-operation-straighten', 'inline operation'),
78517             // interaction icons
78518             leftclick: icon('#iD-walkthrough-mouse-left', 'inline operation'),
78519             rightclick: icon('#iD-walkthrough-mouse-right', 'inline operation'),
78520             mousewheel_icon: icon('#iD-walkthrough-mousewheel', 'inline operation'),
78521             tap_icon: icon('#iD-walkthrough-tap', 'inline operation'),
78522             doubletap_icon: icon('#iD-walkthrough-doubletap', 'inline operation'),
78523             longpress_icon: icon('#iD-walkthrough-longpress', 'inline operation'),
78524             touchdrag_icon: icon('#iD-walkthrough-touchdrag', 'inline operation'),
78525             pinch_icon: icon('#iD-walkthrough-pinch-apart', 'inline operation'),
78526             // insert keys; may be localized and platform-dependent
78527             shift: uiCmd.display('⇧'),
78528             alt: uiCmd.display('⌥'),
78529             "return": uiCmd.display('↵'),
78530             esc: _t.html('shortcuts.key.esc'),
78531             space: _t.html('shortcuts.key.space'),
78532             add_note_key: _t.html('modes.add_note.key'),
78533             help_key: _t.html('help.key'),
78534             shortcuts_key: _t.html('shortcuts.toggle.key'),
78535             // reference localized UI labels directly so that they'll always match
78536             save: _t.html('save.title'),
78537             undo: _t.html('undo.title'),
78538             redo: _t.html('redo.title'),
78539             upload: _t.html('commit.save'),
78540             point: _t.html('modes.add_point.title'),
78541             line: _t.html('modes.add_line.title'),
78542             area: _t.html('modes.add_area.title'),
78543             note: _t.html('modes.add_note.label'),
78544             circularize: _t.html('operations.circularize.title'),
78545             "continue": _t.html('operations.continue.title'),
78546             copy: _t.html('operations.copy.title'),
78547             "delete": _t.html('operations.delete.title'),
78548             disconnect: _t.html('operations.disconnect.title'),
78549             downgrade: _t.html('operations.downgrade.title'),
78550             extract: _t.html('operations.extract.title'),
78551             merge: _t.html('operations.merge.title'),
78552             move: _t.html('operations.move.title'),
78553             orthogonalize: _t.html('operations.orthogonalize.title'),
78554             paste: _t.html('operations.paste.title'),
78555             reflect_long: _t.html('operations.reflect.title.long'),
78556             reflect_short: _t.html('operations.reflect.title.short'),
78557             reverse: _t.html('operations.reverse.title'),
78558             rotate: _t.html('operations.rotate.title'),
78559             split: _t.html('operations.split.title'),
78560             straighten: _t.html('operations.straighten.title'),
78561             map_data: _t.html('map_data.title'),
78562             osm_notes: _t.html('map_data.layers.notes.title'),
78563             fields: _t.html('inspector.fields'),
78564             tags: _t.html('inspector.tags'),
78565             relations: _t.html('inspector.relations'),
78566             new_relation: _t.html('inspector.new_relation'),
78567             turn_restrictions: _t.html('presets.fields.restrictions.label'),
78568             background_settings: _t.html('background.description'),
78569             imagery_offset: _t.html('background.fix_misalignment'),
78570             start_the_walkthrough: _t.html('splash.walkthrough'),
78571             help: _t.html('help.title'),
78572             ok: _t.html('intro.ok')
78573           };
78574           var reps;
78575
78576           if (replacements) {
78577             reps = Object.assign(replacements, helpStringReplacements);
78578           } else {
78579             reps = helpStringReplacements;
78580           }
78581
78582           return _t.html(id, reps) // use keyboard key styling for shortcuts
78583           .replace(/\`(.*?)\`/g, '<kbd>$1</kbd>');
78584         }
78585
78586         function slugify(text) {
78587           return text.toString().toLowerCase().replace(/\s+/g, '-') // Replace spaces with -
78588           .replace(/[^\w\-]+/g, '') // Remove all non-word chars
78589           .replace(/\-\-+/g, '-') // Replace multiple - with single -
78590           .replace(/^-+/, '') // Trim - from start of text
78591           .replace(/-+$/, ''); // Trim - from end of text
78592         } // console warning for missing walkthrough names
78593
78594
78595         var missingStrings = {};
78596
78597         function checkKey(key, text) {
78598           if (_t(key, {
78599             "default": undefined
78600           }) === undefined) {
78601             if (missingStrings.hasOwnProperty(key)) return; // warn once
78602
78603             missingStrings[key] = text;
78604             var missing = key + ': ' + text;
78605             if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
78606           }
78607         }
78608
78609         function localize(obj) {
78610           var key; // Assign name if entity has one..
78611
78612           var name = obj.tags && obj.tags.name;
78613
78614           if (name) {
78615             key = 'intro.graph.name.' + slugify(name);
78616             obj.tags.name = _t(key, {
78617               "default": name
78618             });
78619             checkKey(key, name);
78620           } // Assign street name if entity has one..
78621
78622
78623           var street = obj.tags && obj.tags['addr:street'];
78624
78625           if (street) {
78626             key = 'intro.graph.name.' + slugify(street);
78627             obj.tags['addr:street'] = _t(key, {
78628               "default": street
78629             });
78630             checkKey(key, street); // Add address details common across walkthrough..
78631
78632             var addrTags = ['block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood', 'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'];
78633             addrTags.forEach(function (k) {
78634               var key = 'intro.graph.' + k;
78635               var tag = 'addr:' + k;
78636               var val = obj.tags && obj.tags[tag];
78637               var str = _t(key, {
78638                 "default": val
78639               });
78640
78641               if (str) {
78642                 if (str.match(/^<.*>$/) !== null) {
78643                   delete obj.tags[tag];
78644                 } else {
78645                   obj.tags[tag] = str;
78646                 }
78647               }
78648             });
78649           }
78650
78651           return obj;
78652         } // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
78653
78654         function isMostlySquare(points) {
78655           // note: uses 15 here instead of the 12 from actionOrthogonalize because
78656           // actionOrthogonalize can actually straighten some larger angles as it iterates
78657           var threshold = 15; // degrees within right or straight
78658
78659           var lowerBound = Math.cos((90 - threshold) * Math.PI / 180); // near right
78660
78661           var upperBound = Math.cos(threshold * Math.PI / 180); // near straight
78662
78663           for (var i = 0; i < points.length; i++) {
78664             var a = points[(i - 1 + points.length) % points.length];
78665             var origin = points[i];
78666             var b = points[(i + 1) % points.length];
78667             var dotp = geoVecNormalizedDot(a, b, origin);
78668             var mag = Math.abs(dotp);
78669
78670             if (mag > lowerBound && mag < upperBound) {
78671               return false;
78672             }
78673           }
78674
78675           return true;
78676         }
78677         function selectMenuItem(context, operation) {
78678           return context.container().select('.edit-menu .edit-menu-item-' + operation);
78679         }
78680         function transitionTime(point1, point2) {
78681           var distance = geoSphericalDistance(point1, point2);
78682           if (distance === 0) return 0;else if (distance < 80) return 500;else return 1000;
78683         }
78684
78685         function uiCurtain(containerNode) {
78686           var surface = select(null),
78687               tooltip = select(null),
78688               darkness = select(null);
78689
78690           function curtain(selection) {
78691             surface = selection.append('svg').attr('class', 'curtain').style('top', 0).style('left', 0);
78692             darkness = surface.append('path').attr('x', 0).attr('y', 0).attr('class', 'curtain-darkness');
78693             select(window).on('resize.curtain', resize);
78694             tooltip = selection.append('div').attr('class', 'tooltip');
78695             tooltip.append('div').attr('class', 'popover-arrow');
78696             tooltip.append('div').attr('class', 'popover-inner');
78697             resize();
78698
78699             function resize() {
78700               surface.attr('width', containerNode.clientWidth).attr('height', containerNode.clientHeight);
78701               curtain.cut(darkness.datum());
78702             }
78703           }
78704           /**
78705            * Reveal cuts the curtain to highlight the given box,
78706            * and shows a tooltip with instructions next to the box.
78707            *
78708            * @param  {String|ClientRect} [box]   box used to cut the curtain
78709            * @param  {String}    [text]          text for a tooltip
78710            * @param  {Object}    [options]
78711            * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
78712            * @param  {integer}   [options.duration]        transition time in milliseconds
78713            * @param  {string}    [options.buttonText]      if set, create a button with this text label
78714            * @param  {function}  [options.buttonCallback]  if set, the callback for the button
78715            * @param  {function}  [options.padding]         extra margin in px to put around bbox
78716            * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
78717            */
78718
78719
78720           curtain.reveal = function (box, html, options) {
78721             options = options || {};
78722
78723             if (typeof box === 'string') {
78724               box = select(box).node();
78725             }
78726
78727             if (box && box.getBoundingClientRect) {
78728               box = copyBox(box.getBoundingClientRect());
78729               var containerRect = containerNode.getBoundingClientRect();
78730               box.top -= containerRect.top;
78731               box.left -= containerRect.left;
78732             }
78733
78734             if (box && options.padding) {
78735               box.top -= options.padding;
78736               box.left -= options.padding;
78737               box.bottom += options.padding;
78738               box.right += options.padding;
78739               box.height += options.padding * 2;
78740               box.width += options.padding * 2;
78741             }
78742
78743             var tooltipBox;
78744
78745             if (options.tooltipBox) {
78746               tooltipBox = options.tooltipBox;
78747
78748               if (typeof tooltipBox === 'string') {
78749                 tooltipBox = select(tooltipBox).node();
78750               }
78751
78752               if (tooltipBox && tooltipBox.getBoundingClientRect) {
78753                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
78754               }
78755             } else {
78756               tooltipBox = box;
78757             }
78758
78759             if (tooltipBox && html) {
78760               if (html.indexOf('**') !== -1) {
78761                 if (html.indexOf('<span') === 0) {
78762                   html = html.replace(/^(<span.*?>)(.+?)(\*\*)/, '$1<span>$2</span>$3');
78763                 } else {
78764                   html = html.replace(/^(.+?)(\*\*)/, '<span>$1</span>$2');
78765                 } // pseudo markdown bold text for the instruction section..
78766
78767
78768                 html = html.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
78769               }
78770
78771               html = html.replace(/\*(.*?)\*/g, '<em>$1</em>'); // emphasis
78772
78773               html = html.replace(/\{br\}/g, '<br/><br/>'); // linebreak
78774
78775               if (options.buttonText && options.buttonCallback) {
78776                 html += '<div class="button-section">' + '<button href="#" class="button action">' + options.buttonText + '</button></div>';
78777               }
78778
78779               var classes = 'curtain-tooltip popover tooltip arrowed in ' + (options.tooltipClass || '');
78780               tooltip.classed(classes, true).selectAll('.popover-inner').html(html);
78781
78782               if (options.buttonText && options.buttonCallback) {
78783                 var button = tooltip.selectAll('.button-section .button.action');
78784                 button.on('click', function (d3_event) {
78785                   d3_event.preventDefault();
78786                   options.buttonCallback();
78787                 });
78788               }
78789
78790               var tip = copyBox(tooltip.node().getBoundingClientRect()),
78791                   w = containerNode.clientWidth,
78792                   h = containerNode.clientHeight,
78793                   tooltipWidth = 200,
78794                   tooltipArrow = 5,
78795                   side,
78796                   pos; // hack: this will have bottom placement,
78797               // so need to reserve extra space for the tooltip illustration.
78798
78799               if (options.tooltipClass === 'intro-mouse') {
78800                 tip.height += 80;
78801               } // trim box dimensions to just the portion that fits in the container..
78802
78803
78804               if (tooltipBox.top + tooltipBox.height > h) {
78805                 tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
78806               }
78807
78808               if (tooltipBox.left + tooltipBox.width > w) {
78809                 tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
78810               } // determine tooltip placement..
78811
78812
78813               if (tooltipBox.top + tooltipBox.height < 100) {
78814                 // tooltip below box..
78815                 side = 'bottom';
78816                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top + tooltipBox.height];
78817               } else if (tooltipBox.top > h - 140) {
78818                 // tooltip above box..
78819                 side = 'top';
78820                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top - tip.height];
78821               } else {
78822                 // tooltip to the side of the tooltipBox..
78823                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
78824
78825                 if (_mainLocalizer.textDirection() === 'rtl') {
78826                   if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
78827                     side = 'right';
78828                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
78829                   } else {
78830                     side = 'left';
78831                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
78832                   }
78833                 } else {
78834                   if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
78835                     side = 'left';
78836                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
78837                   } else {
78838                     side = 'right';
78839                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
78840                   }
78841                 }
78842               }
78843
78844               if (options.duration !== 0 || !tooltip.classed(side)) {
78845                 tooltip.call(uiToggle(true));
78846               }
78847
78848               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
78849               // (doesn't affect the placement of the popover-arrow)
78850
78851               var shiftY = 0;
78852
78853               if (side === 'left' || side === 'right') {
78854                 if (pos[1] < 60) {
78855                   shiftY = 60 - pos[1];
78856                 } else if (pos[1] + tip.height > h - 100) {
78857                   shiftY = h - pos[1] - tip.height - 100;
78858                 }
78859               }
78860
78861               tooltip.selectAll('.popover-inner').style('top', shiftY + 'px');
78862             } else {
78863               tooltip.classed('in', false).call(uiToggle(false));
78864             }
78865
78866             curtain.cut(box, options.duration);
78867             return tooltip;
78868           };
78869
78870           curtain.cut = function (datum, duration) {
78871             darkness.datum(datum).interrupt();
78872             var selection;
78873
78874             if (duration === 0) {
78875               selection = darkness;
78876             } else {
78877               selection = darkness.transition().duration(duration || 600).ease(linear$1);
78878             }
78879
78880             selection.attr('d', function (d) {
78881               var containerWidth = containerNode.clientWidth;
78882               var containerHeight = containerNode.clientHeight;
78883               var string = 'M 0,0 L 0,' + containerHeight + ' L ' + containerWidth + ',' + containerHeight + 'L' + containerWidth + ',0 Z';
78884               if (!d) return string;
78885               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';
78886             });
78887           };
78888
78889           curtain.remove = function () {
78890             surface.remove();
78891             tooltip.remove();
78892             select(window).on('resize.curtain', null);
78893           }; // ClientRects are immutable, so copy them to an object,
78894           // in case we need to trim the height/width.
78895
78896
78897           function copyBox(src) {
78898             return {
78899               top: src.top,
78900               right: src.right,
78901               bottom: src.bottom,
78902               left: src.left,
78903               width: src.width,
78904               height: src.height
78905             };
78906           }
78907
78908           return curtain;
78909         }
78910
78911         function uiIntroWelcome(context, reveal) {
78912           var dispatch$1 = dispatch('done');
78913           var chapter = {
78914             title: 'intro.welcome.title'
78915           };
78916
78917           function welcome() {
78918             context.map().centerZoom([-85.63591, 41.94285], 19);
78919             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.welcome'), {
78920               buttonText: _t.html('intro.ok'),
78921               buttonCallback: practice
78922             });
78923           }
78924
78925           function practice() {
78926             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.practice'), {
78927               buttonText: _t.html('intro.ok'),
78928               buttonCallback: words
78929             });
78930           }
78931
78932           function words() {
78933             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.words'), {
78934               buttonText: _t.html('intro.ok'),
78935               buttonCallback: chapters
78936             });
78937           }
78938
78939           function chapters() {
78940             dispatch$1.call('done');
78941             reveal('.intro-nav-wrap .chapter-navigation', helpHtml('intro.welcome.chapters', {
78942               next: _t('intro.navigation.title')
78943             }));
78944           }
78945
78946           chapter.enter = function () {
78947             welcome();
78948           };
78949
78950           chapter.exit = function () {
78951             context.container().select('.curtain-tooltip.intro-mouse').selectAll('.counter').remove();
78952           };
78953
78954           chapter.restart = function () {
78955             chapter.exit();
78956             chapter.enter();
78957           };
78958
78959           return utilRebind(chapter, dispatch$1, 'on');
78960         }
78961
78962         function uiIntroNavigation(context, reveal) {
78963           var dispatch$1 = dispatch('done');
78964           var timeouts = [];
78965           var hallId = 'n2061';
78966           var townHall = [-85.63591, 41.94285];
78967           var springStreetId = 'w397';
78968           var springStreetEndId = 'n1834';
78969           var springStreet = [-85.63582, 41.94255];
78970           var onewayField = _mainPresetIndex.field('oneway');
78971           var maxspeedField = _mainPresetIndex.field('maxspeed');
78972           var chapter = {
78973             title: 'intro.navigation.title'
78974           };
78975
78976           function timeout(f, t) {
78977             timeouts.push(window.setTimeout(f, t));
78978           }
78979
78980           function eventCancel(d3_event) {
78981             d3_event.stopPropagation();
78982             d3_event.preventDefault();
78983           }
78984
78985           function isTownHallSelected() {
78986             var ids = context.selectedIDs();
78987             return ids.length === 1 && ids[0] === hallId;
78988           }
78989
78990           function dragMap() {
78991             context.enter(modeBrowse(context));
78992             context.history().reset('initial');
78993             var msec = transitionTime(townHall, context.map().center());
78994
78995             if (msec) {
78996               reveal(null, null, {
78997                 duration: 0
78998               });
78999             }
79000
79001             context.map().centerZoomEase(townHall, 19, msec);
79002             timeout(function () {
79003               var centerStart = context.map().center();
79004               var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
79005               var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
79006               reveal('.surface', dragString);
79007               context.map().on('drawn.intro', function () {
79008                 reveal('.surface', dragString, {
79009                   duration: 0
79010                 });
79011               });
79012               context.map().on('move.intro', function () {
79013                 var centerNow = context.map().center();
79014
79015                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
79016                   context.map().on('move.intro', null);
79017                   timeout(function () {
79018                     continueTo(zoomMap);
79019                   }, 3000);
79020                 }
79021               });
79022             }, msec + 100);
79023
79024             function continueTo(nextStep) {
79025               context.map().on('move.intro drawn.intro', null);
79026               nextStep();
79027             }
79028           }
79029
79030           function zoomMap() {
79031             var zoomStart = context.map().zoom();
79032             var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
79033             var zoomString = helpHtml('intro.navigation.' + textId);
79034             reveal('.surface', zoomString);
79035             context.map().on('drawn.intro', function () {
79036               reveal('.surface', zoomString, {
79037                 duration: 0
79038               });
79039             });
79040             context.map().on('move.intro', function () {
79041               if (context.map().zoom() !== zoomStart) {
79042                 context.map().on('move.intro', null);
79043                 timeout(function () {
79044                   continueTo(features);
79045                 }, 3000);
79046               }
79047             });
79048
79049             function continueTo(nextStep) {
79050               context.map().on('move.intro drawn.intro', null);
79051               nextStep();
79052             }
79053           }
79054
79055           function features() {
79056             var onClick = function onClick() {
79057               continueTo(pointsLinesAreas);
79058             };
79059
79060             reveal('.surface', helpHtml('intro.navigation.features'), {
79061               buttonText: _t.html('intro.ok'),
79062               buttonCallback: onClick
79063             });
79064             context.map().on('drawn.intro', function () {
79065               reveal('.surface', helpHtml('intro.navigation.features'), {
79066                 duration: 0,
79067                 buttonText: _t.html('intro.ok'),
79068                 buttonCallback: onClick
79069               });
79070             });
79071
79072             function continueTo(nextStep) {
79073               context.map().on('drawn.intro', null);
79074               nextStep();
79075             }
79076           }
79077
79078           function pointsLinesAreas() {
79079             var onClick = function onClick() {
79080               continueTo(nodesWays);
79081             };
79082
79083             reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
79084               buttonText: _t.html('intro.ok'),
79085               buttonCallback: onClick
79086             });
79087             context.map().on('drawn.intro', function () {
79088               reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
79089                 duration: 0,
79090                 buttonText: _t.html('intro.ok'),
79091                 buttonCallback: onClick
79092               });
79093             });
79094
79095             function continueTo(nextStep) {
79096               context.map().on('drawn.intro', null);
79097               nextStep();
79098             }
79099           }
79100
79101           function nodesWays() {
79102             var onClick = function onClick() {
79103               continueTo(clickTownHall);
79104             };
79105
79106             reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
79107               buttonText: _t.html('intro.ok'),
79108               buttonCallback: onClick
79109             });
79110             context.map().on('drawn.intro', function () {
79111               reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
79112                 duration: 0,
79113                 buttonText: _t.html('intro.ok'),
79114                 buttonCallback: onClick
79115               });
79116             });
79117
79118             function continueTo(nextStep) {
79119               context.map().on('drawn.intro', null);
79120               nextStep();
79121             }
79122           }
79123
79124           function clickTownHall() {
79125             context.enter(modeBrowse(context));
79126             context.history().reset('initial');
79127             var entity = context.hasEntity(hallId);
79128             if (!entity) return;
79129             reveal(null, null, {
79130               duration: 0
79131             });
79132             context.map().centerZoomEase(entity.loc, 19, 500);
79133             timeout(function () {
79134               var entity = context.hasEntity(hallId);
79135               if (!entity) return;
79136               var box = pointBox(entity.loc, context);
79137               var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
79138               reveal(box, helpHtml('intro.navigation.' + textId));
79139               context.map().on('move.intro drawn.intro', function () {
79140                 var entity = context.hasEntity(hallId);
79141                 if (!entity) return;
79142                 var box = pointBox(entity.loc, context);
79143                 reveal(box, helpHtml('intro.navigation.' + textId), {
79144                   duration: 0
79145                 });
79146               });
79147               context.on('enter.intro', function () {
79148                 if (isTownHallSelected()) continueTo(selectedTownHall);
79149               });
79150             }, 550); // after centerZoomEase
79151
79152             context.history().on('change.intro', function () {
79153               if (!context.hasEntity(hallId)) {
79154                 continueTo(clickTownHall);
79155               }
79156             });
79157
79158             function continueTo(nextStep) {
79159               context.on('enter.intro', null);
79160               context.map().on('move.intro drawn.intro', null);
79161               context.history().on('change.intro', null);
79162               nextStep();
79163             }
79164           }
79165
79166           function selectedTownHall() {
79167             if (!isTownHallSelected()) return clickTownHall();
79168             var entity = context.hasEntity(hallId);
79169             if (!entity) return clickTownHall();
79170             var box = pointBox(entity.loc, context);
79171
79172             var onClick = function onClick() {
79173               continueTo(editorTownHall);
79174             };
79175
79176             reveal(box, helpHtml('intro.navigation.selected_townhall'), {
79177               buttonText: _t.html('intro.ok'),
79178               buttonCallback: onClick
79179             });
79180             context.map().on('move.intro drawn.intro', function () {
79181               var entity = context.hasEntity(hallId);
79182               if (!entity) return;
79183               var box = pointBox(entity.loc, context);
79184               reveal(box, helpHtml('intro.navigation.selected_townhall'), {
79185                 duration: 0,
79186                 buttonText: _t.html('intro.ok'),
79187                 buttonCallback: onClick
79188               });
79189             });
79190             context.history().on('change.intro', function () {
79191               if (!context.hasEntity(hallId)) {
79192                 continueTo(clickTownHall);
79193               }
79194             });
79195
79196             function continueTo(nextStep) {
79197               context.map().on('move.intro drawn.intro', null);
79198               context.history().on('change.intro', null);
79199               nextStep();
79200             }
79201           }
79202
79203           function editorTownHall() {
79204             if (!isTownHallSelected()) return clickTownHall(); // disallow scrolling
79205
79206             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79207
79208             var onClick = function onClick() {
79209               continueTo(presetTownHall);
79210             };
79211
79212             reveal('.entity-editor-pane', helpHtml('intro.navigation.editor_townhall'), {
79213               buttonText: _t.html('intro.ok'),
79214               buttonCallback: onClick
79215             });
79216             context.on('exit.intro', function () {
79217               continueTo(clickTownHall);
79218             });
79219             context.history().on('change.intro', function () {
79220               if (!context.hasEntity(hallId)) {
79221                 continueTo(clickTownHall);
79222               }
79223             });
79224
79225             function continueTo(nextStep) {
79226               context.on('exit.intro', null);
79227               context.history().on('change.intro', null);
79228               context.container().select('.inspector-wrap').on('wheel.intro', null);
79229               nextStep();
79230             }
79231           }
79232
79233           function presetTownHall() {
79234             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
79235
79236             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
79237
79238             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel); // preset match, in case the user happened to change it.
79239
79240             var entity = context.entity(context.selectedIDs()[0]);
79241             var preset = _mainPresetIndex.match(entity, context.graph());
79242
79243             var onClick = function onClick() {
79244               continueTo(fieldsTownHall);
79245             };
79246
79247             reveal('.entity-editor-pane .section-feature-type', helpHtml('intro.navigation.preset_townhall', {
79248               preset: preset.name()
79249             }), {
79250               buttonText: _t.html('intro.ok'),
79251               buttonCallback: onClick
79252             });
79253             context.on('exit.intro', function () {
79254               continueTo(clickTownHall);
79255             });
79256             context.history().on('change.intro', function () {
79257               if (!context.hasEntity(hallId)) {
79258                 continueTo(clickTownHall);
79259               }
79260             });
79261
79262             function continueTo(nextStep) {
79263               context.on('exit.intro', null);
79264               context.history().on('change.intro', null);
79265               context.container().select('.inspector-wrap').on('wheel.intro', null);
79266               nextStep();
79267             }
79268           }
79269
79270           function fieldsTownHall() {
79271             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
79272
79273             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
79274
79275             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79276
79277             var onClick = function onClick() {
79278               continueTo(closeTownHall);
79279             };
79280
79281             reveal('.entity-editor-pane .section-preset-fields', helpHtml('intro.navigation.fields_townhall'), {
79282               buttonText: _t.html('intro.ok'),
79283               buttonCallback: onClick
79284             });
79285             context.on('exit.intro', function () {
79286               continueTo(clickTownHall);
79287             });
79288             context.history().on('change.intro', function () {
79289               if (!context.hasEntity(hallId)) {
79290                 continueTo(clickTownHall);
79291               }
79292             });
79293
79294             function continueTo(nextStep) {
79295               context.on('exit.intro', null);
79296               context.history().on('change.intro', null);
79297               context.container().select('.inspector-wrap').on('wheel.intro', null);
79298               nextStep();
79299             }
79300           }
79301
79302           function closeTownHall() {
79303             if (!isTownHallSelected()) return clickTownHall();
79304             var selector = '.entity-editor-pane button.close svg use';
79305             var href = select(selector).attr('href') || '#iD-icon-close';
79306             reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
79307               button: icon(href, 'inline')
79308             }));
79309             context.on('exit.intro', function () {
79310               continueTo(searchStreet);
79311             });
79312             context.history().on('change.intro', function () {
79313               // update the close icon in the tooltip if the user edits something.
79314               var selector = '.entity-editor-pane button.close svg use';
79315               var href = select(selector).attr('href') || '#iD-icon-close';
79316               reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
79317                 button: icon(href, 'inline')
79318               }), {
79319                 duration: 0
79320               });
79321             });
79322
79323             function continueTo(nextStep) {
79324               context.on('exit.intro', null);
79325               context.history().on('change.intro', null);
79326               nextStep();
79327             }
79328           }
79329
79330           function searchStreet() {
79331             context.enter(modeBrowse(context));
79332             context.history().reset('initial'); // ensure spring street exists
79333
79334             var msec = transitionTime(springStreet, context.map().center());
79335
79336             if (msec) {
79337               reveal(null, null, {
79338                 duration: 0
79339               });
79340             }
79341
79342             context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
79343
79344             timeout(function () {
79345               reveal('.search-header input', helpHtml('intro.navigation.search_street', {
79346                 name: _t('intro.graph.name.spring-street')
79347               }));
79348               context.container().select('.search-header input').on('keyup.intro', checkSearchResult);
79349             }, msec + 100);
79350           }
79351
79352           function checkSearchResult() {
79353             var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
79354
79355             var firstName = first.select('.entity-name');
79356             var name = _t('intro.graph.name.spring-street');
79357
79358             if (!firstName.empty() && firstName.html() === name) {
79359               reveal(first.node(), helpHtml('intro.navigation.choose_street', {
79360                 name: name
79361               }), {
79362                 duration: 300
79363               });
79364               context.on('exit.intro', function () {
79365                 continueTo(selectedStreet);
79366               });
79367               context.container().select('.search-header input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
79368             }
79369
79370             function continueTo(nextStep) {
79371               context.on('exit.intro', null);
79372               context.container().select('.search-header input').on('keydown.intro', null).on('keyup.intro', null);
79373               nextStep();
79374             }
79375           }
79376
79377           function selectedStreet() {
79378             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
79379               return searchStreet();
79380             }
79381
79382             var onClick = function onClick() {
79383               continueTo(editorStreet);
79384             };
79385
79386             var entity = context.entity(springStreetEndId);
79387             var box = pointBox(entity.loc, context);
79388             box.height = 500;
79389             reveal(box, helpHtml('intro.navigation.selected_street', {
79390               name: _t('intro.graph.name.spring-street')
79391             }), {
79392               duration: 600,
79393               buttonText: _t.html('intro.ok'),
79394               buttonCallback: onClick
79395             });
79396             timeout(function () {
79397               context.map().on('move.intro drawn.intro', function () {
79398                 var entity = context.hasEntity(springStreetEndId);
79399                 if (!entity) return;
79400                 var box = pointBox(entity.loc, context);
79401                 box.height = 500;
79402                 reveal(box, helpHtml('intro.navigation.selected_street', {
79403                   name: _t('intro.graph.name.spring-street')
79404                 }), {
79405                   duration: 0,
79406                   buttonText: _t.html('intro.ok'),
79407                   buttonCallback: onClick
79408                 });
79409               });
79410             }, 600); // after reveal.
79411
79412             context.on('enter.intro', function (mode) {
79413               if (!context.hasEntity(springStreetId)) {
79414                 return continueTo(searchStreet);
79415               }
79416
79417               var ids = context.selectedIDs();
79418
79419               if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
79420                 // keep Spring Street selected..
79421                 context.enter(modeSelect(context, [springStreetId]));
79422               }
79423             });
79424             context.history().on('change.intro', function () {
79425               if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
79426                 timeout(function () {
79427                   continueTo(searchStreet);
79428                 }, 300); // after any transition (e.g. if user deleted intersection)
79429               }
79430             });
79431
79432             function continueTo(nextStep) {
79433               context.map().on('move.intro drawn.intro', null);
79434               context.on('enter.intro', null);
79435               context.history().on('change.intro', null);
79436               nextStep();
79437             }
79438           }
79439
79440           function editorStreet() {
79441             var selector = '.entity-editor-pane button.close svg use';
79442             var href = select(selector).attr('href') || '#iD-icon-close';
79443             reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
79444               button: icon(href, 'inline'),
79445               field1: onewayField.label(),
79446               field2: maxspeedField.label()
79447             }));
79448             context.on('exit.intro', function () {
79449               continueTo(play);
79450             });
79451             context.history().on('change.intro', function () {
79452               // update the close icon in the tooltip if the user edits something.
79453               var selector = '.entity-editor-pane button.close svg use';
79454               var href = select(selector).attr('href') || '#iD-icon-close';
79455               reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
79456                 button: icon(href, 'inline'),
79457                 field1: onewayField.label(),
79458                 field2: maxspeedField.label()
79459               }), {
79460                 duration: 0
79461               });
79462             });
79463
79464             function continueTo(nextStep) {
79465               context.on('exit.intro', null);
79466               context.history().on('change.intro', null);
79467               nextStep();
79468             }
79469           }
79470
79471           function play() {
79472             dispatch$1.call('done');
79473             reveal('.ideditor', helpHtml('intro.navigation.play', {
79474               next: _t('intro.points.title')
79475             }), {
79476               tooltipBox: '.intro-nav-wrap .chapter-point',
79477               buttonText: _t.html('intro.ok'),
79478               buttonCallback: function buttonCallback() {
79479                 reveal('.ideditor');
79480               }
79481             });
79482           }
79483
79484           chapter.enter = function () {
79485             dragMap();
79486           };
79487
79488           chapter.exit = function () {
79489             timeouts.forEach(window.clearTimeout);
79490             context.on('enter.intro exit.intro', null);
79491             context.map().on('move.intro drawn.intro', null);
79492             context.history().on('change.intro', null);
79493             context.container().select('.inspector-wrap').on('wheel.intro', null);
79494             context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
79495           };
79496
79497           chapter.restart = function () {
79498             chapter.exit();
79499             chapter.enter();
79500           };
79501
79502           return utilRebind(chapter, dispatch$1, 'on');
79503         }
79504
79505         function uiIntroPoint(context, reveal) {
79506           var dispatch$1 = dispatch('done');
79507           var timeouts = [];
79508           var intersection = [-85.63279, 41.94394];
79509           var building = [-85.632422, 41.944045];
79510           var cafePreset = _mainPresetIndex.item('amenity/cafe');
79511           var _pointID = null;
79512           var chapter = {
79513             title: 'intro.points.title'
79514           };
79515
79516           function timeout(f, t) {
79517             timeouts.push(window.setTimeout(f, t));
79518           }
79519
79520           function eventCancel(d3_event) {
79521             d3_event.stopPropagation();
79522             d3_event.preventDefault();
79523           }
79524
79525           function addPoint() {
79526             context.enter(modeBrowse(context));
79527             context.history().reset('initial');
79528             var msec = transitionTime(intersection, context.map().center());
79529
79530             if (msec) {
79531               reveal(null, null, {
79532                 duration: 0
79533               });
79534             }
79535
79536             context.map().centerZoomEase(intersection, 19, msec);
79537             timeout(function () {
79538               var tooltip = reveal('button.add-point', helpHtml('intro.points.points_info') + '{br}' + helpHtml('intro.points.add_point'));
79539               _pointID = null;
79540               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-points');
79541               context.on('enter.intro', function (mode) {
79542                 if (mode.id !== 'add-point') return;
79543                 continueTo(placePoint);
79544               });
79545             }, msec + 100);
79546
79547             function continueTo(nextStep) {
79548               context.on('enter.intro', null);
79549               nextStep();
79550             }
79551           }
79552
79553           function placePoint() {
79554             if (context.mode().id !== 'add-point') {
79555               return chapter.restart();
79556             }
79557
79558             var pointBox = pad(building, 150, context);
79559             var textId = context.lastPointerType() === 'mouse' ? 'place_point' : 'place_point_touch';
79560             reveal(pointBox, helpHtml('intro.points.' + textId));
79561             context.map().on('move.intro drawn.intro', function () {
79562               pointBox = pad(building, 150, context);
79563               reveal(pointBox, helpHtml('intro.points.' + textId), {
79564                 duration: 0
79565               });
79566             });
79567             context.on('enter.intro', function (mode) {
79568               if (mode.id !== 'select') return chapter.restart();
79569               _pointID = context.mode().selectedIDs()[0];
79570               continueTo(searchPreset);
79571             });
79572
79573             function continueTo(nextStep) {
79574               context.map().on('move.intro drawn.intro', null);
79575               context.on('enter.intro', null);
79576               nextStep();
79577             }
79578           }
79579
79580           function searchPreset() {
79581             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79582               return addPoint();
79583             } // disallow scrolling
79584
79585
79586             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79587             context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79588             reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
79589               preset: cafePreset.name()
79590             }));
79591             context.on('enter.intro', function (mode) {
79592               if (!_pointID || !context.hasEntity(_pointID)) {
79593                 return continueTo(addPoint);
79594               }
79595
79596               var ids = context.selectedIDs();
79597
79598               if (mode.id !== 'select' || !ids.length || ids[0] !== _pointID) {
79599                 // keep the user's point selected..
79600                 context.enter(modeSelect(context, [_pointID])); // disallow scrolling
79601
79602                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79603                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79604                 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
79605                   preset: cafePreset.name()
79606                 }));
79607                 context.history().on('change.intro', null);
79608               }
79609             });
79610
79611             function checkPresetSearch() {
79612               var first = context.container().select('.preset-list-item:first-child');
79613
79614               if (first.classed('preset-amenity-cafe')) {
79615                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
79616                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.points.choose_cafe', {
79617                   preset: cafePreset.name()
79618                 }), {
79619                   duration: 300
79620                 });
79621                 context.history().on('change.intro', function () {
79622                   continueTo(aboutFeatureEditor);
79623                 });
79624               }
79625             }
79626
79627             function continueTo(nextStep) {
79628               context.on('enter.intro', null);
79629               context.history().on('change.intro', null);
79630               context.container().select('.inspector-wrap').on('wheel.intro', null);
79631               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
79632               nextStep();
79633             }
79634           }
79635
79636           function aboutFeatureEditor() {
79637             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79638               return addPoint();
79639             }
79640
79641             timeout(function () {
79642               reveal('.entity-editor-pane', helpHtml('intro.points.feature_editor'), {
79643                 tooltipClass: 'intro-points-describe',
79644                 buttonText: _t.html('intro.ok'),
79645                 buttonCallback: function buttonCallback() {
79646                   continueTo(addName);
79647                 }
79648               });
79649             }, 400);
79650             context.on('exit.intro', function () {
79651               // if user leaves select mode here, just continue with the tutorial.
79652               continueTo(reselectPoint);
79653             });
79654
79655             function continueTo(nextStep) {
79656               context.on('exit.intro', null);
79657               nextStep();
79658             }
79659           }
79660
79661           function addName() {
79662             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79663               return addPoint();
79664             } // reset pane, in case user happened to change it..
79665
79666
79667             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79668             var addNameString = helpHtml('intro.points.fields_info') + '{br}' + helpHtml('intro.points.add_name');
79669             timeout(function () {
79670               // It's possible for the user to add a name in a previous step..
79671               // If so, don't tell them to add the name in this step.
79672               // Give them an OK button instead.
79673               var entity = context.entity(_pointID);
79674
79675               if (entity.tags.name) {
79676                 var tooltip = reveal('.entity-editor-pane', addNameString, {
79677                   tooltipClass: 'intro-points-describe',
79678                   buttonText: _t.html('intro.ok'),
79679                   buttonCallback: function buttonCallback() {
79680                     continueTo(addCloseEditor);
79681                   }
79682                 });
79683                 tooltip.select('.instruction').style('display', 'none');
79684               } else {
79685                 reveal('.entity-editor-pane', addNameString, {
79686                   tooltipClass: 'intro-points-describe'
79687                 });
79688               }
79689             }, 400);
79690             context.history().on('change.intro', function () {
79691               continueTo(addCloseEditor);
79692             });
79693             context.on('exit.intro', function () {
79694               // if user leaves select mode here, just continue with the tutorial.
79695               continueTo(reselectPoint);
79696             });
79697
79698             function continueTo(nextStep) {
79699               context.on('exit.intro', null);
79700               context.history().on('change.intro', null);
79701               nextStep();
79702             }
79703           }
79704
79705           function addCloseEditor() {
79706             // reset pane, in case user happened to change it..
79707             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79708             var selector = '.entity-editor-pane button.close svg use';
79709             var href = select(selector).attr('href') || '#iD-icon-close';
79710             context.on('exit.intro', function () {
79711               continueTo(reselectPoint);
79712             });
79713             reveal('.entity-editor-pane', helpHtml('intro.points.add_close', {
79714               button: icon(href, 'inline')
79715             }));
79716
79717             function continueTo(nextStep) {
79718               context.on('exit.intro', null);
79719               nextStep();
79720             }
79721           }
79722
79723           function reselectPoint() {
79724             if (!_pointID) return chapter.restart();
79725             var entity = context.hasEntity(_pointID);
79726             if (!entity) return chapter.restart(); // make sure it's still a cafe, in case user somehow changed it..
79727
79728             var oldPreset = _mainPresetIndex.match(entity, context.graph());
79729             context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
79730             context.enter(modeBrowse(context));
79731             var msec = transitionTime(entity.loc, context.map().center());
79732
79733             if (msec) {
79734               reveal(null, null, {
79735                 duration: 0
79736               });
79737             }
79738
79739             context.map().centerEase(entity.loc, msec);
79740             timeout(function () {
79741               var box = pointBox(entity.loc, context);
79742               reveal(box, helpHtml('intro.points.reselect'), {
79743                 duration: 600
79744               });
79745               timeout(function () {
79746                 context.map().on('move.intro drawn.intro', function () {
79747                   var entity = context.hasEntity(_pointID);
79748                   if (!entity) return chapter.restart();
79749                   var box = pointBox(entity.loc, context);
79750                   reveal(box, helpHtml('intro.points.reselect'), {
79751                     duration: 0
79752                   });
79753                 });
79754               }, 600); // after reveal..
79755
79756               context.on('enter.intro', function (mode) {
79757                 if (mode.id !== 'select') return;
79758                 continueTo(updatePoint);
79759               });
79760             }, msec + 100);
79761
79762             function continueTo(nextStep) {
79763               context.map().on('move.intro drawn.intro', null);
79764               context.on('enter.intro', null);
79765               nextStep();
79766             }
79767           }
79768
79769           function updatePoint() {
79770             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79771               return continueTo(reselectPoint);
79772             } // reset pane, in case user happened to untag the point..
79773
79774
79775             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79776             context.on('exit.intro', function () {
79777               continueTo(reselectPoint);
79778             });
79779             context.history().on('change.intro', function () {
79780               continueTo(updateCloseEditor);
79781             });
79782             timeout(function () {
79783               reveal('.entity-editor-pane', helpHtml('intro.points.update'), {
79784                 tooltipClass: 'intro-points-describe'
79785               });
79786             }, 400);
79787
79788             function continueTo(nextStep) {
79789               context.on('exit.intro', null);
79790               context.history().on('change.intro', null);
79791               nextStep();
79792             }
79793           }
79794
79795           function updateCloseEditor() {
79796             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79797               return continueTo(reselectPoint);
79798             } // reset pane, in case user happened to change it..
79799
79800
79801             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79802             context.on('exit.intro', function () {
79803               continueTo(rightClickPoint);
79804             });
79805             timeout(function () {
79806               reveal('.entity-editor-pane', helpHtml('intro.points.update_close', {
79807                 button: icon('#iD-icon-close', 'inline')
79808               }));
79809             }, 500);
79810
79811             function continueTo(nextStep) {
79812               context.on('exit.intro', null);
79813               nextStep();
79814             }
79815           }
79816
79817           function rightClickPoint() {
79818             if (!_pointID) return chapter.restart();
79819             var entity = context.hasEntity(_pointID);
79820             if (!entity) return chapter.restart();
79821             context.enter(modeBrowse(context));
79822             var box = pointBox(entity.loc, context);
79823             var textId = context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch';
79824             reveal(box, helpHtml('intro.points.' + textId), {
79825               duration: 600
79826             });
79827             timeout(function () {
79828               context.map().on('move.intro', function () {
79829                 var entity = context.hasEntity(_pointID);
79830                 if (!entity) return chapter.restart();
79831                 var box = pointBox(entity.loc, context);
79832                 reveal(box, helpHtml('intro.points.' + textId), {
79833                   duration: 0
79834                 });
79835               });
79836             }, 600); // after reveal
79837
79838             context.on('enter.intro', function (mode) {
79839               if (mode.id !== 'select') return;
79840               var ids = context.selectedIDs();
79841               if (ids.length !== 1 || ids[0] !== _pointID) return;
79842               timeout(function () {
79843                 var node = selectMenuItem(context, 'delete').node();
79844                 if (!node) return;
79845                 continueTo(enterDelete);
79846               }, 50); // after menu visible
79847             });
79848
79849             function continueTo(nextStep) {
79850               context.on('enter.intro', null);
79851               context.map().on('move.intro', null);
79852               nextStep();
79853             }
79854           }
79855
79856           function enterDelete() {
79857             if (!_pointID) return chapter.restart();
79858             var entity = context.hasEntity(_pointID);
79859             if (!entity) return chapter.restart();
79860             var node = selectMenuItem(context, 'delete').node();
79861
79862             if (!node) {
79863               return continueTo(rightClickPoint);
79864             }
79865
79866             reveal('.edit-menu', helpHtml('intro.points.delete'), {
79867               padding: 50
79868             });
79869             timeout(function () {
79870               context.map().on('move.intro', function () {
79871                 reveal('.edit-menu', helpHtml('intro.points.delete'), {
79872                   duration: 0,
79873                   padding: 50
79874                 });
79875               });
79876             }, 300); // after menu visible
79877
79878             context.on('exit.intro', function () {
79879               if (!_pointID) return chapter.restart();
79880               var entity = context.hasEntity(_pointID);
79881               if (entity) return continueTo(rightClickPoint); // point still exists
79882             });
79883             context.history().on('change.intro', function (changed) {
79884               if (changed.deleted().length) {
79885                 continueTo(undo);
79886               }
79887             });
79888
79889             function continueTo(nextStep) {
79890               context.map().on('move.intro', null);
79891               context.history().on('change.intro', null);
79892               context.on('exit.intro', null);
79893               nextStep();
79894             }
79895           }
79896
79897           function undo() {
79898             context.history().on('change.intro', function () {
79899               continueTo(play);
79900             });
79901             reveal('.top-toolbar button.undo-button', helpHtml('intro.points.undo'));
79902
79903             function continueTo(nextStep) {
79904               context.history().on('change.intro', null);
79905               nextStep();
79906             }
79907           }
79908
79909           function play() {
79910             dispatch$1.call('done');
79911             reveal('.ideditor', helpHtml('intro.points.play', {
79912               next: _t('intro.areas.title')
79913             }), {
79914               tooltipBox: '.intro-nav-wrap .chapter-area',
79915               buttonText: _t.html('intro.ok'),
79916               buttonCallback: function buttonCallback() {
79917                 reveal('.ideditor');
79918               }
79919             });
79920           }
79921
79922           chapter.enter = function () {
79923             addPoint();
79924           };
79925
79926           chapter.exit = function () {
79927             timeouts.forEach(window.clearTimeout);
79928             context.on('enter.intro exit.intro', null);
79929             context.map().on('move.intro drawn.intro', null);
79930             context.history().on('change.intro', null);
79931             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79932             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
79933           };
79934
79935           chapter.restart = function () {
79936             chapter.exit();
79937             chapter.enter();
79938           };
79939
79940           return utilRebind(chapter, dispatch$1, 'on');
79941         }
79942
79943         function uiIntroArea(context, reveal) {
79944           var dispatch$1 = dispatch('done');
79945           var playground = [-85.63552, 41.94159];
79946           var playgroundPreset = _mainPresetIndex.item('leisure/playground');
79947           var nameField = _mainPresetIndex.field('name');
79948           var descriptionField = _mainPresetIndex.field('description');
79949           var timeouts = [];
79950
79951           var _areaID;
79952
79953           var chapter = {
79954             title: 'intro.areas.title'
79955           };
79956
79957           function timeout(f, t) {
79958             timeouts.push(window.setTimeout(f, t));
79959           }
79960
79961           function eventCancel(d3_event) {
79962             d3_event.stopPropagation();
79963             d3_event.preventDefault();
79964           }
79965
79966           function revealPlayground(center, text, options) {
79967             var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
79968             var box = pad(center, padding, context);
79969             reveal(box, text, options);
79970           }
79971
79972           function addArea() {
79973             context.enter(modeBrowse(context));
79974             context.history().reset('initial');
79975             _areaID = null;
79976             var msec = transitionTime(playground, context.map().center());
79977
79978             if (msec) {
79979               reveal(null, null, {
79980                 duration: 0
79981               });
79982             }
79983
79984             context.map().centerZoomEase(playground, 19, msec);
79985             timeout(function () {
79986               var tooltip = reveal('button.add-area', helpHtml('intro.areas.add_playground'));
79987               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-areas');
79988               context.on('enter.intro', function (mode) {
79989                 if (mode.id !== 'add-area') return;
79990                 continueTo(startPlayground);
79991               });
79992             }, msec + 100);
79993
79994             function continueTo(nextStep) {
79995               context.on('enter.intro', null);
79996               nextStep();
79997             }
79998           }
79999
80000           function startPlayground() {
80001             if (context.mode().id !== 'add-area') {
80002               return chapter.restart();
80003             }
80004
80005             _areaID = null;
80006             context.map().zoomEase(19.5, 500);
80007             timeout(function () {
80008               var textId = context.lastPointerType() === 'mouse' ? 'starting_node_click' : 'starting_node_tap';
80009               var startDrawString = helpHtml('intro.areas.start_playground') + helpHtml('intro.areas.' + textId);
80010               revealPlayground(playground, startDrawString, {
80011                 duration: 250
80012               });
80013               timeout(function () {
80014                 context.map().on('move.intro drawn.intro', function () {
80015                   revealPlayground(playground, startDrawString, {
80016                     duration: 0
80017                   });
80018                 });
80019                 context.on('enter.intro', function (mode) {
80020                   if (mode.id !== 'draw-area') return chapter.restart();
80021                   continueTo(continuePlayground);
80022                 });
80023               }, 250); // after reveal
80024             }, 550); // after easing
80025
80026             function continueTo(nextStep) {
80027               context.map().on('move.intro drawn.intro', null);
80028               context.on('enter.intro', null);
80029               nextStep();
80030             }
80031           }
80032
80033           function continuePlayground() {
80034             if (context.mode().id !== 'draw-area') {
80035               return chapter.restart();
80036             }
80037
80038             _areaID = null;
80039             revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
80040               duration: 250
80041             });
80042             timeout(function () {
80043               context.map().on('move.intro drawn.intro', function () {
80044                 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
80045                   duration: 0
80046                 });
80047               });
80048             }, 250); // after reveal
80049
80050             context.on('enter.intro', function (mode) {
80051               if (mode.id === 'draw-area') {
80052                 var entity = context.hasEntity(context.selectedIDs()[0]);
80053
80054                 if (entity && entity.nodes.length >= 6) {
80055                   return continueTo(finishPlayground);
80056                 } else {
80057                   return;
80058                 }
80059               } else if (mode.id === 'select') {
80060                 _areaID = context.selectedIDs()[0];
80061                 return continueTo(searchPresets);
80062               } else {
80063                 return chapter.restart();
80064               }
80065             });
80066
80067             function continueTo(nextStep) {
80068               context.map().on('move.intro drawn.intro', null);
80069               context.on('enter.intro', null);
80070               nextStep();
80071             }
80072           }
80073
80074           function finishPlayground() {
80075             if (context.mode().id !== 'draw-area') {
80076               return chapter.restart();
80077             }
80078
80079             _areaID = null;
80080             var finishString = helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.areas.finish_playground');
80081             revealPlayground(playground, finishString, {
80082               duration: 250
80083             });
80084             timeout(function () {
80085               context.map().on('move.intro drawn.intro', function () {
80086                 revealPlayground(playground, finishString, {
80087                   duration: 0
80088                 });
80089               });
80090             }, 250); // after reveal
80091
80092             context.on('enter.intro', function (mode) {
80093               if (mode.id === 'draw-area') {
80094                 return;
80095               } else if (mode.id === 'select') {
80096                 _areaID = context.selectedIDs()[0];
80097                 return continueTo(searchPresets);
80098               } else {
80099                 return chapter.restart();
80100               }
80101             });
80102
80103             function continueTo(nextStep) {
80104               context.map().on('move.intro drawn.intro', null);
80105               context.on('enter.intro', null);
80106               nextStep();
80107             }
80108           }
80109
80110           function searchPresets() {
80111             if (!_areaID || !context.hasEntity(_areaID)) {
80112               return addArea();
80113             }
80114
80115             var ids = context.selectedIDs();
80116
80117             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80118               context.enter(modeSelect(context, [_areaID]));
80119             } // disallow scrolling
80120
80121
80122             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80123             timeout(function () {
80124               // reset pane, in case user somehow happened to change it..
80125               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80126               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
80127               reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
80128                 preset: playgroundPreset.name()
80129               }));
80130             }, 400); // after preset list pane visible..
80131
80132             context.on('enter.intro', function (mode) {
80133               if (!_areaID || !context.hasEntity(_areaID)) {
80134                 return continueTo(addArea);
80135               }
80136
80137               var ids = context.selectedIDs();
80138
80139               if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
80140                 // keep the user's area selected..
80141                 context.enter(modeSelect(context, [_areaID])); // reset pane, in case user somehow happened to change it..
80142
80143                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
80144
80145                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80146                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
80147                 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
80148                   preset: playgroundPreset.name()
80149                 }));
80150                 context.history().on('change.intro', null);
80151               }
80152             });
80153
80154             function checkPresetSearch() {
80155               var first = context.container().select('.preset-list-item:first-child');
80156
80157               if (first.classed('preset-leisure-playground')) {
80158                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.areas.choose_playground', {
80159                   preset: playgroundPreset.name()
80160                 }), {
80161                   duration: 300
80162                 });
80163                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
80164                 context.history().on('change.intro', function () {
80165                   continueTo(clickAddField);
80166                 });
80167               }
80168             }
80169
80170             function continueTo(nextStep) {
80171               context.container().select('.inspector-wrap').on('wheel.intro', null);
80172               context.on('enter.intro', null);
80173               context.history().on('change.intro', null);
80174               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80175               nextStep();
80176             }
80177           }
80178
80179           function clickAddField() {
80180             if (!_areaID || !context.hasEntity(_areaID)) {
80181               return addArea();
80182             }
80183
80184             var ids = context.selectedIDs();
80185
80186             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80187               return searchPresets();
80188             }
80189
80190             if (!context.container().select('.form-field-description').empty()) {
80191               return continueTo(describePlayground);
80192             } // disallow scrolling
80193
80194
80195             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80196             timeout(function () {
80197               // reset pane, in case user somehow happened to change it..
80198               context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // It's possible for the user to add a description in a previous step..
80199               // If they did this already, just continue to next step.
80200
80201               var entity = context.entity(_areaID);
80202
80203               if (entity.tags.description) {
80204                 return continueTo(play);
80205               } // scroll "Add field" into view
80206
80207
80208               var box = context.container().select('.more-fields').node().getBoundingClientRect();
80209
80210               if (box.top > 300) {
80211                 var pane = context.container().select('.entity-editor-pane .inspector-body');
80212                 var start = pane.node().scrollTop;
80213                 var end = start + (box.top - 300);
80214                 pane.transition().duration(250).tween('scroll.inspector', function () {
80215                   var node = this;
80216                   var i = d3_interpolateNumber(start, end);
80217                   return function (t) {
80218                     node.scrollTop = i(t);
80219                   };
80220                 });
80221               }
80222
80223               timeout(function () {
80224                 reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', {
80225                   name: nameField.label(),
80226                   description: descriptionField.label()
80227                 }), {
80228                   duration: 300
80229                 });
80230                 context.container().select('.more-fields .combobox-input').on('click.intro', function () {
80231                   // Watch for the combobox to appear...
80232                   var watcher;
80233                   watcher = window.setInterval(function () {
80234                     if (!context.container().select('div.combobox').empty()) {
80235                       window.clearInterval(watcher);
80236                       continueTo(chooseDescriptionField);
80237                     }
80238                   }, 300);
80239                 });
80240               }, 300); // after "Add Field" visible
80241             }, 400); // after editor pane visible
80242
80243             context.on('exit.intro', function () {
80244               return continueTo(searchPresets);
80245             });
80246
80247             function continueTo(nextStep) {
80248               context.container().select('.inspector-wrap').on('wheel.intro', null);
80249               context.container().select('.more-fields .combobox-input').on('click.intro', null);
80250               context.on('exit.intro', null);
80251               nextStep();
80252             }
80253           }
80254
80255           function chooseDescriptionField() {
80256             if (!_areaID || !context.hasEntity(_areaID)) {
80257               return addArea();
80258             }
80259
80260             var ids = context.selectedIDs();
80261
80262             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80263               return searchPresets();
80264             }
80265
80266             if (!context.container().select('.form-field-description').empty()) {
80267               return continueTo(describePlayground);
80268             } // Make sure combobox is ready..
80269
80270
80271             if (context.container().select('div.combobox').empty()) {
80272               return continueTo(clickAddField);
80273             } // Watch for the combobox to go away..
80274
80275
80276             var watcher;
80277             watcher = window.setInterval(function () {
80278               if (context.container().select('div.combobox').empty()) {
80279                 window.clearInterval(watcher);
80280                 timeout(function () {
80281                   if (context.container().select('.form-field-description').empty()) {
80282                     continueTo(retryChooseDescription);
80283                   } else {
80284                     continueTo(describePlayground);
80285                   }
80286                 }, 300); // after description field added.
80287               }
80288             }, 300);
80289             reveal('div.combobox', helpHtml('intro.areas.choose_field', {
80290               field: descriptionField.label()
80291             }), {
80292               duration: 300
80293             });
80294             context.on('exit.intro', function () {
80295               return continueTo(searchPresets);
80296             });
80297
80298             function continueTo(nextStep) {
80299               if (watcher) window.clearInterval(watcher);
80300               context.on('exit.intro', null);
80301               nextStep();
80302             }
80303           }
80304
80305           function describePlayground() {
80306             if (!_areaID || !context.hasEntity(_areaID)) {
80307               return addArea();
80308             }
80309
80310             var ids = context.selectedIDs();
80311
80312             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80313               return searchPresets();
80314             } // reset pane, in case user happened to change it..
80315
80316
80317             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
80318
80319             if (context.container().select('.form-field-description').empty()) {
80320               return continueTo(retryChooseDescription);
80321             }
80322
80323             context.on('exit.intro', function () {
80324               continueTo(play);
80325             });
80326             reveal('.entity-editor-pane', helpHtml('intro.areas.describe_playground', {
80327               button: icon('#iD-icon-close', 'inline')
80328             }), {
80329               duration: 300
80330             });
80331
80332             function continueTo(nextStep) {
80333               context.on('exit.intro', null);
80334               nextStep();
80335             }
80336           }
80337
80338           function retryChooseDescription() {
80339             if (!_areaID || !context.hasEntity(_areaID)) {
80340               return addArea();
80341             }
80342
80343             var ids = context.selectedIDs();
80344
80345             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80346               return searchPresets();
80347             } // reset pane, in case user happened to change it..
80348
80349
80350             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
80351             reveal('.entity-editor-pane', helpHtml('intro.areas.retry_add_field', {
80352               field: descriptionField.label()
80353             }), {
80354               buttonText: _t.html('intro.ok'),
80355               buttonCallback: function buttonCallback() {
80356                 continueTo(clickAddField);
80357               }
80358             });
80359             context.on('exit.intro', function () {
80360               return continueTo(searchPresets);
80361             });
80362
80363             function continueTo(nextStep) {
80364               context.on('exit.intro', null);
80365               nextStep();
80366             }
80367           }
80368
80369           function play() {
80370             dispatch$1.call('done');
80371             reveal('.ideditor', helpHtml('intro.areas.play', {
80372               next: _t('intro.lines.title')
80373             }), {
80374               tooltipBox: '.intro-nav-wrap .chapter-line',
80375               buttonText: _t.html('intro.ok'),
80376               buttonCallback: function buttonCallback() {
80377                 reveal('.ideditor');
80378               }
80379             });
80380           }
80381
80382           chapter.enter = function () {
80383             addArea();
80384           };
80385
80386           chapter.exit = function () {
80387             timeouts.forEach(window.clearTimeout);
80388             context.on('enter.intro exit.intro', null);
80389             context.map().on('move.intro drawn.intro', null);
80390             context.history().on('change.intro', null);
80391             context.container().select('.inspector-wrap').on('wheel.intro', null);
80392             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80393             context.container().select('.more-fields .combobox-input').on('click.intro', null);
80394           };
80395
80396           chapter.restart = function () {
80397             chapter.exit();
80398             chapter.enter();
80399           };
80400
80401           return utilRebind(chapter, dispatch$1, 'on');
80402         }
80403
80404         function uiIntroLine(context, reveal) {
80405           var dispatch$1 = dispatch('done');
80406           var timeouts = [];
80407           var _tulipRoadID = null;
80408           var flowerRoadID = 'w646';
80409           var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
80410           var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
80411           var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
80412           var roadCategory = _mainPresetIndex.item('category-road_minor');
80413           var residentialPreset = _mainPresetIndex.item('highway/residential');
80414           var woodRoadID = 'w525';
80415           var woodRoadEndID = 'n2862';
80416           var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
80417           var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
80418           var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
80419           var washingtonStreetID = 'w522';
80420           var twelfthAvenueID = 'w1';
80421           var eleventhAvenueEndID = 'n3550';
80422           var twelfthAvenueEndID = 'n5';
80423           var _washingtonSegmentID = null;
80424           var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
80425           var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
80426           var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
80427           var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
80428           var chapter = {
80429             title: 'intro.lines.title'
80430           };
80431
80432           function timeout(f, t) {
80433             timeouts.push(window.setTimeout(f, t));
80434           }
80435
80436           function eventCancel(d3_event) {
80437             d3_event.stopPropagation();
80438             d3_event.preventDefault();
80439           }
80440
80441           function addLine() {
80442             context.enter(modeBrowse(context));
80443             context.history().reset('initial');
80444             var msec = transitionTime(tulipRoadStart, context.map().center());
80445
80446             if (msec) {
80447               reveal(null, null, {
80448                 duration: 0
80449               });
80450             }
80451
80452             context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
80453             timeout(function () {
80454               var tooltip = reveal('button.add-line', helpHtml('intro.lines.add_line'));
80455               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-lines');
80456               context.on('enter.intro', function (mode) {
80457                 if (mode.id !== 'add-line') return;
80458                 continueTo(startLine);
80459               });
80460             }, msec + 100);
80461
80462             function continueTo(nextStep) {
80463               context.on('enter.intro', null);
80464               nextStep();
80465             }
80466           }
80467
80468           function startLine() {
80469             if (context.mode().id !== 'add-line') return chapter.restart();
80470             _tulipRoadID = null;
80471             var padding = 70 * Math.pow(2, context.map().zoom() - 18);
80472             var box = pad(tulipRoadStart, padding, context);
80473             box.height = box.height + 100;
80474             var textId = context.lastPointerType() === 'mouse' ? 'start_line' : 'start_line_tap';
80475             var startLineString = helpHtml('intro.lines.missing_road') + '{br}' + helpHtml('intro.lines.line_draw_info') + helpHtml('intro.lines.' + textId);
80476             reveal(box, startLineString);
80477             context.map().on('move.intro drawn.intro', function () {
80478               padding = 70 * Math.pow(2, context.map().zoom() - 18);
80479               box = pad(tulipRoadStart, padding, context);
80480               box.height = box.height + 100;
80481               reveal(box, startLineString, {
80482                 duration: 0
80483               });
80484             });
80485             context.on('enter.intro', function (mode) {
80486               if (mode.id !== 'draw-line') return chapter.restart();
80487               continueTo(drawLine);
80488             });
80489
80490             function continueTo(nextStep) {
80491               context.map().on('move.intro drawn.intro', null);
80492               context.on('enter.intro', null);
80493               nextStep();
80494             }
80495           }
80496
80497           function drawLine() {
80498             if (context.mode().id !== 'draw-line') return chapter.restart();
80499             _tulipRoadID = context.mode().selectedIDs()[0];
80500             context.map().centerEase(tulipRoadMidpoint, 500);
80501             timeout(function () {
80502               var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
80503               var box = pad(tulipRoadMidpoint, padding, context);
80504               box.height = box.height * 2;
80505               reveal(box, helpHtml('intro.lines.intersect', {
80506                 name: _t('intro.graph.name.flower-street')
80507               }));
80508               context.map().on('move.intro drawn.intro', function () {
80509                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
80510                 box = pad(tulipRoadMidpoint, padding, context);
80511                 box.height = box.height * 2;
80512                 reveal(box, helpHtml('intro.lines.intersect', {
80513                   name: _t('intro.graph.name.flower-street')
80514                 }), {
80515                   duration: 0
80516                 });
80517               });
80518             }, 550); // after easing..
80519
80520             context.history().on('change.intro', function () {
80521               if (isLineConnected()) {
80522                 continueTo(continueLine);
80523               }
80524             });
80525             context.on('enter.intro', function (mode) {
80526               if (mode.id === 'draw-line') {
80527                 return;
80528               } else if (mode.id === 'select') {
80529                 continueTo(retryIntersect);
80530                 return;
80531               } else {
80532                 return chapter.restart();
80533               }
80534             });
80535
80536             function continueTo(nextStep) {
80537               context.map().on('move.intro drawn.intro', null);
80538               context.history().on('change.intro', null);
80539               context.on('enter.intro', null);
80540               nextStep();
80541             }
80542           }
80543
80544           function isLineConnected() {
80545             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
80546
80547             if (!entity) return false;
80548             var drawNodes = context.graph().childNodes(entity);
80549             return drawNodes.some(function (node) {
80550               return context.graph().parentWays(node).some(function (parent) {
80551                 return parent.id === flowerRoadID;
80552               });
80553             });
80554           }
80555
80556           function retryIntersect() {
80557             select(window).on('pointerdown.intro mousedown.intro', eventCancel, true);
80558             var box = pad(tulipRoadIntersection, 80, context);
80559             reveal(box, helpHtml('intro.lines.retry_intersect', {
80560               name: _t('intro.graph.name.flower-street')
80561             }));
80562             timeout(chapter.restart, 3000);
80563           }
80564
80565           function continueLine() {
80566             if (context.mode().id !== 'draw-line') return chapter.restart();
80567
80568             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
80569
80570             if (!entity) return chapter.restart();
80571             context.map().centerEase(tulipRoadIntersection, 500);
80572             var continueLineText = helpHtml('intro.lines.continue_line') + '{br}' + helpHtml('intro.lines.finish_line_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.lines.finish_road');
80573             reveal('.surface', continueLineText);
80574             context.on('enter.intro', function (mode) {
80575               if (mode.id === 'draw-line') return;else if (mode.id === 'select') return continueTo(chooseCategoryRoad);else return chapter.restart();
80576             });
80577
80578             function continueTo(nextStep) {
80579               context.on('enter.intro', null);
80580               nextStep();
80581             }
80582           }
80583
80584           function chooseCategoryRoad() {
80585             if (context.mode().id !== 'select') return chapter.restart();
80586             context.on('exit.intro', function () {
80587               return chapter.restart();
80588             });
80589             var button = context.container().select('.preset-category-road_minor .preset-list-button');
80590             if (button.empty()) return chapter.restart(); // disallow scrolling
80591
80592             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80593             timeout(function () {
80594               // reset pane, in case user somehow happened to change it..
80595               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80596               reveal(button.node(), helpHtml('intro.lines.choose_category_road', {
80597                 category: roadCategory.name()
80598               }));
80599               button.on('click.intro', function () {
80600                 continueTo(choosePresetResidential);
80601               });
80602             }, 400); // after editor pane visible
80603
80604             function continueTo(nextStep) {
80605               context.container().select('.inspector-wrap').on('wheel.intro', null);
80606               context.container().select('.preset-list-button').on('click.intro', null);
80607               context.on('exit.intro', null);
80608               nextStep();
80609             }
80610           }
80611
80612           function choosePresetResidential() {
80613             if (context.mode().id !== 'select') return chapter.restart();
80614             context.on('exit.intro', function () {
80615               return chapter.restart();
80616             });
80617             var subgrid = context.container().select('.preset-category-road_minor .subgrid');
80618             if (subgrid.empty()) return chapter.restart();
80619             subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button').on('click.intro', function () {
80620               continueTo(retryPresetResidential);
80621             });
80622             subgrid.selectAll('.preset-highway-residential .preset-list-button').on('click.intro', function () {
80623               continueTo(nameRoad);
80624             });
80625             timeout(function () {
80626               reveal(subgrid.node(), helpHtml('intro.lines.choose_preset_residential', {
80627                 preset: residentialPreset.name()
80628               }), {
80629                 tooltipBox: '.preset-highway-residential .preset-list-button',
80630                 duration: 300
80631               });
80632             }, 300);
80633
80634             function continueTo(nextStep) {
80635               context.container().select('.preset-list-button').on('click.intro', null);
80636               context.on('exit.intro', null);
80637               nextStep();
80638             }
80639           } // selected wrong road type
80640
80641
80642           function retryPresetResidential() {
80643             if (context.mode().id !== 'select') return chapter.restart();
80644             context.on('exit.intro', function () {
80645               return chapter.restart();
80646             }); // disallow scrolling
80647
80648             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80649             timeout(function () {
80650               var button = context.container().select('.entity-editor-pane .preset-list-button');
80651               reveal(button.node(), helpHtml('intro.lines.retry_preset_residential', {
80652                 preset: residentialPreset.name()
80653               }));
80654               button.on('click.intro', function () {
80655                 continueTo(chooseCategoryRoad);
80656               });
80657             }, 500);
80658
80659             function continueTo(nextStep) {
80660               context.container().select('.inspector-wrap').on('wheel.intro', null);
80661               context.container().select('.preset-list-button').on('click.intro', null);
80662               context.on('exit.intro', null);
80663               nextStep();
80664             }
80665           }
80666
80667           function nameRoad() {
80668             context.on('exit.intro', function () {
80669               continueTo(didNameRoad);
80670             });
80671             timeout(function () {
80672               reveal('.entity-editor-pane', helpHtml('intro.lines.name_road', {
80673                 button: icon('#iD-icon-close', 'inline')
80674               }), {
80675                 tooltipClass: 'intro-lines-name_road'
80676               });
80677             }, 500);
80678
80679             function continueTo(nextStep) {
80680               context.on('exit.intro', null);
80681               nextStep();
80682             }
80683           }
80684
80685           function didNameRoad() {
80686             context.history().checkpoint('doneAddLine');
80687             timeout(function () {
80688               reveal('.surface', helpHtml('intro.lines.did_name_road'), {
80689                 buttonText: _t.html('intro.ok'),
80690                 buttonCallback: function buttonCallback() {
80691                   continueTo(updateLine);
80692                 }
80693               });
80694             }, 500);
80695
80696             function continueTo(nextStep) {
80697               nextStep();
80698             }
80699           }
80700
80701           function updateLine() {
80702             context.history().reset('doneAddLine');
80703
80704             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80705               return chapter.restart();
80706             }
80707
80708             var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
80709
80710             if (msec) {
80711               reveal(null, null, {
80712                 duration: 0
80713               });
80714             }
80715
80716             context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
80717             timeout(function () {
80718               var padding = 250 * Math.pow(2, context.map().zoom() - 19);
80719               var box = pad(woodRoadDragMidpoint, padding, context);
80720
80721               var advance = function advance() {
80722                 continueTo(addNode);
80723               };
80724
80725               reveal(box, helpHtml('intro.lines.update_line'), {
80726                 buttonText: _t.html('intro.ok'),
80727                 buttonCallback: advance
80728               });
80729               context.map().on('move.intro drawn.intro', function () {
80730                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
80731                 var box = pad(woodRoadDragMidpoint, padding, context);
80732                 reveal(box, helpHtml('intro.lines.update_line'), {
80733                   duration: 0,
80734                   buttonText: _t.html('intro.ok'),
80735                   buttonCallback: advance
80736                 });
80737               });
80738             }, msec + 100);
80739
80740             function continueTo(nextStep) {
80741               context.map().on('move.intro drawn.intro', null);
80742               nextStep();
80743             }
80744           }
80745
80746           function addNode() {
80747             context.history().reset('doneAddLine');
80748
80749             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80750               return chapter.restart();
80751             }
80752
80753             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
80754             var box = pad(woodRoadAddNode, padding, context);
80755             var addNodeString = helpHtml('intro.lines.add_node' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
80756             reveal(box, addNodeString);
80757             context.map().on('move.intro drawn.intro', function () {
80758               var padding = 40 * Math.pow(2, context.map().zoom() - 19);
80759               var box = pad(woodRoadAddNode, padding, context);
80760               reveal(box, addNodeString, {
80761                 duration: 0
80762               });
80763             });
80764             context.history().on('change.intro', function (changed) {
80765               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80766                 return continueTo(updateLine);
80767               }
80768
80769               if (changed.created().length === 1) {
80770                 timeout(function () {
80771                   continueTo(startDragEndpoint);
80772                 }, 500);
80773               }
80774             });
80775             context.on('enter.intro', function (mode) {
80776               if (mode.id !== 'select') {
80777                 continueTo(updateLine);
80778               }
80779             });
80780
80781             function continueTo(nextStep) {
80782               context.map().on('move.intro drawn.intro', null);
80783               context.history().on('change.intro', null);
80784               context.on('enter.intro', null);
80785               nextStep();
80786             }
80787           }
80788
80789           function startDragEndpoint() {
80790             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80791               return continueTo(updateLine);
80792             }
80793
80794             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80795             var box = pad(woodRoadDragEndpoint, padding, context);
80796             var startDragString = helpHtml('intro.lines.start_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch')) + helpHtml('intro.lines.drag_to_intersection');
80797             reveal(box, startDragString);
80798             context.map().on('move.intro drawn.intro', function () {
80799               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80800                 return continueTo(updateLine);
80801               }
80802
80803               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80804               var box = pad(woodRoadDragEndpoint, padding, context);
80805               reveal(box, startDragString, {
80806                 duration: 0
80807               });
80808               var entity = context.entity(woodRoadEndID);
80809
80810               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
80811                 continueTo(finishDragEndpoint);
80812               }
80813             });
80814
80815             function continueTo(nextStep) {
80816               context.map().on('move.intro drawn.intro', null);
80817               nextStep();
80818             }
80819           }
80820
80821           function finishDragEndpoint() {
80822             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80823               return continueTo(updateLine);
80824             }
80825
80826             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80827             var box = pad(woodRoadDragEndpoint, padding, context);
80828             var finishDragString = helpHtml('intro.lines.spot_looks_good') + helpHtml('intro.lines.finish_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
80829             reveal(box, finishDragString);
80830             context.map().on('move.intro drawn.intro', function () {
80831               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80832                 return continueTo(updateLine);
80833               }
80834
80835               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80836               var box = pad(woodRoadDragEndpoint, padding, context);
80837               reveal(box, finishDragString, {
80838                 duration: 0
80839               });
80840               var entity = context.entity(woodRoadEndID);
80841
80842               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
80843                 continueTo(startDragEndpoint);
80844               }
80845             });
80846             context.on('enter.intro', function () {
80847               continueTo(startDragMidpoint);
80848             });
80849
80850             function continueTo(nextStep) {
80851               context.map().on('move.intro drawn.intro', null);
80852               context.on('enter.intro', null);
80853               nextStep();
80854             }
80855           }
80856
80857           function startDragMidpoint() {
80858             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80859               return continueTo(updateLine);
80860             }
80861
80862             if (context.selectedIDs().indexOf(woodRoadID) === -1) {
80863               context.enter(modeSelect(context, [woodRoadID]));
80864             }
80865
80866             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
80867             var box = pad(woodRoadDragMidpoint, padding, context);
80868             reveal(box, helpHtml('intro.lines.start_drag_midpoint'));
80869             context.map().on('move.intro drawn.intro', function () {
80870               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80871                 return continueTo(updateLine);
80872               }
80873
80874               var padding = 80 * Math.pow(2, context.map().zoom() - 19);
80875               var box = pad(woodRoadDragMidpoint, padding, context);
80876               reveal(box, helpHtml('intro.lines.start_drag_midpoint'), {
80877                 duration: 0
80878               });
80879             });
80880             context.history().on('change.intro', function (changed) {
80881               if (changed.created().length === 1) {
80882                 continueTo(continueDragMidpoint);
80883               }
80884             });
80885             context.on('enter.intro', function (mode) {
80886               if (mode.id !== 'select') {
80887                 // keep Wood Road selected so midpoint triangles are drawn..
80888                 context.enter(modeSelect(context, [woodRoadID]));
80889               }
80890             });
80891
80892             function continueTo(nextStep) {
80893               context.map().on('move.intro drawn.intro', null);
80894               context.history().on('change.intro', null);
80895               context.on('enter.intro', null);
80896               nextStep();
80897             }
80898           }
80899
80900           function continueDragMidpoint() {
80901             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80902               return continueTo(updateLine);
80903             }
80904
80905             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80906             var box = pad(woodRoadDragEndpoint, padding, context);
80907             box.height += 400;
80908
80909             var advance = function advance() {
80910               context.history().checkpoint('doneUpdateLine');
80911               continueTo(deleteLines);
80912             };
80913
80914             reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
80915               buttonText: _t.html('intro.ok'),
80916               buttonCallback: advance
80917             });
80918             context.map().on('move.intro drawn.intro', function () {
80919               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80920                 return continueTo(updateLine);
80921               }
80922
80923               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80924               var box = pad(woodRoadDragEndpoint, padding, context);
80925               box.height += 400;
80926               reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
80927                 duration: 0,
80928                 buttonText: _t.html('intro.ok'),
80929                 buttonCallback: advance
80930               });
80931             });
80932
80933             function continueTo(nextStep) {
80934               context.map().on('move.intro drawn.intro', null);
80935               nextStep();
80936             }
80937           }
80938
80939           function deleteLines() {
80940             context.history().reset('doneUpdateLine');
80941             context.enter(modeBrowse(context));
80942
80943             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80944               return chapter.restart();
80945             }
80946
80947             var msec = transitionTime(deleteLinesLoc, context.map().center());
80948
80949             if (msec) {
80950               reveal(null, null, {
80951                 duration: 0
80952               });
80953             }
80954
80955             context.map().centerZoomEase(deleteLinesLoc, 18, msec);
80956             timeout(function () {
80957               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80958               var box = pad(deleteLinesLoc, padding, context);
80959               box.top -= 200;
80960               box.height += 400;
80961
80962               var advance = function advance() {
80963                 continueTo(rightClickIntersection);
80964               };
80965
80966               reveal(box, helpHtml('intro.lines.delete_lines', {
80967                 street: _t('intro.graph.name.12th-avenue')
80968               }), {
80969                 buttonText: _t.html('intro.ok'),
80970                 buttonCallback: advance
80971               });
80972               context.map().on('move.intro drawn.intro', function () {
80973                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80974                 var box = pad(deleteLinesLoc, padding, context);
80975                 box.top -= 200;
80976                 box.height += 400;
80977                 reveal(box, helpHtml('intro.lines.delete_lines', {
80978                   street: _t('intro.graph.name.12th-avenue')
80979                 }), {
80980                   duration: 0,
80981                   buttonText: _t.html('intro.ok'),
80982                   buttonCallback: advance
80983                 });
80984               });
80985               context.history().on('change.intro', function () {
80986                 timeout(function () {
80987                   continueTo(deleteLines);
80988                 }, 500); // after any transition (e.g. if user deleted intersection)
80989               });
80990             }, msec + 100);
80991
80992             function continueTo(nextStep) {
80993               context.map().on('move.intro drawn.intro', null);
80994               context.history().on('change.intro', null);
80995               nextStep();
80996             }
80997           }
80998
80999           function rightClickIntersection() {
81000             context.history().reset('doneUpdateLine');
81001             context.enter(modeBrowse(context));
81002             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
81003             var rightClickString = helpHtml('intro.lines.split_street', {
81004               street1: _t('intro.graph.name.11th-avenue'),
81005               street2: _t('intro.graph.name.washington-street')
81006             }) + helpHtml('intro.lines.' + (context.lastPointerType() === 'mouse' ? 'rightclick_intersection' : 'edit_menu_intersection_touch'));
81007             timeout(function () {
81008               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81009               var box = pad(eleventhAvenueEnd, padding, context);
81010               reveal(box, rightClickString);
81011               context.map().on('move.intro drawn.intro', function () {
81012                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81013                 var box = pad(eleventhAvenueEnd, padding, context);
81014                 reveal(box, rightClickString, {
81015                   duration: 0
81016                 });
81017               });
81018               context.on('enter.intro', function (mode) {
81019                 if (mode.id !== 'select') return;
81020                 var ids = context.selectedIDs();
81021                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
81022                 timeout(function () {
81023                   var node = selectMenuItem(context, 'split').node();
81024                   if (!node) return;
81025                   continueTo(splitIntersection);
81026                 }, 50); // after menu visible
81027               });
81028               context.history().on('change.intro', function () {
81029                 timeout(function () {
81030                   continueTo(deleteLines);
81031                 }, 300); // after any transition (e.g. if user deleted intersection)
81032               });
81033             }, 600);
81034
81035             function continueTo(nextStep) {
81036               context.map().on('move.intro drawn.intro', null);
81037               context.on('enter.intro', null);
81038               context.history().on('change.intro', null);
81039               nextStep();
81040             }
81041           }
81042
81043           function splitIntersection() {
81044             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81045               return continueTo(deleteLines);
81046             }
81047
81048             var node = selectMenuItem(context, 'split').node();
81049
81050             if (!node) {
81051               return continueTo(rightClickIntersection);
81052             }
81053
81054             var wasChanged = false;
81055             _washingtonSegmentID = null;
81056             reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
81057               street: _t('intro.graph.name.washington-street')
81058             }), {
81059               padding: 50
81060             });
81061             context.map().on('move.intro drawn.intro', function () {
81062               var node = selectMenuItem(context, 'split').node();
81063
81064               if (!wasChanged && !node) {
81065                 return continueTo(rightClickIntersection);
81066               }
81067
81068               reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
81069                 street: _t('intro.graph.name.washington-street')
81070               }), {
81071                 duration: 0,
81072                 padding: 50
81073               });
81074             });
81075             context.history().on('change.intro', function (changed) {
81076               wasChanged = true;
81077               timeout(function () {
81078                 if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
81079                   n: 1
81080                 })) {
81081                   _washingtonSegmentID = changed.created()[0].id;
81082                   continueTo(didSplit);
81083                 } else {
81084                   _washingtonSegmentID = null;
81085                   continueTo(retrySplit);
81086                 }
81087               }, 300); // after any transition (e.g. if user deleted intersection)
81088             });
81089
81090             function continueTo(nextStep) {
81091               context.map().on('move.intro drawn.intro', null);
81092               context.history().on('change.intro', null);
81093               nextStep();
81094             }
81095           }
81096
81097           function retrySplit() {
81098             context.enter(modeBrowse(context));
81099             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
81100
81101             var advance = function advance() {
81102               continueTo(rightClickIntersection);
81103             };
81104
81105             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81106             var box = pad(eleventhAvenueEnd, padding, context);
81107             reveal(box, helpHtml('intro.lines.retry_split'), {
81108               buttonText: _t.html('intro.ok'),
81109               buttonCallback: advance
81110             });
81111             context.map().on('move.intro drawn.intro', function () {
81112               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81113               var box = pad(eleventhAvenueEnd, padding, context);
81114               reveal(box, helpHtml('intro.lines.retry_split'), {
81115                 duration: 0,
81116                 buttonText: _t.html('intro.ok'),
81117                 buttonCallback: advance
81118               });
81119             });
81120
81121             function continueTo(nextStep) {
81122               context.map().on('move.intro drawn.intro', null);
81123               nextStep();
81124             }
81125           }
81126
81127           function didSplit() {
81128             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81129               return continueTo(rightClickIntersection);
81130             }
81131
81132             var ids = context.selectedIDs();
81133             var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
81134             var street = _t('intro.graph.name.washington-street');
81135             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81136             var box = pad(twelfthAvenue, padding, context);
81137             box.width = box.width / 2;
81138             reveal(box, helpHtml(string, {
81139               street1: street,
81140               street2: street
81141             }), {
81142               duration: 500
81143             });
81144             timeout(function () {
81145               context.map().centerZoomEase(twelfthAvenue, 18, 500);
81146               context.map().on('move.intro drawn.intro', function () {
81147                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81148                 var box = pad(twelfthAvenue, padding, context);
81149                 box.width = box.width / 2;
81150                 reveal(box, helpHtml(string, {
81151                   street1: street,
81152                   street2: street
81153                 }), {
81154                   duration: 0
81155                 });
81156               });
81157             }, 600); // after initial reveal and curtain cut
81158
81159             context.on('enter.intro', function () {
81160               var ids = context.selectedIDs();
81161
81162               if (ids.length === 1 && ids[0] === _washingtonSegmentID) {
81163                 continueTo(multiSelect);
81164               }
81165             });
81166             context.history().on('change.intro', function () {
81167               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81168                 return continueTo(rightClickIntersection);
81169               }
81170             });
81171
81172             function continueTo(nextStep) {
81173               context.map().on('move.intro drawn.intro', null);
81174               context.on('enter.intro', null);
81175               context.history().on('change.intro', null);
81176               nextStep();
81177             }
81178           }
81179
81180           function multiSelect() {
81181             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81182               return continueTo(rightClickIntersection);
81183             }
81184
81185             var ids = context.selectedIDs();
81186             var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
81187             var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
81188
81189             if (hasWashington && hasTwelfth) {
81190               return continueTo(multiRightClick);
81191             } else if (!hasWashington && !hasTwelfth) {
81192               return continueTo(didSplit);
81193             }
81194
81195             context.map().centerZoomEase(twelfthAvenue, 18, 500);
81196             timeout(function () {
81197               var selected, other, padding, box;
81198
81199               if (hasWashington) {
81200                 selected = _t('intro.graph.name.washington-street');
81201                 other = _t('intro.graph.name.12th-avenue');
81202                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
81203                 box = pad(twelfthAvenueEnd, padding, context);
81204                 box.width *= 3;
81205               } else {
81206                 selected = _t('intro.graph.name.12th-avenue');
81207                 other = _t('intro.graph.name.washington-street');
81208                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
81209                 box = pad(twelfthAvenue, padding, context);
81210                 box.width /= 2;
81211               }
81212
81213               reveal(box, helpHtml('intro.lines.multi_select', {
81214                 selected: selected,
81215                 other1: other
81216               }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
81217                 selected: selected,
81218                 other2: other
81219               }));
81220               context.map().on('move.intro drawn.intro', function () {
81221                 if (hasWashington) {
81222                   selected = _t('intro.graph.name.washington-street');
81223                   other = _t('intro.graph.name.12th-avenue');
81224                   padding = 60 * Math.pow(2, context.map().zoom() - 18);
81225                   box = pad(twelfthAvenueEnd, padding, context);
81226                   box.width *= 3;
81227                 } else {
81228                   selected = _t('intro.graph.name.12th-avenue');
81229                   other = _t('intro.graph.name.washington-street');
81230                   padding = 200 * Math.pow(2, context.map().zoom() - 18);
81231                   box = pad(twelfthAvenue, padding, context);
81232                   box.width /= 2;
81233                 }
81234
81235                 reveal(box, helpHtml('intro.lines.multi_select', {
81236                   selected: selected,
81237                   other1: other
81238                 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
81239                   selected: selected,
81240                   other2: other
81241                 }), {
81242                   duration: 0
81243                 });
81244               });
81245               context.on('enter.intro', function () {
81246                 continueTo(multiSelect);
81247               });
81248               context.history().on('change.intro', function () {
81249                 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81250                   return continueTo(rightClickIntersection);
81251                 }
81252               });
81253             }, 600);
81254
81255             function continueTo(nextStep) {
81256               context.map().on('move.intro drawn.intro', null);
81257               context.on('enter.intro', null);
81258               context.history().on('change.intro', null);
81259               nextStep();
81260             }
81261           }
81262
81263           function multiRightClick() {
81264             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81265               return continueTo(rightClickIntersection);
81266             }
81267
81268             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81269             var box = pad(twelfthAvenue, padding, context);
81270             var rightClickString = helpHtml('intro.lines.multi_select_success') + helpHtml('intro.lines.multi_' + (context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch'));
81271             reveal(box, rightClickString);
81272             context.map().on('move.intro drawn.intro', function () {
81273               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81274               var box = pad(twelfthAvenue, padding, context);
81275               reveal(box, rightClickString, {
81276                 duration: 0
81277               });
81278             });
81279             context.ui().editMenu().on('toggled.intro', function (open) {
81280               if (!open) return;
81281               timeout(function () {
81282                 var ids = context.selectedIDs();
81283
81284                 if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
81285                   var node = selectMenuItem(context, 'delete').node();
81286                   if (!node) return;
81287                   continueTo(multiDelete);
81288                 } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
81289                   return continueTo(multiSelect);
81290                 } else {
81291                   return continueTo(didSplit);
81292                 }
81293               }, 300); // after edit menu visible
81294             });
81295             context.history().on('change.intro', function () {
81296               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81297                 return continueTo(rightClickIntersection);
81298               }
81299             });
81300
81301             function continueTo(nextStep) {
81302               context.map().on('move.intro drawn.intro', null);
81303               context.ui().editMenu().on('toggled.intro', null);
81304               context.history().on('change.intro', null);
81305               nextStep();
81306             }
81307           }
81308
81309           function multiDelete() {
81310             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81311               return continueTo(rightClickIntersection);
81312             }
81313
81314             var node = selectMenuItem(context, 'delete').node();
81315             if (!node) return continueTo(multiRightClick);
81316             reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
81317               padding: 50
81318             });
81319             context.map().on('move.intro drawn.intro', function () {
81320               reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
81321                 duration: 0,
81322                 padding: 50
81323               });
81324             });
81325             context.on('exit.intro', function () {
81326               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
81327                 return continueTo(multiSelect); // left select mode but roads still exist
81328               }
81329             });
81330             context.history().on('change.intro', function () {
81331               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
81332                 continueTo(retryDelete); // changed something but roads still exist
81333               } else {
81334                 continueTo(play);
81335               }
81336             });
81337
81338             function continueTo(nextStep) {
81339               context.map().on('move.intro drawn.intro', null);
81340               context.on('exit.intro', null);
81341               context.history().on('change.intro', null);
81342               nextStep();
81343             }
81344           }
81345
81346           function retryDelete() {
81347             context.enter(modeBrowse(context));
81348             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81349             var box = pad(twelfthAvenue, padding, context);
81350             reveal(box, helpHtml('intro.lines.retry_delete'), {
81351               buttonText: _t.html('intro.ok'),
81352               buttonCallback: function buttonCallback() {
81353                 continueTo(multiSelect);
81354               }
81355             });
81356
81357             function continueTo(nextStep) {
81358               nextStep();
81359             }
81360           }
81361
81362           function play() {
81363             dispatch$1.call('done');
81364             reveal('.ideditor', helpHtml('intro.lines.play', {
81365               next: _t('intro.buildings.title')
81366             }), {
81367               tooltipBox: '.intro-nav-wrap .chapter-building',
81368               buttonText: _t.html('intro.ok'),
81369               buttonCallback: function buttonCallback() {
81370                 reveal('.ideditor');
81371               }
81372             });
81373           }
81374
81375           chapter.enter = function () {
81376             addLine();
81377           };
81378
81379           chapter.exit = function () {
81380             timeouts.forEach(window.clearTimeout);
81381             select(window).on('pointerdown.intro mousedown.intro', null, true);
81382             context.on('enter.intro exit.intro', null);
81383             context.map().on('move.intro drawn.intro', null);
81384             context.history().on('change.intro', null);
81385             context.container().select('.inspector-wrap').on('wheel.intro', null);
81386             context.container().select('.preset-list-button').on('click.intro', null);
81387           };
81388
81389           chapter.restart = function () {
81390             chapter.exit();
81391             chapter.enter();
81392           };
81393
81394           return utilRebind(chapter, dispatch$1, 'on');
81395         }
81396
81397         function uiIntroBuilding(context, reveal) {
81398           var dispatch$1 = dispatch('done');
81399           var house = [-85.62815, 41.95638];
81400           var tank = [-85.62732, 41.95347];
81401           var buildingCatetory = _mainPresetIndex.item('category-building');
81402           var housePreset = _mainPresetIndex.item('building/house');
81403           var tankPreset = _mainPresetIndex.item('man_made/storage_tank');
81404           var timeouts = [];
81405           var _houseID = null;
81406           var _tankID = null;
81407           var chapter = {
81408             title: 'intro.buildings.title'
81409           };
81410
81411           function timeout(f, t) {
81412             timeouts.push(window.setTimeout(f, t));
81413           }
81414
81415           function eventCancel(d3_event) {
81416             d3_event.stopPropagation();
81417             d3_event.preventDefault();
81418           }
81419
81420           function revealHouse(center, text, options) {
81421             var padding = 160 * Math.pow(2, context.map().zoom() - 20);
81422             var box = pad(center, padding, context);
81423             reveal(box, text, options);
81424           }
81425
81426           function revealTank(center, text, options) {
81427             var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
81428             var box = pad(center, padding, context);
81429             reveal(box, text, options);
81430           }
81431
81432           function addHouse() {
81433             context.enter(modeBrowse(context));
81434             context.history().reset('initial');
81435             _houseID = null;
81436             var msec = transitionTime(house, context.map().center());
81437
81438             if (msec) {
81439               reveal(null, null, {
81440                 duration: 0
81441               });
81442             }
81443
81444             context.map().centerZoomEase(house, 19, msec);
81445             timeout(function () {
81446               var tooltip = reveal('button.add-area', helpHtml('intro.buildings.add_building'));
81447               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-buildings');
81448               context.on('enter.intro', function (mode) {
81449                 if (mode.id !== 'add-area') return;
81450                 continueTo(startHouse);
81451               });
81452             }, msec + 100);
81453
81454             function continueTo(nextStep) {
81455               context.on('enter.intro', null);
81456               nextStep();
81457             }
81458           }
81459
81460           function startHouse() {
81461             if (context.mode().id !== 'add-area') {
81462               return continueTo(addHouse);
81463             }
81464
81465             _houseID = null;
81466             context.map().zoomEase(20, 500);
81467             timeout(function () {
81468               var startString = helpHtml('intro.buildings.start_building') + helpHtml('intro.buildings.building_corner_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
81469               revealHouse(house, startString);
81470               context.map().on('move.intro drawn.intro', function () {
81471                 revealHouse(house, startString, {
81472                   duration: 0
81473                 });
81474               });
81475               context.on('enter.intro', function (mode) {
81476                 if (mode.id !== 'draw-area') return chapter.restart();
81477                 continueTo(continueHouse);
81478               });
81479             }, 550); // after easing
81480
81481             function continueTo(nextStep) {
81482               context.map().on('move.intro drawn.intro', null);
81483               context.on('enter.intro', null);
81484               nextStep();
81485             }
81486           }
81487
81488           function continueHouse() {
81489             if (context.mode().id !== 'draw-area') {
81490               return continueTo(addHouse);
81491             }
81492
81493             _houseID = null;
81494             var continueString = helpHtml('intro.buildings.continue_building') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_building');
81495             revealHouse(house, continueString);
81496             context.map().on('move.intro drawn.intro', function () {
81497               revealHouse(house, continueString, {
81498                 duration: 0
81499               });
81500             });
81501             context.on('enter.intro', function (mode) {
81502               if (mode.id === 'draw-area') {
81503                 return;
81504               } else if (mode.id === 'select') {
81505                 var graph = context.graph();
81506                 var way = context.entity(context.selectedIDs()[0]);
81507                 var nodes = graph.childNodes(way);
81508                 var points = utilArrayUniq(nodes).map(function (n) {
81509                   return context.projection(n.loc);
81510                 });
81511
81512                 if (isMostlySquare(points)) {
81513                   _houseID = way.id;
81514                   return continueTo(chooseCategoryBuilding);
81515                 } else {
81516                   return continueTo(retryHouse);
81517                 }
81518               } else {
81519                 return chapter.restart();
81520               }
81521             });
81522
81523             function continueTo(nextStep) {
81524               context.map().on('move.intro drawn.intro', null);
81525               context.on('enter.intro', null);
81526               nextStep();
81527             }
81528           }
81529
81530           function retryHouse() {
81531             var onClick = function onClick() {
81532               continueTo(addHouse);
81533             };
81534
81535             revealHouse(house, helpHtml('intro.buildings.retry_building'), {
81536               buttonText: _t.html('intro.ok'),
81537               buttonCallback: onClick
81538             });
81539             context.map().on('move.intro drawn.intro', function () {
81540               revealHouse(house, helpHtml('intro.buildings.retry_building'), {
81541                 duration: 0,
81542                 buttonText: _t.html('intro.ok'),
81543                 buttonCallback: onClick
81544               });
81545             });
81546
81547             function continueTo(nextStep) {
81548               context.map().on('move.intro drawn.intro', null);
81549               nextStep();
81550             }
81551           }
81552
81553           function chooseCategoryBuilding() {
81554             if (!_houseID || !context.hasEntity(_houseID)) {
81555               return addHouse();
81556             }
81557
81558             var ids = context.selectedIDs();
81559
81560             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81561               context.enter(modeSelect(context, [_houseID]));
81562             } // disallow scrolling
81563
81564
81565             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81566             timeout(function () {
81567               // reset pane, in case user somehow happened to change it..
81568               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81569               var button = context.container().select('.preset-category-building .preset-list-button');
81570               reveal(button.node(), helpHtml('intro.buildings.choose_category_building', {
81571                 category: buildingCatetory.name()
81572               }));
81573               button.on('click.intro', function () {
81574                 button.on('click.intro', null);
81575                 continueTo(choosePresetHouse);
81576               });
81577             }, 400); // after preset list pane visible..
81578
81579             context.on('enter.intro', function (mode) {
81580               if (!_houseID || !context.hasEntity(_houseID)) {
81581                 return continueTo(addHouse);
81582               }
81583
81584               var ids = context.selectedIDs();
81585
81586               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
81587                 return continueTo(chooseCategoryBuilding);
81588               }
81589             });
81590
81591             function continueTo(nextStep) {
81592               context.container().select('.inspector-wrap').on('wheel.intro', null);
81593               context.container().select('.preset-list-button').on('click.intro', null);
81594               context.on('enter.intro', null);
81595               nextStep();
81596             }
81597           }
81598
81599           function choosePresetHouse() {
81600             if (!_houseID || !context.hasEntity(_houseID)) {
81601               return addHouse();
81602             }
81603
81604             var ids = context.selectedIDs();
81605
81606             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81607               context.enter(modeSelect(context, [_houseID]));
81608             } // disallow scrolling
81609
81610
81611             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81612             timeout(function () {
81613               // reset pane, in case user somehow happened to change it..
81614               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81615               var button = context.container().select('.preset-building-house .preset-list-button');
81616               reveal(button.node(), helpHtml('intro.buildings.choose_preset_house', {
81617                 preset: housePreset.name()
81618               }), {
81619                 duration: 300
81620               });
81621               button.on('click.intro', function () {
81622                 button.on('click.intro', null);
81623                 continueTo(closeEditorHouse);
81624               });
81625             }, 400); // after preset list pane visible..
81626
81627             context.on('enter.intro', function (mode) {
81628               if (!_houseID || !context.hasEntity(_houseID)) {
81629                 return continueTo(addHouse);
81630               }
81631
81632               var ids = context.selectedIDs();
81633
81634               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
81635                 return continueTo(chooseCategoryBuilding);
81636               }
81637             });
81638
81639             function continueTo(nextStep) {
81640               context.container().select('.inspector-wrap').on('wheel.intro', null);
81641               context.container().select('.preset-list-button').on('click.intro', null);
81642               context.on('enter.intro', null);
81643               nextStep();
81644             }
81645           }
81646
81647           function closeEditorHouse() {
81648             if (!_houseID || !context.hasEntity(_houseID)) {
81649               return addHouse();
81650             }
81651
81652             var ids = context.selectedIDs();
81653
81654             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81655               context.enter(modeSelect(context, [_houseID]));
81656             }
81657
81658             context.history().checkpoint('hasHouse');
81659             context.on('exit.intro', function () {
81660               continueTo(rightClickHouse);
81661             });
81662             timeout(function () {
81663               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
81664                 button: icon('#iD-icon-close', 'inline')
81665               }));
81666             }, 500);
81667
81668             function continueTo(nextStep) {
81669               context.on('exit.intro', null);
81670               nextStep();
81671             }
81672           }
81673
81674           function rightClickHouse() {
81675             if (!_houseID) return chapter.restart();
81676             context.enter(modeBrowse(context));
81677             context.history().reset('hasHouse');
81678             var zoom = context.map().zoom();
81679
81680             if (zoom < 20) {
81681               zoom = 20;
81682             }
81683
81684             context.map().centerZoomEase(house, zoom, 500);
81685             context.on('enter.intro', function (mode) {
81686               if (mode.id !== 'select') return;
81687               var ids = context.selectedIDs();
81688               if (ids.length !== 1 || ids[0] !== _houseID) return;
81689               timeout(function () {
81690                 var node = selectMenuItem(context, 'orthogonalize').node();
81691                 if (!node) return;
81692                 continueTo(clickSquare);
81693               }, 50); // after menu visible
81694             });
81695             context.map().on('move.intro drawn.intro', function () {
81696               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_building' : 'edit_menu_building_touch'));
81697               revealHouse(house, rightclickString, {
81698                 duration: 0
81699               });
81700             });
81701             context.history().on('change.intro', function () {
81702               continueTo(rightClickHouse);
81703             });
81704
81705             function continueTo(nextStep) {
81706               context.on('enter.intro', null);
81707               context.map().on('move.intro drawn.intro', null);
81708               context.history().on('change.intro', null);
81709               nextStep();
81710             }
81711           }
81712
81713           function clickSquare() {
81714             if (!_houseID) return chapter.restart();
81715             var entity = context.hasEntity(_houseID);
81716             if (!entity) return continueTo(rightClickHouse);
81717             var node = selectMenuItem(context, 'orthogonalize').node();
81718
81719             if (!node) {
81720               return continueTo(rightClickHouse);
81721             }
81722
81723             var wasChanged = false;
81724             reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
81725               padding: 50
81726             });
81727             context.on('enter.intro', function (mode) {
81728               if (mode.id === 'browse') {
81729                 continueTo(rightClickHouse);
81730               } else if (mode.id === 'move' || mode.id === 'rotate') {
81731                 continueTo(retryClickSquare);
81732               }
81733             });
81734             context.map().on('move.intro', function () {
81735               var node = selectMenuItem(context, 'orthogonalize').node();
81736
81737               if (!wasChanged && !node) {
81738                 return continueTo(rightClickHouse);
81739               }
81740
81741               reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
81742                 duration: 0,
81743                 padding: 50
81744               });
81745             });
81746             context.history().on('change.intro', function () {
81747               wasChanged = true;
81748               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
81749
81750               timeout(function () {
81751                 if (context.history().undoAnnotation() === _t('operations.orthogonalize.annotation.feature', {
81752                   n: 1
81753                 })) {
81754                   continueTo(doneSquare);
81755                 } else {
81756                   continueTo(retryClickSquare);
81757                 }
81758               }, 500); // after transitioned actions
81759             });
81760
81761             function continueTo(nextStep) {
81762               context.on('enter.intro', null);
81763               context.map().on('move.intro', null);
81764               context.history().on('change.intro', null);
81765               nextStep();
81766             }
81767           }
81768
81769           function retryClickSquare() {
81770             context.enter(modeBrowse(context));
81771             revealHouse(house, helpHtml('intro.buildings.retry_square'), {
81772               buttonText: _t.html('intro.ok'),
81773               buttonCallback: function buttonCallback() {
81774                 continueTo(rightClickHouse);
81775               }
81776             });
81777
81778             function continueTo(nextStep) {
81779               nextStep();
81780             }
81781           }
81782
81783           function doneSquare() {
81784             context.history().checkpoint('doneSquare');
81785             revealHouse(house, helpHtml('intro.buildings.done_square'), {
81786               buttonText: _t.html('intro.ok'),
81787               buttonCallback: function buttonCallback() {
81788                 continueTo(addTank);
81789               }
81790             });
81791
81792             function continueTo(nextStep) {
81793               nextStep();
81794             }
81795           }
81796
81797           function addTank() {
81798             context.enter(modeBrowse(context));
81799             context.history().reset('doneSquare');
81800             _tankID = null;
81801             var msec = transitionTime(tank, context.map().center());
81802
81803             if (msec) {
81804               reveal(null, null, {
81805                 duration: 0
81806               });
81807             }
81808
81809             context.map().centerZoomEase(tank, 19.5, msec);
81810             timeout(function () {
81811               reveal('button.add-area', helpHtml('intro.buildings.add_tank'));
81812               context.on('enter.intro', function (mode) {
81813                 if (mode.id !== 'add-area') return;
81814                 continueTo(startTank);
81815               });
81816             }, msec + 100);
81817
81818             function continueTo(nextStep) {
81819               context.on('enter.intro', null);
81820               nextStep();
81821             }
81822           }
81823
81824           function startTank() {
81825             if (context.mode().id !== 'add-area') {
81826               return continueTo(addTank);
81827             }
81828
81829             _tankID = null;
81830             timeout(function () {
81831               var startString = helpHtml('intro.buildings.start_tank') + helpHtml('intro.buildings.tank_edge_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
81832               revealTank(tank, startString);
81833               context.map().on('move.intro drawn.intro', function () {
81834                 revealTank(tank, startString, {
81835                   duration: 0
81836                 });
81837               });
81838               context.on('enter.intro', function (mode) {
81839                 if (mode.id !== 'draw-area') return chapter.restart();
81840                 continueTo(continueTank);
81841               });
81842             }, 550); // after easing
81843
81844             function continueTo(nextStep) {
81845               context.map().on('move.intro drawn.intro', null);
81846               context.on('enter.intro', null);
81847               nextStep();
81848             }
81849           }
81850
81851           function continueTank() {
81852             if (context.mode().id !== 'draw-area') {
81853               return continueTo(addTank);
81854             }
81855
81856             _tankID = null;
81857             var continueString = helpHtml('intro.buildings.continue_tank') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_tank');
81858             revealTank(tank, continueString);
81859             context.map().on('move.intro drawn.intro', function () {
81860               revealTank(tank, continueString, {
81861                 duration: 0
81862               });
81863             });
81864             context.on('enter.intro', function (mode) {
81865               if (mode.id === 'draw-area') {
81866                 return;
81867               } else if (mode.id === 'select') {
81868                 _tankID = context.selectedIDs()[0];
81869                 return continueTo(searchPresetTank);
81870               } else {
81871                 return continueTo(addTank);
81872               }
81873             });
81874
81875             function continueTo(nextStep) {
81876               context.map().on('move.intro drawn.intro', null);
81877               context.on('enter.intro', null);
81878               nextStep();
81879             }
81880           }
81881
81882           function searchPresetTank() {
81883             if (!_tankID || !context.hasEntity(_tankID)) {
81884               return addTank();
81885             }
81886
81887             var ids = context.selectedIDs();
81888
81889             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
81890               context.enter(modeSelect(context, [_tankID]));
81891             } // disallow scrolling
81892
81893
81894             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81895             timeout(function () {
81896               // reset pane, in case user somehow happened to change it..
81897               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81898               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
81899               reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
81900                 preset: tankPreset.name()
81901               }));
81902             }, 400); // after preset list pane visible..
81903
81904             context.on('enter.intro', function (mode) {
81905               if (!_tankID || !context.hasEntity(_tankID)) {
81906                 return continueTo(addTank);
81907               }
81908
81909               var ids = context.selectedIDs();
81910
81911               if (mode.id !== 'select' || !ids.length || ids[0] !== _tankID) {
81912                 // keep the user's area selected..
81913                 context.enter(modeSelect(context, [_tankID])); // reset pane, in case user somehow happened to change it..
81914
81915                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
81916
81917                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81918                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
81919                 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
81920                   preset: tankPreset.name()
81921                 }));
81922                 context.history().on('change.intro', null);
81923               }
81924             });
81925
81926             function checkPresetSearch() {
81927               var first = context.container().select('.preset-list-item:first-child');
81928
81929               if (first.classed('preset-man_made-storage_tank')) {
81930                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.buildings.choose_tank', {
81931                   preset: tankPreset.name()
81932                 }), {
81933                   duration: 300
81934                 });
81935                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
81936                 context.history().on('change.intro', function () {
81937                   continueTo(closeEditorTank);
81938                 });
81939               }
81940             }
81941
81942             function continueTo(nextStep) {
81943               context.container().select('.inspector-wrap').on('wheel.intro', null);
81944               context.on('enter.intro', null);
81945               context.history().on('change.intro', null);
81946               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
81947               nextStep();
81948             }
81949           }
81950
81951           function closeEditorTank() {
81952             if (!_tankID || !context.hasEntity(_tankID)) {
81953               return addTank();
81954             }
81955
81956             var ids = context.selectedIDs();
81957
81958             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
81959               context.enter(modeSelect(context, [_tankID]));
81960             }
81961
81962             context.history().checkpoint('hasTank');
81963             context.on('exit.intro', function () {
81964               continueTo(rightClickTank);
81965             });
81966             timeout(function () {
81967               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
81968                 button: icon('#iD-icon-close', 'inline')
81969               }));
81970             }, 500);
81971
81972             function continueTo(nextStep) {
81973               context.on('exit.intro', null);
81974               nextStep();
81975             }
81976           }
81977
81978           function rightClickTank() {
81979             if (!_tankID) return continueTo(addTank);
81980             context.enter(modeBrowse(context));
81981             context.history().reset('hasTank');
81982             context.map().centerEase(tank, 500);
81983             timeout(function () {
81984               context.on('enter.intro', function (mode) {
81985                 if (mode.id !== 'select') return;
81986                 var ids = context.selectedIDs();
81987                 if (ids.length !== 1 || ids[0] !== _tankID) return;
81988                 timeout(function () {
81989                   var node = selectMenuItem(context, 'circularize').node();
81990                   if (!node) return;
81991                   continueTo(clickCircle);
81992                 }, 50); // after menu visible
81993               });
81994               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_tank' : 'edit_menu_tank_touch'));
81995               revealTank(tank, rightclickString);
81996               context.map().on('move.intro drawn.intro', function () {
81997                 revealTank(tank, rightclickString, {
81998                   duration: 0
81999                 });
82000               });
82001               context.history().on('change.intro', function () {
82002                 continueTo(rightClickTank);
82003               });
82004             }, 600);
82005
82006             function continueTo(nextStep) {
82007               context.on('enter.intro', null);
82008               context.map().on('move.intro drawn.intro', null);
82009               context.history().on('change.intro', null);
82010               nextStep();
82011             }
82012           }
82013
82014           function clickCircle() {
82015             if (!_tankID) return chapter.restart();
82016             var entity = context.hasEntity(_tankID);
82017             if (!entity) return continueTo(rightClickTank);
82018             var node = selectMenuItem(context, 'circularize').node();
82019
82020             if (!node) {
82021               return continueTo(rightClickTank);
82022             }
82023
82024             var wasChanged = false;
82025             reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
82026               padding: 50
82027             });
82028             context.on('enter.intro', function (mode) {
82029               if (mode.id === 'browse') {
82030                 continueTo(rightClickTank);
82031               } else if (mode.id === 'move' || mode.id === 'rotate') {
82032                 continueTo(retryClickCircle);
82033               }
82034             });
82035             context.map().on('move.intro', function () {
82036               var node = selectMenuItem(context, 'circularize').node();
82037
82038               if (!wasChanged && !node) {
82039                 return continueTo(rightClickTank);
82040               }
82041
82042               reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
82043                 duration: 0,
82044                 padding: 50
82045               });
82046             });
82047             context.history().on('change.intro', function () {
82048               wasChanged = true;
82049               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
82050
82051               timeout(function () {
82052                 if (context.history().undoAnnotation() === _t('operations.circularize.annotation.feature', {
82053                   n: 1
82054                 })) {
82055                   continueTo(play);
82056                 } else {
82057                   continueTo(retryClickCircle);
82058                 }
82059               }, 500); // after transitioned actions
82060             });
82061
82062             function continueTo(nextStep) {
82063               context.on('enter.intro', null);
82064               context.map().on('move.intro', null);
82065               context.history().on('change.intro', null);
82066               nextStep();
82067             }
82068           }
82069
82070           function retryClickCircle() {
82071             context.enter(modeBrowse(context));
82072             revealTank(tank, helpHtml('intro.buildings.retry_circle'), {
82073               buttonText: _t.html('intro.ok'),
82074               buttonCallback: function buttonCallback() {
82075                 continueTo(rightClickTank);
82076               }
82077             });
82078
82079             function continueTo(nextStep) {
82080               nextStep();
82081             }
82082           }
82083
82084           function play() {
82085             dispatch$1.call('done');
82086             reveal('.ideditor', helpHtml('intro.buildings.play', {
82087               next: _t('intro.startediting.title')
82088             }), {
82089               tooltipBox: '.intro-nav-wrap .chapter-startEditing',
82090               buttonText: _t.html('intro.ok'),
82091               buttonCallback: function buttonCallback() {
82092                 reveal('.ideditor');
82093               }
82094             });
82095           }
82096
82097           chapter.enter = function () {
82098             addHouse();
82099           };
82100
82101           chapter.exit = function () {
82102             timeouts.forEach(window.clearTimeout);
82103             context.on('enter.intro exit.intro', null);
82104             context.map().on('move.intro drawn.intro', null);
82105             context.history().on('change.intro', null);
82106             context.container().select('.inspector-wrap').on('wheel.intro', null);
82107             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
82108             context.container().select('.more-fields .combobox-input').on('click.intro', null);
82109           };
82110
82111           chapter.restart = function () {
82112             chapter.exit();
82113             chapter.enter();
82114           };
82115
82116           return utilRebind(chapter, dispatch$1, 'on');
82117         }
82118
82119         function uiIntroStartEditing(context, reveal) {
82120           var dispatch$1 = dispatch('done', 'startEditing');
82121           var modalSelection = select(null);
82122           var chapter = {
82123             title: 'intro.startediting.title'
82124           };
82125
82126           function showHelp() {
82127             reveal('.map-control.help-control', helpHtml('intro.startediting.help'), {
82128               buttonText: _t.html('intro.ok'),
82129               buttonCallback: function buttonCallback() {
82130                 shortcuts();
82131               }
82132             });
82133           }
82134
82135           function shortcuts() {
82136             reveal('.map-control.help-control', helpHtml('intro.startediting.shortcuts'), {
82137               buttonText: _t.html('intro.ok'),
82138               buttonCallback: function buttonCallback() {
82139                 showSave();
82140               }
82141             });
82142           }
82143
82144           function showSave() {
82145             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82146
82147             reveal('.top-toolbar button.save', helpHtml('intro.startediting.save'), {
82148               buttonText: _t.html('intro.ok'),
82149               buttonCallback: function buttonCallback() {
82150                 showStart();
82151               }
82152             });
82153           }
82154
82155           function showStart() {
82156             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82157
82158             modalSelection = uiModal(context.container());
82159             modalSelection.select('.modal').attr('class', 'modal-splash modal');
82160             modalSelection.selectAll('.close').remove();
82161             var startbutton = modalSelection.select('.content').attr('class', 'fillL').append('button').attr('class', 'modal-section huge-modal-button').on('click', function () {
82162               modalSelection.remove();
82163             });
82164             startbutton.append('svg').attr('class', 'illustration').append('use').attr('xlink:href', '#iD-logo-walkthrough');
82165             startbutton.append('h2').html(_t.html('intro.startediting.start'));
82166             dispatch$1.call('startEditing');
82167           }
82168
82169           chapter.enter = function () {
82170             showHelp();
82171           };
82172
82173           chapter.exit = function () {
82174             modalSelection.remove();
82175             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82176           };
82177
82178           return utilRebind(chapter, dispatch$1, 'on');
82179         }
82180
82181         var chapterUi = {
82182           welcome: uiIntroWelcome,
82183           navigation: uiIntroNavigation,
82184           point: uiIntroPoint,
82185           area: uiIntroArea,
82186           line: uiIntroLine,
82187           building: uiIntroBuilding,
82188           startEditing: uiIntroStartEditing
82189         };
82190         var chapterFlow = ['welcome', 'navigation', 'point', 'area', 'line', 'building', 'startEditing'];
82191         function uiIntro(context) {
82192           var INTRO_IMAGERY = 'EsriWorldImageryClarity';
82193           var _introGraph = {};
82194
82195           var _currChapter;
82196
82197           function intro(selection) {
82198             _mainFileFetcher.get('intro_graph').then(function (dataIntroGraph) {
82199               // create entities for intro graph and localize names
82200               for (var id in dataIntroGraph) {
82201                 if (!_introGraph[id]) {
82202                   _introGraph[id] = osmEntity(localize(dataIntroGraph[id]));
82203                 }
82204               }
82205
82206               selection.call(startIntro);
82207             })["catch"](function () {
82208               /* ignore */
82209             });
82210           }
82211
82212           function startIntro(selection) {
82213             context.enter(modeBrowse(context)); // Save current map state
82214
82215             var osm = context.connection();
82216             var history = context.history().toJSON();
82217             var hash = window.location.hash;
82218             var center = context.map().center();
82219             var zoom = context.map().zoom();
82220             var background = context.background().baseLayerSource();
82221             var overlays = context.background().overlayLayerSources();
82222             var opacity = context.container().selectAll('.main-map .layer-background').style('opacity');
82223             var caches = osm && osm.caches();
82224             var baseEntities = context.history().graph().base().entities; // Show sidebar and disable the sidebar resizing button
82225             // (this needs to be before `context.inIntro(true)`)
82226
82227             context.ui().sidebar.expand();
82228             context.container().selectAll('button.sidebar-toggle').classed('disabled', true); // Block saving
82229
82230             context.inIntro(true); // Load semi-real data used in intro
82231
82232             if (osm) {
82233               osm.toggle(false).reset();
82234             }
82235
82236             context.history().reset();
82237             context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
82238             context.history().checkpoint('initial'); // Setup imagery
82239
82240             var imagery = context.background().findSource(INTRO_IMAGERY);
82241
82242             if (imagery) {
82243               context.background().baseLayerSource(imagery);
82244             } else {
82245               context.background().bing();
82246             }
82247
82248             overlays.forEach(function (d) {
82249               return context.background().toggleOverlayLayer(d);
82250             }); // Setup data layers (only OSM)
82251
82252             var layers = context.layers();
82253             layers.all().forEach(function (item) {
82254               // if the layer has the function `enabled`
82255               if (typeof item.layer.enabled === 'function') {
82256                 item.layer.enabled(item.id === 'osm');
82257               }
82258             });
82259             context.container().selectAll('.main-map .layer-background').style('opacity', 1);
82260             var curtain = uiCurtain(context.container().node());
82261             selection.call(curtain); // Store that the user started the walkthrough..
82262
82263             corePreferences('walkthrough_started', 'yes'); // Restore previous walkthrough progress..
82264
82265             var storedProgress = corePreferences('walkthrough_progress') || '';
82266             var progress = storedProgress.split(';').filter(Boolean);
82267             var chapters = chapterFlow.map(function (chapter, i) {
82268               var s = chapterUi[chapter](context, curtain.reveal).on('done', function () {
82269                 buttons.filter(function (d) {
82270                   return d.title === s.title;
82271                 }).classed('finished', true);
82272
82273                 if (i < chapterFlow.length - 1) {
82274                   var next = chapterFlow[i + 1];
82275                   context.container().select("button.chapter-".concat(next)).classed('next', true);
82276                 } // Store walkthrough progress..
82277
82278
82279                 progress.push(chapter);
82280                 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';'));
82281               });
82282               return s;
82283             });
82284             chapters[chapters.length - 1].on('startEditing', function () {
82285               // Store walkthrough progress..
82286               progress.push('startEditing');
82287               corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';')); // Store if walkthrough is completed..
82288
82289               var incomplete = utilArrayDifference(chapterFlow, progress);
82290
82291               if (!incomplete.length) {
82292                 corePreferences('walkthrough_completed', 'yes');
82293               }
82294
82295               curtain.remove();
82296               navwrap.remove();
82297               context.container().selectAll('.main-map .layer-background').style('opacity', opacity);
82298               context.container().selectAll('button.sidebar-toggle').classed('disabled', false);
82299
82300               if (osm) {
82301                 osm.toggle(true).reset().caches(caches);
82302               }
82303
82304               context.history().reset().merge(Object.values(baseEntities));
82305               context.background().baseLayerSource(background);
82306               overlays.forEach(function (d) {
82307                 return context.background().toggleOverlayLayer(d);
82308               });
82309
82310               if (history) {
82311                 context.history().fromJSON(history, false);
82312               }
82313
82314               context.map().centerZoom(center, zoom);
82315               window.location.replace(hash);
82316               context.inIntro(false);
82317             });
82318             var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
82319             navwrap.append('svg').attr('class', 'intro-nav-wrap-logo').append('use').attr('xlink:href', '#iD-logo-walkthrough');
82320             var buttonwrap = navwrap.append('div').attr('class', 'joined').selectAll('button.chapter');
82321             var buttons = buttonwrap.data(chapters).enter().append('button').attr('class', function (d, i) {
82322               return "chapter chapter-".concat(chapterFlow[i]);
82323             }).on('click', enterChapter);
82324             buttons.append('span').html(function (d) {
82325               return _t.html(d.title);
82326             });
82327             buttons.append('span').attr('class', 'status').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
82328             enterChapter(null, chapters[0]);
82329
82330             function enterChapter(d3_event, newChapter) {
82331               if (_currChapter) {
82332                 _currChapter.exit();
82333               }
82334
82335               context.enter(modeBrowse(context));
82336               _currChapter = newChapter;
82337
82338               _currChapter.enter();
82339
82340               buttons.classed('next', false).classed('active', function (d) {
82341                 return d.title === _currChapter.title;
82342               });
82343             }
82344           }
82345
82346           return intro;
82347         }
82348
82349         function uiIssuesInfo(context) {
82350           var warningsItem = {
82351             id: 'warnings',
82352             count: 0,
82353             iconID: 'iD-icon-alert',
82354             descriptionID: 'issues.warnings_and_errors'
82355           };
82356           var resolvedItem = {
82357             id: 'resolved',
82358             count: 0,
82359             iconID: 'iD-icon-apply',
82360             descriptionID: 'issues.user_resolved_issues'
82361           };
82362
82363           function update(selection) {
82364             var shownItems = [];
82365             var liveIssues = context.validator().getIssues({
82366               what: corePreferences('validate-what') || 'edited',
82367               where: corePreferences('validate-where') || 'all'
82368             });
82369
82370             if (liveIssues.length) {
82371               warningsItem.count = liveIssues.length;
82372               shownItems.push(warningsItem);
82373             }
82374
82375             if (corePreferences('validate-what') === 'all') {
82376               var resolvedIssues = context.validator().getResolvedIssues();
82377
82378               if (resolvedIssues.length) {
82379                 resolvedItem.count = resolvedIssues.length;
82380                 shownItems.push(resolvedItem);
82381               }
82382             }
82383
82384             var chips = selection.selectAll('.chip').data(shownItems, function (d) {
82385               return d.id;
82386             });
82387             chips.exit().remove();
82388             var enter = chips.enter().append('a').attr('class', function (d) {
82389               return 'chip ' + d.id + '-count';
82390             }).attr('href', '#').each(function (d) {
82391               var chipSelection = select(this);
82392               var tooltipBehavior = uiTooltip().placement('top').title(_t.html(d.descriptionID));
82393               chipSelection.call(tooltipBehavior).on('click', function (d3_event) {
82394                 d3_event.preventDefault();
82395                 tooltipBehavior.hide(select(this)); // open the Issues pane
82396
82397                 context.ui().togglePanes(context.container().select('.map-panes .issues-pane'));
82398               });
82399               chipSelection.call(svgIcon('#' + d.iconID));
82400             });
82401             enter.append('span').attr('class', 'count');
82402             enter.merge(chips).selectAll('span.count').html(function (d) {
82403               return d.count.toString();
82404             });
82405           }
82406
82407           return function (selection) {
82408             update(selection);
82409             context.validator().on('validated.infobox', function () {
82410               update(selection);
82411             });
82412           };
82413         }
82414
82415         function uiMapInMap(context) {
82416           function mapInMap(selection) {
82417             var backgroundLayer = rendererTileLayer(context);
82418             var overlayLayers = {};
82419             var projection = geoRawMercator();
82420             var dataLayer = svgData(projection, context).showLabels(false);
82421             var debugLayer = svgDebug(projection, context);
82422             var zoom = d3_zoom().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on('start', zoomStarted).on('zoom', zoomed).on('end', zoomEnded);
82423             var wrap = select(null);
82424             var tiles = select(null);
82425             var viewport = select(null);
82426             var _isTransformed = false;
82427             var _isHidden = true;
82428             var _skipEvents = false;
82429             var _gesture = null;
82430             var _zDiff = 6; // by default, minimap renders at (main zoom - 6)
82431
82432             var _dMini; // dimensions of minimap
82433
82434
82435             var _cMini; // center pixel of minimap
82436
82437
82438             var _tStart; // transform at start of gesture
82439
82440
82441             var _tCurr; // transform at most recent event
82442
82443
82444             var _timeoutID;
82445
82446             function zoomStarted() {
82447               if (_skipEvents) return;
82448               _tStart = _tCurr = projection.transform();
82449               _gesture = null;
82450             }
82451
82452             function zoomed(d3_event) {
82453               if (_skipEvents) return;
82454               var x = d3_event.transform.x;
82455               var y = d3_event.transform.y;
82456               var k = d3_event.transform.k;
82457               var isZooming = k !== _tStart.k;
82458               var isPanning = x !== _tStart.x || y !== _tStart.y;
82459
82460               if (!isZooming && !isPanning) {
82461                 return; // no change
82462               } // lock in either zooming or panning, don't allow both in minimap.
82463
82464
82465               if (!_gesture) {
82466                 _gesture = isZooming ? 'zoom' : 'pan';
82467               }
82468
82469               var tMini = projection.transform();
82470               var tX, tY, scale;
82471
82472               if (_gesture === 'zoom') {
82473                 scale = k / tMini.k;
82474                 tX = (_cMini[0] / scale - _cMini[0]) * scale;
82475                 tY = (_cMini[1] / scale - _cMini[1]) * scale;
82476               } else {
82477                 k = tMini.k;
82478                 scale = 1;
82479                 tX = x - tMini.x;
82480                 tY = y - tMini.y;
82481               }
82482
82483               utilSetTransform(tiles, tX, tY, scale);
82484               utilSetTransform(viewport, 0, 0, scale);
82485               _isTransformed = true;
82486               _tCurr = identity$2.translate(x, y).scale(k);
82487               var zMain = geoScaleToZoom(context.projection.scale());
82488               var zMini = geoScaleToZoom(k);
82489               _zDiff = zMain - zMini;
82490               queueRedraw();
82491             }
82492
82493             function zoomEnded() {
82494               if (_skipEvents) return;
82495               if (_gesture !== 'pan') return;
82496               updateProjection();
82497               _gesture = null;
82498               context.map().center(projection.invert(_cMini)); // recenter main map..
82499             }
82500
82501             function updateProjection() {
82502               var loc = context.map().center();
82503               var tMain = context.projection.transform();
82504               var zMain = geoScaleToZoom(tMain.k);
82505               var zMini = Math.max(zMain - _zDiff, 0.5);
82506               var kMini = geoZoomToScale(zMini);
82507               projection.translate([tMain.x, tMain.y]).scale(kMini);
82508               var point = projection(loc);
82509               var mouse = _gesture === 'pan' ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
82510               var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
82511               var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
82512               projection.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
82513               _tCurr = projection.transform();
82514
82515               if (_isTransformed) {
82516                 utilSetTransform(tiles, 0, 0);
82517                 utilSetTransform(viewport, 0, 0);
82518                 _isTransformed = false;
82519               }
82520
82521               zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
82522               _skipEvents = true;
82523               wrap.call(zoom.transform, _tCurr);
82524               _skipEvents = false;
82525             }
82526
82527             function redraw() {
82528               clearTimeout(_timeoutID);
82529               if (_isHidden) return;
82530               updateProjection();
82531               var zMini = geoScaleToZoom(projection.scale()); // setup tile container
82532
82533               tiles = wrap.selectAll('.map-in-map-tiles').data([0]);
82534               tiles = tiles.enter().append('div').attr('class', 'map-in-map-tiles').merge(tiles); // redraw background
82535
82536               backgroundLayer.source(context.background().baseLayerSource()).projection(projection).dimensions(_dMini);
82537               var background = tiles.selectAll('.map-in-map-background').data([0]);
82538               background.enter().append('div').attr('class', 'map-in-map-background').merge(background).call(backgroundLayer); // redraw overlay
82539
82540               var overlaySources = context.background().overlayLayerSources();
82541               var activeOverlayLayers = [];
82542
82543               for (var i = 0; i < overlaySources.length; i++) {
82544                 if (overlaySources[i].validZoom(zMini)) {
82545                   if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
82546                   activeOverlayLayers.push(overlayLayers[i].source(overlaySources[i]).projection(projection).dimensions(_dMini));
82547                 }
82548               }
82549
82550               var overlay = tiles.selectAll('.map-in-map-overlay').data([0]);
82551               overlay = overlay.enter().append('div').attr('class', 'map-in-map-overlay').merge(overlay);
82552               var overlays = overlay.selectAll('div').data(activeOverlayLayers, function (d) {
82553                 return d.source().name();
82554               });
82555               overlays.exit().remove();
82556               overlays = overlays.enter().append('div').merge(overlays).each(function (layer) {
82557                 select(this).call(layer);
82558               });
82559               var dataLayers = tiles.selectAll('.map-in-map-data').data([0]);
82560               dataLayers.exit().remove();
82561               dataLayers = dataLayers.enter().append('svg').attr('class', 'map-in-map-data').merge(dataLayers).call(dataLayer).call(debugLayer); // redraw viewport bounding box
82562
82563               if (_gesture !== 'pan') {
82564                 var getPath = d3_geoPath(projection);
82565                 var bbox = {
82566                   type: 'Polygon',
82567                   coordinates: [context.map().extent().polygon()]
82568                 };
82569                 viewport = wrap.selectAll('.map-in-map-viewport').data([0]);
82570                 viewport = viewport.enter().append('svg').attr('class', 'map-in-map-viewport').merge(viewport);
82571                 var path = viewport.selectAll('.map-in-map-bbox').data([bbox]);
82572                 path.enter().append('path').attr('class', 'map-in-map-bbox').merge(path).attr('d', getPath).classed('thick', function (d) {
82573                   return getPath.area(d) < 30;
82574                 });
82575               }
82576             }
82577
82578             function queueRedraw() {
82579               clearTimeout(_timeoutID);
82580               _timeoutID = setTimeout(function () {
82581                 redraw();
82582               }, 750);
82583             }
82584
82585             function toggle(d3_event) {
82586               if (d3_event) d3_event.preventDefault();
82587               _isHidden = !_isHidden;
82588               context.container().select('.minimap-toggle-item').classed('active', !_isHidden).select('input').property('checked', !_isHidden);
82589
82590               if (_isHidden) {
82591                 wrap.style('display', 'block').style('opacity', '1').transition().duration(200).style('opacity', '0').on('end', function () {
82592                   selection.selectAll('.map-in-map').style('display', 'none');
82593                 });
82594               } else {
82595                 wrap.style('display', 'block').style('opacity', '0').transition().duration(200).style('opacity', '1').on('end', function () {
82596                   redraw();
82597                 });
82598               }
82599             }
82600
82601             uiMapInMap.toggle = toggle;
82602             wrap = selection.selectAll('.map-in-map').data([0]);
82603             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..
82604
82605             _dMini = [200, 150]; //utilGetDimensions(wrap);
82606
82607             _cMini = geoVecScale(_dMini, 0.5);
82608             context.map().on('drawn.map-in-map', function (drawn) {
82609               if (drawn.full === true) {
82610                 redraw();
82611               }
82612             });
82613             redraw();
82614             context.keybinding().on(_t('background.minimap.key'), toggle);
82615           }
82616
82617           return mapInMap;
82618         }
82619
82620         function uiNotice(context) {
82621           return function (selection) {
82622             var div = selection.append('div').attr('class', 'notice');
82623             var button = div.append('button').attr('class', 'zoom-to notice fillD').on('click', function () {
82624               context.map().zoomEase(context.minEditableZoom());
82625             }).on('wheel', function (d3_event) {
82626               // let wheel events pass through #4482
82627               var e2 = new WheelEvent(d3_event.type, d3_event);
82628               context.surface().node().dispatchEvent(e2);
82629             });
82630             button.call(svgIcon('#iD-icon-plus', 'pre-text')).append('span').attr('class', 'label').html(_t.html('zoom_in_edit'));
82631
82632             function disableTooHigh() {
82633               var canEdit = context.map().zoom() >= context.minEditableZoom();
82634               div.style('display', canEdit ? 'none' : 'block');
82635             }
82636
82637             context.map().on('move.notice', debounce(disableTooHigh, 500));
82638             disableTooHigh();
82639           };
82640         }
82641
82642         function uiPhotoviewer(context) {
82643           var dispatch$1 = dispatch('resize');
82644
82645           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
82646
82647           function photoviewer(selection) {
82648             selection.append('button').attr('class', 'thumb-hide').on('click', function () {
82649               if (services.streetside) {
82650                 services.streetside.hideViewer(context);
82651               }
82652
82653               if (services.mapillary) {
82654                 services.mapillary.hideViewer(context);
82655               }
82656
82657               if (services.openstreetcam) {
82658                 services.openstreetcam.hideViewer(context);
82659               }
82660             }).append('div').call(svgIcon('#iD-icon-close'));
82661
82662             function preventDefault(d3_event) {
82663               d3_event.preventDefault();
82664             }
82665
82666             selection.append('button').attr('class', 'resize-handle-xy').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82667               resizeOnX: true,
82668               resizeOnY: true
82669             }));
82670             selection.append('button').attr('class', 'resize-handle-x').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82671               resizeOnX: true
82672             }));
82673             selection.append('button').attr('class', 'resize-handle-y').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82674               resizeOnY: true
82675             }));
82676
82677             function buildResizeListener(target, eventName, dispatch, options) {
82678               var resizeOnX = !!options.resizeOnX;
82679               var resizeOnY = !!options.resizeOnY;
82680               var minHeight = options.minHeight || 240;
82681               var minWidth = options.minWidth || 320;
82682               var pointerId;
82683               var startX;
82684               var startY;
82685               var startWidth;
82686               var startHeight;
82687
82688               function startResize(d3_event) {
82689                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
82690                 d3_event.preventDefault();
82691                 d3_event.stopPropagation();
82692                 var mapSize = context.map().dimensions();
82693
82694                 if (resizeOnX) {
82695                   var maxWidth = mapSize[0];
82696                   var newWidth = clamp(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
82697                   target.style('width', newWidth + 'px');
82698                 }
82699
82700                 if (resizeOnY) {
82701                   var maxHeight = mapSize[1] - 90; // preserve space at top/bottom of map
82702
82703                   var newHeight = clamp(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
82704                   target.style('height', newHeight + 'px');
82705                 }
82706
82707                 dispatch.call(eventName, target, utilGetDimensions(target, true));
82708               }
82709
82710               function clamp(num, min, max) {
82711                 return Math.max(min, Math.min(num, max));
82712               }
82713
82714               function stopResize(d3_event) {
82715                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
82716                 d3_event.preventDefault();
82717                 d3_event.stopPropagation(); // remove all the listeners we added
82718
82719                 select(window).on('.' + eventName, null);
82720               }
82721
82722               return function initResize(d3_event) {
82723                 d3_event.preventDefault();
82724                 d3_event.stopPropagation();
82725                 pointerId = d3_event.pointerId || 'mouse';
82726                 startX = d3_event.clientX;
82727                 startY = d3_event.clientY;
82728                 var targetRect = target.node().getBoundingClientRect();
82729                 startWidth = targetRect.width;
82730                 startHeight = targetRect.height;
82731                 select(window).on(_pointerPrefix + 'move.' + eventName, startResize, false).on(_pointerPrefix + 'up.' + eventName, stopResize, false);
82732
82733                 if (_pointerPrefix === 'pointer') {
82734                   select(window).on('pointercancel.' + eventName, stopResize, false);
82735                 }
82736               };
82737             }
82738           }
82739
82740           photoviewer.onMapResize = function () {
82741             var photoviewer = context.container().select('.photoviewer');
82742             var content = context.container().select('.main-content');
82743             var mapDimensions = utilGetDimensions(content, true); // shrink photo viewer if it is too big
82744             // (-90 preserves space at top and bottom of map used by menus)
82745
82746             var photoDimensions = utilGetDimensions(photoviewer, true);
82747
82748             if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
82749               var setPhotoDimensions = [Math.min(photoDimensions[0], mapDimensions[0]), Math.min(photoDimensions[1], mapDimensions[1] - 90)];
82750               photoviewer.style('width', setPhotoDimensions[0] + 'px').style('height', setPhotoDimensions[1] + 'px');
82751               dispatch$1.call('resize', photoviewer, setPhotoDimensions);
82752             }
82753           };
82754
82755           return utilRebind(photoviewer, dispatch$1, 'on');
82756         }
82757
82758         function uiRestore(context) {
82759           return function (selection) {
82760             if (!context.history().hasRestorableChanges()) return;
82761             var modalSelection = uiModal(selection, true);
82762             modalSelection.select('.modal').attr('class', 'modal fillL');
82763             var introModal = modalSelection.select('.content');
82764             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('restore.heading'));
82765             introModal.append('div').attr('class', 'modal-section').append('p').html(_t.html('restore.description'));
82766             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
82767             var restore = buttonWrap.append('button').attr('class', 'restore').on('click', function () {
82768               context.history().restore();
82769               modalSelection.remove();
82770             });
82771             restore.append('svg').attr('class', 'logo logo-restore').append('use').attr('xlink:href', '#iD-logo-restore');
82772             restore.append('div').html(_t.html('restore.restore'));
82773             var reset = buttonWrap.append('button').attr('class', 'reset').on('click', function () {
82774               context.history().clearSaved();
82775               modalSelection.remove();
82776             });
82777             reset.append('svg').attr('class', 'logo logo-reset').append('use').attr('xlink:href', '#iD-logo-reset');
82778             reset.append('div').html(_t.html('restore.reset'));
82779             restore.node().focus();
82780           };
82781         }
82782
82783         function uiScale(context) {
82784           var projection = context.projection,
82785               isImperial = !_mainLocalizer.usesMetric(),
82786               maxLength = 180,
82787               tickHeight = 8;
82788
82789           function scaleDefs(loc1, loc2) {
82790             var lat = (loc2[1] + loc1[1]) / 2,
82791                 conversion = isImperial ? 3.28084 : 1,
82792                 dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
82793                 scale = {
82794               dist: 0,
82795               px: 0,
82796               text: ''
82797             },
82798                 buckets,
82799                 i,
82800                 val,
82801                 dLon;
82802
82803             if (isImperial) {
82804               buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
82805             } else {
82806               buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
82807             } // determine a user-friendly endpoint for the scale
82808
82809
82810             for (i = 0; i < buckets.length; i++) {
82811               val = buckets[i];
82812
82813               if (dist >= val) {
82814                 scale.dist = Math.floor(dist / val) * val;
82815                 break;
82816               } else {
82817                 scale.dist = +dist.toFixed(2);
82818               }
82819             }
82820
82821             dLon = geoMetersToLon(scale.dist / conversion, lat);
82822             scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
82823             scale.text = displayLength(scale.dist / conversion, isImperial);
82824             return scale;
82825           }
82826
82827           function update(selection) {
82828             // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
82829             var dims = context.map().dimensions(),
82830                 loc1 = projection.invert([0, dims[1]]),
82831                 loc2 = projection.invert([maxLength, dims[1]]),
82832                 scale = scaleDefs(loc1, loc2);
82833             selection.select('.scale-path').attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
82834             selection.select('.scale-text').style(_mainLocalizer.textDirection() === 'ltr' ? 'left' : 'right', scale.px + 16 + 'px').html(scale.text);
82835           }
82836
82837           return function (selection) {
82838             function switchUnits() {
82839               isImperial = !isImperial;
82840               selection.call(update);
82841             }
82842
82843             var scalegroup = selection.append('svg').attr('class', 'scale').on('click', switchUnits).append('g').attr('transform', 'translate(10,11)');
82844             scalegroup.append('path').attr('class', 'scale-path');
82845             selection.append('div').attr('class', 'scale-text');
82846             selection.call(update);
82847             context.map().on('move.scale', function () {
82848               update(selection);
82849             });
82850           };
82851         }
82852
82853         function uiShortcuts(context) {
82854           var detected = utilDetect();
82855           var _activeTab = 0;
82856
82857           var _modalSelection;
82858
82859           var _selection = select(null);
82860
82861           function shortcutsModal(_modalSelection) {
82862             _modalSelection.select('.modal').classed('modal-shortcuts', true);
82863
82864             var content = _modalSelection.select('.content');
82865
82866             content.append('div').attr('class', 'modal-section').append('h3').html(_t.html('shortcuts.title'));
82867             _mainFileFetcher.get('shortcuts').then(function (data) {
82868               content.call(render, data);
82869             })["catch"](function () {
82870               /* ignore */
82871             });
82872           }
82873
82874           function render(selection, dataShortcuts) {
82875             var wrapper = selection.selectAll('.wrapper').data([0]);
82876             var wrapperEnter = wrapper.enter().append('div').attr('class', 'wrapper modal-section');
82877             var tabsBar = wrapperEnter.append('div').attr('class', 'tabs-bar');
82878             var shortcutsList = wrapperEnter.append('div').attr('class', 'shortcuts-list');
82879             wrapper = wrapper.merge(wrapperEnter);
82880             var tabs = tabsBar.selectAll('.tab').data(dataShortcuts);
82881             var tabsEnter = tabs.enter().append('a').attr('class', 'tab').attr('href', '#').on('click', function (d3_event) {
82882               d3_event.preventDefault();
82883               var i = tabs.nodes().indexOf(this);
82884               _activeTab = i;
82885               render(selection, dataShortcuts);
82886             });
82887             tabsEnter.append('span').html(function (d) {
82888               return _t.html(d.text);
82889             }); // Update
82890
82891             wrapper.selectAll('.tab').classed('active', function (d, i) {
82892               return i === _activeTab;
82893             });
82894             var shortcuts = shortcutsList.selectAll('.shortcut-tab').data(dataShortcuts);
82895             var shortcutsEnter = shortcuts.enter().append('div').attr('class', function (d) {
82896               return 'shortcut-tab shortcut-tab-' + d.tab;
82897             });
82898             var columnsEnter = shortcutsEnter.selectAll('.shortcut-column').data(function (d) {
82899               return d.columns;
82900             }).enter().append('table').attr('class', 'shortcut-column');
82901             var rowsEnter = columnsEnter.selectAll('.shortcut-row').data(function (d) {
82902               return d.rows;
82903             }).enter().append('tr').attr('class', 'shortcut-row');
82904             var sectionRows = rowsEnter.filter(function (d) {
82905               return !d.shortcuts;
82906             });
82907             sectionRows.append('td');
82908             sectionRows.append('td').attr('class', 'shortcut-section').append('h3').html(function (d) {
82909               return _t.html(d.text);
82910             });
82911             var shortcutRows = rowsEnter.filter(function (d) {
82912               return d.shortcuts;
82913             });
82914             var shortcutKeys = shortcutRows.append('td').attr('class', 'shortcut-keys');
82915             var modifierKeys = shortcutKeys.filter(function (d) {
82916               return d.modifiers;
82917             });
82918             modifierKeys.selectAll('kbd.modifier').data(function (d) {
82919               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
82920                 return ['⌘'];
82921               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
82922                 return [];
82923               } else {
82924                 return d.modifiers;
82925               }
82926             }).enter().each(function () {
82927               var selection = select(this);
82928               selection.append('kbd').attr('class', 'modifier').html(function (d) {
82929                 return uiCmd.display(d);
82930               });
82931               selection.append('span').html('+');
82932             });
82933             shortcutKeys.selectAll('kbd.shortcut').data(function (d) {
82934               var arr = d.shortcuts;
82935
82936               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
82937                 arr = ['Y'];
82938               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
82939                 arr = ['F11'];
82940               } // replace translations
82941
82942
82943               arr = arr.map(function (s) {
82944                 return uiCmd.display(s.indexOf('.') !== -1 ? _t(s) : s);
82945               });
82946               return utilArrayUniq(arr).map(function (s) {
82947                 return {
82948                   shortcut: s,
82949                   separator: d.separator,
82950                   suffix: d.suffix
82951                 };
82952               });
82953             }).enter().each(function (d, i, nodes) {
82954               var selection = select(this);
82955               var click = d.shortcut.toLowerCase().match(/(.*).click/);
82956
82957               if (click && click[1]) {
82958                 // replace "left_click", "right_click" with mouse icon
82959                 selection.call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation'));
82960               } else if (d.shortcut.toLowerCase() === 'long-press') {
82961                 selection.call(svgIcon('#iD-walkthrough-longpress', 'longpress operation'));
82962               } else if (d.shortcut.toLowerCase() === 'tap') {
82963                 selection.call(svgIcon('#iD-walkthrough-tap', 'tap operation'));
82964               } else {
82965                 selection.append('kbd').attr('class', 'shortcut').html(function (d) {
82966                   return d.shortcut;
82967                 });
82968               }
82969
82970               if (i < nodes.length - 1) {
82971                 selection.append('span').html(d.separator || "\xA0" + _t.html('shortcuts.or') + "\xA0");
82972               } else if (i === nodes.length - 1 && d.suffix) {
82973                 selection.append('span').html(d.suffix);
82974               }
82975             });
82976             shortcutKeys.filter(function (d) {
82977               return d.gesture;
82978             }).each(function () {
82979               var selection = select(this);
82980               selection.append('span').html('+');
82981               selection.append('span').attr('class', 'gesture').html(function (d) {
82982                 return _t.html(d.gesture);
82983               });
82984             });
82985             shortcutRows.append('td').attr('class', 'shortcut-desc').html(function (d) {
82986               return d.text ? _t.html(d.text) : "\xA0";
82987             }); // Update
82988
82989             wrapper.selectAll('.shortcut-tab').style('display', function (d, i) {
82990               return i === _activeTab ? 'flex' : 'none';
82991             });
82992           }
82993
82994           return function (selection, show) {
82995             _selection = selection;
82996
82997             if (show) {
82998               _modalSelection = uiModal(selection);
82999
83000               _modalSelection.call(shortcutsModal);
83001             } else {
83002               context.keybinding().on([_t('shortcuts.toggle.key'), '?'], function () {
83003                 if (context.container().selectAll('.modal-shortcuts').size()) {
83004                   // already showing
83005                   if (_modalSelection) {
83006                     _modalSelection.close();
83007
83008                     _modalSelection = null;
83009                   }
83010                 } else {
83011                   _modalSelection = uiModal(_selection);
83012
83013                   _modalSelection.call(shortcutsModal);
83014                 }
83015               });
83016             }
83017           };
83018         }
83019
83020         var pair_1 = pair;
83021
83022         function search(input, dims) {
83023           if (!dims) dims = 'NSEW';
83024           if (typeof input !== 'string') return null;
83025           input = input.toUpperCase();
83026           var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
83027           var m = input.match(regex);
83028           if (!m) return null; // no match
83029
83030           var matched = m[0]; // extract dimension.. m[1] = leading, m[5] = trailing
83031
83032           var dim;
83033
83034           if (m[1] && m[5]) {
83035             // if matched both..
83036             dim = m[1]; // keep leading
83037
83038             matched = matched.slice(0, -1); // remove trailing dimension from match
83039           } else {
83040             dim = m[1] || m[5];
83041           } // if unrecognized dimension
83042
83043
83044           if (dim && dims.indexOf(dim) === -1) return null; // extract DMS
83045
83046           var deg = m[2] ? parseFloat(m[2]) : 0;
83047           var min = m[3] ? parseFloat(m[3]) / 60 : 0;
83048           var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
83049           var sign = deg < 0 ? -1 : 1;
83050           if (dim === 'S' || dim === 'W') sign *= -1;
83051           return {
83052             val: (Math.abs(deg) + min + sec) * sign,
83053             dim: dim,
83054             matched: matched,
83055             remain: input.slice(matched.length)
83056           };
83057         }
83058
83059         function pair(input, dims) {
83060           input = input.trim();
83061           var one = search(input, dims);
83062           if (!one) return null;
83063           input = one.remain.trim();
83064           var two = search(input, dims);
83065           if (!two || two.remain) return null;
83066
83067           if (one.dim) {
83068             return swapdim(one.val, two.val, one.dim);
83069           } else {
83070             return [one.val, two.val];
83071           }
83072         }
83073
83074         function swapdim(a, b, dim) {
83075           if (dim === 'N' || dim === 'S') return [a, b];
83076           if (dim === 'W' || dim === 'E') return [b, a];
83077         }
83078
83079         function uiFeatureList(context) {
83080           var _geocodeResults;
83081
83082           function featureList(selection) {
83083             var header = selection.append('div').attr('class', 'header fillL');
83084             header.append('h3').html(_t.html('inspector.feature_list'));
83085             var searchWrap = selection.append('div').attr('class', 'search-header');
83086             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
83087             var search = searchWrap.append('input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keypress', keypress).on('keydown', keydown).on('input', inputevent);
83088             var listWrap = selection.append('div').attr('class', 'inspector-body');
83089             var list = listWrap.append('div').attr('class', 'feature-list');
83090             context.on('exit.feature-list', clearSearch);
83091             context.map().on('drawn.feature-list', mapDrawn);
83092             context.keybinding().on(uiCmd('⌘F'), focusSearch);
83093
83094             function focusSearch(d3_event) {
83095               var mode = context.mode() && context.mode().id;
83096               if (mode !== 'browse') return;
83097               d3_event.preventDefault();
83098               search.node().focus();
83099             }
83100
83101             function keydown(d3_event) {
83102               if (d3_event.keyCode === 27) {
83103                 // escape
83104                 search.node().blur();
83105               }
83106             }
83107
83108             function keypress(d3_event) {
83109               var q = search.property('value'),
83110                   items = list.selectAll('.feature-list-item');
83111
83112               if (d3_event.keyCode === 13 && // ↩ Return
83113               q.length && items.size()) {
83114                 click(items.datum());
83115               }
83116             }
83117
83118             function inputevent() {
83119               _geocodeResults = undefined;
83120               drawList();
83121             }
83122
83123             function clearSearch() {
83124               search.property('value', '');
83125               drawList();
83126             }
83127
83128             function mapDrawn(e) {
83129               if (e.full) {
83130                 drawList();
83131               }
83132             }
83133
83134             function features() {
83135               var result = [];
83136               var graph = context.graph();
83137               var visibleCenter = context.map().extent().center();
83138               var q = search.property('value').toLowerCase();
83139               if (!q) return result;
83140               var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
83141
83142               if (locationMatch) {
83143                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
83144                 result.push({
83145                   id: -1,
83146                   geometry: 'point',
83147                   type: _t('inspector.location'),
83148                   name: dmsCoordinatePair([loc[1], loc[0]]),
83149                   location: loc
83150                 });
83151               } // A location search takes priority over an ID search
83152
83153
83154               var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
83155
83156               if (idMatch) {
83157                 var elemType = idMatch[1].charAt(0);
83158                 var elemId = idMatch[2];
83159                 result.push({
83160                   id: elemType + elemId,
83161                   geometry: elemType === 'n' ? 'point' : elemType === 'w' ? 'line' : 'relation',
83162                   type: elemType === 'n' ? _t('inspector.node') : elemType === 'w' ? _t('inspector.way') : _t('inspector.relation'),
83163                   name: elemId
83164                 });
83165               }
83166
83167               var allEntities = graph.entities;
83168               var localResults = [];
83169
83170               for (var id in allEntities) {
83171                 var entity = allEntities[id];
83172                 if (!entity) continue;
83173                 var name = utilDisplayName(entity) || '';
83174                 if (name.toLowerCase().indexOf(q) < 0) continue;
83175                 var matched = _mainPresetIndex.match(entity, graph);
83176                 var type = matched && matched.name() || utilDisplayType(entity.id);
83177                 var extent = entity.extent(graph);
83178                 var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
83179                 localResults.push({
83180                   id: entity.id,
83181                   entity: entity,
83182                   geometry: entity.geometry(graph),
83183                   type: type,
83184                   name: name,
83185                   distance: distance
83186                 });
83187                 if (localResults.length > 100) break;
83188               }
83189
83190               localResults = localResults.sort(function byDistance(a, b) {
83191                 return a.distance - b.distance;
83192               });
83193               result = result.concat(localResults);
83194
83195               (_geocodeResults || []).forEach(function (d) {
83196                 if (d.osm_type && d.osm_id) {
83197                   // some results may be missing these - #1890
83198                   // Make a temporary osmEntity so we can preset match
83199                   // and better localize the search result - #4725
83200                   var id = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
83201                   var tags = {};
83202                   tags[d["class"]] = d.type;
83203                   var attrs = {
83204                     id: id,
83205                     type: d.osm_type,
83206                     tags: tags
83207                   };
83208
83209                   if (d.osm_type === 'way') {
83210                     // for ways, add some fake closed nodes
83211                     attrs.nodes = ['a', 'a']; // so that geometry area is possible
83212                   }
83213
83214                   var tempEntity = osmEntity(attrs);
83215                   var tempGraph = coreGraph([tempEntity]);
83216                   var matched = _mainPresetIndex.match(tempEntity, tempGraph);
83217                   var type = matched && matched.name() || utilDisplayType(id);
83218                   result.push({
83219                     id: tempEntity.id,
83220                     geometry: tempEntity.geometry(tempGraph),
83221                     type: type,
83222                     name: d.display_name,
83223                     extent: new geoExtent([parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])], [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
83224                   });
83225                 }
83226               });
83227
83228               if (q.match(/^[0-9]+$/)) {
83229                 // if query is just a number, possibly an OSM ID without a prefix
83230                 result.push({
83231                   id: 'n' + q,
83232                   geometry: 'point',
83233                   type: _t('inspector.node'),
83234                   name: q
83235                 });
83236                 result.push({
83237                   id: 'w' + q,
83238                   geometry: 'line',
83239                   type: _t('inspector.way'),
83240                   name: q
83241                 });
83242                 result.push({
83243                   id: 'r' + q,
83244                   geometry: 'relation',
83245                   type: _t('inspector.relation'),
83246                   name: q
83247                 });
83248               }
83249
83250               return result;
83251             }
83252
83253             function drawList() {
83254               var value = search.property('value');
83255               var results = features();
83256               list.classed('filtered', value.length);
83257               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'));
83258               resultsIndicator.append('span').attr('class', 'entity-name');
83259               list.selectAll('.no-results-item .entity-name').html(_t.html('geocoder.no_results_worldwide'));
83260
83261               if (services.geocoder) {
83262                 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'));
83263               }
83264
83265               list.selectAll('.no-results-item').style('display', value.length && !results.length ? 'block' : 'none');
83266               list.selectAll('.geocode-item').style('display', value && _geocodeResults === undefined ? 'block' : 'none');
83267               list.selectAll('.feature-list-item').data([-1]).remove();
83268               var items = list.selectAll('.feature-list-item').data(results, function (d) {
83269                 return d.id;
83270               });
83271               var enter = items.enter().insert('button', '.geocode-item').attr('class', 'feature-list-item').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
83272               var label = enter.append('div').attr('class', 'label');
83273               label.each(function (d) {
83274                 select(this).call(svgIcon('#iD-icon-' + d.geometry, 'pre-text'));
83275               });
83276               label.append('span').attr('class', 'entity-type').html(function (d) {
83277                 return d.type;
83278               });
83279               label.append('span').attr('class', 'entity-name').html(function (d) {
83280                 return d.name;
83281               });
83282               enter.style('opacity', 0).transition().style('opacity', 1);
83283               items.order();
83284               items.exit().remove();
83285             }
83286
83287             function mouseover(d3_event, d) {
83288               if (d.id === -1) return;
83289               utilHighlightEntities([d.id], true, context);
83290             }
83291
83292             function mouseout(d3_event, d) {
83293               if (d.id === -1) return;
83294               utilHighlightEntities([d.id], false, context);
83295             }
83296
83297             function click(d3_event, d) {
83298               d3_event.preventDefault();
83299
83300               if (d.location) {
83301                 context.map().centerZoomEase([d.location[1], d.location[0]], 19);
83302               } else if (d.entity) {
83303                 utilHighlightEntities([d.id], false, context);
83304                 context.enter(modeSelect(context, [d.entity.id]));
83305                 context.map().zoomToEase(d.entity);
83306               } else {
83307                 // download, zoom to, and select the entity with the given ID
83308                 context.zoomToEntity(d.id);
83309               }
83310             }
83311
83312             function geocoderSearch() {
83313               services.geocoder.search(search.property('value'), function (err, resp) {
83314                 _geocodeResults = resp || [];
83315                 drawList();
83316               });
83317             }
83318           }
83319
83320           return featureList;
83321         }
83322
83323         function uiSectionEntityIssues(context) {
83324           var _entityIDs = [];
83325           var _issues = [];
83326
83327           var _activeIssueID;
83328
83329           var section = uiSection('entity-issues', context).shouldDisplay(function () {
83330             return _issues.length > 0;
83331           }).label(function () {
83332             return _t('inspector.title_count', {
83333               title: _t.html('issues.list_title'),
83334               count: _issues.length
83335             });
83336           }).disclosureContent(renderDisclosureContent);
83337           context.validator().on('validated.entity_issues', function () {
83338             // Refresh on validated events
83339             reloadIssues();
83340             section.reRender();
83341           }).on('focusedIssue.entity_issues', function (issue) {
83342             makeActiveIssue(issue.id);
83343           });
83344
83345           function reloadIssues() {
83346             _issues = context.validator().getSharedEntityIssues(_entityIDs, {
83347               includeDisabledRules: true
83348             });
83349           }
83350
83351           function makeActiveIssue(issueID) {
83352             _activeIssueID = issueID;
83353             section.selection().selectAll('.issue-container').classed('active', function (d) {
83354               return d.id === _activeIssueID;
83355             });
83356           }
83357
83358           function renderDisclosureContent(selection) {
83359             selection.classed('grouped-items-area', true);
83360             _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
83361             var containers = selection.selectAll('.issue-container').data(_issues, function (d) {
83362               return d.id;
83363             }); // Exit
83364
83365             containers.exit().remove(); // Enter
83366
83367             var containersEnter = containers.enter().append('div').attr('class', 'issue-container');
83368             var itemsEnter = containersEnter.append('div').attr('class', function (d) {
83369               return 'issue severity-' + d.severity;
83370             }).on('mouseover.highlight', function (d3_event, d) {
83371               // don't hover-highlight the selected entity
83372               var ids = d.entityIds.filter(function (e) {
83373                 return _entityIDs.indexOf(e) === -1;
83374               });
83375               utilHighlightEntities(ids, true, context);
83376             }).on('mouseout.highlight', function (d3_event, d) {
83377               var ids = d.entityIds.filter(function (e) {
83378                 return _entityIDs.indexOf(e) === -1;
83379               });
83380               utilHighlightEntities(ids, false, context);
83381             });
83382             var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
83383             var textEnter = labelsEnter.append('button').attr('class', 'issue-text').on('click', function (d3_event, d) {
83384               makeActiveIssue(d.id); // expand only the clicked item
83385
83386               var extent = d.extent(context.graph());
83387
83388               if (extent) {
83389                 var setZoom = Math.max(context.map().zoom(), 19);
83390                 context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
83391               }
83392             });
83393             textEnter.each(function (d) {
83394               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
83395               select(this).call(svgIcon(iconName, 'issue-icon'));
83396             });
83397             textEnter.append('span').attr('class', 'issue-message');
83398             var infoButton = labelsEnter.append('button').attr('class', 'issue-info-button').attr('title', _t('icons.information')).call(svgIcon('#iD-icon-inspect'));
83399             infoButton.on('click', function (d3_event) {
83400               d3_event.stopPropagation();
83401               d3_event.preventDefault();
83402               this.blur(); // avoid keeping focus on the button - #4641
83403
83404               var container = select(this.parentNode.parentNode.parentNode);
83405               var info = container.selectAll('.issue-info');
83406               var isExpanded = info.classed('expanded');
83407
83408               if (isExpanded) {
83409                 info.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
83410                   info.classed('expanded', false);
83411                 });
83412               } else {
83413                 info.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1').on('end', function () {
83414                   info.style('max-height', null);
83415                 });
83416               }
83417             });
83418             itemsEnter.append('ul').attr('class', 'issue-fix-list');
83419             containersEnter.append('div').attr('class', 'issue-info').style('max-height', '0').style('opacity', '0').each(function (d) {
83420               if (typeof d.reference === 'function') {
83421                 select(this).call(d.reference);
83422               } else {
83423                 select(this).html(_t.html('inspector.no_documentation_key'));
83424               }
83425             }); // Update
83426
83427             containers = containers.merge(containersEnter).classed('active', function (d) {
83428               return d.id === _activeIssueID;
83429             });
83430             containers.selectAll('.issue-message').html(function (d) {
83431               return d.message(context);
83432             }); // fixes
83433
83434             var fixLists = containers.selectAll('.issue-fix-list');
83435             var fixes = fixLists.selectAll('.issue-fix-item').data(function (d) {
83436               return d.fixes ? d.fixes(context) : [];
83437             }, function (fix) {
83438               return fix.id;
83439             });
83440             fixes.exit().remove();
83441             var fixesEnter = fixes.enter().append('li').attr('class', 'issue-fix-item');
83442             var buttons = fixesEnter.append('button').on('click', function (d3_event, d) {
83443               // not all fixes are actionable
83444               if (select(this).attr('disabled') || !d.onClick) return; // Don't run another fix for this issue within a second of running one
83445               // (Necessary for "Select a feature type" fix. Most fixes should only ever run once)
83446
83447               if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1000) return;
83448               d.issue.dateLastRanFix = new Date(); // remove hover-highlighting
83449
83450               utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
83451               new Promise(function (resolve, reject) {
83452                 d.onClick(context, resolve, reject);
83453
83454                 if (d.onClick.length <= 1) {
83455                   // if the fix doesn't take any completion parameters then consider it resolved
83456                   resolve();
83457                 }
83458               }).then(function () {
83459                 // revalidate whenever the fix has finished running successfully
83460                 context.validator().validate();
83461               });
83462             }).on('mouseover.highlight', function (d3_event, d) {
83463               utilHighlightEntities(d.entityIds, true, context);
83464             }).on('mouseout.highlight', function (d3_event, d) {
83465               utilHighlightEntities(d.entityIds, false, context);
83466             });
83467             buttons.each(function (d) {
83468               var iconName = d.icon || 'iD-icon-wrench';
83469
83470               if (iconName.startsWith('maki')) {
83471                 iconName += '-15';
83472               }
83473
83474               select(this).call(svgIcon('#' + iconName, 'fix-icon'));
83475             });
83476             buttons.append('span').attr('class', 'fix-message').html(function (d) {
83477               return d.title;
83478             });
83479             fixesEnter.merge(fixes).selectAll('button').classed('actionable', function (d) {
83480               return d.onClick;
83481             }).attr('disabled', function (d) {
83482               return d.onClick ? null : 'true';
83483             }).attr('title', function (d) {
83484               if (d.disabledReason) {
83485                 return d.disabledReason;
83486               }
83487
83488               return null;
83489             });
83490           }
83491
83492           section.entityIDs = function (val) {
83493             if (!arguments.length) return _entityIDs;
83494
83495             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
83496               _entityIDs = val;
83497               _activeIssueID = null;
83498               reloadIssues();
83499             }
83500
83501             return section;
83502           };
83503
83504           return section;
83505         }
83506
83507         function uiPresetIcon() {
83508           var _preset;
83509
83510           var _geometry;
83511
83512           var _sizeClass = 'medium';
83513
83514           function isSmall() {
83515             return _sizeClass === 'small';
83516           }
83517
83518           function presetIcon(selection) {
83519             selection.each(render);
83520           }
83521
83522           function getIcon(p, geom) {
83523             if (isSmall() && p.isFallback && p.isFallback()) return 'iD-icon-' + p.id;else if (p.icon) return p.icon;else if (geom === 'line') return 'iD-other-line';else if (geom === 'vertex') return p.isFallback() ? '' : 'temaki-vertex';else if (isSmall() && geom === 'point') return '';else return 'maki-marker-stroked';
83524           }
83525
83526           function renderPointBorder(container, drawPoint) {
83527             var pointBorder = container.selectAll('.preset-icon-point-border').data(drawPoint ? [0] : []);
83528             pointBorder.exit().remove();
83529             var pointBorderEnter = pointBorder.enter();
83530             var w = 40;
83531             var h = 40;
83532             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');
83533             pointBorder = pointBorderEnter.merge(pointBorder);
83534           }
83535
83536           function renderCircleFill(container, drawVertex) {
83537             var vertexFill = container.selectAll('.preset-icon-fill-vertex').data(drawVertex ? [0] : []);
83538             vertexFill.exit().remove();
83539             var vertexFillEnter = vertexFill.enter();
83540             var w = 60;
83541             var h = 60;
83542             var d = 40;
83543             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);
83544             vertexFill = vertexFillEnter.merge(vertexFill);
83545           }
83546
83547           function renderSquareFill(container, drawArea, tagClasses) {
83548             var fill = container.selectAll('.preset-icon-fill-area').data(drawArea ? [0] : []);
83549             fill.exit().remove();
83550             var fillEnter = fill.enter();
83551             var d = isSmall() ? 40 : 60;
83552             var w = d;
83553             var h = d;
83554             var l = d * 2 / 3;
83555             var c1 = (w - l) / 2;
83556             var c2 = c1 + l;
83557             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));
83558             ['fill', 'stroke'].forEach(function (klass) {
83559               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', "line area ".concat(klass));
83560             });
83561             var rVertex = 2.5;
83562             [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach(function (point) {
83563               fillEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', rVertex);
83564             });
83565
83566             if (!isSmall()) {
83567               var rMidpoint = 1.25;
83568               [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach(function (point) {
83569                 fillEnter.append('circle').attr('class', 'midpoint').attr('cx', point[0]).attr('cy', point[1]).attr('r', rMidpoint);
83570               });
83571             }
83572
83573             fill = fillEnter.merge(fill);
83574             fill.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
83575             fill.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
83576           }
83577
83578           function renderLine(container, drawLine, tagClasses) {
83579             var line = container.selectAll('.preset-icon-line').data(drawLine ? [0] : []);
83580             line.exit().remove();
83581             var lineEnter = line.enter();
83582             var d = isSmall() ? 40 : 60; // draw the line parametrically
83583
83584             var w = d;
83585             var h = d;
83586             var y = Math.round(d * 0.72);
83587             var l = Math.round(d * 0.6);
83588             var r = 2.5;
83589             var x1 = (w - l) / 2;
83590             var x2 = x1 + l;
83591             lineEnter = lineEnter.append('svg').attr('class', 'preset-icon-line').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
83592             ['casing', 'stroke'].forEach(function (klass) {
83593               lineEnter.append('path').attr('d', "M".concat(x1, " ").concat(y, " L").concat(x2, " ").concat(y)).attr('class', "line ".concat(klass));
83594             });
83595             [[x1 - 1, y], [x2 + 1, y]].forEach(function (point) {
83596               lineEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
83597             });
83598             line = lineEnter.merge(line);
83599             line.selectAll('path.stroke').attr('class', "line stroke ".concat(tagClasses));
83600             line.selectAll('path.casing').attr('class', "line casing ".concat(tagClasses));
83601           }
83602
83603           function renderRoute(container, drawRoute, p) {
83604             var route = container.selectAll('.preset-icon-route').data(drawRoute ? [0] : []);
83605             route.exit().remove();
83606             var routeEnter = route.enter();
83607             var d = isSmall() ? 40 : 60; // draw the route parametrically
83608
83609             var w = d;
83610             var h = d;
83611             var y1 = Math.round(d * 0.80);
83612             var y2 = Math.round(d * 0.68);
83613             var l = Math.round(d * 0.6);
83614             var r = 2;
83615             var x1 = (w - l) / 2;
83616             var x2 = x1 + l / 3;
83617             var x3 = x2 + l / 3;
83618             var x4 = x3 + l / 3;
83619             routeEnter = routeEnter.append('svg').attr('class', 'preset-icon-route').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
83620             ['casing', 'stroke'].forEach(function (klass) {
83621               routeEnter.append('path').attr('d', "M".concat(x1, " ").concat(y1, " L").concat(x2, " ").concat(y2)).attr('class', "segment0 line ".concat(klass));
83622               routeEnter.append('path').attr('d', "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y1)).attr('class', "segment1 line ".concat(klass));
83623               routeEnter.append('path').attr('d', "M".concat(x3, " ").concat(y1, " L").concat(x4, " ").concat(y2)).attr('class', "segment2 line ".concat(klass));
83624             });
83625             [[x1, y1], [x2, y2], [x3, y1], [x4, y2]].forEach(function (point) {
83626               routeEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
83627             });
83628             route = routeEnter.merge(route);
83629
83630             if (drawRoute) {
83631               var routeType = p.tags.type === 'waterway' ? 'waterway' : p.tags.route;
83632               var segmentPresetIDs = routeSegments[routeType];
83633
83634               for (var i in segmentPresetIDs) {
83635                 var segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i]);
83636                 var segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, '');
83637                 route.selectAll("path.stroke.segment".concat(i)).attr('class', "segment".concat(i, " line stroke ").concat(segmentTagClasses));
83638                 route.selectAll("path.casing.segment".concat(i)).attr('class', "segment".concat(i, " line casing ").concat(segmentTagClasses));
83639               }
83640             }
83641           } // Route icons are drawn with a zigzag annotation underneath:
83642           //     o   o
83643           //    / \ /
83644           //   o   o
83645           // This dataset defines the styles that are used to draw the zigzag segments.
83646
83647
83648           var routeSegments = {
83649             bicycle: ['highway/cycleway', 'highway/cycleway', 'highway/cycleway'],
83650             bus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
83651             trolleybus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
83652             detour: ['highway/tertiary', 'highway/residential', 'highway/unclassified'],
83653             ferry: ['route/ferry', 'route/ferry', 'route/ferry'],
83654             foot: ['highway/footway', 'highway/footway', 'highway/footway'],
83655             hiking: ['highway/path', 'highway/path', 'highway/path'],
83656             horse: ['highway/bridleway', 'highway/bridleway', 'highway/bridleway'],
83657             light_rail: ['railway/light_rail', 'railway/light_rail', 'railway/light_rail'],
83658             monorail: ['railway/monorail', 'railway/monorail', 'railway/monorail'],
83659             pipeline: ['man_made/pipeline', 'man_made/pipeline', 'man_made/pipeline'],
83660             piste: ['piste/downhill', 'piste/hike', 'piste/nordic'],
83661             power: ['power/line', 'power/line', 'power/line'],
83662             road: ['highway/secondary', 'highway/primary', 'highway/trunk'],
83663             subway: ['railway/subway', 'railway/subway', 'railway/subway'],
83664             train: ['railway/rail', 'railway/rail', 'railway/rail'],
83665             tram: ['railway/tram', 'railway/tram', 'railway/tram'],
83666             waterway: ['waterway/stream', 'waterway/stream', 'waterway/stream']
83667           };
83668
83669           function render() {
83670             var p = _preset.apply(this, arguments);
83671
83672             var geom = _geometry ? _geometry.apply(this, arguments) : null;
83673
83674             if (geom === 'relation' && p.tags && (p.tags.type === 'route' && p.tags.route && routeSegments[p.tags.route] || p.tags.type === 'waterway')) {
83675               geom = 'route';
83676             }
83677
83678             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
83679             var isFallback = isSmall() && p.isFallback && p.isFallback();
83680             var imageURL = showThirdPartyIcons === 'true' && p.imageURL;
83681             var picon = getIcon(p, geom);
83682             var isMaki = picon && /^maki-/.test(picon);
83683             var isTemaki = picon && /^temaki-/.test(picon);
83684             var isFa = picon && /^fa[srb]-/.test(picon);
83685             var isiDIcon = picon && !(isMaki || isTemaki || isFa);
83686             var isCategory = !p.setTags;
83687             var drawPoint = picon && geom === 'point' && isSmall() && !isFallback;
83688             var drawVertex = picon !== null && geom === 'vertex' && (!isSmall() || !isFallback);
83689             var drawLine = picon && geom === 'line' && !isFallback && !isCategory;
83690             var drawArea = picon && geom === 'area' && !isFallback;
83691             var drawRoute = picon && geom === 'route';
83692             var isFramed = drawVertex || drawArea || drawLine || drawRoute;
83693             var tags = !isCategory ? p.setTags({}, geom) : {};
83694
83695             for (var k in tags) {
83696               if (tags[k] === '*') {
83697                 tags[k] = 'yes';
83698               }
83699             }
83700
83701             var tagClasses = svgTagClasses().getClassesString(tags, '');
83702             var selection = select(this);
83703             var container = selection.selectAll('.preset-icon-container').data([0]);
83704             container = container.enter().append('div').attr('class', "preset-icon-container ".concat(_sizeClass)).merge(container);
83705             container.classed('showing-img', !!imageURL).classed('fallback', isFallback);
83706             renderPointBorder(container, drawPoint);
83707             renderCircleFill(container, drawVertex);
83708             renderSquareFill(container, drawArea, tagClasses);
83709             renderLine(container, drawLine, tagClasses);
83710             renderRoute(container, drawRoute, p);
83711             var icon = container.selectAll('.preset-icon').data(picon ? [0] : []);
83712             icon.exit().remove();
83713             icon = icon.enter().append('div').attr('class', 'preset-icon').call(svgIcon('')).merge(icon);
83714             icon.attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')).classed('framed', isFramed).classed('preset-icon-iD', isiDIcon);
83715             icon.selectAll('svg').attr('class', 'icon ' + picon + ' ' + (!isiDIcon && geom !== 'line' ? '' : tagClasses));
83716             icon.selectAll('use').attr('href', '#' + picon + (isMaki ? isSmall() && geom === 'point' ? '-11' : '-15' : ''));
83717             var imageIcon = container.selectAll('img.image-icon').data(imageURL ? [0] : []);
83718             imageIcon.exit().remove();
83719             imageIcon = imageIcon.enter().append('img').attr('class', 'image-icon').on('load', function () {
83720               return container.classed('showing-img', true);
83721             }).on('error', function () {
83722               return container.classed('showing-img', false);
83723             }).merge(imageIcon);
83724             imageIcon.attr('src', imageURL);
83725           }
83726
83727           presetIcon.preset = function (val) {
83728             if (!arguments.length) return _preset;
83729             _preset = utilFunctor(val);
83730             return presetIcon;
83731           };
83732
83733           presetIcon.geometry = function (val) {
83734             if (!arguments.length) return _geometry;
83735             _geometry = utilFunctor(val);
83736             return presetIcon;
83737           };
83738
83739           presetIcon.sizeClass = function (val) {
83740             if (!arguments.length) return _sizeClass;
83741             _sizeClass = val;
83742             return presetIcon;
83743           };
83744
83745           return presetIcon;
83746         }
83747
83748         function uiSectionFeatureType(context) {
83749           var dispatch$1 = dispatch('choose');
83750           var _entityIDs = [];
83751           var _presets = [];
83752
83753           var _tagReference;
83754
83755           var section = uiSection('feature-type', context).label(_t.html('inspector.feature_type')).disclosureContent(renderDisclosureContent);
83756
83757           function renderDisclosureContent(selection) {
83758             selection.classed('preset-list-item', true);
83759             selection.classed('mixed-types', _presets.length > 1);
83760             var presetButtonWrap = selection.selectAll('.preset-list-button-wrap').data([0]).enter().append('div').attr('class', 'preset-list-button-wrap');
83761             var presetButton = presetButtonWrap.append('button').attr('class', 'preset-list-button preset-reset').call(uiTooltip().title(_t.html('inspector.back_tooltip')).placement('bottom'));
83762             presetButton.append('div').attr('class', 'preset-icon-container');
83763             presetButton.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
83764             presetButtonWrap.append('div').attr('class', 'accessory-buttons');
83765             var tagReferenceBodyWrap = selection.selectAll('.tag-reference-body-wrap').data([0]);
83766             tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append('div').attr('class', 'tag-reference-body-wrap').merge(tagReferenceBodyWrap); // update header
83767
83768             if (_tagReference) {
83769               selection.selectAll('.preset-list-button-wrap .accessory-buttons').style('display', _presets.length === 1 ? null : 'none').call(_tagReference.button);
83770               tagReferenceBodyWrap.style('display', _presets.length === 1 ? null : 'none').call(_tagReference.body);
83771             }
83772
83773             selection.selectAll('.preset-reset').on('click', function () {
83774               dispatch$1.call('choose', this, _presets);
83775             }).on('pointerdown pointerup mousedown mouseup', function (d3_event) {
83776               d3_event.preventDefault();
83777               d3_event.stopPropagation();
83778             });
83779             var geometries = entityGeometries();
83780             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')));
83781             var names = _presets.length === 1 ? [_presets[0].nameLabel(), _presets[0].subtitleLabel()].filter(Boolean) : [_t('inspector.multiple_types')];
83782             var label = selection.select('.label-inner');
83783             var nameparts = label.selectAll('.namepart').data(names, function (d) {
83784               return d;
83785             });
83786             nameparts.exit().remove();
83787             nameparts.enter().append('div').attr('class', 'namepart').html(function (d) {
83788               return d;
83789             });
83790           }
83791
83792           section.entityIDs = function (val) {
83793             if (!arguments.length) return _entityIDs;
83794             _entityIDs = val;
83795             return section;
83796           };
83797
83798           section.presets = function (val) {
83799             if (!arguments.length) return _presets; // don't reload the same preset
83800
83801             if (!utilArrayIdentical(val, _presets)) {
83802               _presets = val;
83803
83804               if (_presets.length === 1) {
83805                 _tagReference = uiTagReference(_presets[0].reference()).showing(false);
83806               }
83807             }
83808
83809             return section;
83810           };
83811
83812           function entityGeometries() {
83813             var counts = {};
83814
83815             for (var i in _entityIDs) {
83816               var geometry = context.graph().geometry(_entityIDs[i]);
83817               if (!counts[geometry]) counts[geometry] = 0;
83818               counts[geometry] += 1;
83819             }
83820
83821             return Object.keys(counts).sort(function (geom1, geom2) {
83822               return counts[geom2] - counts[geom1];
83823             });
83824           }
83825
83826           return utilRebind(section, dispatch$1, 'on');
83827         }
83828
83829         // It borrows some code from uiHelp
83830
83831         function uiFieldHelp(context, fieldName) {
83832           var fieldHelp = {};
83833
83834           var _inspector = select(null);
83835
83836           var _wrap = select(null);
83837
83838           var _body = select(null);
83839
83840           var fieldHelpKeys = {
83841             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']]]
83842           };
83843           var fieldHelpHeadings = {};
83844           var replacements = {
83845             distField: _t.html('restriction.controls.distance'),
83846             viaField: _t.html('restriction.controls.via'),
83847             fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
83848             allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
83849             restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
83850             onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
83851             allowTurn: icon('#iD-turn-yes', 'inline turn'),
83852             restrictTurn: icon('#iD-turn-no', 'inline turn'),
83853             onlyTurn: icon('#iD-turn-only', 'inline turn')
83854           }; // For each section, squash all the texts into a single markdown document
83855
83856           var docs = fieldHelpKeys[fieldName].map(function (key) {
83857             var helpkey = 'help.field.' + fieldName + '.' + key[0];
83858             var text = key[1].reduce(function (all, part) {
83859               var subkey = helpkey + '.' + part;
83860               var depth = fieldHelpHeadings[subkey]; // is this subkey a heading?
83861
83862               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
83863
83864               return all + hhh + _t.html(subkey, replacements) + '\n\n';
83865             }, '');
83866             return {
83867               key: helpkey,
83868               title: _t.html(helpkey + '.title'),
83869               html: marked_1(text.trim())
83870             };
83871           });
83872
83873           function show() {
83874             updatePosition();
83875
83876             _body.classed('hide', false).style('opacity', '0').transition().duration(200).style('opacity', '1');
83877           }
83878
83879           function hide() {
83880             _body.classed('hide', true).transition().duration(200).style('opacity', '0').on('end', function () {
83881               _body.classed('hide', true);
83882             });
83883           }
83884
83885           function clickHelp(index) {
83886             var d = docs[index];
83887             var tkeys = fieldHelpKeys[fieldName][index][1];
83888
83889             _body.selectAll('.field-help-nav-item').classed('active', function (d, i) {
83890               return i === index;
83891             });
83892
83893             var content = _body.selectAll('.field-help-content').html(d.html); // class the paragraphs so we can find and style them
83894
83895
83896             content.selectAll('p').attr('class', function (d, i) {
83897               return tkeys[i];
83898             }); // insert special content for certain help sections
83899
83900             if (d.key === 'help.field.restrictions.inspecting') {
83901               content.insert('img', 'p.from_shadow').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_inspect.gif'));
83902             } else if (d.key === 'help.field.restrictions.modifying') {
83903               content.insert('img', 'p.allow_turn').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_modify.gif'));
83904             }
83905           }
83906
83907           fieldHelp.button = function (selection) {
83908             if (_body.empty()) return;
83909             var button = selection.selectAll('.field-help-button').data([0]); // enter/update
83910
83911             button.enter().append('button').attr('class', 'field-help-button').call(svgIcon('#iD-icon-help')).merge(button).on('click', function (d3_event) {
83912               d3_event.stopPropagation();
83913               d3_event.preventDefault();
83914
83915               if (_body.classed('hide')) {
83916                 show();
83917               } else {
83918                 hide();
83919               }
83920             });
83921           };
83922
83923           function updatePosition() {
83924             var wrap = _wrap.node();
83925
83926             var inspector = _inspector.node();
83927
83928             var wRect = wrap.getBoundingClientRect();
83929             var iRect = inspector.getBoundingClientRect();
83930
83931             _body.style('top', wRect.top + inspector.scrollTop - iRect.top + 'px');
83932           }
83933
83934           fieldHelp.body = function (selection) {
83935             // This control expects the field to have a form-field-input-wrap div
83936             _wrap = selection.selectAll('.form-field-input-wrap');
83937             if (_wrap.empty()) return; // absolute position relative to the inspector, so it "floats" above the fields
83938
83939             _inspector = context.container().select('.sidebar .entity-editor-pane .inspector-body');
83940             if (_inspector.empty()) return;
83941             _body = _inspector.selectAll('.field-help-body').data([0]);
83942
83943             var enter = _body.enter().append('div').attr('class', 'field-help-body hide'); // initially hidden
83944
83945
83946             var titleEnter = enter.append('div').attr('class', 'field-help-title cf');
83947             titleEnter.append('h2').attr('class', _mainLocalizer.textDirection() === 'rtl' ? 'fr' : 'fl').html(_t.html('help.field.' + fieldName + '.title'));
83948             titleEnter.append('button').attr('class', 'fr close').on('click', function (d3_event) {
83949               d3_event.stopPropagation();
83950               d3_event.preventDefault();
83951               hide();
83952             }).call(svgIcon('#iD-icon-close'));
83953             var navEnter = enter.append('div').attr('class', 'field-help-nav cf');
83954             var titles = docs.map(function (d) {
83955               return d.title;
83956             });
83957             navEnter.selectAll('.field-help-nav-item').data(titles).enter().append('div').attr('class', 'field-help-nav-item').html(function (d) {
83958               return d;
83959             }).on('click', function (d3_event, d) {
83960               d3_event.stopPropagation();
83961               d3_event.preventDefault();
83962               clickHelp(titles.indexOf(d));
83963             });
83964             enter.append('div').attr('class', 'field-help-content');
83965             _body = _body.merge(enter);
83966             clickHelp(0);
83967           };
83968
83969           return fieldHelp;
83970         }
83971
83972         function uiFieldCheck(field, context) {
83973           var dispatch$1 = dispatch('change');
83974           var options = field.strings && field.strings.options;
83975           var values = [];
83976           var texts = [];
83977
83978           var _tags;
83979
83980           var input = select(null);
83981           var text = select(null);
83982           var label = select(null);
83983           var reverser = select(null);
83984
83985           var _impliedYes;
83986
83987           var _entityIDs = [];
83988
83989           var _value;
83990
83991           if (options) {
83992             for (var k in options) {
83993               values.push(k === 'undefined' ? undefined : k);
83994               texts.push(field.t.html('options.' + k, {
83995                 'default': options[k]
83996               }));
83997             }
83998           } else {
83999             values = [undefined, 'yes'];
84000             texts = [_t.html('inspector.unknown'), _t.html('inspector.check.yes')];
84001
84002             if (field.type !== 'defaultCheck') {
84003               values.push('no');
84004               texts.push(_t.html('inspector.check.no'));
84005             }
84006           } // Checks tags to see whether an undefined value is "Assumed to be Yes"
84007
84008
84009           function checkImpliedYes() {
84010             _impliedYes = field.id === 'oneway_yes'; // hack: pretend `oneway` field is a `oneway_yes` field
84011             // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
84012
84013             if (field.id === 'oneway') {
84014               var entity = context.entity(_entityIDs[0]);
84015
84016               for (var key in entity.tags) {
84017                 if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
84018                   _impliedYes = true;
84019                   texts[0] = _t.html('presets.fields.oneway_yes.options.undefined');
84020                   break;
84021                 }
84022               }
84023             }
84024           }
84025
84026           function reverserHidden() {
84027             if (!context.container().select('div.inspector-hover').empty()) return true;
84028             return !(_value === 'yes' || _impliedYes && !_value);
84029           }
84030
84031           function reverserSetText(selection) {
84032             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
84033             if (reverserHidden() || !entity) return selection;
84034             var first = entity.first();
84035             var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
84036             var pseudoDirection = first < last;
84037             var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
84038             selection.selectAll('.reverser-span').html(_t.html('inspector.check.reverser')).call(svgIcon(icon, 'inline'));
84039             return selection;
84040           }
84041
84042           var check = function check(selection) {
84043             checkImpliedYes();
84044             label = selection.selectAll('.form-field-input-wrap').data([0]);
84045             var enter = label.enter().append('label').attr('class', 'form-field-input-wrap form-field-input-check');
84046             enter.append('input').property('indeterminate', field.type !== 'defaultCheck').attr('type', 'checkbox').attr('id', field.domId);
84047             enter.append('span').html(texts[0]).attr('class', 'value');
84048
84049             if (field.type === 'onewayCheck') {
84050               enter.append('button').attr('class', 'reverser' + (reverserHidden() ? ' hide' : '')).append('span').attr('class', 'reverser-span');
84051             }
84052
84053             label = label.merge(enter);
84054             input = label.selectAll('input');
84055             text = label.selectAll('span.value');
84056             input.on('click', function (d3_event) {
84057               d3_event.stopPropagation();
84058               var t = {};
84059
84060               if (Array.isArray(_tags[field.key])) {
84061                 if (values.indexOf('yes') !== -1) {
84062                   t[field.key] = 'yes';
84063                 } else {
84064                   t[field.key] = values[0];
84065                 }
84066               } else {
84067                 t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
84068               } // Don't cycle through `alternating` or `reversible` states - #4970
84069               // (They are supported as translated strings, but should not toggle with clicks)
84070
84071
84072               if (t[field.key] === 'reversible' || t[field.key] === 'alternating') {
84073                 t[field.key] = values[0];
84074               }
84075
84076               dispatch$1.call('change', this, t);
84077             });
84078
84079             if (field.type === 'onewayCheck') {
84080               reverser = label.selectAll('.reverser');
84081               reverser.call(reverserSetText).on('click', function (d3_event) {
84082                 d3_event.preventDefault();
84083                 d3_event.stopPropagation();
84084                 context.perform(function (graph) {
84085                   for (var i in _entityIDs) {
84086                     graph = actionReverse(_entityIDs[i])(graph);
84087                   }
84088
84089                   return graph;
84090                 }, _t('operations.reverse.annotation.line', {
84091                   n: 1
84092                 })); // must manually revalidate since no 'change' event was called
84093
84094                 context.validator().validate();
84095                 select(this).call(reverserSetText);
84096               });
84097             }
84098           };
84099
84100           check.entityIDs = function (val) {
84101             if (!arguments.length) return _entityIDs;
84102             _entityIDs = val;
84103             return check;
84104           };
84105
84106           check.tags = function (tags) {
84107             _tags = tags;
84108
84109             function isChecked(val) {
84110               return val !== 'no' && val !== '' && val !== undefined && val !== null;
84111             }
84112
84113             function textFor(val) {
84114               if (val === '') val = undefined;
84115               var index = values.indexOf(val);
84116               return index !== -1 ? texts[index] : '"' + val + '"';
84117             }
84118
84119             checkImpliedYes();
84120             var isMixed = Array.isArray(tags[field.key]);
84121             _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
84122
84123             if (field.type === 'onewayCheck' && (_value === '1' || _value === '-1')) {
84124               _value = 'yes';
84125             }
84126
84127             input.property('indeterminate', isMixed || field.type !== 'defaultCheck' && !_value).property('checked', isChecked(_value));
84128             text.html(isMixed ? _t.html('inspector.multiple_values') : textFor(_value)).classed('mixed', isMixed);
84129             label.classed('set', !!_value);
84130
84131             if (field.type === 'onewayCheck') {
84132               reverser.classed('hide', reverserHidden()).call(reverserSetText);
84133             }
84134           };
84135
84136           check.focus = function () {
84137             input.node().focus();
84138           };
84139
84140           return utilRebind(check, dispatch$1, 'on');
84141         }
84142
84143         function uiFieldCombo(field, context) {
84144           var dispatch$1 = dispatch('change');
84145
84146           var _isMulti = field.type === 'multiCombo' || field.type === 'manyCombo';
84147
84148           var _isNetwork = field.type === 'networkCombo';
84149
84150           var _isSemi = field.type === 'semiCombo';
84151
84152           var _optstrings = field.strings && field.strings.options;
84153
84154           var _optarray = field.options;
84155
84156           var _snake_case = field.snake_case || field.snake_case === undefined;
84157
84158           var _combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(field.caseSensitive).minItems(_isMulti || _isSemi ? 1 : 2);
84159
84160           var _container = select(null);
84161
84162           var _inputWrap = select(null);
84163
84164           var _input = select(null);
84165
84166           var _comboData = [];
84167           var _multiData = [];
84168           var _entityIDs = [];
84169
84170           var _tags;
84171
84172           var _countryCode;
84173
84174           var _staticPlaceholder; // initialize deprecated tags array
84175
84176
84177           var _dataDeprecated = [];
84178           _mainFileFetcher.get('deprecated').then(function (d) {
84179             _dataDeprecated = d;
84180           })["catch"](function () {
84181             /* ignore */
84182           }); // ensure multiCombo field.key ends with a ':'
84183
84184           if (_isMulti && field.key && /[^:]$/.test(field.key)) {
84185             field.key += ':';
84186           }
84187
84188           function snake(s) {
84189             return s.replace(/\s+/g, '_');
84190           }
84191
84192           function unsnake(s) {
84193             return s.replace(/_+/g, ' ');
84194           }
84195
84196           function clean(s) {
84197             return s.split(';').map(function (s) {
84198               return s.trim();
84199             }).join(';');
84200           } // returns the tag value for a display value
84201           // (for multiCombo, dval should be the key suffix, not the entire key)
84202
84203
84204           function tagValue(dval) {
84205             dval = clean(dval || '');
84206
84207             if (_optstrings) {
84208               var found = _comboData.find(function (o) {
84209                 return o.key && clean(o.value) === dval;
84210               });
84211
84212               if (found) {
84213                 return found.key;
84214               }
84215             }
84216
84217             if (field.type === 'typeCombo' && !dval) {
84218               return 'yes';
84219             }
84220
84221             return (_snake_case ? snake(dval) : dval) || undefined;
84222           } // returns the display value for a tag value
84223           // (for multiCombo, tval should be the key suffix, not the entire key)
84224
84225
84226           function displayValue(tval) {
84227             tval = tval || '';
84228
84229             if (_optstrings) {
84230               var found = _comboData.find(function (o) {
84231                 return o.key === tval && o.value;
84232               });
84233
84234               if (found) {
84235                 return found.value;
84236               }
84237             }
84238
84239             if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
84240               return '';
84241             }
84242
84243             return _snake_case ? unsnake(tval) : tval;
84244           } // Compute the difference between arrays of objects by `value` property
84245           //
84246           // objectDifference([{value:1}, {value:2}, {value:3}], [{value:2}])
84247           // > [{value:1}, {value:3}]
84248           //
84249
84250
84251           function objectDifference(a, b) {
84252             return a.filter(function (d1) {
84253               return !b.some(function (d2) {
84254                 return !d2.isMixed && d1.value === d2.value;
84255               });
84256             });
84257           }
84258
84259           function initCombo(selection, attachTo) {
84260             if (_optstrings) {
84261               selection.attr('readonly', 'readonly');
84262               selection.call(_combobox, attachTo);
84263               setStaticValues(setPlaceholder);
84264             } else if (_optarray) {
84265               selection.call(_combobox, attachTo);
84266               setStaticValues(setPlaceholder);
84267             } else if (services.taginfo) {
84268               selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
84269               setTaginfoValues('', setPlaceholder);
84270             }
84271           }
84272
84273           function setStaticValues(callback) {
84274             if (!(_optstrings || _optarray)) return;
84275
84276             if (_optstrings) {
84277               _comboData = Object.keys(_optstrings).map(function (k) {
84278                 var v = field.t('options.' + k, {
84279                   'default': _optstrings[k]
84280                 });
84281                 return {
84282                   key: k,
84283                   value: v,
84284                   title: v,
84285                   display: field.t.html('options.' + k, {
84286                     'default': _optstrings[k]
84287                   })
84288                 };
84289               });
84290             } else if (_optarray) {
84291               _comboData = _optarray.map(function (k) {
84292                 var v = _snake_case ? unsnake(k) : k;
84293                 return {
84294                   key: k,
84295                   value: v,
84296                   title: v
84297                 };
84298               });
84299             }
84300
84301             _combobox.data(objectDifference(_comboData, _multiData));
84302
84303             if (callback) callback(_comboData);
84304           }
84305
84306           function setTaginfoValues(q, callback) {
84307             var fn = _isMulti ? 'multikeys' : 'values';
84308             var query = (_isMulti ? field.key : '') + q;
84309             var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
84310
84311             if (hasCountryPrefix) {
84312               query = _countryCode + ':';
84313             }
84314
84315             var params = {
84316               debounce: q !== '',
84317               key: field.key,
84318               query: query
84319             };
84320
84321             if (_entityIDs.length) {
84322               params.geometry = context.graph().geometry(_entityIDs[0]);
84323             }
84324
84325             services.taginfo[fn](params, function (err, data) {
84326               if (err) return;
84327               data = data.filter(function (d) {
84328                 if (field.type === 'typeCombo' && d.value === 'yes') {
84329                   // don't show the fallback value
84330                   return false;
84331                 } // don't show values with very low usage
84332
84333
84334                 return !d.count || d.count > 10;
84335               });
84336               var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
84337
84338               if (deprecatedValues) {
84339                 // don't suggest deprecated tag values
84340                 data = data.filter(function (d) {
84341                   return deprecatedValues.indexOf(d.value) === -1;
84342                 });
84343               }
84344
84345               if (hasCountryPrefix) {
84346                 data = data.filter(function (d) {
84347                   return d.value.toLowerCase().indexOf(_countryCode + ':') === 0;
84348                 });
84349               } // hide the caret if there are no suggestions
84350
84351
84352               _container.classed('empty-combobox', data.length === 0);
84353
84354               _comboData = data.map(function (d) {
84355                 var k = d.value;
84356                 if (_isMulti) k = k.replace(field.key, '');
84357                 var v = _snake_case ? unsnake(k) : k;
84358                 return {
84359                   key: k,
84360                   value: v,
84361                   title: _isMulti ? v : d.title
84362                 };
84363               });
84364               _comboData = objectDifference(_comboData, _multiData);
84365               if (callback) callback(_comboData);
84366             });
84367           }
84368
84369           function setPlaceholder(values) {
84370             if (_isMulti || _isSemi) {
84371               _staticPlaceholder = field.placeholder() || _t('inspector.add');
84372             } else {
84373               var vals = values.map(function (d) {
84374                 return d.value;
84375               }).filter(function (s) {
84376                 return s.length < 20;
84377               });
84378               var placeholders = vals.length > 1 ? vals : values.map(function (d) {
84379                 return d.key;
84380               });
84381               _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(', ');
84382             }
84383
84384             if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
84385               _staticPlaceholder += '…';
84386             }
84387
84388             var ph;
84389
84390             if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
84391               ph = _t('inspector.multiple_values');
84392             } else {
84393               ph = _staticPlaceholder;
84394             }
84395
84396             _container.selectAll('input').attr('placeholder', ph);
84397           }
84398
84399           function change() {
84400             var t = {};
84401             var val;
84402
84403             if (_isMulti || _isSemi) {
84404               val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
84405
84406               _container.classed('active', false);
84407
84408               utilGetSetValue(_input, '');
84409               var vals = val.split(';').filter(Boolean);
84410               if (!vals.length) return;
84411
84412               if (_isMulti) {
84413                 utilArrayUniq(vals).forEach(function (v) {
84414                   var key = (field.key || '') + v;
84415
84416                   if (_tags) {
84417                     // don't set a multicombo value to 'yes' if it already has a non-'no' value
84418                     // e.g. `language:de=main`
84419                     var old = _tags[key];
84420                     if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
84421                   }
84422
84423                   key = context.cleanTagKey(key);
84424                   field.keys.push(key);
84425                   t[key] = 'yes';
84426                 });
84427               } else if (_isSemi) {
84428                 var arr = _multiData.map(function (d) {
84429                   return d.key;
84430                 });
84431
84432                 arr = arr.concat(vals);
84433                 t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
84434               }
84435
84436               window.setTimeout(function () {
84437                 _input.node().focus();
84438               }, 10);
84439             } else {
84440               var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string
84441
84442               if (!rawValue && Array.isArray(_tags[field.key])) return;
84443               val = context.cleanTagValue(tagValue(rawValue));
84444               t[field.key] = val || undefined;
84445             }
84446
84447             dispatch$1.call('change', this, t);
84448           }
84449
84450           function removeMultikey(d3_event, d) {
84451             d3_event.preventDefault();
84452             d3_event.stopPropagation();
84453             var t = {};
84454
84455             if (_isMulti) {
84456               t[d.key] = undefined;
84457             } else if (_isSemi) {
84458               var arr = _multiData.map(function (md) {
84459                 return md.key === d.key ? null : md.key;
84460               }).filter(Boolean);
84461
84462               arr = utilArrayUniq(arr);
84463               t[field.key] = arr.length ? arr.join(';') : undefined;
84464             }
84465
84466             dispatch$1.call('change', this, t);
84467           }
84468
84469           function combo(selection) {
84470             _container = selection.selectAll('.form-field-input-wrap').data([0]);
84471             var type = _isMulti || _isSemi ? 'multicombo' : 'combo';
84472             _container = _container.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + type).merge(_container);
84473
84474             if (_isMulti || _isSemi) {
84475               _container = _container.selectAll('.chiplist').data([0]);
84476               var listClass = 'chiplist'; // Use a separate line for each value in the Destinations field
84477               // to mimic highway exit signs
84478
84479               if (field.key === 'destination') {
84480                 listClass += ' full-line-chips';
84481               }
84482
84483               _container = _container.enter().append('ul').attr('class', listClass).on('click', function () {
84484                 window.setTimeout(function () {
84485                   _input.node().focus();
84486                 }, 10);
84487               }).merge(_container);
84488               _inputWrap = _container.selectAll('.input-wrap').data([0]);
84489               _inputWrap = _inputWrap.enter().append('li').attr('class', 'input-wrap').merge(_inputWrap);
84490               _input = _inputWrap.selectAll('input').data([0]);
84491             } else {
84492               _input = _container.selectAll('input').data([0]);
84493             }
84494
84495             _input = _input.enter().append('input').attr('type', 'text').attr('id', field.domId).call(utilNoAuto).call(initCombo, selection).merge(_input);
84496
84497             if (_isNetwork) {
84498               var extent = combinedEntityExtent();
84499               var countryCode = extent && iso1A2Code(extent.center());
84500               _countryCode = countryCode && countryCode.toLowerCase();
84501             }
84502
84503             _input.on('change', change).on('blur', change);
84504
84505             _input.on('keydown.field', function (d3_event) {
84506               switch (d3_event.keyCode) {
84507                 case 13:
84508                   // ↩ Return
84509                   _input.node().blur(); // blurring also enters the value
84510
84511
84512                   d3_event.stopPropagation();
84513                   break;
84514               }
84515             });
84516
84517             if (_isMulti || _isSemi) {
84518               _combobox.on('accept', function () {
84519                 _input.node().blur();
84520
84521                 _input.node().focus();
84522               });
84523
84524               _input.on('focus', function () {
84525                 _container.classed('active', true);
84526               });
84527             }
84528           }
84529
84530           combo.tags = function (tags) {
84531             _tags = tags;
84532
84533             if (_isMulti || _isSemi) {
84534               _multiData = [];
84535               var maxLength;
84536
84537               if (_isMulti) {
84538                 // Build _multiData array containing keys already set..
84539                 for (var k in tags) {
84540                   if (field.key && k.indexOf(field.key) !== 0 || field.keys.indexOf(k) === -1) continue;
84541                   var v = tags[k];
84542                   if (!v || typeof v === 'string' && v.toLowerCase() === 'no') continue;
84543                   var suffix = field.key ? k.substring(field.key.length) : k;
84544
84545                   _multiData.push({
84546                     key: k,
84547                     value: displayValue(suffix),
84548                     isMixed: Array.isArray(v)
84549                   });
84550                 }
84551
84552                 if (field.key) {
84553                   // Set keys for form-field modified (needed for undo and reset buttons)..
84554                   field.keys = _multiData.map(function (d) {
84555                     return d.key;
84556                   }); // limit the input length so it fits after prepending the key prefix
84557
84558                   maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
84559                 } else {
84560                   maxLength = context.maxCharsForTagKey();
84561                 }
84562               } else if (_isSemi) {
84563                 var allValues = [];
84564                 var commonValues;
84565
84566                 if (Array.isArray(tags[field.key])) {
84567                   tags[field.key].forEach(function (tagVal) {
84568                     var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
84569                     allValues = allValues.concat(thisVals);
84570
84571                     if (!commonValues) {
84572                       commonValues = thisVals;
84573                     } else {
84574                       commonValues = commonValues.filter(function (value) {
84575                         return thisVals.includes(value);
84576                       });
84577                     }
84578                   });
84579                   allValues = utilArrayUniq(allValues).filter(Boolean);
84580                 } else {
84581                   allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
84582                   commonValues = allValues;
84583                 }
84584
84585                 _multiData = allValues.map(function (v) {
84586                   return {
84587                     key: v,
84588                     value: displayValue(v),
84589                     isMixed: !commonValues.includes(v)
84590                   };
84591                 });
84592                 var currLength = utilUnicodeCharsCount(commonValues.join(';')); // limit the input length to the remaining available characters
84593
84594                 maxLength = context.maxCharsForTagValue() - currLength;
84595
84596                 if (currLength > 0) {
84597                   // account for the separator if a new value will be appended to existing
84598                   maxLength -= 1;
84599                 }
84600               } // a negative maxlength doesn't make sense
84601
84602
84603               maxLength = Math.max(0, maxLength);
84604               var allowDragAndDrop = _isSemi // only semiCombo values are ordered
84605               && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options..
84606
84607               var available = objectDifference(_comboData, _multiData);
84608
84609               _combobox.data(available); // Hide 'Add' button if this field uses fixed set of
84610               // translateable _optstrings and they're all currently used,
84611               // or if the field is already at its character limit
84612
84613
84614               var hideAdd = _optstrings && !available.length || maxLength <= 0;
84615
84616               _container.selectAll('.chiplist .input-wrap').style('display', hideAdd ? 'none' : null); // Render chips
84617
84618
84619               var chips = _container.selectAll('.chip').data(_multiData);
84620
84621               chips.exit().remove();
84622               var enter = chips.enter().insert('li', '.input-wrap').attr('class', 'chip');
84623               enter.append('span');
84624               enter.append('a');
84625               chips = chips.merge(enter).order().classed('draggable', allowDragAndDrop).classed('mixed', function (d) {
84626                 return d.isMixed;
84627               }).attr('title', function (d) {
84628                 return d.isMixed ? _t('inspector.unshared_value_tooltip') : null;
84629               });
84630
84631               if (allowDragAndDrop) {
84632                 registerDragAndDrop(chips);
84633               }
84634
84635               chips.select('span').html(function (d) {
84636                 return d.value;
84637               });
84638               chips.select('a').attr('href', '#').on('click', removeMultikey).attr('class', 'remove').html('×');
84639             } else {
84640               var isMixed = Array.isArray(tags[field.key]);
84641               var mixedValues = isMixed && tags[field.key].map(function (val) {
84642                 return displayValue(val);
84643               }).filter(Boolean);
84644               utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : '').attr('title', isMixed ? mixedValues.join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : _staticPlaceholder || '').classed('mixed', isMixed);
84645             }
84646           };
84647
84648           function registerDragAndDrop(selection) {
84649             // allow drag and drop re-ordering of chips
84650             var dragOrigin, targetIndex;
84651             selection.call(d3_drag().on('start', function (d3_event) {
84652               dragOrigin = {
84653                 x: d3_event.x,
84654                 y: d3_event.y
84655               };
84656               targetIndex = null;
84657             }).on('drag', function (d3_event) {
84658               var x = d3_event.x - dragOrigin.x,
84659                   y = d3_event.y - dragOrigin.y;
84660               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
84661               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
84662               var index = selection.nodes().indexOf(this);
84663               select(this).classed('dragging', true);
84664               targetIndex = null;
84665               var targetIndexOffsetTop = null;
84666               var draggedTagWidth = select(this).node().offsetWidth;
84667
84668               if (field.key === 'destination') {
84669                 // meaning tags are full width
84670                 _container.selectAll('.chip').style('transform', function (d2, index2) {
84671                   var node = select(this).node();
84672
84673                   if (index === index2) {
84674                     return 'translate(' + x + 'px, ' + y + 'px)'; // move the dragged tag up the order
84675                   } else if (index2 > index && d3_event.y > node.offsetTop) {
84676                     if (targetIndex === null || index2 > targetIndex) {
84677                       targetIndex = index2;
84678                     }
84679
84680                     return 'translateY(-100%)'; // move the dragged tag down the order
84681                   } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
84682                     if (targetIndex === null || index2 < targetIndex) {
84683                       targetIndex = index2;
84684                     }
84685
84686                     return 'translateY(100%)';
84687                   }
84688
84689                   return null;
84690                 });
84691               } else {
84692                 _container.selectAll('.chip').each(function (d2, index2) {
84693                   var node = select(this).node(); // check the cursor is in the bounding box
84694
84695                   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) {
84696                     targetIndex = index2;
84697                     targetIndexOffsetTop = node.offsetTop;
84698                   }
84699                 }).style('transform', function (d2, index2) {
84700                   var node = select(this).node();
84701
84702                   if (index === index2) {
84703                     return 'translate(' + x + 'px, ' + y + 'px)';
84704                   } // only translate tags in the same row
84705
84706
84707                   if (node.offsetTop === targetIndexOffsetTop) {
84708                     if (index2 < index && index2 >= targetIndex) {
84709                       return 'translateX(' + draggedTagWidth + 'px)';
84710                     } else if (index2 > index && index2 <= targetIndex) {
84711                       return 'translateX(-' + draggedTagWidth + 'px)';
84712                     }
84713                   }
84714
84715                   return null;
84716                 });
84717               }
84718             }).on('end', function () {
84719               if (!select(this).classed('dragging')) {
84720                 return;
84721               }
84722
84723               var index = selection.nodes().indexOf(this);
84724               select(this).classed('dragging', false);
84725
84726               _container.selectAll('.chip').style('transform', null);
84727
84728               if (typeof targetIndex === 'number') {
84729                 var element = _multiData[index];
84730
84731                 _multiData.splice(index, 1);
84732
84733                 _multiData.splice(targetIndex, 0, element);
84734
84735                 var t = {};
84736
84737                 if (_multiData.length) {
84738                   t[field.key] = _multiData.map(function (element) {
84739                     return element.key;
84740                   }).join(';');
84741                 } else {
84742                   t[field.key] = undefined;
84743                 }
84744
84745                 dispatch$1.call('change', this, t);
84746               }
84747
84748               dragOrigin = undefined;
84749               targetIndex = undefined;
84750             }));
84751           }
84752
84753           combo.focus = function () {
84754             _input.node().focus();
84755           };
84756
84757           combo.entityIDs = function (val) {
84758             if (!arguments.length) return _entityIDs;
84759             _entityIDs = val;
84760             return combo;
84761           };
84762
84763           function combinedEntityExtent() {
84764             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
84765           }
84766
84767           return utilRebind(combo, dispatch$1, 'on');
84768         }
84769
84770         function uiFieldText(field, context) {
84771           var dispatch$1 = dispatch('change');
84772           var input = select(null);
84773           var outlinkButton = select(null);
84774           var _entityIDs = [];
84775
84776           var _tags;
84777
84778           var _phoneFormats = {};
84779
84780           if (field.type === 'tel') {
84781             _mainFileFetcher.get('phone_formats').then(function (d) {
84782               _phoneFormats = d;
84783               updatePhonePlaceholder();
84784             })["catch"](function () {
84785               /* ignore */
84786             });
84787           }
84788
84789           function i(selection) {
84790             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
84791             var preset = entity && _mainPresetIndex.match(entity, context.graph());
84792             var isLocked = preset && preset.suggestion && field.id === 'brand';
84793             field.locked(isLocked);
84794             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84795             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84796             input = wrap.selectAll('input').data([0]);
84797             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);
84798             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
84799
84800             if (field.type === 'tel') {
84801               updatePhonePlaceholder();
84802             } else if (field.type === 'number') {
84803               var rtl = _mainLocalizer.textDirection() === 'rtl';
84804               input.attr('type', 'text');
84805               var inc = field.increment;
84806               var buttons = wrap.selectAll('.increment, .decrement').data(rtl ? [inc, -inc] : [-inc, inc]);
84807               buttons.enter().append('button').attr('class', function (d) {
84808                 var which = d > 0 ? 'increment' : 'decrement';
84809                 return 'form-field-button ' + which;
84810               }).merge(buttons).on('click', function (d3_event, d) {
84811                 d3_event.preventDefault();
84812                 var raw_vals = input.node().value || '0';
84813                 var vals = raw_vals.split(';');
84814                 vals = vals.map(function (v) {
84815                   var num = parseFloat(v.trim(), 10);
84816                   return isFinite(num) ? clamped(num + d) : v.trim();
84817                 });
84818                 input.node().value = vals.join(';');
84819                 change()();
84820               });
84821             } else if (field.type === 'identifier' && field.urlFormat && field.pattern) {
84822               input.attr('type', 'text');
84823               outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
84824               outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
84825                 var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
84826
84827                 if (domainResults.length >= 2 && domainResults[1]) {
84828                   var domain = domainResults[1];
84829                   return _t('icons.view_on', {
84830                     domain: domain
84831                   });
84832                 }
84833
84834                 return '';
84835               }).on('click', function (d3_event) {
84836                 d3_event.preventDefault();
84837                 var value = validIdentifierValueForLink();
84838
84839                 if (value) {
84840                   var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
84841                   window.open(url, '_blank');
84842                 }
84843               }).merge(outlinkButton);
84844             }
84845           }
84846
84847           function updatePhonePlaceholder() {
84848             if (input.empty() || !Object.keys(_phoneFormats).length) return;
84849             var extent = combinedEntityExtent();
84850             var countryCode = extent && iso1A2Code(extent.center());
84851
84852             var format = countryCode && _phoneFormats[countryCode.toLowerCase()];
84853
84854             if (format) input.attr('placeholder', format);
84855           }
84856
84857           function validIdentifierValueForLink() {
84858             if (field.type === 'identifier' && field.pattern) {
84859               var value = utilGetSetValue(input).trim().split(';')[0];
84860               return value && value.match(new RegExp(field.pattern));
84861             }
84862
84863             return null;
84864           } // clamp number to min/max
84865
84866
84867           function clamped(num) {
84868             if (field.minValue !== undefined) {
84869               num = Math.max(num, field.minValue);
84870             }
84871
84872             if (field.maxValue !== undefined) {
84873               num = Math.min(num, field.maxValue);
84874             }
84875
84876             return num;
84877           }
84878
84879           function change(onInput) {
84880             return function () {
84881               var t = {};
84882               var val = utilGetSetValue(input);
84883               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
84884
84885               if (!val && Array.isArray(_tags[field.key])) return;
84886
84887               if (!onInput) {
84888                 if (field.type === 'number' && val) {
84889                   var vals = val.split(';');
84890                   vals = vals.map(function (v) {
84891                     var num = parseFloat(v.trim(), 10);
84892                     return isFinite(num) ? clamped(num) : v.trim();
84893                   });
84894                   val = vals.join(';');
84895                 }
84896
84897                 utilGetSetValue(input, val);
84898               }
84899
84900               t[field.key] = val || undefined;
84901               dispatch$1.call('change', this, t, onInput);
84902             };
84903           }
84904
84905           i.entityIDs = function (val) {
84906             if (!arguments.length) return _entityIDs;
84907             _entityIDs = val;
84908             return i;
84909           };
84910
84911           i.tags = function (tags) {
84912             _tags = tags;
84913             var isMixed = Array.isArray(tags[field.key]);
84914             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);
84915
84916             if (outlinkButton && !outlinkButton.empty()) {
84917               var disabled = !validIdentifierValueForLink();
84918               outlinkButton.classed('disabled', disabled);
84919             }
84920           };
84921
84922           i.focus = function () {
84923             var node = input.node();
84924             if (node) node.focus();
84925           };
84926
84927           function combinedEntityExtent() {
84928             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
84929           }
84930
84931           return utilRebind(i, dispatch$1, 'on');
84932         }
84933
84934         function uiFieldAccess(field, context) {
84935           var dispatch$1 = dispatch('change');
84936           var items = select(null);
84937
84938           var _tags;
84939
84940           function access(selection) {
84941             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84942             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84943             var list = wrap.selectAll('ul').data([0]);
84944             list = list.enter().append('ul').attr('class', 'rows').merge(list);
84945             items = list.selectAll('li').data(field.keys); // Enter
84946
84947             var enter = items.enter().append('li').attr('class', function (d) {
84948               return 'labeled-input preset-access-' + d;
84949             });
84950             enter.append('span').attr('class', 'label preset-label-access').attr('for', function (d) {
84951               return 'preset-input-access-' + d;
84952             }).html(function (d) {
84953               return field.t.html('types.' + d);
84954             });
84955             enter.append('div').attr('class', 'preset-input-access-wrap').append('input').attr('type', 'text').attr('class', function (d) {
84956               return 'preset-input-access preset-input-access-' + d;
84957             }).call(utilNoAuto).each(function (d) {
84958               select(this).call(uiCombobox(context, 'access-' + d).data(access.options(d)));
84959             }); // Update
84960
84961             items = items.merge(enter);
84962             wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
84963           }
84964
84965           function change(d3_event, d) {
84966             var tag = {};
84967             var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
84968
84969             if (!value && typeof _tags[d] !== 'string') return;
84970             tag[d] = value || undefined;
84971             dispatch$1.call('change', this, tag);
84972           }
84973
84974           access.options = function (type) {
84975             var options = ['no', 'permissive', 'private', 'permit', 'destination'];
84976
84977             if (type !== 'access') {
84978               options.unshift('yes');
84979               options.push('designated');
84980
84981               if (type === 'bicycle') {
84982                 options.push('dismount');
84983               }
84984             }
84985
84986             return options.map(function (option) {
84987               return {
84988                 title: field.t('options.' + option + '.description'),
84989                 value: option
84990               };
84991             });
84992           };
84993
84994           var placeholdersByHighway = {
84995             footway: {
84996               foot: 'designated',
84997               motor_vehicle: 'no'
84998             },
84999             steps: {
85000               foot: 'yes',
85001               motor_vehicle: 'no',
85002               bicycle: 'no',
85003               horse: 'no'
85004             },
85005             pedestrian: {
85006               foot: 'yes',
85007               motor_vehicle: 'no'
85008             },
85009             cycleway: {
85010               motor_vehicle: 'no',
85011               bicycle: 'designated'
85012             },
85013             bridleway: {
85014               motor_vehicle: 'no',
85015               horse: 'designated'
85016             },
85017             path: {
85018               foot: 'yes',
85019               motor_vehicle: 'no',
85020               bicycle: 'yes',
85021               horse: 'yes'
85022             },
85023             motorway: {
85024               foot: 'no',
85025               motor_vehicle: 'yes',
85026               bicycle: 'no',
85027               horse: 'no'
85028             },
85029             trunk: {
85030               motor_vehicle: 'yes'
85031             },
85032             primary: {
85033               foot: 'yes',
85034               motor_vehicle: 'yes',
85035               bicycle: 'yes',
85036               horse: 'yes'
85037             },
85038             secondary: {
85039               foot: 'yes',
85040               motor_vehicle: 'yes',
85041               bicycle: 'yes',
85042               horse: 'yes'
85043             },
85044             tertiary: {
85045               foot: 'yes',
85046               motor_vehicle: 'yes',
85047               bicycle: 'yes',
85048               horse: 'yes'
85049             },
85050             residential: {
85051               foot: 'yes',
85052               motor_vehicle: 'yes',
85053               bicycle: 'yes',
85054               horse: 'yes'
85055             },
85056             unclassified: {
85057               foot: 'yes',
85058               motor_vehicle: 'yes',
85059               bicycle: 'yes',
85060               horse: 'yes'
85061             },
85062             service: {
85063               foot: 'yes',
85064               motor_vehicle: 'yes',
85065               bicycle: 'yes',
85066               horse: 'yes'
85067             },
85068             motorway_link: {
85069               foot: 'no',
85070               motor_vehicle: 'yes',
85071               bicycle: 'no',
85072               horse: 'no'
85073             },
85074             trunk_link: {
85075               motor_vehicle: 'yes'
85076             },
85077             primary_link: {
85078               foot: 'yes',
85079               motor_vehicle: 'yes',
85080               bicycle: 'yes',
85081               horse: 'yes'
85082             },
85083             secondary_link: {
85084               foot: 'yes',
85085               motor_vehicle: 'yes',
85086               bicycle: 'yes',
85087               horse: 'yes'
85088             },
85089             tertiary_link: {
85090               foot: 'yes',
85091               motor_vehicle: 'yes',
85092               bicycle: 'yes',
85093               horse: 'yes'
85094             }
85095           };
85096
85097           access.tags = function (tags) {
85098             _tags = tags;
85099             utilGetSetValue(items.selectAll('.preset-input-access'), function (d) {
85100               return typeof tags[d] === 'string' ? tags[d] : '';
85101             }).classed('mixed', function (d) {
85102               return tags[d] && Array.isArray(tags[d]);
85103             }).attr('title', function (d) {
85104               return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join('\n');
85105             }).attr('placeholder', function (d) {
85106               if (tags[d] && Array.isArray(tags[d])) {
85107                 return _t('inspector.multiple_values');
85108               }
85109
85110               if (d === 'access') {
85111                 return 'yes';
85112               }
85113
85114               if (tags.access && typeof tags.access === 'string') {
85115                 return tags.access;
85116               }
85117
85118               if (tags.highway) {
85119                 if (typeof tags.highway === 'string') {
85120                   if (placeholdersByHighway[tags.highway] && placeholdersByHighway[tags.highway][d]) {
85121                     return placeholdersByHighway[tags.highway][d];
85122                   }
85123                 } else {
85124                   var impliedAccesses = tags.highway.filter(Boolean).map(function (highwayVal) {
85125                     return placeholdersByHighway[highwayVal] && placeholdersByHighway[highwayVal][d];
85126                   }).filter(Boolean);
85127
85128                   if (impliedAccesses.length === tags.highway.length && new Set(impliedAccesses).size === 1) {
85129                     // if all the highway values have the same implied access for this type then use that
85130                     return impliedAccesses[0];
85131                   }
85132                 }
85133               }
85134
85135               return field.placeholder();
85136             });
85137           };
85138
85139           access.focus = function () {
85140             items.selectAll('.preset-input-access').node().focus();
85141           };
85142
85143           return utilRebind(access, dispatch$1, 'on');
85144         }
85145
85146         function uiFieldAddress(field, context) {
85147           var dispatch$1 = dispatch('change');
85148
85149           var _selection = select(null);
85150
85151           var _wrap = select(null);
85152
85153           var addrField = _mainPresetIndex.field('address'); // needed for placeholder strings
85154
85155           var _entityIDs = [];
85156
85157           var _tags;
85158
85159           var _countryCode;
85160
85161           var _addressFormats = [{
85162             format: [['housenumber', 'street'], ['city', 'postcode']]
85163           }];
85164           _mainFileFetcher.get('address_formats').then(function (d) {
85165             _addressFormats = d;
85166
85167             if (!_selection.empty()) {
85168               _selection.call(address);
85169             }
85170           })["catch"](function () {
85171             /* ignore */
85172           });
85173
85174           function getNearStreets() {
85175             var extent = combinedEntityExtent();
85176             var l = extent.center();
85177             var box = geoExtent(l).padByMeters(200);
85178             var streets = context.history().intersects(box).filter(isAddressable).map(function (d) {
85179               var loc = context.projection([(extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2]);
85180               var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
85181               return {
85182                 title: d.tags.name,
85183                 value: d.tags.name,
85184                 dist: choice.distance
85185               };
85186             }).sort(function (a, b) {
85187               return a.dist - b.dist;
85188             });
85189             return utilArrayUniqBy(streets, 'value');
85190
85191             function isAddressable(d) {
85192               return d.tags.highway && d.tags.name && d.type === 'way';
85193             }
85194           }
85195
85196           function getNearCities() {
85197             var extent = combinedEntityExtent();
85198             var l = extent.center();
85199             var box = geoExtent(l).padByMeters(200);
85200             var cities = context.history().intersects(box).filter(isAddressable).map(function (d) {
85201               return {
85202                 title: d.tags['addr:city'] || d.tags.name,
85203                 value: d.tags['addr:city'] || d.tags.name,
85204                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
85205               };
85206             }).sort(function (a, b) {
85207               return a.dist - b.dist;
85208             });
85209             return utilArrayUniqBy(cities, 'value');
85210
85211             function isAddressable(d) {
85212               if (d.tags.name) {
85213                 if (d.tags.admin_level === '8' && d.tags.boundary === 'administrative') return true;
85214                 if (d.tags.border_type === 'city') return true;
85215                 if (d.tags.place === 'city' || d.tags.place === 'town' || d.tags.place === 'village') return true;
85216               }
85217
85218               if (d.tags['addr:city']) return true;
85219               return false;
85220             }
85221           }
85222
85223           function getNearValues(key) {
85224             var extent = combinedEntityExtent();
85225             var l = extent.center();
85226             var box = geoExtent(l).padByMeters(200);
85227             var results = context.history().intersects(box).filter(function hasTag(d) {
85228               return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
85229             }).map(function (d) {
85230               return {
85231                 title: d.tags[key],
85232                 value: d.tags[key],
85233                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
85234               };
85235             }).sort(function (a, b) {
85236               return a.dist - b.dist;
85237             });
85238             return utilArrayUniqBy(results, 'value');
85239           }
85240
85241           function updateForCountryCode() {
85242             if (!_countryCode) return;
85243             var addressFormat;
85244
85245             for (var i = 0; i < _addressFormats.length; i++) {
85246               var format = _addressFormats[i];
85247
85248               if (!format.countryCodes) {
85249                 addressFormat = format; // choose the default format, keep going
85250               } else if (format.countryCodes.indexOf(_countryCode) !== -1) {
85251                 addressFormat = format; // choose the country format, stop here
85252
85253                 break;
85254               }
85255             }
85256
85257             var dropdowns = addressFormat.dropdowns || ['city', 'county', 'country', 'district', 'hamlet', 'neighbourhood', 'place', 'postcode', 'province', 'quarter', 'state', 'street', 'subdistrict', 'suburb'];
85258             var widths = addressFormat.widths || {
85259               housenumber: 1 / 3,
85260               street: 2 / 3,
85261               city: 2 / 3,
85262               state: 1 / 4,
85263               postcode: 1 / 3
85264             };
85265
85266             function row(r) {
85267               // Normalize widths.
85268               var total = r.reduce(function (sum, key) {
85269                 return sum + (widths[key] || 0.5);
85270               }, 0);
85271               return r.map(function (key) {
85272                 return {
85273                   id: key,
85274                   width: (widths[key] || 0.5) / total
85275                 };
85276               });
85277             }
85278
85279             var rows = _wrap.selectAll('.addr-row').data(addressFormat.format, function (d) {
85280               return d.toString();
85281             });
85282
85283             rows.exit().remove();
85284             rows.enter().append('div').attr('class', 'addr-row').selectAll('input').data(row).enter().append('input').property('type', 'text').call(updatePlaceholder).attr('class', function (d) {
85285               return 'addr-' + d.id;
85286             }).call(utilNoAuto).each(addDropdown).style('width', function (d) {
85287               return d.width * 100 + '%';
85288             });
85289
85290             function addDropdown(d) {
85291               if (dropdowns.indexOf(d.id) === -1) return; // not a dropdown
85292
85293               var nearValues = d.id === 'street' ? getNearStreets : d.id === 'city' ? getNearCities : getNearValues;
85294               select(this).call(uiCombobox(context, 'address-' + d.id).minItems(1).caseSensitive(true).fetcher(function (value, callback) {
85295                 callback(nearValues('addr:' + d.id));
85296               }));
85297             }
85298
85299             _wrap.selectAll('input').on('blur', change()).on('change', change());
85300
85301             _wrap.selectAll('input:not(.combobox-input)').on('input', change(true));
85302
85303             if (_tags) updateTags(_tags);
85304           }
85305
85306           function address(selection) {
85307             _selection = selection;
85308             _wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85309             _wrap = _wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(_wrap);
85310             var extent = combinedEntityExtent();
85311
85312             if (extent) {
85313               var countryCode;
85314
85315               if (context.inIntro()) {
85316                 // localize the address format for the walkthrough
85317                 countryCode = _t('intro.graph.countrycode');
85318               } else {
85319                 var center = extent.center();
85320                 countryCode = iso1A2Code(center);
85321               }
85322
85323               if (countryCode) {
85324                 _countryCode = countryCode.toLowerCase();
85325                 updateForCountryCode();
85326               }
85327             }
85328           }
85329
85330           function change(onInput) {
85331             return function () {
85332               var tags = {};
85333
85334               _wrap.selectAll('input').each(function (subfield) {
85335                 var key = field.key + ':' + subfield.id;
85336                 var value = this.value;
85337                 if (!onInput) value = context.cleanTagValue(value); // don't override multiple values with blank string
85338
85339                 if (Array.isArray(_tags[key]) && !value) return;
85340                 tags[key] = value || undefined;
85341               });
85342
85343               dispatch$1.call('change', this, tags, onInput);
85344             };
85345           }
85346
85347           function updatePlaceholder(inputSelection) {
85348             return inputSelection.attr('placeholder', function (subfield) {
85349               if (_tags && Array.isArray(_tags[field.key + ':' + subfield.id])) {
85350                 return _t('inspector.multiple_values');
85351               }
85352
85353               if (_countryCode) {
85354                 var localkey = subfield.id + '!' + _countryCode;
85355                 var tkey = addrField.strings.placeholders[localkey] ? localkey : subfield.id;
85356                 return addrField.t('placeholders.' + tkey);
85357               }
85358             });
85359           }
85360
85361           function updateTags(tags) {
85362             utilGetSetValue(_wrap.selectAll('input'), function (subfield) {
85363               var val = tags[field.key + ':' + subfield.id];
85364               return typeof val === 'string' ? val : '';
85365             }).attr('title', function (subfield) {
85366               var val = tags[field.key + ':' + subfield.id];
85367               return val && Array.isArray(val) && val.filter(Boolean).join('\n');
85368             }).classed('mixed', function (subfield) {
85369               return Array.isArray(tags[field.key + ':' + subfield.id]);
85370             }).call(updatePlaceholder);
85371           }
85372
85373           function combinedEntityExtent() {
85374             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
85375           }
85376
85377           address.entityIDs = function (val) {
85378             if (!arguments.length) return _entityIDs;
85379             _entityIDs = val;
85380             return address;
85381           };
85382
85383           address.tags = function (tags) {
85384             _tags = tags;
85385             updateTags(tags);
85386           };
85387
85388           address.focus = function () {
85389             var node = _wrap.selectAll('input').node();
85390
85391             if (node) node.focus();
85392           };
85393
85394           return utilRebind(address, dispatch$1, 'on');
85395         }
85396
85397         function uiFieldCycleway(field, context) {
85398           var dispatch$1 = dispatch('change');
85399           var items = select(null);
85400           var wrap = select(null);
85401
85402           var _tags;
85403
85404           function cycleway(selection) {
85405             function stripcolon(s) {
85406               return s.replace(':', '');
85407             }
85408
85409             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85410             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85411             var div = wrap.selectAll('ul').data([0]);
85412             div = div.enter().append('ul').attr('class', 'rows').merge(div);
85413             var keys = ['cycleway:left', 'cycleway:right'];
85414             items = div.selectAll('li').data(keys);
85415             var enter = items.enter().append('li').attr('class', function (d) {
85416               return 'labeled-input preset-cycleway-' + stripcolon(d);
85417             });
85418             enter.append('span').attr('class', 'label preset-label-cycleway').attr('for', function (d) {
85419               return 'preset-input-cycleway-' + stripcolon(d);
85420             }).html(function (d) {
85421               return field.t.html('types.' + d);
85422             });
85423             enter.append('div').attr('class', 'preset-input-cycleway-wrap').append('input').attr('type', 'text').attr('class', function (d) {
85424               return 'preset-input-cycleway preset-input-' + stripcolon(d);
85425             }).call(utilNoAuto).each(function (d) {
85426               select(this).call(uiCombobox(context, 'cycleway-' + stripcolon(d)).data(cycleway.options(d)));
85427             });
85428             items = items.merge(enter); // Update
85429
85430             wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
85431           }
85432
85433           function change(d3_event, key) {
85434             var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
85435
85436             if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
85437
85438             if (newValue === 'none' || newValue === '') {
85439               newValue = undefined;
85440             }
85441
85442             var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left';
85443             var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey];
85444
85445             if (otherValue && Array.isArray(otherValue)) {
85446               // we must always have an explicit value for comparison
85447               otherValue = otherValue[0];
85448             }
85449
85450             if (otherValue === 'none' || otherValue === '') {
85451               otherValue = undefined;
85452             }
85453
85454             var tag = {}; // If the left and right tags match, use the cycleway tag to tag both
85455             // sides the same way
85456
85457             if (newValue === otherValue) {
85458               tag = {
85459                 cycleway: newValue,
85460                 'cycleway:left': undefined,
85461                 'cycleway:right': undefined
85462               };
85463             } else {
85464               // Always set both left and right as changing one can affect the other
85465               tag = {
85466                 cycleway: undefined
85467               };
85468               tag[key] = newValue;
85469               tag[otherKey] = otherValue;
85470             }
85471
85472             dispatch$1.call('change', this, tag);
85473           }
85474
85475           cycleway.options = function () {
85476             return Object.keys(field.strings.options).map(function (option) {
85477               return {
85478                 title: field.t('options.' + option + '.description'),
85479                 value: option
85480               };
85481             });
85482           };
85483
85484           cycleway.tags = function (tags) {
85485             _tags = tags; // If cycleway is set, use that instead of individual values
85486
85487             var commonValue = typeof tags.cycleway === 'string' && tags.cycleway;
85488             utilGetSetValue(items.selectAll('.preset-input-cycleway'), function (d) {
85489               if (commonValue) return commonValue;
85490               return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : '';
85491             }).attr('title', function (d) {
85492               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
85493                 var vals = [];
85494
85495                 if (Array.isArray(tags.cycleway)) {
85496                   vals = vals.concat(tags.cycleway);
85497                 }
85498
85499                 if (Array.isArray(tags[d])) {
85500                   vals = vals.concat(tags[d]);
85501                 }
85502
85503                 return vals.filter(Boolean).join('\n');
85504               }
85505
85506               return null;
85507             }).attr('placeholder', function (d) {
85508               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
85509                 return _t('inspector.multiple_values');
85510               }
85511
85512               return field.placeholder();
85513             }).classed('mixed', function (d) {
85514               return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
85515             });
85516           };
85517
85518           cycleway.focus = function () {
85519             var node = wrap.selectAll('input').node();
85520             if (node) node.focus();
85521           };
85522
85523           return utilRebind(cycleway, dispatch$1, 'on');
85524         }
85525
85526         function uiFieldLanes(field, context) {
85527           var dispatch$1 = dispatch('change');
85528           var LANE_WIDTH = 40;
85529           var LANE_HEIGHT = 200;
85530           var _entityIDs = [];
85531
85532           function lanes(selection) {
85533             var lanesData = context.entity(_entityIDs[0]).lanes();
85534
85535             if (!context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
85536               selection.call(lanes.off);
85537               return;
85538             }
85539
85540             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85541             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85542             var surface = wrap.selectAll('.surface').data([0]);
85543             var d = utilGetDimensions(wrap);
85544             var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
85545             surface = surface.enter().append('svg').attr('width', d[0]).attr('height', 300).attr('class', 'surface').merge(surface);
85546             var lanesSelection = surface.selectAll('.lanes').data([0]);
85547             lanesSelection = lanesSelection.enter().append('g').attr('class', 'lanes').merge(lanesSelection);
85548             lanesSelection.attr('transform', function () {
85549               return 'translate(' + freeSpace / 2 + ', 0)';
85550             });
85551             var lane = lanesSelection.selectAll('.lane').data(lanesData.lanes);
85552             lane.exit().remove();
85553             var enter = lane.enter().append('g').attr('class', 'lane');
85554             enter.append('g').append('rect').attr('y', 50).attr('width', LANE_WIDTH).attr('height', LANE_HEIGHT);
85555             enter.append('g').attr('class', 'forward').append('text').attr('y', 40).attr('x', 14).html('▲');
85556             enter.append('g').attr('class', 'bothways').append('text').attr('y', 40).attr('x', 14).html('▲▼');
85557             enter.append('g').attr('class', 'backward').append('text').attr('y', 40).attr('x', 14).html('▼');
85558             lane = lane.merge(enter);
85559             lane.attr('transform', function (d) {
85560               return 'translate(' + LANE_WIDTH * d.index * 1.5 + ', 0)';
85561             });
85562             lane.select('.forward').style('visibility', function (d) {
85563               return d.direction === 'forward' ? 'visible' : 'hidden';
85564             });
85565             lane.select('.bothways').style('visibility', function (d) {
85566               return d.direction === 'bothways' ? 'visible' : 'hidden';
85567             });
85568             lane.select('.backward').style('visibility', function (d) {
85569               return d.direction === 'backward' ? 'visible' : 'hidden';
85570             });
85571           }
85572
85573           lanes.entityIDs = function (val) {
85574             _entityIDs = val;
85575           };
85576
85577           lanes.tags = function () {};
85578
85579           lanes.focus = function () {};
85580
85581           lanes.off = function () {};
85582
85583           return utilRebind(lanes, dispatch$1, 'on');
85584         }
85585         uiFieldLanes.supportsMultiselection = false;
85586
85587         var _languagesArray = [];
85588         function uiFieldLocalized(field, context) {
85589           var dispatch$1 = dispatch('change', 'input');
85590           var wikipedia = services.wikipedia;
85591           var input = select(null);
85592           var localizedInputs = select(null);
85593
85594           var _countryCode;
85595
85596           var _tags; // A concern here in switching to async data means that _languagesArray will not
85597           // be available the first time through, so things like the fetchers and
85598           // the language() function will not work immediately.
85599
85600
85601           _mainFileFetcher.get('languages').then(loadLanguagesArray)["catch"](function () {
85602             /* ignore */
85603           });
85604           var _territoryLanguages = {};
85605           _mainFileFetcher.get('territory_languages').then(function (d) {
85606             _territoryLanguages = d;
85607           })["catch"](function () {
85608             /* ignore */
85609           });
85610           var allSuggestions = _mainPresetIndex.collection.filter(function (p) {
85611             return p.suggestion === true;
85612           }); // reuse these combos
85613
85614           var langCombo = uiCombobox(context, 'localized-lang').fetcher(fetchLanguages).minItems(0);
85615           var brandCombo = uiCombobox(context, 'localized-brand').canAutocomplete(false).minItems(1);
85616
85617           var _selection = select(null);
85618
85619           var _multilingual = [];
85620
85621           var _buttonTip = uiTooltip().title(_t.html('translate.translate')).placement('left');
85622
85623           var _wikiTitles;
85624
85625           var _entityIDs = [];
85626
85627           function loadLanguagesArray(dataLanguages) {
85628             if (_languagesArray.length !== 0) return; // some conversion is needed to ensure correct OSM tags are used
85629
85630             var replacements = {
85631               sr: 'sr-Cyrl',
85632               // in OSM, `sr` implies Cyrillic
85633               'sr-Cyrl': false // `sr-Cyrl` isn't used in OSM
85634
85635             };
85636
85637             for (var code in dataLanguages) {
85638               if (replacements[code] === false) continue;
85639               var metaCode = code;
85640               if (replacements[code]) metaCode = replacements[code];
85641
85642               _languagesArray.push({
85643                 localName: _mainLocalizer.languageName(metaCode, {
85644                   localOnly: true
85645                 }),
85646                 nativeName: dataLanguages[metaCode].nativeName,
85647                 code: code,
85648                 label: _mainLocalizer.languageName(metaCode)
85649               });
85650             }
85651           }
85652
85653           function calcLocked() {
85654             // only lock the Name field
85655             var isLocked = field.id === 'name' && _entityIDs.length && // lock the field if any feature needs it
85656             _entityIDs.some(function (entityID) {
85657               var entity = context.graph().hasEntity(entityID);
85658               if (!entity) return false;
85659
85660               var original = context.graph().base().entities[_entityIDs[0]];
85661
85662               var hasOriginalName = original && entity.tags.name && entity.tags.name === original.tags.name; // if the name was already edited manually then allow further editing
85663
85664               if (!hasOriginalName) return false; // features linked to Wikidata are likely important and should be protected
85665
85666               if (entity.tags.wikidata) return true; // assume the name has already been confirmed if its source has been researched
85667
85668               if (entity.tags['name:etymology:wikidata']) return true;
85669               var preset = _mainPresetIndex.match(entity, context.graph());
85670               var isSuggestion = preset && preset.suggestion;
85671               var showsBrand = preset && preset.originalFields.filter(function (d) {
85672                 return d.id === 'brand';
85673               }).length; // protect standardized brand names
85674
85675               return isSuggestion && !showsBrand;
85676             });
85677
85678             field.locked(isLocked);
85679           } // update _multilingual, maintaining the existing order
85680
85681
85682           function calcMultilingual(tags) {
85683             var existingLangsOrdered = _multilingual.map(function (item) {
85684               return item.lang;
85685             });
85686
85687             var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
85688
85689             for (var k in tags) {
85690               var m = k.match(/^(.*):([a-zA-Z_-]+)$/);
85691
85692               if (m && m[1] === field.key && m[2]) {
85693                 var item = {
85694                   lang: m[2],
85695                   value: tags[k]
85696                 };
85697
85698                 if (existingLangs.has(item.lang)) {
85699                   // update the value
85700                   _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
85701                   existingLangs["delete"](item.lang);
85702                 } else {
85703                   _multilingual.push(item);
85704                 }
85705               }
85706             }
85707
85708             _multilingual = _multilingual.filter(function (item) {
85709               return !item.lang || !existingLangs.has(item.lang);
85710             });
85711           }
85712
85713           function localized(selection) {
85714             _selection = selection;
85715             calcLocked();
85716             var isLocked = field.locked();
85717             var singularEntity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85718             var preset = singularEntity && _mainPresetIndex.match(singularEntity, context.graph());
85719             var wrap = selection.selectAll('.form-field-input-wrap').data([0]); // enter/update
85720
85721             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85722             input = wrap.selectAll('.localized-main').data([0]); // enter/update
85723
85724             input = input.enter().append('input').attr('type', 'text').attr('id', field.domId).attr('class', 'localized-main').call(utilNoAuto).merge(input);
85725
85726             if (preset && field.id === 'name') {
85727               var pTag = preset.id.split('/', 2);
85728               var pKey = pTag[0];
85729               var pValue = pTag[1];
85730
85731               if (!preset.suggestion) {
85732                 // Not a suggestion preset - Add a suggestions dropdown if it makes sense to.
85733                 // This code attempts to determine if the matched preset is the
85734                 // kind of preset that even can benefit from name suggestions..
85735                 // - true = shops, cafes, hotels, etc. (also generic and fallback presets)
85736                 // - false = churches, parks, hospitals, etc. (things not in the index)
85737                 var isFallback = preset.isFallback();
85738                 var goodSuggestions = allSuggestions.filter(function (s) {
85739                   if (isFallback) return true;
85740                   var sTag = s.id.split('/', 2);
85741                   var sKey = sTag[0];
85742                   var sValue = sTag[1];
85743                   return pKey === sKey && (!pValue || pValue === sValue);
85744                 }); // Show the suggestions.. If the user picks one, change the tags..
85745
85746                 if (allSuggestions.length && goodSuggestions.length) {
85747                   input.on('blur.localized', checkBrandOnBlur).call(brandCombo.fetcher(fetchBrandNames(preset, allSuggestions)).on('accept', acceptBrand).on('cancel', cancelBrand));
85748                 }
85749               }
85750             }
85751
85752             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
85753             var translateButton = wrap.selectAll('.localized-add').data([0]);
85754             translateButton = translateButton.enter().append('button').attr('class', 'localized-add form-field-button').call(svgIcon('#iD-icon-plus')).merge(translateButton);
85755             translateButton.classed('disabled', !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on('click', addNew);
85756
85757             if (_tags && !_multilingual.length) {
85758               calcMultilingual(_tags);
85759             }
85760
85761             localizedInputs = selection.selectAll('.localized-multilingual').data([0]);
85762             localizedInputs = localizedInputs.enter().append('div').attr('class', 'localized-multilingual').merge(localizedInputs);
85763             localizedInputs.call(renderMultilingual);
85764             localizedInputs.selectAll('button, input').classed('disabled', !!isLocked).attr('readonly', isLocked || null); // We are not guaranteed to get an `accept` or `cancel` when blurring the field.
85765             // (This can happen if the user actives the combo, arrows down, and then clicks off to blur)
85766             // So compare the current field value against the suggestions one last time.
85767
85768             function checkBrandOnBlur() {
85769               var latest = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85770               if (!latest) return; // deleting the entity blurred the field?
85771
85772               var preset = _mainPresetIndex.match(latest, context.graph());
85773               if (preset && preset.suggestion) return; // already accepted
85774
85775               var name = utilGetSetValue(input).trim();
85776               var matched = allSuggestions.filter(function (s) {
85777                 return name === s.name();
85778               });
85779
85780               if (matched.length === 1) {
85781                 acceptBrand({
85782                   suggestion: matched[0]
85783                 });
85784               } else {
85785                 cancelBrand();
85786               }
85787             }
85788
85789             function acceptBrand(d) {
85790               var entity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85791
85792               if (!d || !entity) {
85793                 cancelBrand();
85794                 return;
85795               }
85796
85797               var tags = entity.tags;
85798               var geometry = entity.geometry(context.graph());
85799               var removed = preset.unsetTags(tags, geometry);
85800
85801               for (var k in tags) {
85802                 tags[k] = removed[k]; // set removed tags to `undefined`
85803               }
85804
85805               tags = d.suggestion.setTags(tags, geometry);
85806               utilGetSetValue(input, tags.name);
85807               dispatch$1.call('change', this, tags);
85808             } // user hit escape
85809
85810
85811             function cancelBrand() {
85812               var name = utilGetSetValue(input);
85813               dispatch$1.call('change', this, {
85814                 name: name
85815               });
85816             }
85817
85818             function fetchBrandNames(preset, suggestions) {
85819               var pTag = preset.id.split('/', 2);
85820               var pKey = pTag[0];
85821               var pValue = pTag[1];
85822               return function (value, callback) {
85823                 var results = [];
85824
85825                 if (value && value.length > 2) {
85826                   for (var i = 0; i < suggestions.length; i++) {
85827                     var s = suggestions[i]; // don't suggest brands from incompatible countries
85828
85829                     if (_countryCode && s.countryCodes && s.countryCodes.indexOf(_countryCode) === -1) continue;
85830                     var sTag = s.id.split('/', 2);
85831                     var sKey = sTag[0];
85832                     var sValue = sTag[1];
85833                     var subtitle = s.subtitle();
85834                     var name = s.name();
85835                     if (subtitle) name += ' – ' + subtitle;
85836                     var dist = utilEditDistance(value, name.substring(0, value.length));
85837                     var matchesPreset = pKey === sKey && (!pValue || pValue === sValue);
85838
85839                     if (dist < 1 || matchesPreset && dist < 3) {
85840                       var obj = {
85841                         value: s.name(),
85842                         title: name,
85843                         display: s.nameLabel() + (subtitle ? ' – ' + s.subtitleLabel() : ''),
85844                         suggestion: s,
85845                         dist: dist + (matchesPreset ? 0 : 1) // penalize if not matched preset
85846
85847                       };
85848                       results.push(obj);
85849                     }
85850                   }
85851
85852                   results.sort(function (a, b) {
85853                     return a.dist - b.dist;
85854                   });
85855                 }
85856
85857                 results = results.slice(0, 10);
85858                 callback(results);
85859               };
85860             }
85861
85862             function addNew(d3_event) {
85863               d3_event.preventDefault();
85864               if (field.locked()) return;
85865               var defaultLang = _mainLocalizer.languageCode().toLowerCase();
85866
85867               var langExists = _multilingual.find(function (datum) {
85868                 return datum.lang === defaultLang;
85869               });
85870
85871               var isLangEn = defaultLang.indexOf('en') > -1;
85872
85873               if (isLangEn || langExists) {
85874                 defaultLang = '';
85875                 langExists = _multilingual.find(function (datum) {
85876                   return datum.lang === defaultLang;
85877                 });
85878               }
85879
85880               if (!langExists) {
85881                 // prepend the value so it appears at the top
85882                 _multilingual.unshift({
85883                   lang: defaultLang,
85884                   value: ''
85885                 });
85886
85887                 localizedInputs.call(renderMultilingual);
85888               }
85889             }
85890
85891             function change(onInput) {
85892               return function (d3_event) {
85893                 if (field.locked()) {
85894                   d3_event.preventDefault();
85895                   return;
85896                 }
85897
85898                 var val = utilGetSetValue(select(this));
85899                 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
85900
85901                 if (!val && Array.isArray(_tags[field.key])) return;
85902                 var t = {};
85903                 t[field.key] = val || undefined;
85904                 dispatch$1.call('change', this, t, onInput);
85905               };
85906             }
85907           }
85908
85909           function key(lang) {
85910             return field.key + ':' + lang;
85911           }
85912
85913           function changeLang(d3_event, d) {
85914             var tags = {}; // make sure unrecognized suffixes are lowercase - #7156
85915
85916             var lang = utilGetSetValue(select(this)).toLowerCase();
85917
85918             var language = _languagesArray.find(function (d) {
85919               return d.label.toLowerCase() === lang || d.localName && d.localName.toLowerCase() === lang || d.nativeName && d.nativeName.toLowerCase() === lang;
85920             });
85921
85922             if (language) lang = language.code;
85923
85924             if (d.lang && d.lang !== lang) {
85925               tags[key(d.lang)] = undefined;
85926             }
85927
85928             var newKey = lang && context.cleanTagKey(key(lang));
85929             var value = utilGetSetValue(select(this.parentNode).selectAll('.localized-value'));
85930
85931             if (newKey && value) {
85932               tags[newKey] = value;
85933             } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
85934               tags[newKey] = _wikiTitles[d.lang];
85935             }
85936
85937             d.lang = lang;
85938             dispatch$1.call('change', this, tags);
85939           }
85940
85941           function changeValue(d3_event, d) {
85942             if (!d.lang) return;
85943             var value = context.cleanTagValue(utilGetSetValue(select(this))) || undefined; // don't override multiple values with blank string
85944
85945             if (!value && Array.isArray(d.value)) return;
85946             var t = {};
85947             t[key(d.lang)] = value;
85948             d.value = value;
85949             dispatch$1.call('change', this, t);
85950           }
85951
85952           function fetchLanguages(value, cb) {
85953             var v = value.toLowerCase(); // show the user's language first
85954
85955             var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
85956
85957             if (_countryCode && _territoryLanguages[_countryCode]) {
85958               langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
85959             }
85960
85961             var langItems = [];
85962             langCodes.forEach(function (code) {
85963               var langItem = _languagesArray.find(function (item) {
85964                 return item.code === code;
85965               });
85966
85967               if (langItem) langItems.push(langItem);
85968             });
85969             langItems = utilArrayUniq(langItems.concat(_languagesArray));
85970             cb(langItems.filter(function (d) {
85971               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;
85972             }).map(function (d) {
85973               return {
85974                 value: d.label
85975               };
85976             }));
85977           }
85978
85979           function renderMultilingual(selection) {
85980             var entries = selection.selectAll('div.entry').data(_multilingual, function (d) {
85981               return d.lang;
85982             });
85983             entries.exit().style('top', '0').style('max-height', '240px').transition().duration(200).style('opacity', '0').style('max-height', '0px').remove();
85984             var entriesEnter = entries.enter().append('div').attr('class', 'entry').each(function (_, index) {
85985               var wrap = select(this);
85986               var domId = utilUniqueDomId(index);
85987               var label = wrap.append('label').attr('class', 'field-label').attr('for', domId);
85988               var text = label.append('span').attr('class', 'label-text');
85989               text.append('span').attr('class', 'label-textvalue').html(_t.html('translate.localized_translation_label'));
85990               text.append('span').attr('class', 'label-textannotation');
85991               label.append('button').attr('class', 'remove-icon-multilingual').on('click', function (d3_event, d) {
85992                 if (field.locked()) return;
85993                 d3_event.preventDefault();
85994
85995                 if (!d.lang || !d.value) {
85996                   _multilingual.splice(index, 1);
85997
85998                   renderMultilingual(selection);
85999                 } else {
86000                   // remove from entity tags
86001                   var t = {};
86002                   t[key(d.lang)] = undefined;
86003                   dispatch$1.call('change', this, t);
86004                 }
86005               }).call(svgIcon('#iD-operation-delete'));
86006               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);
86007               wrap.append('input').attr('type', 'text').attr('class', 'localized-value').on('blur', changeValue).on('change', changeValue);
86008             });
86009             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 () {
86010               select(this).style('max-height', '').style('overflow', 'visible');
86011             });
86012             entries = entries.merge(entriesEnter);
86013             entries.order();
86014             entries.classed('present', function (d) {
86015               return d.lang && d.value;
86016             });
86017             utilGetSetValue(entries.select('.localized-lang'), function (d) {
86018               return _mainLocalizer.languageName(d.lang);
86019             });
86020             utilGetSetValue(entries.select('.localized-value'), function (d) {
86021               return typeof d.value === 'string' ? d.value : '';
86022             }).attr('title', function (d) {
86023               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : null;
86024             }).attr('placeholder', function (d) {
86025               return Array.isArray(d.value) ? _t('inspector.multiple_values') : _t('translate.localized_translation_name');
86026             }).classed('mixed', function (d) {
86027               return Array.isArray(d.value);
86028             });
86029           }
86030
86031           localized.tags = function (tags) {
86032             _tags = tags; // Fetch translations from wikipedia
86033
86034             if (typeof tags.wikipedia === 'string' && !_wikiTitles) {
86035               _wikiTitles = {};
86036               var wm = tags.wikipedia.match(/([^:]+):(.+)/);
86037
86038               if (wm && wm[0] && wm[1]) {
86039                 wikipedia.translations(wm[1], wm[2], function (err, d) {
86040                   if (err || !d) return;
86041                   _wikiTitles = d;
86042                 });
86043               }
86044             }
86045
86046             var isMixed = Array.isArray(tags[field.key]);
86047             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);
86048             calcMultilingual(tags);
86049
86050             _selection.call(localized);
86051           };
86052
86053           localized.focus = function () {
86054             input.node().focus();
86055           };
86056
86057           localized.entityIDs = function (val) {
86058             if (!arguments.length) return _entityIDs;
86059             _entityIDs = val;
86060             _multilingual = [];
86061             loadCountryCode();
86062             return localized;
86063           };
86064
86065           function loadCountryCode() {
86066             var extent = combinedEntityExtent();
86067             var countryCode = extent && iso1A2Code(extent.center());
86068             _countryCode = countryCode && countryCode.toLowerCase();
86069           }
86070
86071           function combinedEntityExtent() {
86072             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
86073           }
86074
86075           return utilRebind(localized, dispatch$1, 'on');
86076         }
86077
86078         function uiFieldMaxspeed(field, context) {
86079           var dispatch$1 = dispatch('change');
86080           var unitInput = select(null);
86081           var input = select(null);
86082           var _entityIDs = [];
86083
86084           var _tags;
86085
86086           var _isImperial;
86087
86088           var speedCombo = uiCombobox(context, 'maxspeed');
86089           var unitCombo = uiCombobox(context, 'maxspeed-unit').data(['km/h', 'mph'].map(comboValues));
86090           var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
86091           var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
86092
86093           function maxspeed(selection) {
86094             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86095             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86096             input = wrap.selectAll('input.maxspeed-number').data([0]);
86097             input = input.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-number').attr('id', field.domId).call(utilNoAuto).call(speedCombo).merge(input);
86098             input.on('change', change).on('blur', change);
86099             var loc = combinedEntityExtent().center();
86100             _isImperial = roadSpeedUnit(loc) === 'mph';
86101             unitInput = wrap.selectAll('input.maxspeed-unit').data([0]);
86102             unitInput = unitInput.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-unit').call(unitCombo).merge(unitInput);
86103             unitInput.on('blur', changeUnits).on('change', changeUnits);
86104
86105             function changeUnits() {
86106               _isImperial = utilGetSetValue(unitInput) === 'mph';
86107               utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
86108               setUnitSuggestions();
86109               change();
86110             }
86111           }
86112
86113           function setUnitSuggestions() {
86114             speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
86115             utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
86116           }
86117
86118           function comboValues(d) {
86119             return {
86120               value: d.toString(),
86121               title: d.toString()
86122             };
86123           }
86124
86125           function change() {
86126             var tag = {};
86127             var value = utilGetSetValue(input).trim(); // don't override multiple values with blank string
86128
86129             if (!value && Array.isArray(_tags[field.key])) return;
86130
86131             if (!value) {
86132               tag[field.key] = undefined;
86133             } else if (isNaN(value) || !_isImperial) {
86134               tag[field.key] = context.cleanTagValue(value);
86135             } else {
86136               tag[field.key] = context.cleanTagValue(value + ' mph');
86137             }
86138
86139             dispatch$1.call('change', this, tag);
86140           }
86141
86142           maxspeed.tags = function (tags) {
86143             _tags = tags;
86144             var value = tags[field.key];
86145             var isMixed = Array.isArray(value);
86146
86147             if (!isMixed) {
86148               if (value && value.indexOf('mph') >= 0) {
86149                 value = parseInt(value, 10).toString();
86150                 _isImperial = true;
86151               } else if (value) {
86152                 _isImperial = false;
86153               }
86154             }
86155
86156             setUnitSuggestions();
86157             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);
86158           };
86159
86160           maxspeed.focus = function () {
86161             input.node().focus();
86162           };
86163
86164           maxspeed.entityIDs = function (val) {
86165             _entityIDs = val;
86166           };
86167
86168           function combinedEntityExtent() {
86169             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
86170           }
86171
86172           return utilRebind(maxspeed, dispatch$1, 'on');
86173         }
86174
86175         function uiFieldRadio(field, context) {
86176           var dispatch$1 = dispatch('change');
86177           var placeholder = select(null);
86178           var wrap = select(null);
86179           var labels = select(null);
86180           var radios = select(null);
86181           var radioData = (field.options || field.strings && field.strings.options && Object.keys(field.strings.options) || field.keys).slice(); // shallow copy
86182
86183           var typeField;
86184           var layerField;
86185           var _oldType = {};
86186           var _entityIDs = [];
86187
86188           function selectedKey() {
86189             var node = wrap.selectAll('.form-field-input-radio label.active input');
86190             return !node.empty() && node.datum();
86191           }
86192
86193           function radio(selection) {
86194             selection.classed('preset-radio', true);
86195             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86196             var enter = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-radio');
86197             enter.append('span').attr('class', 'placeholder');
86198             wrap = wrap.merge(enter);
86199             placeholder = wrap.selectAll('.placeholder');
86200             labels = wrap.selectAll('label').data(radioData);
86201             enter = labels.enter().append('label');
86202             enter.append('input').attr('type', 'radio').attr('name', field.id).attr('value', function (d) {
86203               return field.t('options.' + d, {
86204                 'default': d
86205               });
86206             }).attr('checked', false);
86207             enter.append('span').html(function (d) {
86208               return field.t.html('options.' + d, {
86209                 'default': d
86210               });
86211             });
86212             labels = labels.merge(enter);
86213             radios = labels.selectAll('input').on('change', changeRadio);
86214           }
86215
86216           function structureExtras(selection, tags) {
86217             var selected = selectedKey() || tags.layer !== undefined;
86218             var type = _mainPresetIndex.field(selected);
86219             var layer = _mainPresetIndex.field('layer');
86220             var showLayer = selected === 'bridge' || selected === 'tunnel' || tags.layer !== undefined;
86221             var extrasWrap = selection.selectAll('.structure-extras-wrap').data(selected ? [0] : []);
86222             extrasWrap.exit().remove();
86223             extrasWrap = extrasWrap.enter().append('div').attr('class', 'structure-extras-wrap').merge(extrasWrap);
86224             var list = extrasWrap.selectAll('ul').data([0]);
86225             list = list.enter().append('ul').attr('class', 'rows').merge(list); // Type
86226
86227             if (type) {
86228               if (!typeField || typeField.id !== selected) {
86229                 typeField = uiField(context, type, _entityIDs, {
86230                   wrap: false
86231                 }).on('change', changeType);
86232               }
86233
86234               typeField.tags(tags);
86235             } else {
86236               typeField = null;
86237             }
86238
86239             var typeItem = list.selectAll('.structure-type-item').data(typeField ? [typeField] : [], function (d) {
86240               return d.id;
86241             }); // Exit
86242
86243             typeItem.exit().remove(); // Enter
86244
86245             var typeEnter = typeItem.enter().insert('li', ':first-child').attr('class', 'labeled-input structure-type-item');
86246             typeEnter.append('span').attr('class', 'label structure-label-type').attr('for', 'preset-input-' + selected).html(_t.html('inspector.radio.structure.type'));
86247             typeEnter.append('div').attr('class', 'structure-input-type-wrap'); // Update
86248
86249             typeItem = typeItem.merge(typeEnter);
86250
86251             if (typeField) {
86252               typeItem.selectAll('.structure-input-type-wrap').call(typeField.render);
86253             } // Layer
86254
86255
86256             if (layer && showLayer) {
86257               if (!layerField) {
86258                 layerField = uiField(context, layer, _entityIDs, {
86259                   wrap: false
86260                 }).on('change', changeLayer);
86261               }
86262
86263               layerField.tags(tags);
86264               field.keys = utilArrayUnion(field.keys, ['layer']);
86265             } else {
86266               layerField = null;
86267               field.keys = field.keys.filter(function (k) {
86268                 return k !== 'layer';
86269               });
86270             }
86271
86272             var layerItem = list.selectAll('.structure-layer-item').data(layerField ? [layerField] : []); // Exit
86273
86274             layerItem.exit().remove(); // Enter
86275
86276             var layerEnter = layerItem.enter().append('li').attr('class', 'labeled-input structure-layer-item');
86277             layerEnter.append('span').attr('class', 'label structure-label-layer').attr('for', 'preset-input-layer').html(_t.html('inspector.radio.structure.layer'));
86278             layerEnter.append('div').attr('class', 'structure-input-layer-wrap'); // Update
86279
86280             layerItem = layerItem.merge(layerEnter);
86281
86282             if (layerField) {
86283               layerItem.selectAll('.structure-input-layer-wrap').call(layerField.render);
86284             }
86285           }
86286
86287           function changeType(t, onInput) {
86288             var key = selectedKey();
86289             if (!key) return;
86290             var val = t[key];
86291
86292             if (val !== 'no') {
86293               _oldType[key] = val;
86294             }
86295
86296             if (field.type === 'structureRadio') {
86297               // remove layer if it should not be set
86298               if (val === 'no' || key !== 'bridge' && key !== 'tunnel' || key === 'tunnel' && val === 'building_passage') {
86299                 t.layer = undefined;
86300               } // add layer if it should be set
86301
86302
86303               if (t.layer === undefined) {
86304                 if (key === 'bridge' && val !== 'no') {
86305                   t.layer = '1';
86306                 }
86307
86308                 if (key === 'tunnel' && val !== 'no' && val !== 'building_passage') {
86309                   t.layer = '-1';
86310                 }
86311               }
86312             }
86313
86314             dispatch$1.call('change', this, t, onInput);
86315           }
86316
86317           function changeLayer(t, onInput) {
86318             if (t.layer === '0') {
86319               t.layer = undefined;
86320             }
86321
86322             dispatch$1.call('change', this, t, onInput);
86323           }
86324
86325           function changeRadio() {
86326             var t = {};
86327             var activeKey;
86328
86329             if (field.key) {
86330               t[field.key] = undefined;
86331             }
86332
86333             radios.each(function (d) {
86334               var active = select(this).property('checked');
86335               if (active) activeKey = d;
86336
86337               if (field.key) {
86338                 if (active) t[field.key] = d;
86339               } else {
86340                 var val = _oldType[activeKey] || 'yes';
86341                 t[d] = active ? val : undefined;
86342               }
86343             });
86344
86345             if (field.type === 'structureRadio') {
86346               if (activeKey === 'bridge') {
86347                 t.layer = '1';
86348               } else if (activeKey === 'tunnel' && t.tunnel !== 'building_passage') {
86349                 t.layer = '-1';
86350               } else {
86351                 t.layer = undefined;
86352               }
86353             }
86354
86355             dispatch$1.call('change', this, t);
86356           }
86357
86358           radio.tags = function (tags) {
86359             radios.property('checked', function (d) {
86360               if (field.key) {
86361                 return tags[field.key] === d;
86362               }
86363
86364               return !!(typeof tags[d] === 'string' && tags[d].toLowerCase() !== 'no');
86365             });
86366
86367             function isMixed(d) {
86368               if (field.key) {
86369                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
86370               }
86371
86372               return Array.isArray(tags[d]);
86373             }
86374
86375             labels.classed('active', function (d) {
86376               if (field.key) {
86377                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
86378               }
86379
86380               return Array.isArray(tags[d]) || !!(tags[d] && tags[d].toLowerCase() !== 'no');
86381             }).classed('mixed', isMixed).attr('title', function (d) {
86382               return isMixed(d) ? _t('inspector.unshared_value_tooltip') : null;
86383             });
86384             var selection = radios.filter(function () {
86385               return this.checked;
86386             });
86387
86388             if (selection.empty()) {
86389               placeholder.html(_t.html('inspector.none'));
86390             } else {
86391               placeholder.html(selection.attr('value'));
86392               _oldType[selection.datum()] = tags[selection.datum()];
86393             }
86394
86395             if (field.type === 'structureRadio') {
86396               // For waterways without a tunnel tag, set 'culvert' as
86397               // the _oldType to default to if the user picks 'tunnel'
86398               if (!!tags.waterway && !_oldType.tunnel) {
86399                 _oldType.tunnel = 'culvert';
86400               }
86401
86402               wrap.call(structureExtras, tags);
86403             }
86404           };
86405
86406           radio.focus = function () {
86407             radios.node().focus();
86408           };
86409
86410           radio.entityIDs = function (val) {
86411             if (!arguments.length) return _entityIDs;
86412             _entityIDs = val;
86413             _oldType = {};
86414             return radio;
86415           };
86416
86417           radio.isAllowed = function () {
86418             return _entityIDs.length === 1;
86419           };
86420
86421           return utilRebind(radio, dispatch$1, 'on');
86422         }
86423
86424         function uiFieldRestrictions(field, context) {
86425           var dispatch$1 = dispatch('change');
86426           var breathe = behaviorBreathe();
86427           corePreferences('turn-restriction-via-way', null); // remove old key
86428
86429           var storedViaWay = corePreferences('turn-restriction-via-way0'); // use new key #6922
86430
86431           var storedDistance = corePreferences('turn-restriction-distance');
86432
86433           var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
86434
86435           var _maxDistance = storedDistance ? +storedDistance : 30;
86436
86437           var _initialized = false;
86438
86439           var _parent = select(null); // the entire field
86440
86441
86442           var _container = select(null); // just the map
86443
86444
86445           var _oldTurns;
86446
86447           var _graph;
86448
86449           var _vertexID;
86450
86451           var _intersection;
86452
86453           var _fromWayID;
86454
86455           var _lastXPos;
86456
86457           function restrictions(selection) {
86458             _parent = selection; // try to reuse the intersection, but always rebuild it if the graph has changed
86459
86460             if (_vertexID && (context.graph() !== _graph || !_intersection)) {
86461               _graph = context.graph();
86462               _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
86463             } // It's possible for there to be no actual intersection here.
86464             // for example, a vertex of two `highway=path`
86465             // In this case, hide the field.
86466
86467
86468             var isOK = _intersection && _intersection.vertices.length && // has vertices
86469             _intersection.vertices // has the vertex that the user selected
86470             .filter(function (vertex) {
86471               return vertex.id === _vertexID;
86472             }).length && _intersection.ways.length > 2 && // has more than 2 ways
86473             _intersection.ways // has more than 1 TO way
86474             .filter(function (way) {
86475               return way.__to;
86476             }).length > 1; // Also hide in the case where
86477
86478             select(selection.node().parentNode).classed('hide', !isOK); // if form field is hidden or has detached from dom, clean up.
86479
86480             if (!isOK || !context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode || !selection.node().parentNode.parentNode) {
86481               selection.call(restrictions.off);
86482               return;
86483             }
86484
86485             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86486             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86487             var container = wrap.selectAll('.restriction-container').data([0]); // enter
86488
86489             var containerEnter = container.enter().append('div').attr('class', 'restriction-container');
86490             containerEnter.append('div').attr('class', 'restriction-help'); // update
86491
86492             _container = containerEnter.merge(container).call(renderViewer);
86493             var controls = wrap.selectAll('.restriction-controls').data([0]); // enter/update
86494
86495             controls.enter().append('div').attr('class', 'restriction-controls-container').append('div').attr('class', 'restriction-controls').merge(controls).call(renderControls);
86496           }
86497
86498           function renderControls(selection) {
86499             var distControl = selection.selectAll('.restriction-distance').data([0]);
86500             distControl.exit().remove();
86501             var distControlEnter = distControl.enter().append('div').attr('class', 'restriction-control restriction-distance');
86502             distControlEnter.append('span').attr('class', 'restriction-control-label restriction-distance-label').html(_t.html('restriction.controls.distance') + ':');
86503             distControlEnter.append('input').attr('class', 'restriction-distance-input').attr('type', 'range').attr('min', '20').attr('max', '50').attr('step', '5');
86504             distControlEnter.append('span').attr('class', 'restriction-distance-text'); // update
86505
86506             selection.selectAll('.restriction-distance-input').property('value', _maxDistance).on('input', function () {
86507               var val = select(this).property('value');
86508               _maxDistance = +val;
86509               _intersection = null;
86510
86511               _container.selectAll('.layer-osm .layer-turns *').remove();
86512
86513               corePreferences('turn-restriction-distance', _maxDistance);
86514
86515               _parent.call(restrictions);
86516             });
86517             selection.selectAll('.restriction-distance-text').html(displayMaxDistance(_maxDistance));
86518             var viaControl = selection.selectAll('.restriction-via-way').data([0]);
86519             viaControl.exit().remove();
86520             var viaControlEnter = viaControl.enter().append('div').attr('class', 'restriction-control restriction-via-way');
86521             viaControlEnter.append('span').attr('class', 'restriction-control-label restriction-via-way-label').html(_t.html('restriction.controls.via') + ':');
86522             viaControlEnter.append('input').attr('class', 'restriction-via-way-input').attr('type', 'range').attr('min', '0').attr('max', '2').attr('step', '1');
86523             viaControlEnter.append('span').attr('class', 'restriction-via-way-text'); // update
86524
86525             selection.selectAll('.restriction-via-way-input').property('value', _maxViaWay).on('input', function () {
86526               var val = select(this).property('value');
86527               _maxViaWay = +val;
86528
86529               _container.selectAll('.layer-osm .layer-turns *').remove();
86530
86531               corePreferences('turn-restriction-via-way0', _maxViaWay);
86532
86533               _parent.call(restrictions);
86534             });
86535             selection.selectAll('.restriction-via-way-text').html(displayMaxVia(_maxViaWay));
86536           }
86537
86538           function renderViewer(selection) {
86539             if (!_intersection) return;
86540             var vgraph = _intersection.graph;
86541             var filter = utilFunctor(true);
86542             var projection = geoRawMercator(); // Reflow warning: `utilGetDimensions` calls `getBoundingClientRect`
86543             // Instead of asking the restriction-container for its dimensions,
86544             //  we can ask the .sidebar, which can have its dimensions cached.
86545             // width: calc as sidebar - padding
86546             // height: hardcoded (from `80_app.css`)
86547             // var d = utilGetDimensions(selection);
86548
86549             var sdims = utilGetDimensions(context.container().select('.sidebar'));
86550             var d = [sdims[0] - 50, 370];
86551             var c = geoVecScale(d, 0.5);
86552             var z = 22;
86553             projection.scale(geoZoomToScale(z)); // Calculate extent of all key vertices
86554
86555             var extent = geoExtent();
86556
86557             for (var i = 0; i < _intersection.vertices.length; i++) {
86558               extent._extend(_intersection.vertices[i].extent());
86559             } // If this is a large intersection, adjust zoom to fit extent
86560
86561
86562             if (_intersection.vertices.length > 1) {
86563               var padding = 180; // in z22 pixels
86564
86565               var tl = projection([extent[0][0], extent[1][1]]);
86566               var br = projection([extent[1][0], extent[0][1]]);
86567               var hFactor = (br[0] - tl[0]) / (d[0] - padding);
86568               var vFactor = (br[1] - tl[1]) / (d[1] - padding);
86569               var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
86570               var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
86571               z = z - Math.max(hZoomDiff, vZoomDiff);
86572               projection.scale(geoZoomToScale(z));
86573             }
86574
86575             var padTop = 35; // reserve top space for hint text
86576
86577             var extentCenter = projection(extent.center());
86578             extentCenter[1] = extentCenter[1] - padTop;
86579             projection.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
86580             var drawLayers = svgLayers(projection, context).only(['osm', 'touch']).dimensions(d);
86581             var drawVertices = svgVertices(projection, context);
86582             var drawLines = svgLines(projection, context);
86583             var drawTurns = svgTurns(projection, context);
86584             var firstTime = selection.selectAll('.surface').empty();
86585             selection.call(drawLayers);
86586             var surface = selection.selectAll('.surface').classed('tr', true);
86587
86588             if (firstTime) {
86589               _initialized = true;
86590               surface.call(breathe);
86591             } // This can happen if we've lowered the detail while a FROM way
86592             // is selected, and that way is no longer part of the intersection.
86593
86594
86595             if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
86596               _fromWayID = null;
86597               _oldTurns = null;
86598             }
86599
86600             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));
86601             surface.on('click.restrictions', click).on('mouseover.restrictions', mouseover);
86602             surface.selectAll('.selected').classed('selected', false);
86603             surface.selectAll('.related').classed('related', false);
86604             var way;
86605
86606             if (_fromWayID) {
86607               way = vgraph.entity(_fromWayID);
86608               surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
86609             }
86610
86611             document.addEventListener('resizeWindow', function () {
86612               utilSetDimensions(_container, null);
86613               redraw(1);
86614             }, false);
86615             updateHints(null);
86616
86617             function click(d3_event) {
86618               surface.call(breathe.off).call(breathe);
86619               var datum = d3_event.target.__data__;
86620               var entity = datum && datum.properties && datum.properties.entity;
86621
86622               if (entity) {
86623                 datum = entity;
86624               }
86625
86626               if (datum instanceof osmWay && (datum.__from || datum.__via)) {
86627                 _fromWayID = datum.id;
86628                 _oldTurns = null;
86629                 redraw();
86630               } else if (datum instanceof osmTurn) {
86631                 var actions, extraActions, turns, i;
86632                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
86633
86634                 if (datum.restrictionID && !datum.direct) {
86635                   return;
86636                 } else if (datum.restrictionID && !datum.only) {
86637                   // NO -> ONLY
86638                   var seen = {};
86639                   var datumOnly = JSON.parse(JSON.stringify(datum)); // deep clone the datum
86640
86641                   datumOnly.only = true; // but change this property
86642
86643                   restrictionType = restrictionType.replace(/^no/, 'only'); // Adding an ONLY restriction should destroy all other direct restrictions from the FROM towards the VIA.
86644                   // We will remember them in _oldTurns, and restore them if the user clicks again.
86645
86646                   turns = _intersection.turns(_fromWayID, 2);
86647                   extraActions = [];
86648                   _oldTurns = [];
86649
86650                   for (i = 0; i < turns.length; i++) {
86651                     var turn = turns[i];
86652                     if (seen[turn.restrictionID]) continue; // avoid deleting the turn twice (#4968, #4928)
86653
86654                     if (turn.direct && turn.path[1] === datum.path[1]) {
86655                       seen[turns[i].restrictionID] = true;
86656                       turn.restrictionType = osmInferRestriction(vgraph, turn, projection);
86657
86658                       _oldTurns.push(turn);
86659
86660                       extraActions.push(actionUnrestrictTurn(turn));
86661                     }
86662                   }
86663
86664                   actions = _intersection.actions.concat(extraActions, [actionRestrictTurn(datumOnly, restrictionType), _t('operations.restriction.annotation.create')]);
86665                 } else if (datum.restrictionID) {
86666                   // ONLY -> Allowed
86667                   // Restore whatever restrictions we might have destroyed by cycling thru the ONLY state.
86668                   // This relies on the assumption that the intersection was already split up when we
86669                   // performed the previous action (NO -> ONLY), so the IDs in _oldTurns shouldn't have changed.
86670                   turns = _oldTurns || [];
86671                   extraActions = [];
86672
86673                   for (i = 0; i < turns.length; i++) {
86674                     if (turns[i].key !== datum.key) {
86675                       extraActions.push(actionRestrictTurn(turns[i], turns[i].restrictionType));
86676                     }
86677                   }
86678
86679                   _oldTurns = null;
86680                   actions = _intersection.actions.concat(extraActions, [actionUnrestrictTurn(datum), _t('operations.restriction.annotation.delete')]);
86681                 } else {
86682                   // Allowed -> NO
86683                   actions = _intersection.actions.concat([actionRestrictTurn(datum, restrictionType), _t('operations.restriction.annotation.create')]);
86684                 }
86685
86686                 context.perform.apply(context, actions); // At this point the datum will be changed, but will have same key..
86687                 // Refresh it and update the help..
86688
86689                 var s = surface.selectAll('.' + datum.key);
86690                 datum = s.empty() ? null : s.datum();
86691                 updateHints(datum);
86692               } else {
86693                 _fromWayID = null;
86694                 _oldTurns = null;
86695                 redraw();
86696               }
86697             }
86698
86699             function mouseover(d3_event) {
86700               var datum = d3_event.target.__data__;
86701               updateHints(datum);
86702             }
86703
86704             _lastXPos = _lastXPos || sdims[0];
86705
86706             function redraw(minChange) {
86707               var xPos = -1;
86708
86709               if (minChange) {
86710                 xPos = utilGetDimensions(context.container().select('.sidebar'))[0];
86711               }
86712
86713               if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
86714                 if (context.hasEntity(_vertexID)) {
86715                   _lastXPos = xPos;
86716
86717                   _container.call(renderViewer);
86718                 }
86719               }
86720             }
86721
86722             function highlightPathsFrom(wayID) {
86723               surface.selectAll('.related').classed('related', false).classed('allow', false).classed('restrict', false).classed('only', false);
86724               surface.selectAll('.' + wayID).classed('related', true);
86725
86726               if (wayID) {
86727                 var turns = _intersection.turns(wayID, _maxViaWay);
86728
86729                 for (var i = 0; i < turns.length; i++) {
86730                   var turn = turns[i];
86731                   var ids = [turn.to.way];
86732                   var klass = turn.no ? 'restrict' : turn.only ? 'only' : 'allow';
86733
86734                   if (turn.only || turns.length === 1) {
86735                     if (turn.via.ways) {
86736                       ids = ids.concat(turn.via.ways);
86737                     }
86738                   } else if (turn.to.way === wayID) {
86739                     continue;
86740                   }
86741
86742                   surface.selectAll(utilEntitySelector(ids)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only');
86743                 }
86744               }
86745             }
86746
86747             function updateHints(datum) {
86748               var help = _container.selectAll('.restriction-help').html('');
86749
86750               var placeholders = {};
86751               ['from', 'via', 'to'].forEach(function (k) {
86752                 placeholders[k] = '<span class="qualifier">' + _t('restriction.help.' + k) + '</span>';
86753               });
86754               var entity = datum && datum.properties && datum.properties.entity;
86755
86756               if (entity) {
86757                 datum = entity;
86758               }
86759
86760               if (_fromWayID) {
86761                 way = vgraph.entity(_fromWayID);
86762                 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
86763               } // Hovering a way
86764
86765
86766               if (datum instanceof osmWay && datum.__from) {
86767                 way = datum;
86768                 highlightPathsFrom(_fromWayID ? null : way.id);
86769                 surface.selectAll('.' + way.id).classed('related', true);
86770                 var clickSelect = !_fromWayID || _fromWayID !== way.id;
86771                 help.append('div') // "Click to select FROM {fromName}." / "FROM {fromName}"
86772                 .html(_t.html('restriction.help.' + (clickSelect ? 'select_from_name' : 'from_name'), {
86773                   from: placeholders.from,
86774                   fromName: displayName(way.id, vgraph)
86775                 })); // Hovering a turn arrow
86776               } else if (datum instanceof osmTurn) {
86777                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
86778                 var turnType = restrictionType.replace(/^(only|no)\_/, '');
86779                 var indirect = datum.direct === false ? _t.html('restriction.help.indirect') : '';
86780                 var klass, turnText, nextText;
86781
86782                 if (datum.no) {
86783                   klass = 'restrict';
86784                   turnText = _t.html('restriction.help.turn.no_' + turnType, {
86785                     indirect: indirect
86786                   });
86787                   nextText = _t.html('restriction.help.turn.only_' + turnType, {
86788                     indirect: ''
86789                   });
86790                 } else if (datum.only) {
86791                   klass = 'only';
86792                   turnText = _t.html('restriction.help.turn.only_' + turnType, {
86793                     indirect: indirect
86794                   });
86795                   nextText = _t.html('restriction.help.turn.allowed_' + turnType, {
86796                     indirect: ''
86797                   });
86798                 } else {
86799                   klass = 'allow';
86800                   turnText = _t.html('restriction.help.turn.allowed_' + turnType, {
86801                     indirect: indirect
86802                   });
86803                   nextText = _t.html('restriction.help.turn.no_' + turnType, {
86804                     indirect: ''
86805                   });
86806                 }
86807
86808                 help.append('div') // "NO Right Turn (indirect)"
86809                 .attr('class', 'qualifier ' + klass).html(turnText);
86810                 help.append('div') // "FROM {fromName} TO {toName}"
86811                 .html(_t.html('restriction.help.from_name_to_name', {
86812                   from: placeholders.from,
86813                   fromName: displayName(datum.from.way, vgraph),
86814                   to: placeholders.to,
86815                   toName: displayName(datum.to.way, vgraph)
86816                 }));
86817
86818                 if (datum.via.ways && datum.via.ways.length) {
86819                   var names = [];
86820
86821                   for (var i = 0; i < datum.via.ways.length; i++) {
86822                     var prev = names[names.length - 1];
86823                     var curr = displayName(datum.via.ways[i], vgraph);
86824                     if (!prev || curr !== prev) // collapse identical names
86825                       names.push(curr);
86826                   }
86827
86828                   help.append('div') // "VIA {viaNames}"
86829                   .html(_t.html('restriction.help.via_names', {
86830                     via: placeholders.via,
86831                     viaNames: names.join(', ')
86832                   }));
86833                 }
86834
86835                 if (!indirect) {
86836                   help.append('div') // Click for "No Right Turn"
86837                   .html(_t.html('restriction.help.toggle', {
86838                     turn: nextText.trim()
86839                   }));
86840                 }
86841
86842                 highlightPathsFrom(null);
86843                 var alongIDs = datum.path.slice();
86844                 surface.selectAll(utilEntitySelector(alongIDs)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only'); // Hovering empty surface
86845               } else {
86846                 highlightPathsFrom(null);
86847
86848                 if (_fromWayID) {
86849                   help.append('div') // "FROM {fromName}"
86850                   .html(_t.html('restriction.help.from_name', {
86851                     from: placeholders.from,
86852                     fromName: displayName(_fromWayID, vgraph)
86853                   }));
86854                 } else {
86855                   help.append('div') // "Click to select a FROM segment."
86856                   .html(_t.html('restriction.help.select_from', {
86857                     from: placeholders.from
86858                   }));
86859                 }
86860               }
86861             }
86862           }
86863
86864           function displayMaxDistance(maxDist) {
86865             var isImperial = !_mainLocalizer.usesMetric();
86866             var opts;
86867
86868             if (isImperial) {
86869               var distToFeet = {
86870                 // imprecise conversion for prettier display
86871                 20: 70,
86872                 25: 85,
86873                 30: 100,
86874                 35: 115,
86875                 40: 130,
86876                 45: 145,
86877                 50: 160
86878               }[maxDist];
86879               opts = {
86880                 distance: _t('units.feet', {
86881                   quantity: distToFeet
86882                 })
86883               };
86884             } else {
86885               opts = {
86886                 distance: _t('units.meters', {
86887                   quantity: maxDist
86888                 })
86889               };
86890             }
86891
86892             return _t.html('restriction.controls.distance_up_to', opts);
86893           }
86894
86895           function displayMaxVia(maxVia) {
86896             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');
86897           }
86898
86899           function displayName(entityID, graph) {
86900             var entity = graph.entity(entityID);
86901             var name = utilDisplayName(entity) || '';
86902             var matched = _mainPresetIndex.match(entity, graph);
86903             var type = matched && matched.name() || utilDisplayType(entity.id);
86904             return name || type;
86905           }
86906
86907           restrictions.entityIDs = function (val) {
86908             _intersection = null;
86909             _fromWayID = null;
86910             _oldTurns = null;
86911             _vertexID = val[0];
86912           };
86913
86914           restrictions.tags = function () {};
86915
86916           restrictions.focus = function () {};
86917
86918           restrictions.off = function (selection) {
86919             if (!_initialized) return;
86920             selection.selectAll('.surface').call(breathe.off).on('click.restrictions', null).on('mouseover.restrictions', null);
86921             select(window).on('resize.restrictions', null);
86922           };
86923
86924           return utilRebind(restrictions, dispatch$1, 'on');
86925         }
86926         uiFieldRestrictions.supportsMultiselection = false;
86927
86928         function uiFieldTextarea(field, context) {
86929           var dispatch$1 = dispatch('change');
86930           var input = select(null);
86931
86932           var _tags;
86933
86934           function textarea(selection) {
86935             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86936             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86937             input = wrap.selectAll('textarea').data([0]);
86938             input = input.enter().append('textarea').attr('id', field.domId).call(utilNoAuto).on('input', change(true)).on('blur', change()).on('change', change()).merge(input);
86939           }
86940
86941           function change(onInput) {
86942             return function () {
86943               var val = utilGetSetValue(input);
86944               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
86945
86946               if (!val && Array.isArray(_tags[field.key])) return;
86947               var t = {};
86948               t[field.key] = val || undefined;
86949               dispatch$1.call('change', this, t, onInput);
86950             };
86951           }
86952
86953           textarea.tags = function (tags) {
86954             _tags = tags;
86955             var isMixed = Array.isArray(tags[field.key]);
86956             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);
86957           };
86958
86959           textarea.focus = function () {
86960             input.node().focus();
86961           };
86962
86963           return utilRebind(textarea, dispatch$1, 'on');
86964         }
86965
86966         function uiFieldWikidata(field, context) {
86967           var wikidata = services.wikidata;
86968           var dispatch$1 = dispatch('change');
86969
86970           var _selection = select(null);
86971
86972           var _searchInput = select(null);
86973
86974           var _qid = null;
86975           var _wikidataEntity = null;
86976           var _wikiURL = '';
86977           var _entityIDs = [];
86978
86979           var _wikipediaKey = field.keys && field.keys.find(function (key) {
86980             return key.includes('wikipedia');
86981           }),
86982               _hintKey = field.key === 'wikidata' ? 'name' : field.key.split(':')[0];
86983
86984           var combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(true).minItems(1);
86985
86986           function wiki(selection) {
86987             _selection = selection;
86988             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86989             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86990             var list = wrap.selectAll('ul').data([0]);
86991             list = list.enter().append('ul').attr('class', 'rows').merge(list);
86992             var searchRow = list.selectAll('li.wikidata-search').data([0]);
86993             var searchRowEnter = searchRow.enter().append('li').attr('class', 'wikidata-search');
86994             searchRowEnter.append('input').attr('type', 'text').attr('id', field.domId).style('flex', '1').call(utilNoAuto).on('focus', function () {
86995               var node = select(this).node();
86996               node.setSelectionRange(0, node.value.length);
86997             }).on('blur', function () {
86998               setLabelForEntity();
86999             }).call(combobox.fetcher(fetchWikidataItems));
87000             combobox.on('accept', function (d) {
87001               if (d) {
87002                 _qid = d.id;
87003                 change();
87004               }
87005             }).on('cancel', function () {
87006               setLabelForEntity();
87007             });
87008             searchRowEnter.append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
87009               domain: 'wikidata.org'
87010             })).call(svgIcon('#iD-icon-out-link')).on('click', function (d3_event) {
87011               d3_event.preventDefault();
87012               if (_wikiURL) window.open(_wikiURL, '_blank');
87013             });
87014             searchRow = searchRow.merge(searchRowEnter);
87015             _searchInput = searchRow.select('input');
87016             var wikidataProperties = ['description', 'identifier'];
87017             var items = list.selectAll('li.labeled-input').data(wikidataProperties); // Enter
87018
87019             var enter = items.enter().append('li').attr('class', function (d) {
87020               return 'labeled-input preset-wikidata-' + d;
87021             });
87022             enter.append('span').attr('class', 'label').html(function (d) {
87023               return _t.html('wikidata.' + d);
87024             });
87025             enter.append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', 'true').attr('readonly', 'true');
87026             enter.append('button').attr('class', 'form-field-button').attr('title', _t('icons.copy')).call(svgIcon('#iD-operation-copy')).on('click', function (d3_event) {
87027               d3_event.preventDefault();
87028               select(this.parentNode).select('input').node().select();
87029               document.execCommand('copy');
87030             });
87031           }
87032
87033           function fetchWikidataItems(q, callback) {
87034             if (!q && _hintKey) {
87035               // other tags may be good search terms
87036               for (var i in _entityIDs) {
87037                 var entity = context.hasEntity(_entityIDs[i]);
87038
87039                 if (entity.tags[_hintKey]) {
87040                   q = entity.tags[_hintKey];
87041                   break;
87042                 }
87043               }
87044             }
87045
87046             wikidata.itemsForSearchQuery(q, function (err, data) {
87047               if (err) return;
87048
87049               for (var i in data) {
87050                 data[i].value = data[i].label + ' (' + data[i].id + ')';
87051                 data[i].title = data[i].description;
87052               }
87053
87054               if (callback) callback(data);
87055             });
87056           }
87057
87058           function change() {
87059             var syncTags = {};
87060             syncTags[field.key] = _qid;
87061             dispatch$1.call('change', this, syncTags); // attempt asynchronous update of wikidata tag..
87062
87063             var initGraph = context.graph();
87064             var initEntityIDs = _entityIDs;
87065             wikidata.entityByQID(_qid, function (err, entity) {
87066               if (err) return; // If graph has changed, we can't apply this update.
87067
87068               if (context.graph() !== initGraph) return;
87069               if (!entity.sitelinks) return;
87070               var langs = wikidata.languagesToQuery(); // use the label and description languages as fallbacks
87071
87072               ['labels', 'descriptions'].forEach(function (key) {
87073                 if (!entity[key]) return;
87074                 var valueLangs = Object.keys(entity[key]);
87075                 if (valueLangs.length === 0) return;
87076                 var valueLang = valueLangs[0];
87077
87078                 if (langs.indexOf(valueLang) === -1) {
87079                   langs.push(valueLang);
87080                 }
87081               });
87082               var newWikipediaValue;
87083
87084               if (_wikipediaKey) {
87085                 var foundPreferred;
87086
87087                 for (var i in langs) {
87088                   var lang = langs[i];
87089                   var siteID = lang.replace('-', '_') + 'wiki';
87090
87091                   if (entity.sitelinks[siteID]) {
87092                     foundPreferred = true;
87093                     newWikipediaValue = lang + ':' + entity.sitelinks[siteID].title; // use the first match
87094
87095                     break;
87096                   }
87097                 }
87098
87099                 if (!foundPreferred) {
87100                   // No wikipedia sites available in the user's language or the fallback languages,
87101                   // default to any wikipedia sitelink
87102                   var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function (site) {
87103                     return site.endsWith('wiki');
87104                   });
87105
87106                   if (wikiSiteKeys.length === 0) {
87107                     // if no wikipedia pages are linked to this wikidata entity, delete that tag
87108                     newWikipediaValue = null;
87109                   } else {
87110                     var wikiLang = wikiSiteKeys[0].slice(0, -4).replace('_', '-');
87111                     var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
87112                     newWikipediaValue = wikiLang + ':' + wikiTitle;
87113                   }
87114                 }
87115               }
87116
87117               if (newWikipediaValue) {
87118                 newWikipediaValue = context.cleanTagValue(newWikipediaValue);
87119               }
87120
87121               if (typeof newWikipediaValue === 'undefined') return;
87122               var actions = initEntityIDs.map(function (entityID) {
87123                 var entity = context.hasEntity(entityID);
87124                 if (!entity) return null;
87125                 var currTags = Object.assign({}, entity.tags); // shallow copy
87126
87127                 if (newWikipediaValue === null) {
87128                   if (!currTags[_wikipediaKey]) return null;
87129                   delete currTags[_wikipediaKey];
87130                 } else {
87131                   currTags[_wikipediaKey] = newWikipediaValue;
87132                 }
87133
87134                 return actionChangeTags(entityID, currTags);
87135               }).filter(Boolean);
87136               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
87137
87138               context.overwrite(function actionUpdateWikipediaTags(graph) {
87139                 actions.forEach(function (action) {
87140                   graph = action(graph);
87141                 });
87142                 return graph;
87143               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
87144               // changeTags() is not intended to be called asynchronously
87145             });
87146           }
87147
87148           function setLabelForEntity() {
87149             var label = '';
87150
87151             if (_wikidataEntity) {
87152               label = entityPropertyForDisplay(_wikidataEntity, 'labels');
87153
87154               if (label.length === 0) {
87155                 label = _wikidataEntity.id.toString();
87156               }
87157             }
87158
87159             utilGetSetValue(_searchInput, label);
87160           }
87161
87162           wiki.tags = function (tags) {
87163             var isMixed = Array.isArray(tags[field.key]);
87164
87165             _searchInput.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : '').classed('mixed', isMixed);
87166
87167             _qid = typeof tags[field.key] === 'string' && tags[field.key] || '';
87168
87169             if (!/^Q[0-9]*$/.test(_qid)) {
87170               // not a proper QID
87171               unrecognized();
87172               return;
87173             } // QID value in correct format
87174
87175
87176             _wikiURL = 'https://wikidata.org/wiki/' + _qid;
87177             wikidata.entityByQID(_qid, function (err, entity) {
87178               if (err) {
87179                 unrecognized();
87180                 return;
87181               }
87182
87183               _wikidataEntity = entity;
87184               setLabelForEntity();
87185               var description = entityPropertyForDisplay(entity, 'descriptions');
87186
87187               _selection.select('button.wiki-link').classed('disabled', false);
87188
87189               _selection.select('.preset-wikidata-description').style('display', function () {
87190                 return description.length > 0 ? 'flex' : 'none';
87191               }).select('input').attr('value', description);
87192
87193               _selection.select('.preset-wikidata-identifier').style('display', function () {
87194                 return entity.id ? 'flex' : 'none';
87195               }).select('input').attr('value', entity.id);
87196             }); // not a proper QID
87197
87198             function unrecognized() {
87199               _wikidataEntity = null;
87200               setLabelForEntity();
87201
87202               _selection.select('.preset-wikidata-description').style('display', 'none');
87203
87204               _selection.select('.preset-wikidata-identifier').style('display', 'none');
87205
87206               _selection.select('button.wiki-link').classed('disabled', true);
87207
87208               if (_qid && _qid !== '') {
87209                 _wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + _qid;
87210               } else {
87211                 _wikiURL = '';
87212               }
87213             }
87214           };
87215
87216           function entityPropertyForDisplay(wikidataEntity, propKey) {
87217             if (!wikidataEntity[propKey]) return '';
87218             var propObj = wikidataEntity[propKey];
87219             var langKeys = Object.keys(propObj);
87220             if (langKeys.length === 0) return ''; // sorted by priority, since we want to show the user's language first if possible
87221
87222             var langs = wikidata.languagesToQuery();
87223
87224             for (var i in langs) {
87225               var lang = langs[i];
87226               var valueObj = propObj[lang];
87227               if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
87228             } // default to any available value
87229
87230
87231             return propObj[langKeys[0]].value;
87232           }
87233
87234           wiki.entityIDs = function (val) {
87235             if (!arguments.length) return _entityIDs;
87236             _entityIDs = val;
87237             return wiki;
87238           };
87239
87240           wiki.focus = function () {
87241             _searchInput.node().focus();
87242           };
87243
87244           return utilRebind(wiki, dispatch$1, 'on');
87245         }
87246
87247         function uiFieldWikipedia(field, context) {
87248           var _arguments = arguments;
87249           var dispatch$1 = dispatch('change');
87250           var wikipedia = services.wikipedia;
87251           var wikidata = services.wikidata;
87252
87253           var _langInput = select(null);
87254
87255           var _titleInput = select(null);
87256
87257           var _wikiURL = '';
87258
87259           var _entityIDs;
87260
87261           var _tags;
87262
87263           var _dataWikipedia = [];
87264           _mainFileFetcher.get('wmf_sitematrix').then(function (d) {
87265             _dataWikipedia = d;
87266             if (_tags) updateForTags(_tags);
87267           })["catch"](function () {
87268             /* ignore */
87269           });
87270           var langCombo = uiCombobox(context, 'wikipedia-lang').fetcher(function (value, callback) {
87271             var v = value.toLowerCase();
87272             callback(_dataWikipedia.filter(function (d) {
87273               return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
87274             }).map(function (d) {
87275               return {
87276                 value: d[1]
87277               };
87278             }));
87279           });
87280           var titleCombo = uiCombobox(context, 'wikipedia-title').fetcher(function (value, callback) {
87281             if (!value) {
87282               value = '';
87283
87284               for (var i in _entityIDs) {
87285                 var entity = context.hasEntity(_entityIDs[i]);
87286
87287                 if (entity.tags.name) {
87288                   value = entity.tags.name;
87289                   break;
87290                 }
87291               }
87292             }
87293
87294             var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
87295             searchfn(language()[2], value, function (query, data) {
87296               callback(data.map(function (d) {
87297                 return {
87298                   value: d
87299                 };
87300               }));
87301             });
87302           });
87303
87304           function wiki(selection) {
87305             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
87306             wrap = wrap.enter().append('div').attr('class', "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap);
87307             var langContainer = wrap.selectAll('.wiki-lang-container').data([0]);
87308             langContainer = langContainer.enter().append('div').attr('class', 'wiki-lang-container').merge(langContainer);
87309             _langInput = langContainer.selectAll('input.wiki-lang').data([0]);
87310             _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);
87311
87312             _langInput.on('blur', changeLang).on('change', changeLang);
87313
87314             var titleContainer = wrap.selectAll('.wiki-title-container').data([0]);
87315             titleContainer = titleContainer.enter().append('div').attr('class', 'wiki-title-container').merge(titleContainer);
87316             _titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
87317             _titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
87318
87319             _titleInput.on('blur', blur).on('change', change);
87320
87321             var link = titleContainer.selectAll('.wiki-link').data([0]);
87322             link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
87323               domain: 'wikipedia.org'
87324             })).call(svgIcon('#iD-icon-out-link')).merge(link);
87325             link.on('click', function (d3_event) {
87326               d3_event.preventDefault();
87327               if (_wikiURL) window.open(_wikiURL, '_blank');
87328             });
87329           }
87330
87331           function defaultLanguageInfo(skipEnglishFallback) {
87332             var langCode = _mainLocalizer.languageCode().toLowerCase();
87333
87334             for (var i in _dataWikipedia) {
87335               var d = _dataWikipedia[i]; // default to the language of iD's current locale
87336
87337               if (d[2] === langCode) return d;
87338             } // fallback to English
87339
87340
87341             return skipEnglishFallback ? ['', '', ''] : ['English', 'English', 'en'];
87342           }
87343
87344           function language(skipEnglishFallback) {
87345             var value = utilGetSetValue(_langInput).toLowerCase();
87346
87347             for (var i in _dataWikipedia) {
87348               var d = _dataWikipedia[i]; // return the language already set in the UI, if supported
87349
87350               if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value) return d;
87351             } // fallback to English
87352
87353
87354             return defaultLanguageInfo(skipEnglishFallback);
87355           }
87356
87357           function changeLang() {
87358             utilGetSetValue(_langInput, language()[1]);
87359             change(true);
87360           }
87361
87362           function blur() {
87363             change(true);
87364           }
87365
87366           function change(skipWikidata) {
87367             var value = utilGetSetValue(_titleInput);
87368             var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
87369
87370             var langInfo = m && _dataWikipedia.find(function (d) {
87371               return m[1] === d[2];
87372             });
87373
87374             var syncTags = {};
87375
87376             if (langInfo) {
87377               var nativeLangName = langInfo[1]; // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
87378
87379               value = decodeURIComponent(m[2]).replace(/_/g, ' ');
87380
87381               if (m[3]) {
87382                 var anchor; // try {
87383                 // leave this out for now - #6232
87384                 // Best-effort `anchordecode:` implementation
87385                 // anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
87386                 // } catch (e) {
87387
87388                 anchor = decodeURIComponent(m[3]); // }
87389
87390                 value += '#' + anchor.replace(/_/g, ' ');
87391               }
87392
87393               value = value.slice(0, 1).toUpperCase() + value.slice(1);
87394               utilGetSetValue(_langInput, nativeLangName);
87395               utilGetSetValue(_titleInput, value);
87396             }
87397
87398             if (value) {
87399               syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
87400             } else {
87401               syncTags.wikipedia = undefined;
87402             }
87403
87404             dispatch$1.call('change', this, syncTags);
87405             if (skipWikidata || !value || !language()[2]) return; // attempt asynchronous update of wikidata tag..
87406
87407             var initGraph = context.graph();
87408             var initEntityIDs = _entityIDs;
87409             wikidata.itemsByTitle(language()[2], value, function (err, data) {
87410               if (err || !data || !Object.keys(data).length) return; // If graph has changed, we can't apply this update.
87411
87412               if (context.graph() !== initGraph) return;
87413               var qids = Object.keys(data);
87414               var value = qids && qids.find(function (id) {
87415                 return id.match(/^Q\d+$/);
87416               });
87417               var actions = initEntityIDs.map(function (entityID) {
87418                 var entity = context.entity(entityID).tags;
87419                 var currTags = Object.assign({}, entity); // shallow copy
87420
87421                 if (currTags.wikidata !== value) {
87422                   currTags.wikidata = value;
87423                   return actionChangeTags(entityID, currTags);
87424                 }
87425
87426                 return null;
87427               }).filter(Boolean);
87428               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
87429
87430               context.overwrite(function actionUpdateWikidataTags(graph) {
87431                 actions.forEach(function (action) {
87432                   graph = action(graph);
87433                 });
87434                 return graph;
87435               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
87436               // changeTags() is not intended to be called asynchronously
87437             });
87438           }
87439
87440           wiki.tags = function (tags) {
87441             _tags = tags;
87442             updateForTags(tags);
87443           };
87444
87445           function updateForTags(tags) {
87446             var value = typeof tags[field.key] === 'string' ? tags[field.key] : ''; // Expect tag format of `tagLang:tagArticleTitle`, e.g. `fr:Paris`, with
87447             // optional suffix of `#anchor`
87448
87449             var m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
87450             var tagLang = m && m[1];
87451             var tagArticleTitle = m && m[2];
87452             var anchor = m && m[3];
87453
87454             var tagLangInfo = tagLang && _dataWikipedia.find(function (d) {
87455               return tagLang === d[2];
87456             }); // value in correct format
87457
87458
87459             if (tagLangInfo) {
87460               var nativeLangName = tagLangInfo[1];
87461               utilGetSetValue(_langInput, nativeLangName);
87462               utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? '#' + anchor : ''));
87463
87464               if (anchor) {
87465                 try {
87466                   // Best-effort `anchorencode:` implementation
87467                   anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
87468                 } catch (e) {
87469                   anchor = anchor.replace(/ /g, '_');
87470                 }
87471               }
87472
87473               _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + tagArticleTitle.replace(/ /g, '_') + (anchor ? '#' + anchor : ''); // unrecognized value format
87474             } else {
87475               utilGetSetValue(_titleInput, value);
87476
87477               if (value && value !== '') {
87478                 utilGetSetValue(_langInput, '');
87479                 var defaultLangInfo = defaultLanguageInfo();
87480                 _wikiURL = "https://".concat(defaultLangInfo[2], ".wikipedia.org/w/index.php?fulltext=1&search=").concat(value);
87481               } else {
87482                 var shownOrDefaultLangInfo = language(true
87483                 /* skipEnglishFallback */
87484                 );
87485                 utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
87486                 _wikiURL = '';
87487               }
87488             }
87489           }
87490
87491           wiki.entityIDs = function (val) {
87492             if (!_arguments.length) return _entityIDs;
87493             _entityIDs = val;
87494             return wiki;
87495           };
87496
87497           wiki.focus = function () {
87498             _titleInput.node().focus();
87499           };
87500
87501           return utilRebind(wiki, dispatch$1, 'on');
87502         }
87503         uiFieldWikipedia.supportsMultiselection = false;
87504
87505         var uiFields = {
87506           access: uiFieldAccess,
87507           address: uiFieldAddress,
87508           check: uiFieldCheck,
87509           combo: uiFieldCombo,
87510           cycleway: uiFieldCycleway,
87511           defaultCheck: uiFieldCheck,
87512           email: uiFieldText,
87513           identifier: uiFieldText,
87514           lanes: uiFieldLanes,
87515           localized: uiFieldLocalized,
87516           maxspeed: uiFieldMaxspeed,
87517           manyCombo: uiFieldCombo,
87518           multiCombo: uiFieldCombo,
87519           networkCombo: uiFieldCombo,
87520           number: uiFieldText,
87521           onewayCheck: uiFieldCheck,
87522           radio: uiFieldRadio,
87523           restrictions: uiFieldRestrictions,
87524           semiCombo: uiFieldCombo,
87525           structureRadio: uiFieldRadio,
87526           tel: uiFieldText,
87527           text: uiFieldText,
87528           textarea: uiFieldTextarea,
87529           typeCombo: uiFieldCombo,
87530           url: uiFieldText,
87531           wikidata: uiFieldWikidata,
87532           wikipedia: uiFieldWikipedia
87533         };
87534
87535         function uiField(context, presetField, entityIDs, options) {
87536           options = Object.assign({
87537             show: true,
87538             wrap: true,
87539             remove: true,
87540             revert: true,
87541             info: true
87542           }, options);
87543           var dispatch$1 = dispatch('change', 'revert');
87544           var field = Object.assign({}, presetField); // shallow copy
87545
87546           field.domId = utilUniqueDomId('form-field-' + field.safeid);
87547           var _show = options.show;
87548           var _state = '';
87549           var _tags = {};
87550           var _locked = false;
87551
87552           var _lockedTip = uiTooltip().title(_t.html('inspector.lock.suggestion', {
87553             label: field.label
87554           })).placement('bottom');
87555
87556           field.keys = field.keys || [field.key]; // only create the fields that are actually being shown
87557
87558           if (_show && !field.impl) {
87559             createField();
87560           } // Creates the field.. This is done lazily,
87561           // once we know that the field will be shown.
87562
87563
87564           function createField() {
87565             field.impl = uiFields[field.type](field, context).on('change', function (t, onInput) {
87566               dispatch$1.call('change', field, t, onInput);
87567             });
87568
87569             if (entityIDs) {
87570               field.entityIDs = entityIDs; // if this field cares about the entities, pass them along
87571
87572               if (field.impl.entityIDs) {
87573                 field.impl.entityIDs(entityIDs);
87574               }
87575             }
87576           }
87577
87578           function isModified() {
87579             if (!entityIDs || !entityIDs.length) return false;
87580             return entityIDs.some(function (entityID) {
87581               var original = context.graph().base().entities[entityID];
87582               var latest = context.graph().entity(entityID);
87583               return field.keys.some(function (key) {
87584                 return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
87585               });
87586             });
87587           }
87588
87589           function tagsContainFieldKey() {
87590             return field.keys.some(function (key) {
87591               if (field.type === 'multiCombo') {
87592                 for (var tagKey in _tags) {
87593                   if (tagKey.indexOf(key) === 0) {
87594                     return true;
87595                   }
87596                 }
87597
87598                 return false;
87599               }
87600
87601               return _tags[key] !== undefined;
87602             });
87603           }
87604
87605           function revert(d3_event, d) {
87606             d3_event.stopPropagation();
87607             d3_event.preventDefault();
87608             if (!entityIDs || _locked) return;
87609             dispatch$1.call('revert', d, d.keys);
87610           }
87611
87612           function remove(d3_event, d) {
87613             d3_event.stopPropagation();
87614             d3_event.preventDefault();
87615             if (_locked) return;
87616             var t = {};
87617             d.keys.forEach(function (key) {
87618               t[key] = undefined;
87619             });
87620             dispatch$1.call('change', d, t);
87621           }
87622
87623           field.render = function (selection) {
87624             var container = selection.selectAll('.form-field').data([field]); // Enter
87625
87626             var enter = container.enter().append('div').attr('class', function (d) {
87627               return 'form-field form-field-' + d.safeid;
87628             }).classed('nowrap', !options.wrap);
87629
87630             if (options.wrap) {
87631               var labelEnter = enter.append('label').attr('class', 'field-label').attr('for', function (d) {
87632                 return d.domId;
87633               });
87634               var textEnter = labelEnter.append('span').attr('class', 'label-text');
87635               textEnter.append('span').attr('class', 'label-textvalue').html(function (d) {
87636                 return d.label();
87637               });
87638               textEnter.append('span').attr('class', 'label-textannotation');
87639
87640               if (options.remove) {
87641                 labelEnter.append('button').attr('class', 'remove-icon').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete'));
87642               }
87643
87644               if (options.revert) {
87645                 labelEnter.append('button').attr('class', 'modified-icon').attr('title', _t('icons.undo')).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo'));
87646               }
87647             } // Update
87648
87649
87650             container = container.merge(enter);
87651             container.select('.field-label > .remove-icon') // propagate bound data
87652             .on('click', remove);
87653             container.select('.field-label > .modified-icon') // propagate bound data
87654             .on('click', revert);
87655             container.each(function (d) {
87656               var selection = select(this);
87657
87658               if (!d.impl) {
87659                 createField();
87660               }
87661
87662               var reference, help; // instantiate field help
87663
87664               if (options.wrap && field.type === 'restrictions') {
87665                 help = uiFieldHelp(context, 'restrictions');
87666               } // instantiate tag reference
87667
87668
87669               if (options.wrap && options.info) {
87670                 var referenceKey = d.key || '';
87671
87672                 if (d.type === 'multiCombo') {
87673                   // lookup key without the trailing ':'
87674                   referenceKey = referenceKey.replace(/:$/, '');
87675                 }
87676
87677                 reference = uiTagReference(d.reference || {
87678                   key: referenceKey
87679                 });
87680
87681                 if (_state === 'hover') {
87682                   reference.showing(false);
87683                 }
87684               }
87685
87686               selection.call(d.impl); // add field help components
87687
87688               if (help) {
87689                 selection.call(help.body).select('.field-label').call(help.button);
87690               } // add tag reference components
87691
87692
87693               if (reference) {
87694                 selection.call(reference.body).select('.field-label').call(reference.button);
87695               }
87696
87697               d.impl.tags(_tags);
87698             });
87699             container.classed('locked', _locked).classed('modified', isModified()).classed('present', tagsContainFieldKey()); // show a tip and lock icon if the field is locked
87700
87701             var annotation = container.selectAll('.field-label .label-textannotation');
87702             var icon = annotation.selectAll('.icon').data(_locked ? [0] : []);
87703             icon.exit().remove();
87704             icon.enter().append('svg').attr('class', 'icon').append('use').attr('xlink:href', '#fas-lock');
87705             container.call(_locked ? _lockedTip : _lockedTip.destroy);
87706           };
87707
87708           field.state = function (val) {
87709             if (!arguments.length) return _state;
87710             _state = val;
87711             return field;
87712           };
87713
87714           field.tags = function (val) {
87715             if (!arguments.length) return _tags;
87716             _tags = val;
87717
87718             if (tagsContainFieldKey() && !_show) {
87719               // always show a field if it has a value to display
87720               _show = true;
87721
87722               if (!field.impl) {
87723                 createField();
87724               }
87725             }
87726
87727             return field;
87728           };
87729
87730           field.locked = function (val) {
87731             if (!arguments.length) return _locked;
87732             _locked = val;
87733             return field;
87734           };
87735
87736           field.show = function () {
87737             _show = true;
87738
87739             if (!field.impl) {
87740               createField();
87741             }
87742
87743             if (field["default"] && field.key && _tags[field.key] !== field["default"]) {
87744               var t = {};
87745               t[field.key] = field["default"];
87746               dispatch$1.call('change', this, t);
87747             }
87748           }; // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
87749
87750
87751           field.isShown = function () {
87752             return _show;
87753           }; // An allowed field can appear in the UI or in the 'Add field' dropdown.
87754           // A non-allowed field is hidden from the user altogether
87755
87756
87757           field.isAllowed = function () {
87758             if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
87759             if (field.geometry && !entityIDs.every(function (entityID) {
87760               return field.matchGeometry(context.graph().geometry(entityID));
87761             })) return false;
87762
87763             if (field.countryCodes || field.notCountryCodes) {
87764               var extent = combinedEntityExtent();
87765               if (!extent) return true;
87766               var center = extent.center();
87767               var countryCode = iso1A2Code(center);
87768               if (!countryCode) return false;
87769               countryCode = countryCode.toLowerCase();
87770
87771               if (field.countryCodes && field.countryCodes.indexOf(countryCode) === -1) {
87772                 return false;
87773               }
87774
87775               if (field.notCountryCodes && field.notCountryCodes.indexOf(countryCode) !== -1) {
87776                 return false;
87777               }
87778             }
87779
87780             var prerequisiteTag = field.prerequisiteTag;
87781
87782             if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
87783             prerequisiteTag) {
87784               if (!entityIDs.every(function (entityID) {
87785                 var entity = context.graph().entity(entityID);
87786
87787                 if (prerequisiteTag.key) {
87788                   var value = entity.tags[prerequisiteTag.key];
87789                   if (!value) return false;
87790
87791                   if (prerequisiteTag.valueNot) {
87792                     return prerequisiteTag.valueNot !== value;
87793                   }
87794
87795                   if (prerequisiteTag.value) {
87796                     return prerequisiteTag.value === value;
87797                   }
87798                 } else if (prerequisiteTag.keyNot) {
87799                   if (entity.tags[prerequisiteTag.keyNot]) return false;
87800                 }
87801
87802                 return true;
87803               })) return false;
87804             }
87805
87806             return true;
87807           };
87808
87809           field.focus = function () {
87810             if (field.impl) {
87811               field.impl.focus();
87812             }
87813           };
87814
87815           function combinedEntityExtent() {
87816             return entityIDs && entityIDs.length && entityIDs.reduce(function (extent, entityID) {
87817               var entity = context.graph().entity(entityID);
87818               return extent.extend(entity.extent(context.graph()));
87819             }, geoExtent());
87820           }
87821
87822           return utilRebind(field, dispatch$1, 'on');
87823         }
87824
87825         function uiFormFields(context) {
87826           var moreCombo = uiCombobox(context, 'more-fields').minItems(1);
87827           var _fieldsArr = [];
87828           var _lastPlaceholder = '';
87829           var _state = '';
87830           var _klass = '';
87831
87832           function formFields(selection) {
87833             var allowedFields = _fieldsArr.filter(function (field) {
87834               return field.isAllowed();
87835             });
87836
87837             var shown = allowedFields.filter(function (field) {
87838               return field.isShown();
87839             });
87840             var notShown = allowedFields.filter(function (field) {
87841               return !field.isShown();
87842             });
87843             var container = selection.selectAll('.form-fields-container').data([0]);
87844             container = container.enter().append('div').attr('class', 'form-fields-container ' + (_klass || '')).merge(container);
87845             var fields = container.selectAll('.wrap-form-field').data(shown, function (d) {
87846               return d.id + (d.entityIDs ? d.entityIDs.join() : '');
87847             });
87848             fields.exit().remove(); // Enter
87849
87850             var enter = fields.enter().append('div').attr('class', function (d) {
87851               return 'wrap-form-field wrap-form-field-' + d.safeid;
87852             }); // Update
87853
87854             fields = fields.merge(enter);
87855             fields.order().each(function (d) {
87856               select(this).call(d.render);
87857             });
87858             var titles = [];
87859             var moreFields = notShown.map(function (field) {
87860               var title = field.title();
87861               titles.push(title);
87862               var terms = field.terms();
87863               if (field.key) terms.push(field.key);
87864               if (field.keys) terms = terms.concat(field.keys);
87865               return {
87866                 display: field.label(),
87867                 value: title,
87868                 title: title,
87869                 field: field,
87870                 terms: terms
87871               };
87872             });
87873             var placeholder = titles.slice(0, 3).join(', ') + (titles.length > 3 ? '…' : '');
87874             var more = selection.selectAll('.more-fields').data(_state === 'hover' || moreFields.length === 0 ? [] : [0]);
87875             more.exit().remove();
87876             var moreEnter = more.enter().append('div').attr('class', 'more-fields').append('label');
87877             moreEnter.append('span').html(_t.html('inspector.add_fields'));
87878             more = moreEnter.merge(more);
87879             var input = more.selectAll('.value').data([0]);
87880             input.exit().remove();
87881             input = input.enter().append('input').attr('class', 'value').attr('type', 'text').attr('placeholder', placeholder).call(utilNoAuto).merge(input);
87882             input.call(utilGetSetValue, '').call(moreCombo.data(moreFields).on('accept', function (d) {
87883               if (!d) return; // user entered something that was not matched
87884
87885               var field = d.field;
87886               field.show();
87887               selection.call(formFields); // rerender
87888
87889               field.focus();
87890             })); // avoid updating placeholder excessively (triggers style recalc)
87891
87892             if (_lastPlaceholder !== placeholder) {
87893               input.attr('placeholder', placeholder);
87894               _lastPlaceholder = placeholder;
87895             }
87896           }
87897
87898           formFields.fieldsArr = function (val) {
87899             if (!arguments.length) return _fieldsArr;
87900             _fieldsArr = val || [];
87901             return formFields;
87902           };
87903
87904           formFields.state = function (val) {
87905             if (!arguments.length) return _state;
87906             _state = val;
87907             return formFields;
87908           };
87909
87910           formFields.klass = function (val) {
87911             if (!arguments.length) return _klass;
87912             _klass = val;
87913             return formFields;
87914           };
87915
87916           return formFields;
87917         }
87918
87919         function uiSectionPresetFields(context) {
87920           var section = uiSection('preset-fields', context).label(_t.html('inspector.fields')).disclosureContent(renderDisclosureContent);
87921           var dispatch$1 = dispatch('change', 'revert');
87922           var formFields = uiFormFields(context);
87923
87924           var _state;
87925
87926           var _fieldsArr;
87927
87928           var _presets = [];
87929
87930           var _tags;
87931
87932           var _entityIDs;
87933
87934           function renderDisclosureContent(selection) {
87935             if (!_fieldsArr) {
87936               var graph = context.graph();
87937               var geometries = Object.keys(_entityIDs.reduce(function (geoms, entityID) {
87938                 geoms[graph.entity(entityID).geometry(graph)] = true;
87939                 return geoms;
87940               }, {}));
87941               var presetsManager = _mainPresetIndex;
87942               var allFields = [];
87943               var allMoreFields = [];
87944               var sharedTotalFields;
87945
87946               _presets.forEach(function (preset) {
87947                 var fields = preset.fields();
87948                 var moreFields = preset.moreFields();
87949                 allFields = utilArrayUnion(allFields, fields);
87950                 allMoreFields = utilArrayUnion(allMoreFields, moreFields);
87951
87952                 if (!sharedTotalFields) {
87953                   sharedTotalFields = utilArrayUnion(fields, moreFields);
87954                 } else {
87955                   sharedTotalFields = sharedTotalFields.filter(function (field) {
87956                     return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
87957                   });
87958                 }
87959               });
87960
87961               var sharedFields = allFields.filter(function (field) {
87962                 return sharedTotalFields.indexOf(field) !== -1;
87963               });
87964               var sharedMoreFields = allMoreFields.filter(function (field) {
87965                 return sharedTotalFields.indexOf(field) !== -1;
87966               });
87967               _fieldsArr = [];
87968               sharedFields.forEach(function (field) {
87969                 if (field.matchAllGeometry(geometries)) {
87970                   _fieldsArr.push(uiField(context, field, _entityIDs));
87971                 }
87972               });
87973               var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
87974
87975               if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field('restrictions')) {
87976                 _fieldsArr.push(uiField(context, presetsManager.field('restrictions'), _entityIDs));
87977               }
87978
87979               var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
87980               additionalFields.sort(function (field1, field2) {
87981                 return field1.label().localeCompare(field2.label(), _mainLocalizer.localeCode());
87982               });
87983               additionalFields.forEach(function (field) {
87984                 if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
87985                   _fieldsArr.push(uiField(context, field, _entityIDs, {
87986                     show: false
87987                   }));
87988                 }
87989               });
87990
87991               _fieldsArr.forEach(function (field) {
87992                 field.on('change', function (t, onInput) {
87993                   dispatch$1.call('change', field, _entityIDs, t, onInput);
87994                 }).on('revert', function (keys) {
87995                   dispatch$1.call('revert', field, keys);
87996                 });
87997               });
87998             }
87999
88000             _fieldsArr.forEach(function (field) {
88001               field.state(_state).tags(_tags);
88002             });
88003
88004             selection.call(formFields.fieldsArr(_fieldsArr).state(_state).klass('grouped-items-area'));
88005             selection.selectAll('.wrap-form-field input').on('keydown', function (d3_event) {
88006               // if user presses enter, and combobox is not active, accept edits..
88007               if (d3_event.keyCode === 13 && // ↩ Return
88008               context.container().select('.combobox').empty()) {
88009                 context.enter(modeBrowse(context));
88010               }
88011             });
88012           }
88013
88014           section.presets = function (val) {
88015             if (!arguments.length) return _presets;
88016
88017             if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
88018               _presets = val;
88019               _fieldsArr = null;
88020             }
88021
88022             return section;
88023           };
88024
88025           section.state = function (val) {
88026             if (!arguments.length) return _state;
88027             _state = val;
88028             return section;
88029           };
88030
88031           section.tags = function (val) {
88032             if (!arguments.length) return _tags;
88033             _tags = val; // Don't reset _fieldsArr here.
88034
88035             return section;
88036           };
88037
88038           section.entityIDs = function (val) {
88039             if (!arguments.length) return _entityIDs;
88040
88041             if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
88042               _entityIDs = val;
88043               _fieldsArr = null;
88044             }
88045
88046             return section;
88047           };
88048
88049           return utilRebind(section, dispatch$1, 'on');
88050         }
88051
88052         function uiSectionRawMemberEditor(context) {
88053           var section = uiSection('raw-member-editor', context).shouldDisplay(function () {
88054             if (!_entityIDs || _entityIDs.length !== 1) return false;
88055             var entity = context.hasEntity(_entityIDs[0]);
88056             return entity && entity.type === 'relation';
88057           }).label(function () {
88058             var entity = context.hasEntity(_entityIDs[0]);
88059             if (!entity) return '';
88060             var gt = entity.members.length > _maxMembers ? '>' : '';
88061             var count = gt + entity.members.slice(0, _maxMembers).length;
88062             return _t('inspector.title_count', {
88063               title: _t.html('inspector.members'),
88064               count: count
88065             });
88066           }).disclosureContent(renderDisclosureContent);
88067           var taginfo = services.taginfo;
88068
88069           var _entityIDs;
88070
88071           var _maxMembers = 1000;
88072
88073           function downloadMember(d3_event, d) {
88074             d3_event.preventDefault(); // display the loading indicator
88075
88076             select(this.parentNode).classed('tag-reference-loading', true);
88077             context.loadEntity(d.id, function () {
88078               section.reRender();
88079             });
88080           }
88081
88082           function zoomToMember(d3_event, d) {
88083             d3_event.preventDefault();
88084             var entity = context.entity(d.id);
88085             context.map().zoomToEase(entity); // highlight the feature in case it wasn't previously on-screen
88086
88087             utilHighlightEntities([d.id], true, context);
88088           }
88089
88090           function selectMember(d3_event, d) {
88091             d3_event.preventDefault(); // remove the hover-highlight styling
88092
88093             utilHighlightEntities([d.id], false, context);
88094             var entity = context.entity(d.id);
88095             var mapExtent = context.map().extent();
88096
88097             if (!entity.intersects(mapExtent, context.graph())) {
88098               // zoom to the entity if its extent is not visible now
88099               context.map().zoomToEase(entity);
88100             }
88101
88102             context.enter(modeSelect(context, [d.id]));
88103           }
88104
88105           function changeRole(d3_event, d) {
88106             var oldRole = d.role;
88107             var newRole = context.cleanRelationRole(select(this).property('value'));
88108
88109             if (oldRole !== newRole) {
88110               var member = {
88111                 id: d.id,
88112                 type: d.type,
88113                 role: newRole
88114               };
88115               context.perform(actionChangeMember(d.relation.id, member, d.index), _t('operations.change_role.annotation', {
88116                 n: 1
88117               }));
88118               context.validator().validate();
88119             }
88120           }
88121
88122           function deleteMember(d3_event, d) {
88123             // remove the hover-highlight styling
88124             utilHighlightEntities([d.id], false, context);
88125             context.perform(actionDeleteMember(d.relation.id, d.index), _t('operations.delete_member.annotation', {
88126               n: 1
88127             }));
88128
88129             if (!context.hasEntity(d.relation.id)) {
88130               // Removing the last member will also delete the relation.
88131               // If this happens we need to exit the selection mode
88132               context.enter(modeBrowse(context));
88133             } else {
88134               // Changing the mode also runs `validate`, but otherwise we need to
88135               // rerun it manually
88136               context.validator().validate();
88137             }
88138           }
88139
88140           function renderDisclosureContent(selection) {
88141             var entityID = _entityIDs[0];
88142             var memberships = [];
88143             var entity = context.entity(entityID);
88144             entity.members.slice(0, _maxMembers).forEach(function (member, index) {
88145               memberships.push({
88146                 index: index,
88147                 id: member.id,
88148                 type: member.type,
88149                 role: member.role,
88150                 relation: entity,
88151                 member: context.hasEntity(member.id),
88152                 domId: utilUniqueDomId(entityID + '-member-' + index)
88153               });
88154             });
88155             var list = selection.selectAll('.member-list').data([0]);
88156             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
88157             var items = list.selectAll('li').data(memberships, function (d) {
88158               return osmEntity.key(d.relation) + ',' + d.index + ',' + (d.member ? osmEntity.key(d.member) : 'incomplete');
88159             });
88160             items.exit().each(unbind).remove();
88161             var itemsEnter = items.enter().append('li').attr('class', 'member-row form-field').classed('member-incomplete', function (d) {
88162               return !d.member;
88163             });
88164             itemsEnter.each(function (d) {
88165               var item = select(this);
88166               var label = item.append('label').attr('class', 'field-label').attr('for', d.domId);
88167
88168               if (d.member) {
88169                 // highlight the member feature in the map while hovering on the list item
88170                 item.on('mouseover', function () {
88171                   utilHighlightEntities([d.id], true, context);
88172                 }).on('mouseout', function () {
88173                   utilHighlightEntities([d.id], false, context);
88174                 });
88175                 var labelLink = label.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectMember);
88176                 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
88177                   var matched = _mainPresetIndex.match(d.member, context.graph());
88178                   return matched && matched.name() || utilDisplayType(d.member.id);
88179                 });
88180                 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
88181                   return utilDisplayName(d.member);
88182                 });
88183                 label.append('button').attr('title', _t('icons.remove')).attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete'));
88184                 label.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToMember);
88185               } else {
88186                 var labelText = label.append('span').attr('class', 'label-text');
88187                 labelText.append('span').attr('class', 'member-entity-type').html(_t.html('inspector.' + d.type, {
88188                   id: d.id
88189                 }));
88190                 labelText.append('span').attr('class', 'member-entity-name').html(_t.html('inspector.incomplete', {
88191                   id: d.id
88192                 }));
88193                 label.append('button').attr('class', 'member-download').attr('title', _t('icons.download')).call(svgIcon('#iD-icon-load')).on('click', downloadMember);
88194               }
88195             });
88196             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88197             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
88198               return d.domId;
88199             }).property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto);
88200
88201             if (taginfo) {
88202               wrapEnter.each(bindTypeahead);
88203             } // update
88204
88205
88206             items = items.merge(itemsEnter).order();
88207             items.select('input.member-role').property('value', function (d) {
88208               return d.role;
88209             }).on('blur', changeRole).on('change', changeRole);
88210             items.select('button.member-delete').on('click', deleteMember);
88211             var dragOrigin, targetIndex;
88212             items.call(d3_drag().on('start', function (d3_event) {
88213               dragOrigin = {
88214                 x: d3_event.x,
88215                 y: d3_event.y
88216               };
88217               targetIndex = null;
88218             }).on('drag', function (d3_event) {
88219               var x = d3_event.x - dragOrigin.x,
88220                   y = d3_event.y - dragOrigin.y;
88221               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
88222               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
88223               var index = items.nodes().indexOf(this);
88224               select(this).classed('dragging', true);
88225               targetIndex = null;
88226               selection.selectAll('li.member-row').style('transform', function (d2, index2) {
88227                 var node = select(this).node();
88228
88229                 if (index === index2) {
88230                   return 'translate(' + x + 'px, ' + y + 'px)';
88231                 } else if (index2 > index && d3_event.y > node.offsetTop) {
88232                   if (targetIndex === null || index2 > targetIndex) {
88233                     targetIndex = index2;
88234                   }
88235
88236                   return 'translateY(-100%)';
88237                 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
88238                   if (targetIndex === null || index2 < targetIndex) {
88239                     targetIndex = index2;
88240                   }
88241
88242                   return 'translateY(100%)';
88243                 }
88244
88245                 return null;
88246               });
88247             }).on('end', function (d3_event, d) {
88248               if (!select(this).classed('dragging')) return;
88249               var index = items.nodes().indexOf(this);
88250               select(this).classed('dragging', false);
88251               selection.selectAll('li.member-row').style('transform', null);
88252
88253               if (targetIndex !== null) {
88254                 // dragged to a new position, reorder
88255                 context.perform(actionMoveMember(d.relation.id, index, targetIndex), _t('operations.reorder_members.annotation'));
88256                 context.validator().validate();
88257               }
88258             }));
88259
88260             function bindTypeahead(d) {
88261               var row = select(this);
88262               var role = row.selectAll('input.member-role');
88263               var origValue = role.property('value');
88264
88265               function sort(value, data) {
88266                 var sameletter = [];
88267                 var other = [];
88268
88269                 for (var i = 0; i < data.length; i++) {
88270                   if (data[i].value.substring(0, value.length) === value) {
88271                     sameletter.push(data[i]);
88272                   } else {
88273                     other.push(data[i]);
88274                   }
88275                 }
88276
88277                 return sameletter.concat(other);
88278               }
88279
88280               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
88281                 // The `geometry` param is used in the `taginfo.js` interface for
88282                 // filtering results, as a key into the `tag_members_fractions`
88283                 // object.  If we don't know the geometry because the member is
88284                 // not yet downloaded, it's ok to guess based on type.
88285                 var geometry;
88286
88287                 if (d.member) {
88288                   geometry = context.graph().geometry(d.member.id);
88289                 } else if (d.type === 'relation') {
88290                   geometry = 'relation';
88291                 } else if (d.type === 'way') {
88292                   geometry = 'line';
88293                 } else {
88294                   geometry = 'point';
88295                 }
88296
88297                 var rtype = entity.tags.type;
88298                 taginfo.roles({
88299                   debounce: true,
88300                   rtype: rtype || '',
88301                   geometry: geometry,
88302                   query: role
88303                 }, function (err, data) {
88304                   if (!err) callback(sort(role, data));
88305                 });
88306               }).on('cancel', function () {
88307                 role.property('value', origValue);
88308               }));
88309             }
88310
88311             function unbind() {
88312               var row = select(this);
88313               row.selectAll('input.member-role').call(uiCombobox.off, context);
88314             }
88315           }
88316
88317           section.entityIDs = function (val) {
88318             if (!arguments.length) return _entityIDs;
88319             _entityIDs = val;
88320             return section;
88321           };
88322
88323           return section;
88324         }
88325
88326         function actionDeleteMembers(relationId, memberIndexes) {
88327           return function (graph) {
88328             // Remove the members in descending order so removals won't shift what members
88329             // are at the remaining indexes
88330             memberIndexes.sort(function (a, b) {
88331               return b - a;
88332             });
88333
88334             for (var i in memberIndexes) {
88335               graph = actionDeleteMember(relationId, memberIndexes[i])(graph);
88336             }
88337
88338             return graph;
88339           };
88340         }
88341
88342         function uiSectionRawMembershipEditor(context) {
88343           var section = uiSection('raw-membership-editor', context).shouldDisplay(function () {
88344             return _entityIDs && _entityIDs.length;
88345           }).label(function () {
88346             var parents = getSharedParentRelations();
88347             var gt = parents.length > _maxMemberships ? '>' : '';
88348             var count = gt + parents.slice(0, _maxMemberships).length;
88349             return _t('inspector.title_count', {
88350               title: _t.html('inspector.relations'),
88351               count: count
88352             });
88353           }).disclosureContent(renderDisclosureContent);
88354           var taginfo = services.taginfo;
88355           var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d) {
88356             if (d.relation) utilHighlightEntities([d.relation.id], true, context);
88357           }).itemsMouseLeave(function (d) {
88358             if (d.relation) utilHighlightEntities([d.relation.id], false, context);
88359           });
88360           var _inChange = false;
88361           var _entityIDs = [];
88362
88363           var _showBlank;
88364
88365           var _maxMemberships = 1000;
88366
88367           function getSharedParentRelations() {
88368             var parents = [];
88369
88370             for (var i = 0; i < _entityIDs.length; i++) {
88371               var entity = context.graph().hasEntity(_entityIDs[i]);
88372               if (!entity) continue;
88373
88374               if (i === 0) {
88375                 parents = context.graph().parentRelations(entity);
88376               } else {
88377                 parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
88378               }
88379
88380               if (!parents.length) break;
88381             }
88382
88383             return parents;
88384           }
88385
88386           function getMemberships() {
88387             var memberships = [];
88388             var relations = getSharedParentRelations().slice(0, _maxMemberships);
88389             var isMultiselect = _entityIDs.length > 1;
88390             var i, relation, membership, index, member, indexedMember;
88391
88392             for (i = 0; i < relations.length; i++) {
88393               relation = relations[i];
88394               membership = {
88395                 relation: relation,
88396                 members: [],
88397                 hash: osmEntity.key(relation)
88398               };
88399
88400               for (index = 0; index < relation.members.length; index++) {
88401                 member = relation.members[index];
88402
88403                 if (_entityIDs.indexOf(member.id) !== -1) {
88404                   indexedMember = Object.assign({}, member, {
88405                     index: index
88406                   });
88407                   membership.members.push(indexedMember);
88408                   membership.hash += ',' + index.toString();
88409
88410                   if (!isMultiselect) {
88411                     // For single selections, list one entry per membership per relation.
88412                     // For multiselections, list one entry per relation.
88413                     memberships.push(membership);
88414                     membership = {
88415                       relation: relation,
88416                       members: [],
88417                       hash: osmEntity.key(relation)
88418                     };
88419                   }
88420                 }
88421               }
88422
88423               if (membership.members.length) memberships.push(membership);
88424             }
88425
88426             memberships.forEach(function (membership) {
88427               membership.domId = utilUniqueDomId('membership-' + membership.relation.id);
88428               var roles = [];
88429               membership.members.forEach(function (member) {
88430                 if (roles.indexOf(member.role) === -1) roles.push(member.role);
88431               });
88432               membership.role = roles.length === 1 ? roles[0] : roles;
88433             });
88434             return memberships;
88435           }
88436
88437           function selectRelation(d3_event, d) {
88438             d3_event.preventDefault(); // remove the hover-highlight styling
88439
88440             utilHighlightEntities([d.relation.id], false, context);
88441             context.enter(modeSelect(context, [d.relation.id]));
88442           }
88443
88444           function zoomToRelation(d3_event, d) {
88445             d3_event.preventDefault();
88446             var entity = context.entity(d.relation.id);
88447             context.map().zoomToEase(entity); // highlight the relation in case it wasn't previously on-screen
88448
88449             utilHighlightEntities([d.relation.id], true, context);
88450           }
88451
88452           function changeRole(d3_event, d) {
88453             if (d === 0) return; // called on newrow (shouldn't happen)
88454
88455             if (_inChange) return; // avoid accidental recursive call #5731
88456
88457             var newRole = context.cleanRelationRole(select(this).property('value'));
88458             if (!newRole.trim() && typeof d.role !== 'string') return;
88459             var membersToUpdate = d.members.filter(function (member) {
88460               return member.role !== newRole;
88461             });
88462
88463             if (membersToUpdate.length) {
88464               _inChange = true;
88465               context.perform(function actionChangeMemberRoles(graph) {
88466                 membersToUpdate.forEach(function (member) {
88467                   var newMember = Object.assign({}, member, {
88468                     role: newRole
88469                   });
88470                   delete newMember.index;
88471                   graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
88472                 });
88473                 return graph;
88474               }, _t('operations.change_role.annotation', {
88475                 n: membersToUpdate.length
88476               }));
88477               context.validator().validate();
88478             }
88479
88480             _inChange = false;
88481           }
88482
88483           function addMembership(d, role) {
88484             this.blur(); // avoid keeping focus on the button
88485
88486             _showBlank = false;
88487
88488             function actionAddMembers(relationId, ids, role) {
88489               return function (graph) {
88490                 for (var i in ids) {
88491                   var member = {
88492                     id: ids[i],
88493                     type: graph.entity(ids[i]).type,
88494                     role: role
88495                   };
88496                   graph = actionAddMember(relationId, member)(graph);
88497                 }
88498
88499                 return graph;
88500               };
88501             }
88502
88503             if (d.relation) {
88504               context.perform(actionAddMembers(d.relation.id, _entityIDs, role), _t('operations.add_member.annotation', {
88505                 n: _entityIDs.length
88506               }));
88507               context.validator().validate();
88508             } else {
88509               var relation = osmRelation();
88510               context.perform(actionAddEntity(relation), actionAddMembers(relation.id, _entityIDs, role), _t('operations.add.annotation.relation')); // changing the mode also runs `validate`
88511
88512               context.enter(modeSelect(context, [relation.id]).newFeature(true));
88513             }
88514           }
88515
88516           function deleteMembership(d3_event, d) {
88517             this.blur(); // avoid keeping focus on the button
88518
88519             if (d === 0) return; // called on newrow (shouldn't happen)
88520             // remove the hover-highlight styling
88521
88522             utilHighlightEntities([d.relation.id], false, context);
88523             var indexes = d.members.map(function (member) {
88524               return member.index;
88525             });
88526             context.perform(actionDeleteMembers(d.relation.id, indexes), _t('operations.delete_member.annotation', {
88527               n: _entityIDs.length
88528             }));
88529             context.validator().validate();
88530           }
88531
88532           function fetchNearbyRelations(q, callback) {
88533             var newRelation = {
88534               relation: null,
88535               value: _t('inspector.new_relation'),
88536               display: _t.html('inspector.new_relation')
88537             };
88538             var entityID = _entityIDs[0];
88539             var result = [];
88540             var graph = context.graph();
88541
88542             function baseDisplayLabel(entity) {
88543               var matched = _mainPresetIndex.match(entity, graph);
88544               var presetName = matched && matched.name() || _t('inspector.relation');
88545               var entityName = utilDisplayName(entity) || '';
88546               return presetName + ' ' + entityName;
88547             }
88548
88549             var explicitRelation = q && context.hasEntity(q.toLowerCase());
88550
88551             if (explicitRelation && explicitRelation.type === 'relation' && explicitRelation.id !== entityID) {
88552               // loaded relation is specified explicitly, only show that
88553               result.push({
88554                 relation: explicitRelation,
88555                 value: baseDisplayLabel(explicitRelation) + ' ' + explicitRelation.id
88556               });
88557             } else {
88558               context.history().intersects(context.map().extent()).forEach(function (entity) {
88559                 if (entity.type !== 'relation' || entity.id === entityID) return;
88560                 var value = baseDisplayLabel(entity);
88561                 if (q && (value + ' ' + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1) return;
88562                 result.push({
88563                   relation: entity,
88564                   value: value
88565                 });
88566               });
88567               result.sort(function (a, b) {
88568                 return osmRelation.creationOrder(a.relation, b.relation);
88569               }); // Dedupe identical names by appending relation id - see #2891
88570
88571               var dupeGroups = Object.values(utilArrayGroupBy(result, 'value')).filter(function (v) {
88572                 return v.length > 1;
88573               });
88574               dupeGroups.forEach(function (group) {
88575                 group.forEach(function (obj) {
88576                   obj.value += ' ' + obj.relation.id;
88577                 });
88578               });
88579             }
88580
88581             result.forEach(function (obj) {
88582               obj.title = obj.value;
88583             });
88584             result.unshift(newRelation);
88585             callback(result);
88586           }
88587
88588           function renderDisclosureContent(selection) {
88589             var memberships = getMemberships();
88590             var list = selection.selectAll('.member-list').data([0]);
88591             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
88592             var items = list.selectAll('li.member-row-normal').data(memberships, function (d) {
88593               return d.hash;
88594             });
88595             items.exit().each(unbind).remove(); // Enter
88596
88597             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
88598
88599             itemsEnter.on('mouseover', function (d3_event, d) {
88600               utilHighlightEntities([d.relation.id], true, context);
88601             }).on('mouseout', function (d3_event, d) {
88602               utilHighlightEntities([d.relation.id], false, context);
88603             });
88604             var labelEnter = itemsEnter.append('label').attr('class', 'field-label').attr('for', function (d) {
88605               return d.domId;
88606             });
88607             var labelLink = labelEnter.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectRelation);
88608             labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
88609               var matched = _mainPresetIndex.match(d.relation, context.graph());
88610               return matched && matched.name() || _t('inspector.relation');
88611             });
88612             labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
88613               return utilDisplayName(d.relation);
88614             });
88615             labelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', deleteMembership);
88616             labelEnter.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToRelation);
88617             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88618             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
88619               return d.domId;
88620             }).property('type', 'text').property('value', function (d) {
88621               return typeof d.role === 'string' ? d.role : '';
88622             }).attr('title', function (d) {
88623               return Array.isArray(d.role) ? d.role.filter(Boolean).join('\n') : d.role;
88624             }).attr('placeholder', function (d) {
88625               return Array.isArray(d.role) ? _t('inspector.multiple_roles') : _t('inspector.role');
88626             }).classed('mixed', function (d) {
88627               return Array.isArray(d.role);
88628             }).call(utilNoAuto).on('blur', changeRole).on('change', changeRole);
88629
88630             if (taginfo) {
88631               wrapEnter.each(bindTypeahead);
88632             }
88633
88634             var newMembership = list.selectAll('.member-row-new').data(_showBlank ? [0] : []); // Exit
88635
88636             newMembership.exit().remove(); // Enter
88637
88638             var newMembershipEnter = newMembership.enter().append('li').attr('class', 'member-row member-row-new form-field');
88639             var newLabelEnter = newMembershipEnter.append('label').attr('class', 'field-label');
88640             newLabelEnter.append('input').attr('placeholder', _t('inspector.choose_relation')).attr('type', 'text').attr('class', 'member-entity-input').call(utilNoAuto);
88641             newLabelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', function () {
88642               list.selectAll('.member-row-new').remove();
88643             });
88644             var newWrapEnter = newMembershipEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88645             newWrapEnter.append('input').attr('class', 'member-role').property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto); // Update
88646
88647             newMembership = newMembership.merge(newMembershipEnter);
88648             newMembership.selectAll('.member-entity-input').on('blur', cancelEntity) // if it wasn't accepted normally, cancel it
88649             .call(nearbyCombo.on('accept', acceptEntity).on('cancel', cancelEntity)); // Container for the Add button
88650
88651             var addRow = selection.selectAll('.add-row').data([0]); // enter
88652
88653             var addRowEnter = addRow.enter().append('div').attr('class', 'add-row');
88654             var addRelationButton = addRowEnter.append('button').attr('class', 'add-relation');
88655             addRelationButton.call(svgIcon('#iD-icon-plus', 'light'));
88656             addRelationButton.call(uiTooltip().title(_t.html('inspector.add_to_relation')).placement(_mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left'));
88657             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
88658
88659             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
88660             // update
88661
88662             addRow = addRow.merge(addRowEnter);
88663             addRow.select('.add-relation').on('click', function () {
88664               _showBlank = true;
88665               section.reRender();
88666               list.selectAll('.member-entity-input').node().focus();
88667             });
88668
88669             function acceptEntity(d) {
88670               if (!d) {
88671                 cancelEntity();
88672                 return;
88673               } // remove hover-higlighting
88674
88675
88676               if (d.relation) utilHighlightEntities([d.relation.id], false, context);
88677               var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
88678               addMembership(d, role);
88679             }
88680
88681             function cancelEntity() {
88682               var input = newMembership.selectAll('.member-entity-input');
88683               input.property('value', ''); // remove hover-higlighting
88684
88685               context.surface().selectAll('.highlighted').classed('highlighted', false);
88686             }
88687
88688             function bindTypeahead(d) {
88689               var row = select(this);
88690               var role = row.selectAll('input.member-role');
88691               var origValue = role.property('value');
88692
88693               function sort(value, data) {
88694                 var sameletter = [];
88695                 var other = [];
88696
88697                 for (var i = 0; i < data.length; i++) {
88698                   if (data[i].value.substring(0, value.length) === value) {
88699                     sameletter.push(data[i]);
88700                   } else {
88701                     other.push(data[i]);
88702                   }
88703                 }
88704
88705                 return sameletter.concat(other);
88706               }
88707
88708               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
88709                 var rtype = d.relation.tags.type;
88710                 taginfo.roles({
88711                   debounce: true,
88712                   rtype: rtype || '',
88713                   geometry: context.graph().geometry(_entityIDs[0]),
88714                   query: role
88715                 }, function (err, data) {
88716                   if (!err) callback(sort(role, data));
88717                 });
88718               }).on('cancel', function () {
88719                 role.property('value', origValue);
88720               }));
88721             }
88722
88723             function unbind() {
88724               var row = select(this);
88725               row.selectAll('input.member-role').call(uiCombobox.off, context);
88726             }
88727           }
88728
88729           section.entityIDs = function (val) {
88730             if (!arguments.length) return _entityIDs;
88731             _entityIDs = val;
88732             _showBlank = false;
88733             return section;
88734           };
88735
88736           return section;
88737         }
88738
88739         function uiSectionSelectionList(context) {
88740           var _selectedIDs = [];
88741           var section = uiSection('selected-features', context).shouldDisplay(function () {
88742             return _selectedIDs.length > 1;
88743           }).label(function () {
88744             return _t('inspector.title_count', {
88745               title: _t.html('inspector.features'),
88746               count: _selectedIDs.length
88747             });
88748           }).disclosureContent(renderDisclosureContent);
88749           context.history().on('change.selectionList', function (difference) {
88750             if (difference) {
88751               section.reRender();
88752             }
88753           });
88754
88755           section.entityIDs = function (val) {
88756             if (!arguments.length) return _selectedIDs;
88757             _selectedIDs = val;
88758             return section;
88759           };
88760
88761           function selectEntity(d3_event, entity) {
88762             context.enter(modeSelect(context, [entity.id]));
88763           }
88764
88765           function deselectEntity(d3_event, entity) {
88766             d3_event.stopPropagation();
88767
88768             var selectedIDs = _selectedIDs.slice();
88769
88770             var index = selectedIDs.indexOf(entity.id);
88771
88772             if (index > -1) {
88773               selectedIDs.splice(index, 1);
88774               context.enter(modeSelect(context, selectedIDs));
88775             }
88776           }
88777
88778           function renderDisclosureContent(selection) {
88779             var list = selection.selectAll('.feature-list').data([0]);
88780             list = list.enter().append('div').attr('class', 'feature-list').merge(list);
88781
88782             var entities = _selectedIDs.map(function (id) {
88783               return context.hasEntity(id);
88784             }).filter(Boolean);
88785
88786             var items = list.selectAll('.feature-list-item').data(entities, osmEntity.key);
88787             items.exit().remove(); // Enter
88788
88789             var enter = items.enter().append('button').attr('class', 'feature-list-item').on('click', selectEntity);
88790             enter.each(function (d) {
88791               select(this).on('mouseover', function () {
88792                 utilHighlightEntities([d.id], true, context);
88793               });
88794               select(this).on('mouseout', function () {
88795                 utilHighlightEntities([d.id], false, context);
88796               });
88797             });
88798             var label = enter.append('div').attr('class', 'label');
88799             enter.append('button').attr('class', 'close').attr('title', _t('icons.deselect')).on('click', deselectEntity).call(svgIcon('#iD-icon-close'));
88800             label.append('span').attr('class', 'entity-geom-icon').call(svgIcon('', 'pre-text'));
88801             label.append('span').attr('class', 'entity-type');
88802             label.append('span').attr('class', 'entity-name'); // Update
88803
88804             items = items.merge(enter);
88805             items.selectAll('.entity-geom-icon use').attr('href', function () {
88806               var entity = this.parentNode.parentNode.__data__;
88807               return '#iD-icon-' + entity.geometry(context.graph());
88808             });
88809             items.selectAll('.entity-type').html(function (entity) {
88810               return _mainPresetIndex.match(entity, context.graph()).name();
88811             });
88812             items.selectAll('.entity-name').html(function (d) {
88813               // fetch latest entity
88814               var entity = context.entity(d.id);
88815               return utilDisplayName(entity);
88816             });
88817           }
88818
88819           return section;
88820         }
88821
88822         function uiEntityEditor(context) {
88823           var dispatch$1 = dispatch('choose');
88824           var _state = 'select';
88825           var _coalesceChanges = false;
88826           var _modified = false;
88827
88828           var _base;
88829
88830           var _entityIDs;
88831
88832           var _activePresets = [];
88833
88834           var _newFeature;
88835
88836           var _sections;
88837
88838           function entityEditor(selection) {
88839             var combinedTags = utilCombinedTags(_entityIDs, context.graph()); // Header
88840
88841             var header = selection.selectAll('.header').data([0]); // Enter
88842
88843             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
88844             headerEnter.append('button').attr('class', 'preset-reset preset-choose').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-forward' : '#iD-icon-backward'));
88845             headerEnter.append('button').attr('class', 'close').on('click', function () {
88846               context.enter(modeBrowse(context));
88847             }).call(svgIcon(_modified ? '#iD-icon-apply' : '#iD-icon-close'));
88848             headerEnter.append('h3'); // Update
88849
88850             header = header.merge(headerEnter);
88851             header.selectAll('h3').html(_entityIDs.length === 1 ? _t.html('inspector.edit') : _t.html('inspector.edit_features'));
88852             header.selectAll('.preset-reset').on('click', function () {
88853               dispatch$1.call('choose', this, _activePresets);
88854             }); // Body
88855
88856             var body = selection.selectAll('.inspector-body').data([0]); // Enter
88857
88858             var bodyEnter = body.enter().append('div').attr('class', 'entity-editor inspector-body sep-top'); // Update
88859
88860             body = body.merge(bodyEnter);
88861
88862             if (!_sections) {
88863               _sections = [uiSectionSelectionList(context), uiSectionFeatureType(context).on('choose', function (presets) {
88864                 dispatch$1.call('choose', this, presets);
88865               }), uiSectionEntityIssues(context), uiSectionPresetFields(context).on('change', changeTags).on('revert', revertTags), uiSectionRawTagEditor('raw-tag-editor', context).on('change', changeTags), uiSectionRawMemberEditor(context), uiSectionRawMembershipEditor(context)];
88866             }
88867
88868             _sections.forEach(function (section) {
88869               if (section.entityIDs) {
88870                 section.entityIDs(_entityIDs);
88871               }
88872
88873               if (section.presets) {
88874                 section.presets(_activePresets);
88875               }
88876
88877               if (section.tags) {
88878                 section.tags(combinedTags);
88879               }
88880
88881               if (section.state) {
88882                 section.state(_state);
88883               }
88884
88885               body.call(section.render);
88886             });
88887
88888             context.history().on('change.entity-editor', historyChanged);
88889
88890             function historyChanged(difference) {
88891               if (selection.selectAll('.entity-editor').empty()) return;
88892               if (_state === 'hide') return;
88893               var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
88894               if (!significant) return;
88895               _entityIDs = _entityIDs.filter(context.hasEntity);
88896               if (!_entityIDs.length) return;
88897               var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
88898               loadActivePresets();
88899               var graph = context.graph();
88900               entityEditor.modified(_base !== graph);
88901               entityEditor(selection);
88902
88903               if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
88904                 // flash the button to indicate the preset changed
88905                 context.container().selectAll('.entity-editor button.preset-reset .label').style('background-color', '#fff').transition().duration(750).style('background-color', null);
88906               }
88907             }
88908           } // Tag changes that fire on input can all get coalesced into a single
88909           // history operation when the user leaves the field.  #2342
88910           // Use explicit entityIDs in case the selection changes before the event is fired.
88911
88912
88913           function changeTags(entityIDs, changed, onInput) {
88914             var actions = [];
88915
88916             for (var i in entityIDs) {
88917               var entityID = entityIDs[i];
88918               var entity = context.entity(entityID);
88919               var tags = Object.assign({}, entity.tags); // shallow copy
88920
88921               for (var k in changed) {
88922                 if (!k) continue;
88923                 var v = changed[k];
88924
88925                 if (v !== undefined || tags.hasOwnProperty(k)) {
88926                   tags[k] = v;
88927                 }
88928               }
88929
88930               if (!onInput) {
88931                 tags = utilCleanTags(tags);
88932               }
88933
88934               if (!fastDeepEqual(entity.tags, tags)) {
88935                 actions.push(actionChangeTags(entityID, tags));
88936               }
88937             }
88938
88939             if (actions.length) {
88940               var combinedAction = function combinedAction(graph) {
88941                 actions.forEach(function (action) {
88942                   graph = action(graph);
88943                 });
88944                 return graph;
88945               };
88946
88947               var annotation = _t('operations.change_tags.annotation');
88948
88949               if (_coalesceChanges) {
88950                 context.overwrite(combinedAction, annotation);
88951               } else {
88952                 context.perform(combinedAction, annotation);
88953                 _coalesceChanges = !!onInput;
88954               }
88955             } // if leaving field (blur event), rerun validation
88956
88957
88958             if (!onInput) {
88959               context.validator().validate();
88960             }
88961           }
88962
88963           function revertTags(keys) {
88964             var actions = [];
88965
88966             for (var i in _entityIDs) {
88967               var entityID = _entityIDs[i];
88968               var original = context.graph().base().entities[entityID];
88969               var changed = {};
88970
88971               for (var j in keys) {
88972                 var key = keys[j];
88973                 changed[key] = original ? original.tags[key] : undefined;
88974               }
88975
88976               var entity = context.entity(entityID);
88977               var tags = Object.assign({}, entity.tags); // shallow copy
88978
88979               for (var k in changed) {
88980                 if (!k) continue;
88981                 var v = changed[k];
88982
88983                 if (v !== undefined || tags.hasOwnProperty(k)) {
88984                   tags[k] = v;
88985                 }
88986               }
88987
88988               tags = utilCleanTags(tags);
88989
88990               if (!fastDeepEqual(entity.tags, tags)) {
88991                 actions.push(actionChangeTags(entityID, tags));
88992               }
88993             }
88994
88995             if (actions.length) {
88996               var combinedAction = function combinedAction(graph) {
88997                 actions.forEach(function (action) {
88998                   graph = action(graph);
88999                 });
89000                 return graph;
89001               };
89002
89003               var annotation = _t('operations.change_tags.annotation');
89004
89005               if (_coalesceChanges) {
89006                 context.overwrite(combinedAction, annotation);
89007               } else {
89008                 context.perform(combinedAction, annotation);
89009                 _coalesceChanges = false;
89010               }
89011             }
89012
89013             context.validator().validate();
89014           }
89015
89016           entityEditor.modified = function (val) {
89017             if (!arguments.length) return _modified;
89018             _modified = val;
89019             return entityEditor;
89020           };
89021
89022           entityEditor.state = function (val) {
89023             if (!arguments.length) return _state;
89024             _state = val;
89025             return entityEditor;
89026           };
89027
89028           entityEditor.entityIDs = function (val) {
89029             if (!arguments.length) return _entityIDs;
89030             if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor; // exit early if no change
89031
89032             _entityIDs = val;
89033             _base = context.graph();
89034             _coalesceChanges = false;
89035             loadActivePresets(true);
89036             return entityEditor.modified(false);
89037           };
89038
89039           entityEditor.newFeature = function (val) {
89040             if (!arguments.length) return _newFeature;
89041             _newFeature = val;
89042             return entityEditor;
89043           };
89044
89045           function loadActivePresets(isForNewSelection) {
89046             var graph = context.graph();
89047             var counts = {};
89048
89049             for (var i in _entityIDs) {
89050               var entity = graph.hasEntity(_entityIDs[i]);
89051               if (!entity) return;
89052               var match = _mainPresetIndex.match(entity, graph);
89053               if (!counts[match.id]) counts[match.id] = 0;
89054               counts[match.id] += 1;
89055             }
89056
89057             var matches = Object.keys(counts).sort(function (p1, p2) {
89058               return counts[p2] - counts[p1];
89059             }).map(function (pID) {
89060               return _mainPresetIndex.item(pID);
89061             });
89062
89063             if (!isForNewSelection) {
89064               // A "weak" preset doesn't set any tags. (e.g. "Address")
89065               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")
89066
89067               if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
89068             }
89069
89070             entityEditor.presets(matches);
89071           }
89072
89073           entityEditor.presets = function (val) {
89074             if (!arguments.length) return _activePresets; // don't reload the same preset
89075
89076             if (!utilArrayIdentical(val, _activePresets)) {
89077               _activePresets = val;
89078             }
89079
89080             return entityEditor;
89081           };
89082
89083           return utilRebind(entityEditor, dispatch$1, 'on');
89084         }
89085
89086         function uiPresetList(context) {
89087           var dispatch$1 = dispatch('cancel', 'choose');
89088
89089           var _entityIDs;
89090
89091           var _currentPresets;
89092
89093           var _autofocus = false;
89094
89095           function presetList(selection) {
89096             if (!_entityIDs) return;
89097             var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
89098             selection.html('');
89099             var messagewrap = selection.append('div').attr('class', 'header fillL');
89100             var message = messagewrap.append('h3').html(_t.html('inspector.choose'));
89101             messagewrap.append('button').attr('class', 'preset-choose').on('click', function () {
89102               dispatch$1.call('cancel', this);
89103             }).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'));
89104
89105             function initialKeydown(d3_event) {
89106               // hack to let delete shortcut work when search is autofocused
89107               if (search.property('value').length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
89108                 d3_event.preventDefault();
89109                 d3_event.stopPropagation();
89110                 operationDelete(context, _entityIDs)(); // hack to let undo work when search is autofocused
89111               } else if (search.property('value').length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
89112                 d3_event.preventDefault();
89113                 d3_event.stopPropagation();
89114                 context.undo();
89115               } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
89116                 // don't check for delete/undo hack on future keydown events
89117                 select(this).on('keydown', keydown);
89118                 keydown.call(this, d3_event);
89119               }
89120             }
89121
89122             function keydown(d3_event) {
89123               // down arrow
89124               if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] && // if insertion point is at the end of the string
89125               search.node().selectionStart === search.property('value').length) {
89126                 d3_event.preventDefault();
89127                 d3_event.stopPropagation(); // move focus to the first item in the preset list
89128
89129                 var buttons = list.selectAll('.preset-list-button');
89130                 if (!buttons.empty()) buttons.nodes()[0].focus();
89131               }
89132             }
89133
89134             function keypress(d3_event) {
89135               // enter
89136               var value = search.property('value');
89137
89138               if (d3_event.keyCode === 13 && // ↩ Return
89139               value.length) {
89140                 list.selectAll('.preset-list-item:first-child').each(function (d) {
89141                   d.choose.call(this);
89142                 });
89143               }
89144             }
89145
89146             function inputevent() {
89147               var value = search.property('value');
89148               list.classed('filtered', value.length);
89149               var extent = combinedEntityExtent();
89150               var results, messageText;
89151
89152               if (value.length && extent) {
89153                 var center = extent.center();
89154                 var countryCode = iso1A2Code(center);
89155                 results = presets.search(value, entityGeometries()[0], countryCode && countryCode.toLowerCase());
89156                 messageText = _t('inspector.results', {
89157                   n: results.collection.length,
89158                   search: value
89159                 });
89160               } else {
89161                 results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro());
89162                 messageText = _t('inspector.choose');
89163               }
89164
89165               list.call(drawList, results);
89166               message.html(messageText);
89167             }
89168
89169             var searchWrap = selection.append('div').attr('class', 'search-header');
89170             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
89171             var search = searchWrap.append('input').attr('class', 'preset-search-input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keydown', initialKeydown).on('keypress', keypress).on('input', inputevent);
89172
89173             if (_autofocus) {
89174               search.node().focus(); // Safari 14 doesn't always like to focus immediately,
89175               // so try again on the next pass
89176
89177               setTimeout(function () {
89178                 search.node().focus();
89179               }, 0);
89180             }
89181
89182             var listWrap = selection.append('div').attr('class', 'inspector-body');
89183             var list = listWrap.append('div').attr('class', 'preset-list').call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro()));
89184             context.features().on('change.preset-list', updateForFeatureHiddenState);
89185           }
89186
89187           function drawList(list, presets) {
89188             presets = presets.matchAllGeometry(entityGeometries());
89189             var collection = presets.collection.reduce(function (collection, preset) {
89190               if (!preset) return collection;
89191
89192               if (preset.members) {
89193                 if (preset.members.collection.filter(function (preset) {
89194                   return preset.addable();
89195                 }).length > 1) {
89196                   collection.push(CategoryItem(preset));
89197                 }
89198               } else if (preset.addable()) {
89199                 collection.push(PresetItem(preset));
89200               }
89201
89202               return collection;
89203             }, []);
89204             var items = list.selectAll('.preset-list-item').data(collection, function (d) {
89205               return d.preset.id;
89206             });
89207             items.order();
89208             items.exit().remove();
89209             items.enter().append('div').attr('class', function (item) {
89210               return 'preset-list-item preset-' + item.preset.id.replace('/', '-');
89211             }).classed('current', function (item) {
89212               return _currentPresets.indexOf(item.preset) !== -1;
89213             }).each(function (item) {
89214               select(this).call(item);
89215             }).style('opacity', 0).transition().style('opacity', 1);
89216             updateForFeatureHiddenState();
89217           }
89218
89219           function itemKeydown(d3_event) {
89220             // the actively focused item
89221             var item = select(this.closest('.preset-list-item'));
89222             var parentItem = select(item.node().parentNode.closest('.preset-list-item')); // arrow down, move focus to the next, lower item
89223
89224             if (d3_event.keyCode === utilKeybinding.keyCodes['↓']) {
89225               d3_event.preventDefault();
89226               d3_event.stopPropagation(); // the next item in the list at the same level
89227
89228               var nextItem = select(item.node().nextElementSibling); // if there is no next item in this list
89229
89230               if (nextItem.empty()) {
89231                 // if there is a parent item
89232                 if (!parentItem.empty()) {
89233                   // the item is the last item of a sublist,
89234                   // select the next item at the parent level
89235                   nextItem = select(parentItem.node().nextElementSibling);
89236                 } // if the focused item is expanded
89237
89238               } else if (select(this).classed('expanded')) {
89239                 // select the first subitem instead
89240                 nextItem = item.select('.subgrid .preset-list-item:first-child');
89241               }
89242
89243               if (!nextItem.empty()) {
89244                 // focus on the next item
89245                 nextItem.select('.preset-list-button').node().focus();
89246               } // arrow up, move focus to the previous, higher item
89247
89248             } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑']) {
89249               d3_event.preventDefault();
89250               d3_event.stopPropagation(); // the previous item in the list at the same level
89251
89252               var previousItem = select(item.node().previousElementSibling); // if there is no previous item in this list
89253
89254               if (previousItem.empty()) {
89255                 // if there is a parent item
89256                 if (!parentItem.empty()) {
89257                   // the item is the first subitem of a sublist select the parent item
89258                   previousItem = parentItem;
89259                 } // if the previous item is expanded
89260
89261               } else if (previousItem.select('.preset-list-button').classed('expanded')) {
89262                 // select the last subitem of the sublist of the previous item
89263                 previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
89264               }
89265
89266               if (!previousItem.empty()) {
89267                 // focus on the previous item
89268                 previousItem.select('.preset-list-button').node().focus();
89269               } else {
89270                 // the focus is at the top of the list, move focus back to the search field
89271                 var search = select(this.closest('.preset-list-pane')).select('.preset-search-input');
89272                 search.node().focus();
89273               } // arrow left, move focus to the parent item if there is one
89274
89275             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
89276               d3_event.preventDefault();
89277               d3_event.stopPropagation(); // if there is a parent item, focus on the parent item
89278
89279               if (!parentItem.empty()) {
89280                 parentItem.select('.preset-list-button').node().focus();
89281               } // arrow right, choose this item
89282
89283             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
89284               d3_event.preventDefault();
89285               d3_event.stopPropagation();
89286               item.datum().choose.call(select(this).node());
89287             }
89288           }
89289
89290           function CategoryItem(preset) {
89291             var box,
89292                 sublist,
89293                 shown = false;
89294
89295             function item(selection) {
89296               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap category');
89297
89298               function click() {
89299                 var isExpanded = select(this).classed('expanded');
89300                 var iconName = isExpanded ? _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward' : '#iD-icon-down';
89301                 select(this).classed('expanded', !isExpanded);
89302                 select(this).selectAll('div.label-inner svg.icon use').attr('href', iconName);
89303                 item.choose();
89304               }
89305
89306               var geometries = entityGeometries();
89307               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) {
89308                 // right arrow, expand the focused item
89309                 if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
89310                   d3_event.preventDefault();
89311                   d3_event.stopPropagation(); // if the item isn't expanded
89312
89313                   if (!select(this).classed('expanded')) {
89314                     // toggle expansion (expand the item)
89315                     click.call(this, d3_event);
89316                   } // left arrow, collapse the focused item
89317
89318                 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
89319                   d3_event.preventDefault();
89320                   d3_event.stopPropagation(); // if the item is expanded
89321
89322                   if (select(this).classed('expanded')) {
89323                     // toggle expansion (collapse the item)
89324                     click.call(this, d3_event);
89325                   }
89326                 } else {
89327                   itemKeydown.call(this, d3_event);
89328                 }
89329               });
89330               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
89331               label.append('div').attr('class', 'namepart').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline')).append('span').html(function () {
89332                 return preset.nameLabel() + '&hellip;';
89333               });
89334               box = selection.append('div').attr('class', 'subgrid').style('max-height', '0px').style('opacity', 0);
89335               box.append('div').attr('class', 'arrow');
89336               sublist = box.append('div').attr('class', 'preset-list fillL3');
89337             }
89338
89339             item.choose = function () {
89340               if (!box || !sublist) return;
89341
89342               if (shown) {
89343                 shown = false;
89344                 box.transition().duration(200).style('opacity', '0').style('max-height', '0px').style('padding-bottom', '0px');
89345               } else {
89346                 shown = true;
89347                 var members = preset.members.matchAllGeometry(entityGeometries());
89348                 sublist.call(drawList, members);
89349                 box.transition().duration(200).style('opacity', '1').style('max-height', 200 + members.collection.length * 190 + 'px').style('padding-bottom', '10px');
89350               }
89351             };
89352
89353             item.preset = preset;
89354             return item;
89355           }
89356
89357           function PresetItem(preset) {
89358             function item(selection) {
89359               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap');
89360               var geometries = entityGeometries();
89361               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);
89362               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
89363               var nameparts = [preset.nameLabel(), preset.subtitleLabel()].filter(Boolean);
89364               label.selectAll('.namepart').data(nameparts).enter().append('div').attr('class', 'namepart').html(function (d) {
89365                 return d;
89366               });
89367               wrap.call(item.reference.button);
89368               selection.call(item.reference.body);
89369             }
89370
89371             item.choose = function () {
89372               if (select(this).classed('disabled')) return;
89373
89374               if (!context.inIntro()) {
89375                 _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
89376               }
89377
89378               context.perform(function (graph) {
89379                 for (var i in _entityIDs) {
89380                   var entityID = _entityIDs[i];
89381                   var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
89382                   graph = actionChangePreset(entityID, oldPreset, preset)(graph);
89383                 }
89384
89385                 return graph;
89386               }, _t('operations.change_tags.annotation'));
89387               context.validator().validate(); // rerun validation
89388
89389               dispatch$1.call('choose', this, preset);
89390             };
89391
89392             item.help = function (d3_event) {
89393               d3_event.stopPropagation();
89394               item.reference.toggle();
89395             };
89396
89397             item.preset = preset;
89398             item.reference = uiTagReference(preset.reference());
89399             return item;
89400           }
89401
89402           function updateForFeatureHiddenState() {
89403             if (!_entityIDs.every(context.hasEntity)) return;
89404             var geometries = entityGeometries();
89405             var button = context.container().selectAll('.preset-list .preset-list-button'); // remove existing tooltips
89406
89407             button.call(uiTooltip().destroyAny);
89408             button.each(function (item, index) {
89409               var hiddenPresetFeaturesId;
89410
89411               for (var i in geometries) {
89412                 hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i]);
89413                 if (hiddenPresetFeaturesId) break;
89414               }
89415
89416               var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
89417               select(this).classed('disabled', isHiddenPreset);
89418
89419               if (isHiddenPreset) {
89420                 var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
89421                 select(this).call(uiTooltip().title(_t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), {
89422                   features: _t.html('feature.' + hiddenPresetFeaturesId + '.description')
89423                 })).placement(index < 2 ? 'bottom' : 'top'));
89424               }
89425             });
89426           }
89427
89428           presetList.autofocus = function (val) {
89429             if (!arguments.length) return _autofocus;
89430             _autofocus = val;
89431             return presetList;
89432           };
89433
89434           presetList.entityIDs = function (val) {
89435             if (!arguments.length) return _entityIDs;
89436             _entityIDs = val;
89437
89438             if (_entityIDs && _entityIDs.length) {
89439               var presets = _entityIDs.map(function (entityID) {
89440                 return _mainPresetIndex.match(context.entity(entityID), context.graph());
89441               });
89442
89443               presetList.presets(presets);
89444             }
89445
89446             return presetList;
89447           };
89448
89449           presetList.presets = function (val) {
89450             if (!arguments.length) return _currentPresets;
89451             _currentPresets = val;
89452             return presetList;
89453           };
89454
89455           function entityGeometries() {
89456             var counts = {};
89457
89458             for (var i in _entityIDs) {
89459               var entityID = _entityIDs[i];
89460               var entity = context.entity(entityID);
89461               var geometry = entity.geometry(context.graph()); // Treat entities on addr:interpolation lines as points, not vertices (#3241)
89462
89463               if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
89464                 geometry = 'point';
89465               }
89466
89467               if (!counts[geometry]) counts[geometry] = 0;
89468               counts[geometry] += 1;
89469             }
89470
89471             return Object.keys(counts).sort(function (geom1, geom2) {
89472               return counts[geom2] - counts[geom1];
89473             });
89474           }
89475
89476           function combinedEntityExtent() {
89477             return _entityIDs.reduce(function (extent, entityID) {
89478               var entity = context.graph().entity(entityID);
89479               return extent.extend(entity.extent(context.graph()));
89480             }, geoExtent());
89481           }
89482
89483           return utilRebind(presetList, dispatch$1, 'on');
89484         }
89485
89486         function uiInspector(context) {
89487           var presetList = uiPresetList(context);
89488           var entityEditor = uiEntityEditor(context);
89489           var wrap = select(null),
89490               presetPane = select(null),
89491               editorPane = select(null);
89492           var _state = 'select';
89493
89494           var _entityIDs;
89495
89496           var _newFeature = false;
89497
89498           function inspector(selection) {
89499             presetList.entityIDs(_entityIDs).autofocus(_newFeature).on('choose', inspector.setPreset).on('cancel', function () {
89500               inspector.setPreset();
89501             });
89502             entityEditor.state(_state).entityIDs(_entityIDs).on('choose', inspector.showList);
89503             wrap = selection.selectAll('.panewrap').data([0]);
89504             var enter = wrap.enter().append('div').attr('class', 'panewrap');
89505             enter.append('div').attr('class', 'preset-list-pane pane');
89506             enter.append('div').attr('class', 'entity-editor-pane pane');
89507             wrap = wrap.merge(enter);
89508             presetPane = wrap.selectAll('.preset-list-pane');
89509             editorPane = wrap.selectAll('.entity-editor-pane');
89510
89511             function shouldDefaultToPresetList() {
89512               // always show the inspector on hover
89513               if (_state !== 'select') return false; // can only change preset on single selection
89514
89515               if (_entityIDs.length !== 1) return false;
89516               var entityID = _entityIDs[0];
89517               var entity = context.hasEntity(entityID);
89518               if (!entity) return false; // default to inspector if there are already tags
89519
89520               if (entity.hasNonGeometryTags()) return false; // prompt to select preset if feature is new and untagged
89521
89522               if (_newFeature) return true; // all existing features except vertices should default to inspector
89523
89524               if (entity.geometry(context.graph()) !== 'vertex') return false; // show vertex relations if any
89525
89526               if (context.graph().parentRelations(entity).length) return false; // show vertex issues if there are any
89527
89528               if (context.validator().getEntityIssues(entityID).length) return false; // show turn retriction editor for junction vertices
89529
89530               if (entity.isHighwayIntersection(context.graph())) return false; // otherwise show preset list for uninteresting vertices
89531
89532               return true;
89533             }
89534
89535             if (shouldDefaultToPresetList()) {
89536               wrap.style('right', '-100%');
89537               editorPane.classed('hide', true);
89538               presetPane.classed('hide', false).call(presetList);
89539             } else {
89540               wrap.style('right', '0%');
89541               presetPane.classed('hide', true);
89542               editorPane.classed('hide', false).call(entityEditor);
89543             }
89544
89545             var footer = selection.selectAll('.footer').data([0]);
89546             footer = footer.enter().append('div').attr('class', 'footer').merge(footer);
89547             footer.call(uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0])));
89548           }
89549
89550           inspector.showList = function (presets) {
89551             presetPane.classed('hide', false);
89552             wrap.transition().styleTween('right', function () {
89553               return interpolate('0%', '-100%');
89554             }).on('end', function () {
89555               editorPane.classed('hide', true);
89556             });
89557
89558             if (presets) {
89559               presetList.presets(presets);
89560             }
89561
89562             presetPane.call(presetList.autofocus(true));
89563           };
89564
89565           inspector.setPreset = function (preset) {
89566             // upon setting multipolygon, go to the area preset list instead of the editor
89567             if (preset && preset.id === 'type/multipolygon') {
89568               presetPane.call(presetList.autofocus(true));
89569             } else {
89570               editorPane.classed('hide', false);
89571               wrap.transition().styleTween('right', function () {
89572                 return interpolate('-100%', '0%');
89573               }).on('end', function () {
89574                 presetPane.classed('hide', true);
89575               });
89576
89577               if (preset) {
89578                 entityEditor.presets([preset]);
89579               }
89580
89581               editorPane.call(entityEditor);
89582             }
89583           };
89584
89585           inspector.state = function (val) {
89586             if (!arguments.length) return _state;
89587             _state = val;
89588             entityEditor.state(_state); // remove any old field help overlay that might have gotten attached to the inspector
89589
89590             context.container().selectAll('.field-help-body').remove();
89591             return inspector;
89592           };
89593
89594           inspector.entityIDs = function (val) {
89595             if (!arguments.length) return _entityIDs;
89596             _entityIDs = val;
89597             return inspector;
89598           };
89599
89600           inspector.newFeature = function (val) {
89601             if (!arguments.length) return _newFeature;
89602             _newFeature = val;
89603             return inspector;
89604           };
89605
89606           return inspector;
89607         }
89608
89609         function uiSidebar(context) {
89610           var inspector = uiInspector(context);
89611           var dataEditor = uiDataEditor(context);
89612           var noteEditor = uiNoteEditor(context);
89613           var improveOsmEditor = uiImproveOsmEditor(context);
89614           var keepRightEditor = uiKeepRightEditor(context);
89615           var osmoseEditor = uiOsmoseEditor(context);
89616
89617           var _current;
89618
89619           var _wasData = false;
89620           var _wasNote = false;
89621           var _wasQaItem = false; // use pointer events on supported platforms; fallback to mouse events
89622
89623           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
89624
89625           function sidebar(selection) {
89626             var container = context.container();
89627             var minWidth = 240;
89628             var sidebarWidth;
89629             var containerWidth;
89630             var dragOffset; // Set the initial width constraints
89631
89632             selection.style('min-width', minWidth + 'px').style('max-width', '400px').style('width', '33.3333%');
89633             var resizer = selection.append('div').attr('class', 'sidebar-resizer').on(_pointerPrefix + 'down.sidebar-resizer', pointerdown);
89634             var downPointerId, lastClientX, containerLocGetter;
89635
89636             function pointerdown(d3_event) {
89637               if (downPointerId) return;
89638               if ('button' in d3_event && d3_event.button !== 0) return;
89639               downPointerId = d3_event.pointerId || 'mouse';
89640               lastClientX = d3_event.clientX;
89641               containerLocGetter = utilFastMouse(container.node()); // offset from edge of sidebar-resizer
89642
89643               dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
89644               sidebarWidth = selection.node().getBoundingClientRect().width;
89645               containerWidth = container.node().getBoundingClientRect().width;
89646               var widthPct = sidebarWidth / containerWidth * 100;
89647               selection.style('width', widthPct + '%') // lock in current width
89648               .style('max-width', '85%'); // but allow larger widths
89649
89650               resizer.classed('dragging', true);
89651               select(window).on('touchmove.sidebar-resizer', function (d3_event) {
89652                 // disable page scrolling while resizing on touch input
89653                 d3_event.preventDefault();
89654               }, {
89655                 passive: false
89656               }).on(_pointerPrefix + 'move.sidebar-resizer', pointermove).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', pointerup);
89657             }
89658
89659             function pointermove(d3_event) {
89660               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
89661               d3_event.preventDefault();
89662               var dx = d3_event.clientX - lastClientX;
89663               lastClientX = d3_event.clientX;
89664               var isRTL = _mainLocalizer.textDirection() === 'rtl';
89665               var scaleX = isRTL ? 0 : 1;
89666               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
89667               var x = containerLocGetter(d3_event)[0] - dragOffset;
89668               sidebarWidth = isRTL ? containerWidth - x : x;
89669               var isCollapsed = selection.classed('collapsed');
89670               var shouldCollapse = sidebarWidth < minWidth;
89671               selection.classed('collapsed', shouldCollapse);
89672
89673               if (shouldCollapse) {
89674                 if (!isCollapsed) {
89675                   selection.style(xMarginProperty, '-400px').style('width', '400px');
89676                   context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
89677                 }
89678               } else {
89679                 var widthPct = sidebarWidth / containerWidth * 100;
89680                 selection.style(xMarginProperty, null).style('width', widthPct + '%');
89681
89682                 if (isCollapsed) {
89683                   context.ui().onResize([-sidebarWidth * scaleX, 0]);
89684                 } else {
89685                   context.ui().onResize([-dx * scaleX, 0]);
89686                 }
89687               }
89688             }
89689
89690             function pointerup(d3_event) {
89691               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
89692               downPointerId = null;
89693               resizer.classed('dragging', false);
89694               select(window).on('touchmove.sidebar-resizer', null).on(_pointerPrefix + 'move.sidebar-resizer', null).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', null);
89695             }
89696
89697             var featureListWrap = selection.append('div').attr('class', 'feature-list-pane').call(uiFeatureList(context));
89698             var inspectorWrap = selection.append('div').attr('class', 'inspector-hidden inspector-wrap');
89699
89700             var hoverModeSelect = function hoverModeSelect(targets) {
89701               context.container().selectAll('.feature-list-item').classed('hover', false);
89702
89703               if (context.selectedIDs().length > 1 && targets && targets.length) {
89704                 var elements = context.container().selectAll('.feature-list-item').filter(function (node) {
89705                   return targets.indexOf(node) !== -1;
89706                 });
89707
89708                 if (!elements.empty()) {
89709                   elements.classed('hover', true);
89710                 }
89711               }
89712             };
89713
89714             sidebar.hoverModeSelect = throttle(hoverModeSelect, 200);
89715
89716             function hover(targets) {
89717               var datum = targets && targets.length && targets[0];
89718
89719               if (datum && datum.__featurehash__) {
89720                 // hovering on data
89721                 _wasData = true;
89722                 sidebar.show(dataEditor.datum(datum));
89723                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89724               } else if (datum instanceof osmNote) {
89725                 if (context.mode().id === 'drag-note') return;
89726                 _wasNote = true;
89727                 var osm = services.osm;
89728
89729                 if (osm) {
89730                   datum = osm.getNote(datum.id); // marker may contain stale data - get latest
89731                 }
89732
89733                 sidebar.show(noteEditor.note(datum));
89734                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89735               } else if (datum instanceof QAItem) {
89736                 _wasQaItem = true;
89737                 var errService = services[datum.service];
89738
89739                 if (errService) {
89740                   // marker may contain stale data - get latest
89741                   datum = errService.getError(datum.id);
89742                 } // Currently only three possible services
89743
89744
89745                 var errEditor;
89746
89747                 if (datum.service === 'keepRight') {
89748                   errEditor = keepRightEditor;
89749                 } else if (datum.service === 'osmose') {
89750                   errEditor = osmoseEditor;
89751                 } else {
89752                   errEditor = improveOsmEditor;
89753                 }
89754
89755                 context.container().selectAll('.qaItem.' + datum.service).classed('hover', function (d) {
89756                   return d.id === datum.id;
89757                 });
89758                 sidebar.show(errEditor.error(datum));
89759                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89760               } else if (!_current && datum instanceof osmEntity) {
89761                 featureListWrap.classed('inspector-hidden', true);
89762                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', true);
89763
89764                 if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum.id]) || inspector.state() !== 'hover') {
89765                   inspector.state('hover').entityIDs([datum.id]).newFeature(false);
89766                   inspectorWrap.call(inspector);
89767                 }
89768               } else if (!_current) {
89769                 featureListWrap.classed('inspector-hidden', false);
89770                 inspectorWrap.classed('inspector-hidden', true);
89771                 inspector.state('hide');
89772               } else if (_wasData || _wasNote || _wasQaItem) {
89773                 _wasNote = false;
89774                 _wasData = false;
89775                 _wasQaItem = false;
89776                 context.container().selectAll('.note').classed('hover', false);
89777                 context.container().selectAll('.qaItem').classed('hover', false);
89778                 sidebar.hide();
89779               }
89780             }
89781
89782             sidebar.hover = throttle(hover, 200);
89783
89784             sidebar.intersects = function (extent) {
89785               var rect = selection.node().getBoundingClientRect();
89786               return extent.intersects([context.projection.invert([0, rect.height]), context.projection.invert([rect.width, 0])]);
89787             };
89788
89789             sidebar.select = function (ids, newFeature) {
89790               sidebar.hide();
89791
89792               if (ids && ids.length) {
89793                 var entity = ids.length === 1 && context.entity(ids[0]);
89794
89795                 if (entity && newFeature && selection.classed('collapsed')) {
89796                   // uncollapse the sidebar
89797                   var extent = entity.extent(context.graph());
89798                   sidebar.expand(sidebar.intersects(extent));
89799                 }
89800
89801                 featureListWrap.classed('inspector-hidden', true);
89802                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', false); // reload the UI even if the ids are the same since the entities
89803                 // themselves may have changed
89804
89805                 inspector.state('select').entityIDs(ids).newFeature(newFeature);
89806                 inspectorWrap.call(inspector);
89807               } else {
89808                 inspector.state('hide');
89809               }
89810             };
89811
89812             sidebar.showPresetList = function () {
89813               inspector.showList();
89814             };
89815
89816             sidebar.show = function (component, element) {
89817               featureListWrap.classed('inspector-hidden', true);
89818               inspectorWrap.classed('inspector-hidden', true);
89819               if (_current) _current.remove();
89820               _current = selection.append('div').attr('class', 'sidebar-component').call(component, element);
89821             };
89822
89823             sidebar.hide = function () {
89824               featureListWrap.classed('inspector-hidden', false);
89825               inspectorWrap.classed('inspector-hidden', true);
89826               if (_current) _current.remove();
89827               _current = null;
89828             };
89829
89830             sidebar.expand = function (moveMap) {
89831               if (selection.classed('collapsed')) {
89832                 sidebar.toggle(moveMap);
89833               }
89834             };
89835
89836             sidebar.collapse = function (moveMap) {
89837               if (!selection.classed('collapsed')) {
89838                 sidebar.toggle(moveMap);
89839               }
89840             };
89841
89842             sidebar.toggle = function (moveMap) {
89843               // Don't allow sidebar to toggle when the user is in the walkthrough.
89844               if (context.inIntro()) return;
89845               var isCollapsed = selection.classed('collapsed');
89846               var isCollapsing = !isCollapsed;
89847               var isRTL = _mainLocalizer.textDirection() === 'rtl';
89848               var scaleX = isRTL ? 0 : 1;
89849               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
89850               sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px
89851
89852               selection.style('width', sidebarWidth + 'px');
89853               var startMargin, endMargin, lastMargin;
89854
89855               if (isCollapsing) {
89856                 startMargin = lastMargin = 0;
89857                 endMargin = -sidebarWidth;
89858               } else {
89859                 startMargin = lastMargin = -sidebarWidth;
89860                 endMargin = 0;
89861               }
89862
89863               selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
89864                 var i = d3_interpolateNumber(startMargin, endMargin);
89865                 return function (t) {
89866                   var dx = lastMargin - Math.round(i(t));
89867                   lastMargin = lastMargin - dx;
89868                   context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
89869                 };
89870               }).on('end', function () {
89871                 selection.classed('collapsed', isCollapsing); // switch back from px to %
89872
89873                 if (!isCollapsing) {
89874                   var containerWidth = container.node().getBoundingClientRect().width;
89875                   var widthPct = sidebarWidth / containerWidth * 100;
89876                   selection.style(xMarginProperty, null).style('width', widthPct + '%');
89877                 }
89878               });
89879             }; // toggle the sidebar collapse when double-clicking the resizer
89880
89881
89882             resizer.on('dblclick', function (d3_event) {
89883               d3_event.preventDefault();
89884
89885               if (d3_event.sourceEvent) {
89886                 d3_event.sourceEvent.preventDefault();
89887               }
89888
89889               sidebar.toggle();
89890             }); // ensure hover sidebar is closed when zooming out beyond editable zoom
89891
89892             context.map().on('crossEditableZoom.sidebar', function (within) {
89893               if (!within && !selection.select('.inspector-hover').empty()) {
89894                 hover([]);
89895               }
89896             });
89897           }
89898
89899           sidebar.showPresetList = function () {};
89900
89901           sidebar.hover = function () {};
89902
89903           sidebar.hover.cancel = function () {};
89904
89905           sidebar.intersects = function () {};
89906
89907           sidebar.select = function () {};
89908
89909           sidebar.show = function () {};
89910
89911           sidebar.hide = function () {};
89912
89913           sidebar.expand = function () {};
89914
89915           sidebar.collapse = function () {};
89916
89917           sidebar.toggle = function () {};
89918
89919           return sidebar;
89920         }
89921
89922         function uiSourceSwitch(context) {
89923           var keys;
89924
89925           function click(d3_event) {
89926             d3_event.preventDefault();
89927             var osm = context.connection();
89928             if (!osm) return;
89929             if (context.inIntro()) return;
89930             if (context.history().hasChanges() && !window.confirm(_t('source_switch.lose_changes'))) return;
89931             var isLive = select(this).classed('live');
89932             isLive = !isLive;
89933             context.enter(modeBrowse(context));
89934             context.history().clearSaved(); // remove saved history
89935
89936             context.flush(); // remove stored data
89937
89938             select(this).html(isLive ? _t.html('source_switch.live') : _t.html('source_switch.dev')).classed('live', isLive).classed('chip', isLive);
89939             osm["switch"](isLive ? keys[0] : keys[1]); // switch connection (warning: dispatches 'change' event)
89940           }
89941
89942           var sourceSwitch = function sourceSwitch(selection) {
89943             selection.append('a').attr('href', '#').html(_t.html('source_switch.live')).attr('class', 'live chip').on('click', click);
89944           };
89945
89946           sourceSwitch.keys = function (_) {
89947             if (!arguments.length) return keys;
89948             keys = _;
89949             return sourceSwitch;
89950           };
89951
89952           return sourceSwitch;
89953         }
89954
89955         function uiSpinner(context) {
89956           var osm = context.connection();
89957           return function (selection) {
89958             var img = selection.append('img').attr('src', context.imagePath('loader-black.gif')).style('opacity', 0);
89959
89960             if (osm) {
89961               osm.on('loading.spinner', function () {
89962                 img.transition().style('opacity', 1);
89963               }).on('loaded.spinner', function () {
89964                 img.transition().style('opacity', 0);
89965               });
89966             }
89967           };
89968         }
89969
89970         function uiSplash(context) {
89971           return function (selection) {
89972             // Exception - if there are restorable changes, skip this splash screen.
89973             // This is because we currently only support one `uiModal` at a time
89974             //  and we need to show them `uiRestore`` instead of this one.
89975             if (context.history().hasRestorableChanges()) return; // If user has not seen this version of the privacy policy, show the splash again.
89976
89977             var updateMessage = '';
89978             var sawPrivacyVersion = corePreferences('sawPrivacyVersion');
89979             var showSplash = !corePreferences('sawSplash');
89980
89981             if (sawPrivacyVersion !== context.privacyVersion) {
89982               updateMessage = _t('splash.privacy_update');
89983               showSplash = true;
89984             }
89985
89986             if (!showSplash) return;
89987             corePreferences('sawSplash', true);
89988             corePreferences('sawPrivacyVersion', context.privacyVersion); // fetch intro graph data now, while user is looking at the splash screen
89989
89990             _mainFileFetcher.get('intro_graph');
89991             var modalSelection = uiModal(selection);
89992             modalSelection.select('.modal').attr('class', 'modal-splash modal');
89993             var introModal = modalSelection.select('.content').append('div').attr('class', 'fillL');
89994             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('splash.welcome'));
89995             var modalSection = introModal.append('div').attr('class', 'modal-section');
89996             modalSection.append('p').html(_t.html('splash.text', {
89997               version: context.version,
89998               website: '<a target="_blank" href="http://ideditor.blog/">ideditor.blog</a>',
89999               github: '<a target="_blank" href="https://github.com/openstreetmap/iD">github.com</a>'
90000             }));
90001             modalSection.append('p').html(_t.html('splash.privacy', {
90002               updateMessage: updateMessage,
90003               privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t('splash.privacy_policy') + '</a>'
90004             }));
90005             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
90006             var walkthrough = buttonWrap.append('button').attr('class', 'walkthrough').on('click', function () {
90007               context.container().call(uiIntro(context));
90008               modalSelection.close();
90009             });
90010             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
90011             walkthrough.append('div').html(_t.html('splash.walkthrough'));
90012             var startEditing = buttonWrap.append('button').attr('class', 'start-editing').on('click', modalSelection.close);
90013             startEditing.append('svg').attr('class', 'logo logo-features').append('use').attr('xlink:href', '#iD-logo-features');
90014             startEditing.append('div').html(_t.html('splash.start'));
90015             modalSelection.select('button.close').attr('class', 'hide');
90016           };
90017         }
90018
90019         function uiStatus(context) {
90020           var osm = context.connection();
90021           return function (selection) {
90022             if (!osm) return;
90023
90024             function update(err, apiStatus) {
90025               selection.html('');
90026
90027               if (err) {
90028                 if (apiStatus === 'connectionSwitched') {
90029                   // if the connection was just switched, we can't rely on
90030                   // the status (we're getting the status of the previous api)
90031                   return;
90032                 } else if (apiStatus === 'rateLimited') {
90033                   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) {
90034                     d3_event.preventDefault();
90035                     osm.authenticate();
90036                   });
90037                 } else {
90038                   // don't allow retrying too rapidly
90039                   var throttledRetry = throttle(function () {
90040                     // try loading the visible tiles
90041                     context.loadTiles(context.projection); // manually reload the status too in case all visible tiles were already loaded
90042
90043                     osm.reloadApiStatus();
90044                   }, 2000); // eslint-disable-next-line no-warning-comments
90045                   // TODO: nice messages for different error types
90046
90047
90048                   selection.html(_t.html('osm_api_status.message.error') + ' ').append('a').attr('href', '#') // let the user manually retry their connection directly
90049                   .html(_t.html('osm_api_status.retry')).on('click.retry', function (d3_event) {
90050                     d3_event.preventDefault();
90051                     throttledRetry();
90052                   });
90053                 }
90054               } else if (apiStatus === 'readonly') {
90055                 selection.html(_t.html('osm_api_status.message.readonly'));
90056               } else if (apiStatus === 'offline') {
90057                 selection.html(_t.html('osm_api_status.message.offline'));
90058               }
90059
90060               selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
90061             }
90062
90063             osm.on('apiStatusChange.uiStatus', update); // reload the status periodically regardless of other factors
90064
90065             window.setInterval(function () {
90066               osm.reloadApiStatus();
90067             }, 90000); // load the initial status in case no OSM data was loaded yet
90068
90069             osm.reloadApiStatus();
90070           };
90071         }
90072
90073         function modeDrawArea(context, wayID, startGraph, button) {
90074           var mode = {
90075             button: button,
90076             id: 'draw-area'
90077           };
90078           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawArea', function () {
90079             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.areas'))();
90080           });
90081           mode.wayID = wayID;
90082
90083           mode.enter = function () {
90084             context.install(behavior);
90085           };
90086
90087           mode.exit = function () {
90088             context.uninstall(behavior);
90089           };
90090
90091           mode.selectedIDs = function () {
90092             return [wayID];
90093           };
90094
90095           mode.activeID = function () {
90096             return behavior && behavior.activeID() || [];
90097           };
90098
90099           return mode;
90100         }
90101
90102         function modeAddArea(context, mode) {
90103           mode.id = 'add-area';
90104           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
90105           var defaultTags = {
90106             area: 'yes'
90107           };
90108           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
90109
90110           function actionClose(wayId) {
90111             return function (graph) {
90112               return graph.replace(graph.entity(wayId).close());
90113             };
90114           }
90115
90116           function start(loc) {
90117             var startGraph = context.graph();
90118             var node = osmNode({
90119               loc: loc
90120             });
90121             var way = osmWay({
90122               tags: defaultTags
90123             });
90124             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
90125             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90126           }
90127
90128           function startFromWay(loc, edge) {
90129             var startGraph = context.graph();
90130             var node = osmNode({
90131               loc: loc
90132             });
90133             var way = osmWay({
90134               tags: defaultTags
90135             });
90136             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id), actionAddMidpoint({
90137               loc: loc,
90138               edge: edge
90139             }, node));
90140             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90141           }
90142
90143           function startFromNode(node) {
90144             var startGraph = context.graph();
90145             var way = osmWay({
90146               tags: defaultTags
90147             });
90148             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
90149             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90150           }
90151
90152           mode.enter = function () {
90153             context.install(behavior);
90154           };
90155
90156           mode.exit = function () {
90157             context.uninstall(behavior);
90158           };
90159
90160           return mode;
90161         }
90162
90163         function modeAddLine(context, mode) {
90164           mode.id = 'add-line';
90165           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
90166           var defaultTags = {};
90167           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
90168
90169           function start(loc) {
90170             var startGraph = context.graph();
90171             var node = osmNode({
90172               loc: loc
90173             });
90174             var way = osmWay({
90175               tags: defaultTags
90176             });
90177             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id));
90178             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90179           }
90180
90181           function startFromWay(loc, edge) {
90182             var startGraph = context.graph();
90183             var node = osmNode({
90184               loc: loc
90185             });
90186             var way = osmWay({
90187               tags: defaultTags
90188             });
90189             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionAddMidpoint({
90190               loc: loc,
90191               edge: edge
90192             }, node));
90193             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90194           }
90195
90196           function startFromNode(node) {
90197             var startGraph = context.graph();
90198             var way = osmWay({
90199               tags: defaultTags
90200             });
90201             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id));
90202             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90203           }
90204
90205           mode.enter = function () {
90206             context.install(behavior);
90207           };
90208
90209           mode.exit = function () {
90210             context.uninstall(behavior);
90211           };
90212
90213           return mode;
90214         }
90215
90216         function modeAddPoint(context, mode) {
90217           mode.id = 'add-point';
90218           var behavior = behaviorDraw(context).on('click', add).on('clickWay', addWay).on('clickNode', addNode).on('cancel', cancel).on('finish', cancel);
90219           var defaultTags = {};
90220           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
90221
90222           function add(loc) {
90223             var node = osmNode({
90224               loc: loc,
90225               tags: defaultTags
90226             });
90227             context.perform(actionAddEntity(node), _t('operations.add.annotation.point'));
90228             enterSelectMode(node);
90229           }
90230
90231           function addWay(loc, edge) {
90232             var node = osmNode({
90233               tags: defaultTags
90234             });
90235             context.perform(actionAddMidpoint({
90236               loc: loc,
90237               edge: edge
90238             }, node), _t('operations.add.annotation.vertex'));
90239             enterSelectMode(node);
90240           }
90241
90242           function enterSelectMode(node) {
90243             context.enter(modeSelect(context, [node.id]).newFeature(true));
90244           }
90245
90246           function addNode(node) {
90247             if (Object.keys(defaultTags).length === 0) {
90248               enterSelectMode(node);
90249               return;
90250             }
90251
90252             var tags = Object.assign({}, node.tags); // shallow copy
90253
90254             for (var key in defaultTags) {
90255               tags[key] = defaultTags[key];
90256             }
90257
90258             context.perform(actionChangeTags(node.id, tags), _t('operations.add.annotation.point'));
90259             enterSelectMode(node);
90260           }
90261
90262           function cancel() {
90263             context.enter(modeBrowse(context));
90264           }
90265
90266           mode.enter = function () {
90267             context.install(behavior);
90268           };
90269
90270           mode.exit = function () {
90271             context.uninstall(behavior);
90272           };
90273
90274           return mode;
90275         }
90276
90277         function modeAddNote(context) {
90278           var mode = {
90279             id: 'add-note',
90280             button: 'note',
90281             description: _t.html('modes.add_note.description'),
90282             key: _t('modes.add_note.key')
90283           };
90284           var behavior = behaviorDraw(context).on('click', add).on('cancel', cancel).on('finish', cancel);
90285
90286           function add(loc) {
90287             var osm = services.osm;
90288             if (!osm) return;
90289             var note = osmNote({
90290               loc: loc,
90291               status: 'open',
90292               comments: []
90293             });
90294             osm.replaceNote(note); // force a reraw (there is no history change that would otherwise do this)
90295
90296             context.map().pan([0, 0]);
90297             context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
90298           }
90299
90300           function cancel() {
90301             context.enter(modeBrowse(context));
90302           }
90303
90304           mode.enter = function () {
90305             context.install(behavior);
90306           };
90307
90308           mode.exit = function () {
90309             context.uninstall(behavior);
90310           };
90311
90312           return mode;
90313         }
90314
90315         function uiConflicts(context) {
90316           var dispatch$1 = dispatch('cancel', 'save');
90317           var keybinding = utilKeybinding('conflicts');
90318
90319           var _origChanges;
90320
90321           var _conflictList;
90322
90323           var _shownConflictIndex;
90324
90325           function keybindingOn() {
90326             select(document).call(keybinding.on('⎋', cancel, true));
90327           }
90328
90329           function keybindingOff() {
90330             select(document).call(keybinding.unbind);
90331           }
90332
90333           function tryAgain() {
90334             keybindingOff();
90335             dispatch$1.call('save');
90336           }
90337
90338           function cancel() {
90339             keybindingOff();
90340             dispatch$1.call('cancel');
90341           }
90342
90343           function conflicts(selection) {
90344             keybindingOn();
90345             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
90346             headerEnter.append('button').attr('class', 'fr').on('click', cancel).call(svgIcon('#iD-icon-close'));
90347             headerEnter.append('h3').html(_t.html('save.conflict.header'));
90348             var bodyEnter = selection.selectAll('.body').data([0]).enter().append('div').attr('class', 'body fillL');
90349             var conflictsHelpEnter = bodyEnter.append('div').attr('class', 'conflicts-help').html(_t.html('save.conflict.help')); // Download changes link
90350
90351             var detected = utilDetect();
90352             var changeset = new osmChangeset();
90353             delete changeset.id; // Export without changeset_id
90354
90355             var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
90356             var blob = new Blob([data], {
90357               type: 'text/xml;charset=utf-8;'
90358             });
90359             var fileName = 'changes.osc';
90360             var linkEnter = conflictsHelpEnter.selectAll('.download-changes').append('a').attr('class', 'download-changes');
90361
90362             if (detected.download) {
90363               // All except IE11 and Edge
90364               linkEnter // download the data as a file
90365               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
90366             } else {
90367               // IE11 and Edge
90368               linkEnter // open data uri in a new tab
90369               .attr('target', '_blank').on('click.download', function () {
90370                 navigator.msSaveBlob(blob, fileName);
90371               });
90372             }
90373
90374             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('save.conflict.download_changes'));
90375             bodyEnter.append('div').attr('class', 'conflict-container fillL3').call(showConflict, 0);
90376             bodyEnter.append('div').attr('class', 'conflicts-done').attr('opacity', 0).style('display', 'none').html(_t.html('save.conflict.done'));
90377             var buttonsEnter = bodyEnter.append('div').attr('class', 'buttons col12 joined conflicts-buttons');
90378             buttonsEnter.append('button').attr('disabled', _conflictList.length > 1).attr('class', 'action conflicts-button col6').html(_t.html('save.title')).on('click.try_again', tryAgain);
90379             buttonsEnter.append('button').attr('class', 'secondary-action conflicts-button col6').html(_t.html('confirm.cancel')).on('click.cancel', cancel);
90380           }
90381
90382           function showConflict(selection, index) {
90383             index = utilWrap(index, _conflictList.length);
90384             _shownConflictIndex = index;
90385             var parent = select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed..
90386
90387             if (index === _conflictList.length - 1) {
90388               window.setTimeout(function () {
90389                 parent.select('.conflicts-button').attr('disabled', null);
90390                 parent.select('.conflicts-done').transition().attr('opacity', 1).style('display', 'block');
90391               }, 250);
90392             }
90393
90394             var conflict = selection.selectAll('.conflict').data([_conflictList[index]]);
90395             conflict.exit().remove();
90396             var conflictEnter = conflict.enter().append('div').attr('class', 'conflict');
90397             conflictEnter.append('h4').attr('class', 'conflict-count').html(_t.html('save.conflict.count', {
90398               num: index + 1,
90399               total: _conflictList.length
90400             }));
90401             conflictEnter.append('a').attr('class', 'conflict-description').attr('href', '#').html(function (d) {
90402               return d.name;
90403             }).on('click', function (d3_event, d) {
90404               d3_event.preventDefault();
90405               zoomToEntity(d.id);
90406             });
90407             var details = conflictEnter.append('div').attr('class', 'conflict-detail-container');
90408             details.append('ul').attr('class', 'conflict-detail-list').selectAll('li').data(function (d) {
90409               return d.details || [];
90410             }).enter().append('li').attr('class', 'conflict-detail-item').html(function (d) {
90411               return d;
90412             });
90413             details.append('div').attr('class', 'conflict-choices').call(addChoices);
90414             details.append('div').attr('class', 'conflict-nav-buttons joined cf').selectAll('button').data(['previous', 'next']).enter().append('button').html(function (d) {
90415               return _t.html('save.conflict.' + d);
90416             }).attr('class', 'conflict-nav-button action col6').attr('disabled', function (d, i) {
90417               return i === 0 && index === 0 || i === 1 && index === _conflictList.length - 1 || null;
90418             }).on('click', function (d3_event, d) {
90419               d3_event.preventDefault();
90420               var container = parent.selectAll('.conflict-container');
90421               var sign = d === 'previous' ? -1 : 1;
90422               container.selectAll('.conflict').remove();
90423               container.call(showConflict, index + sign);
90424             });
90425           }
90426
90427           function addChoices(selection) {
90428             var choices = selection.append('ul').attr('class', 'layer-list').selectAll('li').data(function (d) {
90429               return d.choices || [];
90430             }); // enter
90431
90432             var choicesEnter = choices.enter().append('li').attr('class', 'layer');
90433             var labelEnter = choicesEnter.append('label');
90434             labelEnter.append('input').attr('type', 'radio').attr('name', function (d) {
90435               return d.id;
90436             }).on('change', function (d3_event, d) {
90437               var ul = this.parentNode.parentNode.parentNode;
90438               ul.__data__.chosen = d.id;
90439               choose(d3_event, ul, d);
90440             });
90441             labelEnter.append('span').html(function (d) {
90442               return d.text;
90443             }); // update
90444
90445             choicesEnter.merge(choices).each(function (d) {
90446               var ul = this.parentNode;
90447
90448               if (ul.__data__.chosen === d.id) {
90449                 choose(null, ul, d);
90450               }
90451             });
90452           }
90453
90454           function choose(d3_event, ul, datum) {
90455             if (d3_event) d3_event.preventDefault();
90456             select(ul).selectAll('li').classed('active', function (d) {
90457               return d === datum;
90458             }).selectAll('input').property('checked', function (d) {
90459               return d === datum;
90460             });
90461             var extent = geoExtent();
90462             var entity;
90463             entity = context.graph().hasEntity(datum.id);
90464             if (entity) extent._extend(entity.extent(context.graph()));
90465             datum.action();
90466             entity = context.graph().hasEntity(datum.id);
90467             if (entity) extent._extend(entity.extent(context.graph()));
90468             zoomToEntity(datum.id, extent);
90469           }
90470
90471           function zoomToEntity(id, extent) {
90472             context.surface().selectAll('.hover').classed('hover', false);
90473             var entity = context.graph().hasEntity(id);
90474
90475             if (entity) {
90476               if (extent) {
90477                 context.map().trimmedExtent(extent);
90478               } else {
90479                 context.map().zoomToEase(entity);
90480               }
90481
90482               context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
90483             }
90484           } // The conflict list should be an array of objects like:
90485           // {
90486           //     id: id,
90487           //     name: entityName(local),
90488           //     details: merge.conflicts(),
90489           //     chosen: 1,
90490           //     choices: [
90491           //         choice(id, keepMine, forceLocal),
90492           //         choice(id, keepTheirs, forceRemote)
90493           //     ]
90494           // }
90495
90496
90497           conflicts.conflictList = function (_) {
90498             if (!arguments.length) return _conflictList;
90499             _conflictList = _;
90500             return conflicts;
90501           };
90502
90503           conflicts.origChanges = function (_) {
90504             if (!arguments.length) return _origChanges;
90505             _origChanges = _;
90506             return conflicts;
90507           };
90508
90509           conflicts.shownEntityIds = function () {
90510             if (_conflictList && typeof _shownConflictIndex === 'number') {
90511               return [_conflictList[_shownConflictIndex].id];
90512             }
90513
90514             return [];
90515           };
90516
90517           return utilRebind(conflicts, dispatch$1, 'on');
90518         }
90519
90520         function uiConfirm(selection) {
90521           var modalSelection = uiModal(selection);
90522           modalSelection.select('.modal').classed('modal-alert', true);
90523           var section = modalSelection.select('.content');
90524           section.append('div').attr('class', 'modal-section header');
90525           section.append('div').attr('class', 'modal-section message-text');
90526           var buttons = section.append('div').attr('class', 'modal-section buttons cf');
90527
90528           modalSelection.okButton = function () {
90529             buttons.append('button').attr('class', 'button ok-button action').on('click.confirm', function () {
90530               modalSelection.remove();
90531             }).html(_t.html('confirm.okay')).node().focus();
90532             return modalSelection;
90533           };
90534
90535           return modalSelection;
90536         }
90537
90538         function uiChangesetEditor(context) {
90539           var dispatch$1 = dispatch('change');
90540           var formFields = uiFormFields(context);
90541           var commentCombo = uiCombobox(context, 'comment').caseSensitive(true);
90542
90543           var _fieldsArr;
90544
90545           var _tags;
90546
90547           var _changesetID;
90548
90549           function changesetEditor(selection) {
90550             render(selection);
90551           }
90552
90553           function render(selection) {
90554             var initial = false;
90555
90556             if (!_fieldsArr) {
90557               initial = true;
90558               var presets = _mainPresetIndex;
90559               _fieldsArr = [uiField(context, presets.field('comment'), null, {
90560                 show: true,
90561                 revert: false
90562               }), uiField(context, presets.field('source'), null, {
90563                 show: false,
90564                 revert: false
90565               }), uiField(context, presets.field('hashtags'), null, {
90566                 show: false,
90567                 revert: false
90568               })];
90569
90570               _fieldsArr.forEach(function (field) {
90571                 field.on('change', function (t, onInput) {
90572                   dispatch$1.call('change', field, undefined, t, onInput);
90573                 });
90574               });
90575             }
90576
90577             _fieldsArr.forEach(function (field) {
90578               field.tags(_tags);
90579             });
90580
90581             selection.call(formFields.fieldsArr(_fieldsArr));
90582
90583             if (initial) {
90584               var commentField = selection.select('.form-field-comment textarea');
90585               var commentNode = commentField.node();
90586
90587               if (commentNode) {
90588                 commentNode.focus();
90589                 commentNode.select();
90590               } // trigger a 'blur' event so that comment field can be cleaned
90591               // and checked for hashtags, even if retrieved from localstorage
90592
90593
90594               utilTriggerEvent(commentField, 'blur');
90595               var osm = context.connection();
90596
90597               if (osm) {
90598                 osm.userChangesets(function (err, changesets) {
90599                   if (err) return;
90600                   var comments = changesets.map(function (changeset) {
90601                     var comment = changeset.tags.comment;
90602                     return comment ? {
90603                       title: comment,
90604                       value: comment
90605                     } : null;
90606                   }).filter(Boolean);
90607                   commentField.call(commentCombo.data(utilArrayUniqBy(comments, 'title')));
90608                 });
90609               }
90610             } // Add warning if comment mentions Google
90611
90612
90613             var hasGoogle = _tags.comment.match(/google/i);
90614
90615             var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning').data(hasGoogle ? [0] : []);
90616             commentWarning.exit().transition().duration(200).style('opacity', 0).remove();
90617             var commentEnter = commentWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning comment-warning').style('opacity', 0);
90618             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'));
90619             commentEnter.transition().duration(200).style('opacity', 1);
90620           }
90621
90622           changesetEditor.tags = function (_) {
90623             if (!arguments.length) return _tags;
90624             _tags = _; // Don't reset _fieldsArr here.
90625
90626             return changesetEditor;
90627           };
90628
90629           changesetEditor.changesetID = function (_) {
90630             if (!arguments.length) return _changesetID;
90631             if (_changesetID === _) return changesetEditor;
90632             _changesetID = _;
90633             _fieldsArr = null;
90634             return changesetEditor;
90635           };
90636
90637           return utilRebind(changesetEditor, dispatch$1, 'on');
90638         }
90639
90640         function uiSectionChanges(context) {
90641           var detected = utilDetect();
90642           var _discardTags = {};
90643           _mainFileFetcher.get('discarded').then(function (d) {
90644             _discardTags = d;
90645           })["catch"](function () {
90646             /* ignore */
90647           });
90648           var section = uiSection('changes-list', context).label(function () {
90649             var history = context.history();
90650             var summary = history.difference().summary();
90651             return _t('inspector.title_count', {
90652               title: _t.html('commit.changes'),
90653               count: summary.length
90654             });
90655           }).disclosureContent(renderDisclosureContent);
90656
90657           function renderDisclosureContent(selection) {
90658             var history = context.history();
90659             var summary = history.difference().summary();
90660             var container = selection.selectAll('.commit-section').data([0]);
90661             var containerEnter = container.enter().append('div').attr('class', 'commit-section');
90662             containerEnter.append('ul').attr('class', 'changeset-list');
90663             container = containerEnter.merge(container);
90664             var items = container.select('ul').selectAll('li').data(summary);
90665             var itemsEnter = items.enter().append('li').attr('class', 'change-item');
90666             var buttons = itemsEnter.append('button').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
90667             buttons.each(function (d) {
90668               select(this).call(svgIcon('#iD-icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
90669             });
90670             buttons.append('span').attr('class', 'change-type').html(function (d) {
90671               return _t.html('commit.' + d.changeType) + ' ';
90672             });
90673             buttons.append('strong').attr('class', 'entity-type').html(function (d) {
90674               var matched = _mainPresetIndex.match(d.entity, d.graph);
90675               return matched && matched.name() || utilDisplayType(d.entity.id);
90676             });
90677             buttons.append('span').attr('class', 'entity-name').html(function (d) {
90678               var name = utilDisplayName(d.entity) || '',
90679                   string = '';
90680
90681               if (name !== '') {
90682                 string += ':';
90683               }
90684
90685               return string += ' ' + name;
90686             });
90687             items = itemsEnter.merge(items); // Download changeset link
90688
90689             var changeset = new osmChangeset().update({
90690               id: undefined
90691             });
90692             var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
90693             delete changeset.id; // Export without chnageset_id
90694
90695             var data = JXON.stringify(changeset.osmChangeJXON(changes));
90696             var blob = new Blob([data], {
90697               type: 'text/xml;charset=utf-8;'
90698             });
90699             var fileName = 'changes.osc';
90700             var linkEnter = container.selectAll('.download-changes').data([0]).enter().append('a').attr('class', 'download-changes');
90701
90702             if (detected.download) {
90703               // All except IE11 and Edge
90704               linkEnter // download the data as a file
90705               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
90706             } else {
90707               // IE11 and Edge
90708               linkEnter // open data uri in a new tab
90709               .attr('target', '_blank').on('click.download', function () {
90710                 navigator.msSaveBlob(blob, fileName);
90711               });
90712             }
90713
90714             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('commit.download_changes'));
90715
90716             function mouseover(d) {
90717               if (d.entity) {
90718                 context.surface().selectAll(utilEntityOrMemberSelector([d.entity.id], context.graph())).classed('hover', true);
90719               }
90720             }
90721
90722             function mouseout() {
90723               context.surface().selectAll('.hover').classed('hover', false);
90724             }
90725
90726             function click(d3_event, change) {
90727               if (change.changeType !== 'deleted') {
90728                 var entity = change.entity;
90729                 context.map().zoomToEase(entity);
90730                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
90731               }
90732             }
90733           }
90734
90735           return section;
90736         }
90737
90738         function uiCommitWarnings(context) {
90739           function commitWarnings(selection) {
90740             var issuesBySeverity = context.validator().getIssuesBySeverity({
90741               what: 'edited',
90742               where: 'all',
90743               includeDisabledRules: true
90744             });
90745
90746             for (var severity in issuesBySeverity) {
90747               var issues = issuesBySeverity[severity];
90748               var section = severity + '-section';
90749               var issueItem = severity + '-item';
90750               var container = selection.selectAll('.' + section).data(issues.length ? [0] : []);
90751               container.exit().remove();
90752               var containerEnter = container.enter().append('div').attr('class', 'modal-section ' + section + ' fillL2');
90753               containerEnter.append('h3').html(severity === 'warning' ? _t.html('commit.warnings') : _t.html('commit.errors'));
90754               containerEnter.append('ul').attr('class', 'changeset-list');
90755               container = containerEnter.merge(container);
90756               var items = container.select('ul').selectAll('li').data(issues, function (d) {
90757                 return d.id;
90758               });
90759               items.exit().remove();
90760               var itemsEnter = items.enter().append('li').attr('class', issueItem);
90761               var buttons = itemsEnter.append('button').on('mouseover', function (d3_event, d) {
90762                 if (d.entityIds) {
90763                   context.surface().selectAll(utilEntityOrMemberSelector(d.entityIds, context.graph())).classed('hover', true);
90764                 }
90765               }).on('mouseout', function () {
90766                 context.surface().selectAll('.hover').classed('hover', false);
90767               }).on('click', function (d3_event, d) {
90768                 context.validator().focusIssue(d);
90769               });
90770               buttons.call(svgIcon('#iD-icon-alert', 'pre-text'));
90771               buttons.append('strong').attr('class', 'issue-message');
90772               buttons.filter(function (d) {
90773                 return d.tooltip;
90774               }).call(uiTooltip().title(function (d) {
90775                 return d.tooltip;
90776               }).placement('top'));
90777               items = itemsEnter.merge(items);
90778               items.selectAll('.issue-message').html(function (d) {
90779                 return d.message(context);
90780               });
90781             }
90782           }
90783
90784           return commitWarnings;
90785         }
90786
90787         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
90788         // from https://stackoverflow.com/a/25575009
90789
90790         var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
90791         function uiCommit(context) {
90792           var dispatch$1 = dispatch('cancel');
90793
90794           var _userDetails;
90795
90796           var _selection;
90797
90798           var changesetEditor = uiChangesetEditor(context).on('change', changeTags);
90799           var rawTagEditor = uiSectionRawTagEditor('changeset-tag-editor', context).on('change', changeTags).readOnlyTags(readOnlyTags);
90800           var commitChanges = uiSectionChanges(context);
90801           var commitWarnings = uiCommitWarnings(context);
90802
90803           function commit(selection) {
90804             _selection = selection; // Initialize changeset if one does not exist yet.
90805
90806             if (!context.changeset) initChangeset();
90807             loadDerivedChangesetTags();
90808             selection.call(render);
90809           }
90810
90811           function initChangeset() {
90812             // expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
90813             var commentDate = +corePreferences('commentDate') || 0;
90814             var currDate = Date.now();
90815             var cutoff = 2 * 86400 * 1000; // 2 days
90816
90817             if (commentDate > currDate || currDate - commentDate > cutoff) {
90818               corePreferences('comment', null);
90819               corePreferences('hashtags', null);
90820               corePreferences('source', null);
90821             } // load in explicitly-set values, if any
90822
90823
90824             if (context.defaultChangesetComment()) {
90825               corePreferences('comment', context.defaultChangesetComment());
90826               corePreferences('commentDate', Date.now());
90827             }
90828
90829             if (context.defaultChangesetSource()) {
90830               corePreferences('source', context.defaultChangesetSource());
90831               corePreferences('commentDate', Date.now());
90832             }
90833
90834             if (context.defaultChangesetHashtags()) {
90835               corePreferences('hashtags', context.defaultChangesetHashtags());
90836               corePreferences('commentDate', Date.now());
90837             }
90838
90839             var detected = utilDetect();
90840             var tags = {
90841               comment: corePreferences('comment') || '',
90842               created_by: context.cleanTagValue('iD ' + context.version),
90843               host: context.cleanTagValue(detected.host),
90844               locale: context.cleanTagValue(_mainLocalizer.localeCode())
90845             }; // call findHashtags initially - this will remove stored
90846             // hashtags if any hashtags are found in the comment - #4304
90847
90848             findHashtags(tags, true);
90849             var hashtags = corePreferences('hashtags');
90850
90851             if (hashtags) {
90852               tags.hashtags = hashtags;
90853             }
90854
90855             var source = corePreferences('source');
90856
90857             if (source) {
90858               tags.source = source;
90859             }
90860
90861             var photoOverlaysUsed = context.history().photoOverlaysUsed();
90862
90863             if (photoOverlaysUsed.length) {
90864               var sources = (tags.source || '').split(';'); // include this tag for any photo layer
90865
90866               if (sources.indexOf('streetlevel imagery') === -1) {
90867                 sources.push('streetlevel imagery');
90868               } // add the photo overlays used during editing as sources
90869
90870
90871               photoOverlaysUsed.forEach(function (photoOverlay) {
90872                 if (sources.indexOf(photoOverlay) === -1) {
90873                   sources.push(photoOverlay);
90874                 }
90875               });
90876               tags.source = context.cleanTagValue(sources.join(';'));
90877             }
90878
90879             context.changeset = new osmChangeset({
90880               tags: tags
90881             });
90882           } // Calculates read-only metadata tags based on the user's editing session and applies
90883           // them to the changeset.
90884
90885
90886           function loadDerivedChangesetTags() {
90887             var osm = context.connection();
90888             if (!osm) return;
90889             var tags = Object.assign({}, context.changeset.tags); // shallow copy
90890             // assign tags for imagery used
90891
90892             var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
90893             tags.imagery_used = imageryUsed || 'None'; // assign tags for closed issues and notes
90894
90895             var osmClosed = osm.getClosedIDs();
90896             var itemType;
90897
90898             if (osmClosed.length) {
90899               tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
90900             }
90901
90902             if (services.keepRight) {
90903               var krClosed = services.keepRight.getClosedIDs();
90904
90905               if (krClosed.length) {
90906                 tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
90907               }
90908             }
90909
90910             if (services.improveOSM) {
90911               var iOsmClosed = services.improveOSM.getClosedCounts();
90912
90913               for (itemType in iOsmClosed) {
90914                 tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
90915               }
90916             }
90917
90918             if (services.osmose) {
90919               var osmoseClosed = services.osmose.getClosedCounts();
90920
90921               for (itemType in osmoseClosed) {
90922                 tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
90923               }
90924             } // remove existing issue counts
90925
90926
90927             for (var key in tags) {
90928               if (key.match(/(^warnings:)|(^resolved:)/)) {
90929                 delete tags[key];
90930               }
90931             }
90932
90933             function addIssueCounts(issues, prefix) {
90934               var issuesByType = utilArrayGroupBy(issues, 'type');
90935
90936               for (var issueType in issuesByType) {
90937                 var issuesOfType = issuesByType[issueType];
90938
90939                 if (issuesOfType[0].subtype) {
90940                   var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
90941
90942                   for (var issueSubtype in issuesBySubtype) {
90943                     var issuesOfSubtype = issuesBySubtype[issueSubtype];
90944                     tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
90945                   }
90946                 } else {
90947                   tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
90948                 }
90949               }
90950             } // add counts of warnings generated by the user's edits
90951
90952
90953             var warnings = context.validator().getIssuesBySeverity({
90954               what: 'edited',
90955               where: 'all',
90956               includeIgnored: true,
90957               includeDisabledRules: true
90958             }).warning;
90959             addIssueCounts(warnings, 'warnings'); // add counts of issues resolved by the user's edits
90960
90961             var resolvedIssues = context.validator().getResolvedIssues();
90962             addIssueCounts(resolvedIssues, 'resolved');
90963             context.changeset = context.changeset.update({
90964               tags: tags
90965             });
90966           }
90967
90968           function render(selection) {
90969             var osm = context.connection();
90970             if (!osm) return;
90971             var header = selection.selectAll('.header').data([0]);
90972             var headerTitle = header.enter().append('div').attr('class', 'header fillL');
90973             headerTitle.append('div').append('h3').html(_t.html('commit.title'));
90974             headerTitle.append('button').attr('class', 'close').on('click', function () {
90975               dispatch$1.call('cancel', this);
90976             }).call(svgIcon('#iD-icon-close'));
90977             var body = selection.selectAll('.body').data([0]);
90978             body = body.enter().append('div').attr('class', 'body').merge(body); // Changeset Section
90979
90980             var changesetSection = body.selectAll('.changeset-editor').data([0]);
90981             changesetSection = changesetSection.enter().append('div').attr('class', 'modal-section changeset-editor').merge(changesetSection);
90982             changesetSection.call(changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)); // Warnings
90983
90984             body.call(commitWarnings); // Upload Explanation
90985
90986             var saveSection = body.selectAll('.save-section').data([0]);
90987             saveSection = saveSection.enter().append('div').attr('class', 'modal-section save-section fillL').merge(saveSection);
90988             var prose = saveSection.selectAll('.commit-info').data([0]);
90989
90990             if (prose.enter().size()) {
90991               // first time, make sure to update user details in prose
90992               _userDetails = null;
90993             }
90994
90995             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()
90996             // if needed, because it can trigger a style recalculation
90997
90998             osm.userDetails(function (err, user) {
90999               if (err) return;
91000               if (_userDetails === user) return; // no change
91001
91002               _userDetails = user;
91003               var userLink = select(document.createElement('div'));
91004
91005               if (user.image_url) {
91006                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
91007               }
91008
91009               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
91010               prose.html(_t.html('commit.upload_explanation_with_user', {
91011                 user: userLink.html()
91012               }));
91013             }); // Request Review
91014
91015             var requestReview = saveSection.selectAll('.request-review').data([0]); // Enter
91016
91017             var requestReviewEnter = requestReview.enter().append('div').attr('class', 'request-review');
91018             var requestReviewDomId = utilUniqueDomId('commit-input-request-review');
91019             var labelEnter = requestReviewEnter.append('label').attr('for', requestReviewDomId);
91020             labelEnter.append('input').attr('type', 'checkbox').attr('id', requestReviewDomId);
91021             labelEnter.append('span').html(_t.html('commit.request_review')); // Update
91022
91023             requestReview = requestReview.merge(requestReviewEnter);
91024             var requestReviewInput = requestReview.selectAll('input').property('checked', isReviewRequested(context.changeset.tags)).on('change', toggleRequestReview); // Buttons
91025
91026             var buttonSection = saveSection.selectAll('.buttons').data([0]); // enter
91027
91028             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons fillL');
91029             buttonEnter.append('button').attr('class', 'secondary-action button cancel-button').append('span').attr('class', 'label').html(_t.html('commit.cancel'));
91030             var uploadButton = buttonEnter.append('button').attr('class', 'action button save-button');
91031             uploadButton.append('span').attr('class', 'label').html(_t.html('commit.save'));
91032             var uploadBlockerTooltipText = getUploadBlockerMessage(); // update
91033
91034             buttonSection = buttonSection.merge(buttonEnter);
91035             buttonSection.selectAll('.cancel-button').on('click.cancel', function () {
91036               dispatch$1.call('cancel', this);
91037             });
91038             buttonSection.selectAll('.save-button').classed('disabled', uploadBlockerTooltipText !== null).on('click.save', function () {
91039               if (!select(this).classed('disabled')) {
91040                 this.blur(); // avoid keeping focus on the button - #4641
91041
91042                 for (var key in context.changeset.tags) {
91043                   // remove any empty keys before upload
91044                   if (!key) delete context.changeset.tags[key];
91045                 }
91046
91047                 context.uploader().save(context.changeset);
91048               }
91049             }); // remove any existing tooltip
91050
91051             uiTooltip().destroyAny(buttonSection.selectAll('.save-button'));
91052
91053             if (uploadBlockerTooltipText) {
91054               buttonSection.selectAll('.save-button').call(uiTooltip().title(uploadBlockerTooltipText).placement('top'));
91055             } // Raw Tag Editor
91056
91057
91058             var tagSection = body.selectAll('.tag-section.raw-tag-editor').data([0]);
91059             tagSection = tagSection.enter().append('div').attr('class', 'modal-section tag-section raw-tag-editor').merge(tagSection);
91060             tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
91061             .render);
91062             var changesSection = body.selectAll('.commit-changes-section').data([0]);
91063             changesSection = changesSection.enter().append('div').attr('class', 'modal-section commit-changes-section').merge(changesSection); // Change summary
91064
91065             changesSection.call(commitChanges.render);
91066
91067             function toggleRequestReview() {
91068               var rr = requestReviewInput.property('checked');
91069               updateChangeset({
91070                 review_requested: rr ? 'yes' : undefined
91071               });
91072               tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
91073               .render);
91074             }
91075           }
91076
91077           function getUploadBlockerMessage() {
91078             var errors = context.validator().getIssuesBySeverity({
91079               what: 'edited',
91080               where: 'all'
91081             }).error;
91082
91083             if (errors.length) {
91084               return _t('commit.outstanding_errors_message', {
91085                 count: errors.length
91086               });
91087             } else {
91088               var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
91089
91090               if (!hasChangesetComment) {
91091                 return _t('commit.comment_needed_message');
91092               }
91093             }
91094
91095             return null;
91096           }
91097
91098           function changeTags(_, changed, onInput) {
91099             if (changed.hasOwnProperty('comment')) {
91100               if (changed.comment === undefined) {
91101                 changed.comment = '';
91102               }
91103
91104               if (!onInput) {
91105                 corePreferences('comment', changed.comment);
91106                 corePreferences('commentDate', Date.now());
91107               }
91108             }
91109
91110             if (changed.hasOwnProperty('source')) {
91111               if (changed.source === undefined) {
91112                 corePreferences('source', null);
91113               } else if (!onInput) {
91114                 corePreferences('source', changed.source);
91115                 corePreferences('commentDate', Date.now());
91116               }
91117             } // no need to update `prefs` for `hashtags` here since it's done in `updateChangeset`
91118
91119
91120             updateChangeset(changed, onInput);
91121
91122             if (_selection) {
91123               _selection.call(render);
91124             }
91125           }
91126
91127           function findHashtags(tags, commentOnly) {
91128             var detectedHashtags = commentHashtags();
91129
91130             if (detectedHashtags.length) {
91131               // always remove stored hashtags if there are hashtags in the comment - #4304
91132               corePreferences('hashtags', null);
91133             }
91134
91135             if (!detectedHashtags.length || !commentOnly) {
91136               detectedHashtags = detectedHashtags.concat(hashtagHashtags());
91137             }
91138
91139             var allLowerCase = new Set();
91140             return detectedHashtags.filter(function (hashtag) {
91141               // Compare tags as lowercase strings, but keep original case tags
91142               var lowerCase = hashtag.toLowerCase();
91143
91144               if (!allLowerCase.has(lowerCase)) {
91145                 allLowerCase.add(lowerCase);
91146                 return true;
91147               }
91148
91149               return false;
91150             }); // Extract hashtags from `comment`
91151
91152             function commentHashtags() {
91153               var matches = (tags.comment || '').replace(/http\S*/g, '') // drop anything that looks like a URL - #4289
91154               .match(hashtagRegex);
91155               return matches || [];
91156             } // Extract and clean hashtags from `hashtags`
91157
91158
91159             function hashtagHashtags() {
91160               var matches = (tags.hashtags || '').split(/[,;\s]+/).map(function (s) {
91161                 if (s[0] !== '#') {
91162                   s = '#' + s;
91163                 } // prepend '#'
91164
91165
91166                 var matched = s.match(hashtagRegex);
91167                 return matched && matched[0];
91168               }).filter(Boolean); // exclude falsy
91169
91170               return matches || [];
91171             }
91172           }
91173
91174           function isReviewRequested(tags) {
91175             var rr = tags.review_requested;
91176             if (rr === undefined) return false;
91177             rr = rr.trim().toLowerCase();
91178             return !(rr === '' || rr === 'no');
91179           }
91180
91181           function updateChangeset(changed, onInput) {
91182             var tags = Object.assign({}, context.changeset.tags); // shallow copy
91183
91184             Object.keys(changed).forEach(function (k) {
91185               var v = changed[k];
91186               k = context.cleanTagKey(k);
91187               if (readOnlyTags.indexOf(k) !== -1) return;
91188
91189               if (v === undefined) {
91190                 delete tags[k];
91191               } else if (onInput) {
91192                 tags[k] = v;
91193               } else {
91194                 tags[k] = context.cleanTagValue(v);
91195               }
91196             });
91197
91198             if (!onInput) {
91199               // when changing the comment, override hashtags with any found in comment.
91200               var commentOnly = changed.hasOwnProperty('comment') && changed.comment !== '';
91201               var arr = findHashtags(tags, commentOnly);
91202
91203               if (arr.length) {
91204                 tags.hashtags = context.cleanTagValue(arr.join(';'));
91205                 corePreferences('hashtags', tags.hashtags);
91206               } else {
91207                 delete tags.hashtags;
91208                 corePreferences('hashtags', null);
91209               }
91210             } // always update userdetails, just in case user reauthenticates as someone else
91211
91212
91213             if (_userDetails && _userDetails.changesets_count !== undefined) {
91214               var changesetsCount = parseInt(_userDetails.changesets_count, 10) + 1; // #4283
91215
91216               tags.changesets_count = String(changesetsCount); // first 100 edits - new user
91217
91218               if (changesetsCount <= 100) {
91219                 var s;
91220                 s = corePreferences('walkthrough_completed');
91221
91222                 if (s) {
91223                   tags['ideditor:walkthrough_completed'] = s;
91224                 }
91225
91226                 s = corePreferences('walkthrough_progress');
91227
91228                 if (s) {
91229                   tags['ideditor:walkthrough_progress'] = s;
91230                 }
91231
91232                 s = corePreferences('walkthrough_started');
91233
91234                 if (s) {
91235                   tags['ideditor:walkthrough_started'] = s;
91236                 }
91237               }
91238             } else {
91239               delete tags.changesets_count;
91240             }
91241
91242             if (!fastDeepEqual(context.changeset.tags, tags)) {
91243               context.changeset = context.changeset.update({
91244                 tags: tags
91245               });
91246             }
91247           }
91248
91249           commit.reset = function () {
91250             context.changeset = null;
91251           };
91252
91253           return utilRebind(commit, dispatch$1, 'on');
91254         }
91255
91256         var globalIsFinite = global_1.isFinite;
91257
91258         // `Number.isFinite` method
91259         // https://tc39.github.io/ecma262/#sec-number.isfinite
91260         var numberIsFinite = Number.isFinite || function isFinite(it) {
91261           return typeof it == 'number' && globalIsFinite(it);
91262         };
91263
91264         // `Number.isFinite` method
91265         // https://tc39.github.io/ecma262/#sec-number.isfinite
91266         _export({ target: 'Number', stat: true }, { isFinite: numberIsFinite });
91267
91268         var RADIUS = 6378137;
91269         var FLATTENING = 1 / 298.257223563;
91270         var POLAR_RADIUS$1 = 6356752.3142;
91271         var wgs84 = {
91272           RADIUS: RADIUS,
91273           FLATTENING: FLATTENING,
91274           POLAR_RADIUS: POLAR_RADIUS$1
91275         };
91276
91277         var geometry_1 = geometry;
91278         var ring = ringArea;
91279
91280         function geometry(_) {
91281           var area = 0,
91282               i;
91283
91284           switch (_.type) {
91285             case 'Polygon':
91286               return polygonArea(_.coordinates);
91287
91288             case 'MultiPolygon':
91289               for (i = 0; i < _.coordinates.length; i++) {
91290                 area += polygonArea(_.coordinates[i]);
91291               }
91292
91293               return area;
91294
91295             case 'Point':
91296             case 'MultiPoint':
91297             case 'LineString':
91298             case 'MultiLineString':
91299               return 0;
91300
91301             case 'GeometryCollection':
91302               for (i = 0; i < _.geometries.length; i++) {
91303                 area += geometry(_.geometries[i]);
91304               }
91305
91306               return area;
91307           }
91308         }
91309
91310         function polygonArea(coords) {
91311           var area = 0;
91312
91313           if (coords && coords.length > 0) {
91314             area += Math.abs(ringArea(coords[0]));
91315
91316             for (var i = 1; i < coords.length; i++) {
91317               area -= Math.abs(ringArea(coords[i]));
91318             }
91319           }
91320
91321           return area;
91322         }
91323         /**
91324          * Calculate the approximate area of the polygon were it projected onto
91325          *     the earth.  Note that this area will be positive if ring is oriented
91326          *     clockwise, otherwise it will be negative.
91327          *
91328          * Reference:
91329          * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
91330          *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
91331          *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
91332          *
91333          * Returns:
91334          * {float} The approximate signed geodesic area of the polygon in square
91335          *     meters.
91336          */
91337
91338
91339         function ringArea(coords) {
91340           var p1,
91341               p2,
91342               p3,
91343               lowerIndex,
91344               middleIndex,
91345               upperIndex,
91346               i,
91347               area = 0,
91348               coordsLength = coords.length;
91349
91350           if (coordsLength > 2) {
91351             for (i = 0; i < coordsLength; i++) {
91352               if (i === coordsLength - 2) {
91353                 // i = N-2
91354                 lowerIndex = coordsLength - 2;
91355                 middleIndex = coordsLength - 1;
91356                 upperIndex = 0;
91357               } else if (i === coordsLength - 1) {
91358                 // i = N-1
91359                 lowerIndex = coordsLength - 1;
91360                 middleIndex = 0;
91361                 upperIndex = 1;
91362               } else {
91363                 // i = 0 to N-3
91364                 lowerIndex = i;
91365                 middleIndex = i + 1;
91366                 upperIndex = i + 2;
91367               }
91368
91369               p1 = coords[lowerIndex];
91370               p2 = coords[middleIndex];
91371               p3 = coords[upperIndex];
91372               area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
91373             }
91374
91375             area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
91376           }
91377
91378           return area;
91379         }
91380
91381         function rad(_) {
91382           return _ * Math.PI / 180;
91383         }
91384
91385         var geojsonArea = {
91386           geometry: geometry_1,
91387           ring: ring
91388         };
91389
91390         function toRadians(angleInDegrees) {
91391           return angleInDegrees * Math.PI / 180;
91392         }
91393
91394         function toDegrees(angleInRadians) {
91395           return angleInRadians * 180 / Math.PI;
91396         }
91397
91398         function offset(c1, distance, bearing) {
91399           var lat1 = toRadians(c1[1]);
91400           var lon1 = toRadians(c1[0]);
91401           var dByR = distance / 6378137; // distance divided by 6378137 (radius of the earth) wgs84
91402
91403           var lat = Math.asin(Math.sin(lat1) * Math.cos(dByR) + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
91404           var lon = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
91405           return [toDegrees(lon), toDegrees(lat)];
91406         }
91407
91408         function validateCenter(center) {
91409           var validCenterLengths = [2, 3];
91410
91411           if (!Array.isArray(center) || !validCenterLengths.includes(center.length)) {
91412             throw new Error("ERROR! Center has to be an array of length two or three");
91413           }
91414
91415           var _center = _slicedToArray(center, 2),
91416               lng = _center[0],
91417               lat = _center[1];
91418
91419           if (typeof lng !== "number" || typeof lat !== "number") {
91420             throw new Error("ERROR! Longitude and Latitude has to be numbers but where ".concat(_typeof(lng), " and ").concat(_typeof(lat)));
91421           }
91422
91423           if (lng > 180 || lng < -180) {
91424             throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
91425           }
91426
91427           if (lat > 90 || lat < -90) {
91428             throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
91429           }
91430         }
91431
91432         function validateRadius(radius) {
91433           if (typeof radius !== "number") {
91434             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(_typeof(radius)));
91435           }
91436
91437           if (radius <= 0) {
91438             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
91439           }
91440         }
91441
91442         function validateNumberOfSegments(numberOfSegments) {
91443           if (typeof numberOfSegments !== "number" && numberOfSegments !== undefined) {
91444             throw new Error("ERROR! Number of segments has to be a number but was: ".concat(_typeof(numberOfSegments)));
91445           }
91446
91447           if (numberOfSegments < 3) {
91448             throw new Error("ERROR! Number of segments has to be at least 3 but was: ".concat(numberOfSegments));
91449           }
91450         }
91451
91452         function validateInput(_ref) {
91453           var center = _ref.center,
91454               radius = _ref.radius,
91455               numberOfSegments = _ref.numberOfSegments;
91456           validateCenter(center);
91457           validateRadius(radius);
91458           validateNumberOfSegments(numberOfSegments);
91459         }
91460
91461         var circleToPolygon = function circleToPolygon(center, radius, numberOfSegments) {
91462           var n = numberOfSegments ? numberOfSegments : 32; // validateInput() throws error on invalid input and do nothing on valid input
91463
91464           validateInput({
91465             center: center,
91466             radius: radius,
91467             numberOfSegments: numberOfSegments
91468           });
91469           var coordinates = [];
91470
91471           for (var i = 0; i < n; ++i) {
91472             coordinates.push(offset(center, radius, 2 * Math.PI * -i / n));
91473           }
91474
91475           coordinates.push(coordinates[0]);
91476           return {
91477             type: "Polygon",
91478             coordinates: [coordinates]
91479           };
91480         };
91481
91482         // `Number.EPSILON` constant
91483         // https://tc39.github.io/ecma262/#sec-number.epsilon
91484         _export({ target: 'Number', stat: true }, {
91485           EPSILON: Math.pow(2, -52)
91486         });
91487
91488         /**
91489          * splaytree v3.0.1
91490          * Fast Splay tree for Node and browser
91491          *
91492          * @author Alexander Milevski <info@w8r.name>
91493          * @license MIT
91494          * @preserve
91495          */
91496         var Node$1 = function Node(key, data) {
91497           _classCallCheck(this, Node);
91498
91499           this.next = null;
91500           this.key = key;
91501           this.data = data;
91502           this.left = null;
91503           this.right = null;
91504         };
91505         /* follows "An implementation of top-down splaying"
91506          * by D. Sleator <sleator@cs.cmu.edu> March 1992
91507          */
91508
91509
91510         function DEFAULT_COMPARE$1(a, b) {
91511           return a > b ? 1 : a < b ? -1 : 0;
91512         }
91513         /**
91514          * Simple top down splay, not requiring i to be in the tree t.
91515          */
91516
91517
91518         function splay(i, t, comparator) {
91519           var N = new Node$1(null, null);
91520           var l = N;
91521           var r = N;
91522
91523           while (true) {
91524             var cmp = comparator(i, t.key); //if (i < t.key) {
91525
91526             if (cmp < 0) {
91527               if (t.left === null) break; //if (i < t.left.key) {
91528
91529               if (comparator(i, t.left.key) < 0) {
91530                 var y = t.left;
91531                 /* rotate right */
91532
91533                 t.left = y.right;
91534                 y.right = t;
91535                 t = y;
91536                 if (t.left === null) break;
91537               }
91538
91539               r.left = t;
91540               /* link right */
91541
91542               r = t;
91543               t = t.left; //} else if (i > t.key) {
91544             } else if (cmp > 0) {
91545               if (t.right === null) break; //if (i > t.right.key) {
91546
91547               if (comparator(i, t.right.key) > 0) {
91548                 var _y = t.right;
91549                 /* rotate left */
91550
91551                 t.right = _y.left;
91552                 _y.left = t;
91553                 t = _y;
91554                 if (t.right === null) break;
91555               }
91556
91557               l.right = t;
91558               /* link left */
91559
91560               l = t;
91561               t = t.right;
91562             } else break;
91563           }
91564           /* assemble */
91565
91566
91567           l.right = t.left;
91568           r.left = t.right;
91569           t.left = N.right;
91570           t.right = N.left;
91571           return t;
91572         }
91573
91574         function _insert(i, data, t, comparator) {
91575           var node = new Node$1(i, data);
91576
91577           if (t === null) {
91578             node.left = node.right = null;
91579             return node;
91580           }
91581
91582           t = splay(i, t, comparator);
91583           var cmp = comparator(i, t.key);
91584
91585           if (cmp < 0) {
91586             node.left = t.left;
91587             node.right = t;
91588             t.left = null;
91589           } else if (cmp >= 0) {
91590             node.right = t.right;
91591             node.left = t;
91592             t.right = null;
91593           }
91594
91595           return node;
91596         }
91597
91598         function _split(key, v, comparator) {
91599           var left = null;
91600           var right = null;
91601
91602           if (v) {
91603             v = splay(key, v, comparator);
91604             var cmp = comparator(v.key, key);
91605
91606             if (cmp === 0) {
91607               left = v.left;
91608               right = v.right;
91609             } else if (cmp < 0) {
91610               right = v.right;
91611               v.right = null;
91612               left = v;
91613             } else {
91614               left = v.left;
91615               v.left = null;
91616               right = v;
91617             }
91618           }
91619
91620           return {
91621             left: left,
91622             right: right
91623           };
91624         }
91625
91626         function merge$4(left, right, comparator) {
91627           if (right === null) return left;
91628           if (left === null) return right;
91629           right = splay(left.key, right, comparator);
91630           right.left = left;
91631           return right;
91632         }
91633         /**
91634          * Prints level of the tree
91635          */
91636
91637
91638         function printRow(root, prefix, isTail, out, printNode) {
91639           if (root) {
91640             out("".concat(prefix).concat(isTail ? '└── ' : '├── ').concat(printNode(root), "\n"));
91641             var indent = prefix + (isTail ? '    ' : '│   ');
91642             if (root.left) printRow(root.left, indent, false, out, printNode);
91643             if (root.right) printRow(root.right, indent, true, out, printNode);
91644           }
91645         }
91646
91647         var Tree = /*#__PURE__*/function () {
91648           function Tree() {
91649             var comparator = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_COMPARE$1;
91650
91651             _classCallCheck(this, Tree);
91652
91653             this._root = null;
91654             this._size = 0;
91655             this._comparator = comparator;
91656           }
91657           /**
91658            * Inserts a key, allows duplicates
91659            */
91660
91661
91662           _createClass(Tree, [{
91663             key: "insert",
91664             value: function insert(key, data) {
91665               this._size++;
91666               return this._root = _insert(key, data, this._root, this._comparator);
91667             }
91668             /**
91669              * Adds a key, if it is not present in the tree
91670              */
91671
91672           }, {
91673             key: "add",
91674             value: function add(key, data) {
91675               var node = new Node$1(key, data);
91676
91677               if (this._root === null) {
91678                 node.left = node.right = null;
91679                 this._size++;
91680                 this._root = node;
91681               }
91682
91683               var comparator = this._comparator;
91684               var t = splay(key, this._root, comparator);
91685               var cmp = comparator(key, t.key);
91686               if (cmp === 0) this._root = t;else {
91687                 if (cmp < 0) {
91688                   node.left = t.left;
91689                   node.right = t;
91690                   t.left = null;
91691                 } else if (cmp > 0) {
91692                   node.right = t.right;
91693                   node.left = t;
91694                   t.right = null;
91695                 }
91696
91697                 this._size++;
91698                 this._root = node;
91699               }
91700               return this._root;
91701             }
91702             /**
91703              * @param  {Key} key
91704              * @return {Node|null}
91705              */
91706
91707           }, {
91708             key: "remove",
91709             value: function remove(key) {
91710               this._root = this._remove(key, this._root, this._comparator);
91711             }
91712             /**
91713              * Deletes i from the tree if it's there
91714              */
91715
91716           }, {
91717             key: "_remove",
91718             value: function _remove(i, t, comparator) {
91719               var x;
91720               if (t === null) return null;
91721               t = splay(i, t, comparator);
91722               var cmp = comparator(i, t.key);
91723
91724               if (cmp === 0) {
91725                 /* found it */
91726                 if (t.left === null) {
91727                   x = t.right;
91728                 } else {
91729                   x = splay(i, t.left, comparator);
91730                   x.right = t.right;
91731                 }
91732
91733                 this._size--;
91734                 return x;
91735               }
91736
91737               return t;
91738               /* It wasn't there */
91739             }
91740             /**
91741              * Removes and returns the node with smallest key
91742              */
91743
91744           }, {
91745             key: "pop",
91746             value: function pop() {
91747               var node = this._root;
91748
91749               if (node) {
91750                 while (node.left) {
91751                   node = node.left;
91752                 }
91753
91754                 this._root = splay(node.key, this._root, this._comparator);
91755                 this._root = this._remove(node.key, this._root, this._comparator);
91756                 return {
91757                   key: node.key,
91758                   data: node.data
91759                 };
91760               }
91761
91762               return null;
91763             }
91764             /**
91765              * Find without splaying
91766              */
91767
91768           }, {
91769             key: "findStatic",
91770             value: function findStatic(key) {
91771               var current = this._root;
91772               var compare = this._comparator;
91773
91774               while (current) {
91775                 var cmp = compare(key, current.key);
91776                 if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
91777               }
91778
91779               return null;
91780             }
91781           }, {
91782             key: "find",
91783             value: function find(key) {
91784               if (this._root) {
91785                 this._root = splay(key, this._root, this._comparator);
91786                 if (this._comparator(key, this._root.key) !== 0) return null;
91787               }
91788
91789               return this._root;
91790             }
91791           }, {
91792             key: "contains",
91793             value: function contains(key) {
91794               var current = this._root;
91795               var compare = this._comparator;
91796
91797               while (current) {
91798                 var cmp = compare(key, current.key);
91799                 if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
91800               }
91801
91802               return false;
91803             }
91804           }, {
91805             key: "forEach",
91806             value: function forEach(visitor, ctx) {
91807               var current = this._root;
91808               var Q = [];
91809               /* Initialize stack s */
91810
91811               var done = false;
91812
91813               while (!done) {
91814                 if (current !== null) {
91815                   Q.push(current);
91816                   current = current.left;
91817                 } else {
91818                   if (Q.length !== 0) {
91819                     current = Q.pop();
91820                     visitor.call(ctx, current);
91821                     current = current.right;
91822                   } else done = true;
91823                 }
91824               }
91825
91826               return this;
91827             }
91828             /**
91829              * Walk key range from `low` to `high`. Stops if `fn` returns a value.
91830              */
91831
91832           }, {
91833             key: "range",
91834             value: function range(low, high, fn, ctx) {
91835               var Q = [];
91836               var compare = this._comparator;
91837               var node = this._root;
91838               var cmp;
91839
91840               while (Q.length !== 0 || node) {
91841                 if (node) {
91842                   Q.push(node);
91843                   node = node.left;
91844                 } else {
91845                   node = Q.pop();
91846                   cmp = compare(node.key, high);
91847
91848                   if (cmp > 0) {
91849                     break;
91850                   } else if (compare(node.key, low) >= 0) {
91851                     if (fn.call(ctx, node)) return this; // stop if smth is returned
91852                   }
91853
91854                   node = node.right;
91855                 }
91856               }
91857
91858               return this;
91859             }
91860             /**
91861              * Returns array of keys
91862              */
91863
91864           }, {
91865             key: "keys",
91866             value: function keys() {
91867               var keys = [];
91868               this.forEach(function (_ref) {
91869                 var key = _ref.key;
91870                 return keys.push(key);
91871               });
91872               return keys;
91873             }
91874             /**
91875              * Returns array of all the data in the nodes
91876              */
91877
91878           }, {
91879             key: "values",
91880             value: function values() {
91881               var values = [];
91882               this.forEach(function (_ref2) {
91883                 var data = _ref2.data;
91884                 return values.push(data);
91885               });
91886               return values;
91887             }
91888           }, {
91889             key: "min",
91890             value: function min() {
91891               if (this._root) return this.minNode(this._root).key;
91892               return null;
91893             }
91894           }, {
91895             key: "max",
91896             value: function max() {
91897               if (this._root) return this.maxNode(this._root).key;
91898               return null;
91899             }
91900           }, {
91901             key: "minNode",
91902             value: function minNode() {
91903               var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
91904               if (t) while (t.left) {
91905                 t = t.left;
91906               }
91907               return t;
91908             }
91909           }, {
91910             key: "maxNode",
91911             value: function maxNode() {
91912               var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
91913               if (t) while (t.right) {
91914                 t = t.right;
91915               }
91916               return t;
91917             }
91918             /**
91919              * Returns node at given index
91920              */
91921
91922           }, {
91923             key: "at",
91924             value: function at(index) {
91925               var current = this._root;
91926               var done = false;
91927               var i = 0;
91928               var Q = [];
91929
91930               while (!done) {
91931                 if (current) {
91932                   Q.push(current);
91933                   current = current.left;
91934                 } else {
91935                   if (Q.length > 0) {
91936                     current = Q.pop();
91937                     if (i === index) return current;
91938                     i++;
91939                     current = current.right;
91940                   } else done = true;
91941                 }
91942               }
91943
91944               return null;
91945             }
91946           }, {
91947             key: "next",
91948             value: function next(d) {
91949               var root = this._root;
91950               var successor = null;
91951
91952               if (d.right) {
91953                 successor = d.right;
91954
91955                 while (successor.left) {
91956                   successor = successor.left;
91957                 }
91958
91959                 return successor;
91960               }
91961
91962               var comparator = this._comparator;
91963
91964               while (root) {
91965                 var cmp = comparator(d.key, root.key);
91966                 if (cmp === 0) break;else if (cmp < 0) {
91967                   successor = root;
91968                   root = root.left;
91969                 } else root = root.right;
91970               }
91971
91972               return successor;
91973             }
91974           }, {
91975             key: "prev",
91976             value: function prev(d) {
91977               var root = this._root;
91978               var predecessor = null;
91979
91980               if (d.left !== null) {
91981                 predecessor = d.left;
91982
91983                 while (predecessor.right) {
91984                   predecessor = predecessor.right;
91985                 }
91986
91987                 return predecessor;
91988               }
91989
91990               var comparator = this._comparator;
91991
91992               while (root) {
91993                 var cmp = comparator(d.key, root.key);
91994                 if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
91995                   predecessor = root;
91996                   root = root.right;
91997                 }
91998               }
91999
92000               return predecessor;
92001             }
92002           }, {
92003             key: "clear",
92004             value: function clear() {
92005               this._root = null;
92006               this._size = 0;
92007               return this;
92008             }
92009           }, {
92010             key: "toList",
92011             value: function toList() {
92012               return _toList(this._root);
92013             }
92014             /**
92015              * Bulk-load items. Both array have to be same size
92016              */
92017
92018           }, {
92019             key: "load",
92020             value: function load(keys) {
92021               var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
92022               var presort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
92023               var size = keys.length;
92024               var comparator = this._comparator; // sort if needed
92025
92026               if (presort) sort$1(keys, values, 0, size - 1, comparator);
92027
92028               if (this._root === null) {
92029                 // empty tree
92030                 this._root = loadRecursive$1(keys, values, 0, size);
92031                 this._size = size;
92032               } else {
92033                 // that re-builds the whole tree from two in-order traversals
92034                 var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
92035                 size = this._size + size;
92036                 this._root = sortedListToBST({
92037                   head: mergedList
92038                 }, 0, size);
92039               }
92040
92041               return this;
92042             }
92043           }, {
92044             key: "isEmpty",
92045             value: function isEmpty() {
92046               return this._root === null;
92047             }
92048           }, {
92049             key: "toString",
92050             value: function toString() {
92051               var printNode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function (n) {
92052                 return String(n.key);
92053               };
92054               var out = [];
92055               printRow(this._root, '', true, function (v) {
92056                 return out.push(v);
92057               }, printNode);
92058               return out.join('');
92059             }
92060           }, {
92061             key: "update",
92062             value: function update(key, newKey, newData) {
92063               var comparator = this._comparator;
92064
92065               var _split2 = _split(key, this._root, comparator),
92066                   left = _split2.left,
92067                   right = _split2.right;
92068
92069               if (comparator(key, newKey) < 0) {
92070                 right = _insert(newKey, newData, right, comparator);
92071               } else {
92072                 left = _insert(newKey, newData, left, comparator);
92073               }
92074
92075               this._root = merge$4(left, right, comparator);
92076             }
92077           }, {
92078             key: "split",
92079             value: function split(key) {
92080               return _split(key, this._root, this._comparator);
92081             }
92082           }, {
92083             key: "size",
92084             get: function get() {
92085               return this._size;
92086             }
92087           }, {
92088             key: "root",
92089             get: function get() {
92090               return this._root;
92091             }
92092           }]);
92093
92094           return Tree;
92095         }();
92096
92097         function loadRecursive$1(keys, values, start, end) {
92098           var size = end - start;
92099
92100           if (size > 0) {
92101             var middle = start + Math.floor(size / 2);
92102             var key = keys[middle];
92103             var data = values[middle];
92104             var node = new Node$1(key, data);
92105             node.left = loadRecursive$1(keys, values, start, middle);
92106             node.right = loadRecursive$1(keys, values, middle + 1, end);
92107             return node;
92108           }
92109
92110           return null;
92111         }
92112
92113         function createList(keys, values) {
92114           var head = new Node$1(null, null);
92115           var p = head;
92116
92117           for (var i = 0; i < keys.length; i++) {
92118             p = p.next = new Node$1(keys[i], values[i]);
92119           }
92120
92121           p.next = null;
92122           return head.next;
92123         }
92124
92125         function _toList(root) {
92126           var current = root;
92127           var Q = [];
92128           var done = false;
92129           var head = new Node$1(null, null);
92130           var p = head;
92131
92132           while (!done) {
92133             if (current) {
92134               Q.push(current);
92135               current = current.left;
92136             } else {
92137               if (Q.length > 0) {
92138                 current = p = p.next = Q.pop();
92139                 current = current.right;
92140               } else done = true;
92141             }
92142           }
92143
92144           p.next = null; // that'll work even if the tree was empty
92145
92146           return head.next;
92147         }
92148
92149         function sortedListToBST(list, start, end) {
92150           var size = end - start;
92151
92152           if (size > 0) {
92153             var middle = start + Math.floor(size / 2);
92154             var left = sortedListToBST(list, start, middle);
92155             var root = list.head;
92156             root.left = left;
92157             list.head = list.head.next;
92158             root.right = sortedListToBST(list, middle + 1, end);
92159             return root;
92160           }
92161
92162           return null;
92163         }
92164
92165         function mergeLists(l1, l2, compare) {
92166           var head = new Node$1(null, null); // dummy
92167
92168           var p = head;
92169           var p1 = l1;
92170           var p2 = l2;
92171
92172           while (p1 !== null && p2 !== null) {
92173             if (compare(p1.key, p2.key) < 0) {
92174               p.next = p1;
92175               p1 = p1.next;
92176             } else {
92177               p.next = p2;
92178               p2 = p2.next;
92179             }
92180
92181             p = p.next;
92182           }
92183
92184           if (p1 !== null) {
92185             p.next = p1;
92186           } else if (p2 !== null) {
92187             p.next = p2;
92188           }
92189
92190           return head.next;
92191         }
92192
92193         function sort$1(keys, values, left, right, compare) {
92194           if (left >= right) return;
92195           var pivot = keys[left + right >> 1];
92196           var i = left - 1;
92197           var j = right + 1;
92198
92199           while (true) {
92200             do {
92201               i++;
92202             } while (compare(keys[i], pivot) < 0);
92203
92204             do {
92205               j--;
92206             } while (compare(keys[j], pivot) > 0);
92207
92208             if (i >= j) break;
92209             var tmp = keys[i];
92210             keys[i] = keys[j];
92211             keys[j] = tmp;
92212             tmp = values[i];
92213             values[i] = values[j];
92214             values[j] = tmp;
92215           }
92216
92217           sort$1(keys, values, left, j, compare);
92218           sort$1(keys, values, j + 1, right, compare);
92219         }
92220
92221         function _classCallCheck$1(instance, Constructor) {
92222           if (!(instance instanceof Constructor)) {
92223             throw new TypeError("Cannot call a class as a function");
92224           }
92225         }
92226
92227         function _defineProperties$1(target, props) {
92228           for (var i = 0; i < props.length; i++) {
92229             var descriptor = props[i];
92230             descriptor.enumerable = descriptor.enumerable || false;
92231             descriptor.configurable = true;
92232             if ("value" in descriptor) descriptor.writable = true;
92233             Object.defineProperty(target, descriptor.key, descriptor);
92234           }
92235         }
92236
92237         function _createClass$1(Constructor, protoProps, staticProps) {
92238           if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
92239           if (staticProps) _defineProperties$1(Constructor, staticProps);
92240           return Constructor;
92241         }
92242         /**
92243          * A bounding box has the format:
92244          *
92245          *  { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
92246          *
92247          */
92248
92249
92250         var isInBbox = function isInBbox(bbox, point) {
92251           return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
92252         };
92253         /* Returns either null, or a bbox (aka an ordered pair of points)
92254          * If there is only one point of overlap, a bbox with identical points
92255          * will be returned */
92256
92257
92258         var getBboxOverlap = function getBboxOverlap(b1, b2) {
92259           // check if the bboxes overlap at all
92260           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
92261
92262           var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
92263           var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
92264
92265           var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
92266           var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
92267
92268           return {
92269             ll: {
92270               x: lowerX,
92271               y: lowerY
92272             },
92273             ur: {
92274               x: upperX,
92275               y: upperY
92276             }
92277           };
92278         };
92279         /* Javascript doesn't do integer math. Everything is
92280          * floating point with percision Number.EPSILON.
92281          *
92282          * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
92283          */
92284
92285
92286         var epsilon$2 = Number.EPSILON; // IE Polyfill
92287
92288         if (epsilon$2 === undefined) epsilon$2 = Math.pow(2, -52);
92289         var EPSILON_SQ = epsilon$2 * epsilon$2;
92290         /* FLP comparator */
92291
92292         var cmp = function cmp(a, b) {
92293           // check if they're both 0
92294           if (-epsilon$2 < a && a < epsilon$2) {
92295             if (-epsilon$2 < b && b < epsilon$2) {
92296               return 0;
92297             }
92298           } // check if they're flp equal
92299
92300
92301           var ab = a - b;
92302
92303           if (ab * ab < EPSILON_SQ * a * b) {
92304             return 0;
92305           } // normal comparison
92306
92307
92308           return a < b ? -1 : 1;
92309         };
92310         /**
92311          * This class rounds incoming values sufficiently so that
92312          * floating points problems are, for the most part, avoided.
92313          *
92314          * Incoming points are have their x & y values tested against
92315          * all previously seen x & y values. If either is 'too close'
92316          * to a previously seen value, it's value is 'snapped' to the
92317          * previously seen value.
92318          *
92319          * All points should be rounded by this class before being
92320          * stored in any data structures in the rest of this algorithm.
92321          */
92322
92323
92324         var PtRounder = /*#__PURE__*/function () {
92325           function PtRounder() {
92326             _classCallCheck$1(this, PtRounder);
92327
92328             this.reset();
92329           }
92330
92331           _createClass$1(PtRounder, [{
92332             key: "reset",
92333             value: function reset() {
92334               this.xRounder = new CoordRounder();
92335               this.yRounder = new CoordRounder();
92336             }
92337           }, {
92338             key: "round",
92339             value: function round(x, y) {
92340               return {
92341                 x: this.xRounder.round(x),
92342                 y: this.yRounder.round(y)
92343               };
92344             }
92345           }]);
92346
92347           return PtRounder;
92348         }();
92349
92350         var CoordRounder = /*#__PURE__*/function () {
92351           function CoordRounder() {
92352             _classCallCheck$1(this, CoordRounder);
92353
92354             this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
92355
92356             this.round(0);
92357           } // Note: this can rounds input values backwards or forwards.
92358           //       You might ask, why not restrict this to just rounding
92359           //       forwards? Wouldn't that allow left endpoints to always
92360           //       remain left endpoints during splitting (never change to
92361           //       right). No - it wouldn't, because we snap intersections
92362           //       to endpoints (to establish independence from the segment
92363           //       angle for t-intersections).
92364
92365
92366           _createClass$1(CoordRounder, [{
92367             key: "round",
92368             value: function round(coord) {
92369               var node = this.tree.add(coord);
92370               var prevNode = this.tree.prev(node);
92371
92372               if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
92373                 this.tree.remove(coord);
92374                 return prevNode.key;
92375               }
92376
92377               var nextNode = this.tree.next(node);
92378
92379               if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
92380                 this.tree.remove(coord);
92381                 return nextNode.key;
92382               }
92383
92384               return coord;
92385             }
92386           }]);
92387
92388           return CoordRounder;
92389         }(); // singleton available by import
92390
92391
92392         var rounder = new PtRounder();
92393         /* Cross Product of two vectors with first point at origin */
92394
92395         var crossProduct$1 = function crossProduct(a, b) {
92396           return a.x * b.y - a.y * b.x;
92397         };
92398         /* Dot Product of two vectors with first point at origin */
92399
92400
92401         var dotProduct$1 = function dotProduct(a, b) {
92402           return a.x * b.x + a.y * b.y;
92403         };
92404         /* Comparator for two vectors with same starting point */
92405
92406
92407         var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
92408           var v1 = {
92409             x: endPt1.x - basePt.x,
92410             y: endPt1.y - basePt.y
92411           };
92412           var v2 = {
92413             x: endPt2.x - basePt.x,
92414             y: endPt2.y - basePt.y
92415           };
92416           var kross = crossProduct$1(v1, v2);
92417           return cmp(kross, 0);
92418         };
92419
92420         var length = function length(v) {
92421           return Math.sqrt(dotProduct$1(v, v));
92422         };
92423         /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
92424
92425
92426         var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
92427           var vBase = {
92428             x: pBase.x - pShared.x,
92429             y: pBase.y - pShared.y
92430           };
92431           var vAngle = {
92432             x: pAngle.x - pShared.x,
92433             y: pAngle.y - pShared.y
92434           };
92435           return crossProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
92436         };
92437         /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
92438
92439
92440         var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
92441           var vBase = {
92442             x: pBase.x - pShared.x,
92443             y: pBase.y - pShared.y
92444           };
92445           var vAngle = {
92446             x: pAngle.x - pShared.x,
92447             y: pAngle.y - pShared.y
92448           };
92449           return dotProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
92450         };
92451         /* Get the x coordinate where the given line (defined by a point and vector)
92452          * crosses the horizontal line with the given y coordiante.
92453          * In the case of parrallel lines (including overlapping ones) returns null. */
92454
92455
92456         var horizontalIntersection = function horizontalIntersection(pt, v, y) {
92457           if (v.y === 0) return null;
92458           return {
92459             x: pt.x + v.x / v.y * (y - pt.y),
92460             y: y
92461           };
92462         };
92463         /* Get the y coordinate where the given line (defined by a point and vector)
92464          * crosses the vertical line with the given x coordiante.
92465          * In the case of parrallel lines (including overlapping ones) returns null. */
92466
92467
92468         var verticalIntersection = function verticalIntersection(pt, v, x) {
92469           if (v.x === 0) return null;
92470           return {
92471             x: x,
92472             y: pt.y + v.y / v.x * (x - pt.x)
92473           };
92474         };
92475         /* Get the intersection of two lines, each defined by a base point and a vector.
92476          * In the case of parrallel lines (including overlapping ones) returns null. */
92477
92478
92479         var intersection$1 = function intersection(pt1, v1, pt2, v2) {
92480           // take some shortcuts for vertical and horizontal lines
92481           // this also ensures we don't calculate an intersection and then discover
92482           // it's actually outside the bounding box of the line
92483           if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
92484           if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
92485           if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
92486           if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
92487           // This algorithm is based on Schneider and Eberly.
92488           // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
92489
92490           var kross = crossProduct$1(v1, v2);
92491           if (kross == 0) return null;
92492           var ve = {
92493             x: pt2.x - pt1.x,
92494             y: pt2.y - pt1.y
92495           };
92496           var d1 = crossProduct$1(ve, v1) / kross;
92497           var d2 = crossProduct$1(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
92498
92499           var x1 = pt1.x + d2 * v1.x,
92500               x2 = pt2.x + d1 * v2.x;
92501           var y1 = pt1.y + d2 * v1.y,
92502               y2 = pt2.y + d1 * v2.y;
92503           var x = (x1 + x2) / 2;
92504           var y = (y1 + y2) / 2;
92505           return {
92506             x: x,
92507             y: y
92508           };
92509         };
92510
92511         var SweepEvent$1 = /*#__PURE__*/function () {
92512           _createClass$1(SweepEvent, null, [{
92513             key: "compare",
92514             // for ordering sweep events in the sweep event queue
92515             value: function compare(a, b) {
92516               // favor event with a point that the sweep line hits first
92517               var ptCmp = SweepEvent.comparePoints(a.point, b.point);
92518               if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
92519
92520               if (a.point !== b.point) a.link(b); // favor right events over left
92521
92522               if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
92523               // ordering of this case is the same as for their segments
92524
92525               return Segment.compare(a.segment, b.segment);
92526             } // for ordering points in sweep line order
92527
92528           }, {
92529             key: "comparePoints",
92530             value: function comparePoints(aPt, bPt) {
92531               if (aPt.x < bPt.x) return -1;
92532               if (aPt.x > bPt.x) return 1;
92533               if (aPt.y < bPt.y) return -1;
92534               if (aPt.y > bPt.y) return 1;
92535               return 0;
92536             } // Warning: 'point' input will be modified and re-used (for performance)
92537
92538           }]);
92539
92540           function SweepEvent(point, isLeft) {
92541             _classCallCheck$1(this, SweepEvent);
92542
92543             if (point.events === undefined) point.events = [this];else point.events.push(this);
92544             this.point = point;
92545             this.isLeft = isLeft; // this.segment, this.otherSE set by factory
92546           }
92547
92548           _createClass$1(SweepEvent, [{
92549             key: "link",
92550             value: function link(other) {
92551               if (other.point === this.point) {
92552                 throw new Error('Tried to link already linked events');
92553               }
92554
92555               var otherEvents = other.point.events;
92556
92557               for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
92558                 var evt = otherEvents[i];
92559                 this.point.events.push(evt);
92560                 evt.point = this.point;
92561               }
92562
92563               this.checkForConsuming();
92564             }
92565             /* Do a pass over our linked events and check to see if any pair
92566              * of segments match, and should be consumed. */
92567
92568           }, {
92569             key: "checkForConsuming",
92570             value: function checkForConsuming() {
92571               // FIXME: The loops in this method run O(n^2) => no good.
92572               //        Maintain little ordered sweep event trees?
92573               //        Can we maintaining an ordering that avoids the need
92574               //        for the re-sorting with getLeftmostComparator in geom-out?
92575               // Compare each pair of events to see if other events also match
92576               var numEvents = this.point.events.length;
92577
92578               for (var i = 0; i < numEvents; i++) {
92579                 var evt1 = this.point.events[i];
92580                 if (evt1.segment.consumedBy !== undefined) continue;
92581
92582                 for (var j = i + 1; j < numEvents; j++) {
92583                   var evt2 = this.point.events[j];
92584                   if (evt2.consumedBy !== undefined) continue;
92585                   if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
92586                   evt1.segment.consume(evt2.segment);
92587                 }
92588               }
92589             }
92590           }, {
92591             key: "getAvailableLinkedEvents",
92592             value: function getAvailableLinkedEvents() {
92593               // point.events is always of length 2 or greater
92594               var events = [];
92595
92596               for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
92597                 var evt = this.point.events[i];
92598
92599                 if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
92600                   events.push(evt);
92601                 }
92602               }
92603
92604               return events;
92605             }
92606             /**
92607              * Returns a comparator function for sorting linked events that will
92608              * favor the event that will give us the smallest left-side angle.
92609              * All ring construction starts as low as possible heading to the right,
92610              * so by always turning left as sharp as possible we'll get polygons
92611              * without uncessary loops & holes.
92612              *
92613              * The comparator function has a compute cache such that it avoids
92614              * re-computing already-computed values.
92615              */
92616
92617           }, {
92618             key: "getLeftmostComparator",
92619             value: function getLeftmostComparator(baseEvent) {
92620               var _this = this;
92621
92622               var cache = new Map();
92623
92624               var fillCache = function fillCache(linkedEvent) {
92625                 var nextEvent = linkedEvent.otherSE;
92626                 cache.set(linkedEvent, {
92627                   sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
92628                   cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
92629                 });
92630               };
92631
92632               return function (a, b) {
92633                 if (!cache.has(a)) fillCache(a);
92634                 if (!cache.has(b)) fillCache(b);
92635
92636                 var _cache$get = cache.get(a),
92637                     asine = _cache$get.sine,
92638                     acosine = _cache$get.cosine;
92639
92640                 var _cache$get2 = cache.get(b),
92641                     bsine = _cache$get2.sine,
92642                     bcosine = _cache$get2.cosine; // both on or above x-axis
92643
92644
92645                 if (asine >= 0 && bsine >= 0) {
92646                   if (acosine < bcosine) return 1;
92647                   if (acosine > bcosine) return -1;
92648                   return 0;
92649                 } // both below x-axis
92650
92651
92652                 if (asine < 0 && bsine < 0) {
92653                   if (acosine < bcosine) return -1;
92654                   if (acosine > bcosine) return 1;
92655                   return 0;
92656                 } // one above x-axis, one below
92657
92658
92659                 if (bsine < asine) return -1;
92660                 if (bsine > asine) return 1;
92661                 return 0;
92662               };
92663             }
92664           }]);
92665
92666           return SweepEvent;
92667         }(); // segments and sweep events when all else is identical
92668
92669
92670         var segmentId = 0;
92671
92672         var Segment = /*#__PURE__*/function () {
92673           _createClass$1(Segment, null, [{
92674             key: "compare",
92675
92676             /* This compare() function is for ordering segments in the sweep
92677              * line tree, and does so according to the following criteria:
92678              *
92679              * Consider the vertical line that lies an infinestimal step to the
92680              * right of the right-more of the two left endpoints of the input
92681              * segments. Imagine slowly moving a point up from negative infinity
92682              * in the increasing y direction. Which of the two segments will that
92683              * point intersect first? That segment comes 'before' the other one.
92684              *
92685              * If neither segment would be intersected by such a line, (if one
92686              * or more of the segments are vertical) then the line to be considered
92687              * is directly on the right-more of the two left inputs.
92688              */
92689             value: function compare(a, b) {
92690               var alx = a.leftSE.point.x;
92691               var blx = b.leftSE.point.x;
92692               var arx = a.rightSE.point.x;
92693               var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
92694
92695               if (brx < alx) return 1;
92696               if (arx < blx) return -1;
92697               var aly = a.leftSE.point.y;
92698               var bly = b.leftSE.point.y;
92699               var ary = a.rightSE.point.y;
92700               var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
92701
92702               if (alx < blx) {
92703                 // are the two segments in the same horizontal plane?
92704                 if (bly < aly && bly < ary) return 1;
92705                 if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
92706
92707                 var aCmpBLeft = a.comparePoint(b.leftSE.point);
92708                 if (aCmpBLeft < 0) return 1;
92709                 if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
92710
92711                 var bCmpARight = b.comparePoint(a.rightSE.point);
92712                 if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
92713                 // left endpoint to be first (arbitrary?)
92714
92715                 return -1;
92716               } // is left endpoint of segment A the right-more?
92717
92718
92719               if (alx > blx) {
92720                 if (aly < bly && aly < bry) return -1;
92721                 if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
92722
92723                 var bCmpALeft = b.comparePoint(a.leftSE.point);
92724                 if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
92725
92726                 var aCmpBRight = a.comparePoint(b.rightSE.point);
92727                 if (aCmpBRight < 0) return 1;
92728                 if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
92729                 // left endpoint to be first (arbitrary?)
92730
92731                 return 1;
92732               } // if we get here, the two left endpoints are in the same
92733               // vertical plane, ie alx === blx
92734               // consider the lower left-endpoint to come first
92735
92736
92737               if (aly < bly) return -1;
92738               if (aly > bly) return 1; // left endpoints are identical
92739               // check for colinearity by using the left-more right endpoint
92740               // is the A right endpoint more left-more?
92741
92742               if (arx < brx) {
92743                 var _bCmpARight = b.comparePoint(a.rightSE.point);
92744
92745                 if (_bCmpARight !== 0) return _bCmpARight;
92746               } // is the B right endpoint more left-more?
92747
92748
92749               if (arx > brx) {
92750                 var _aCmpBRight = a.comparePoint(b.rightSE.point);
92751
92752                 if (_aCmpBRight < 0) return 1;
92753                 if (_aCmpBRight > 0) return -1;
92754               }
92755
92756               if (arx !== brx) {
92757                 // are these two [almost] vertical segments with opposite orientation?
92758                 // if so, the one with the lower right endpoint comes first
92759                 var ay = ary - aly;
92760                 var ax = arx - alx;
92761                 var by = bry - bly;
92762                 var bx = brx - blx;
92763                 if (ay > ax && by < bx) return 1;
92764                 if (ay < ax && by > bx) return -1;
92765               } // we have colinear segments with matching orientation
92766               // consider the one with more left-more right endpoint to be first
92767
92768
92769               if (arx > brx) return 1;
92770               if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
92771               // vertical plane, ie arx === brx
92772               // consider the lower right-endpoint to come first
92773
92774               if (ary < bry) return -1;
92775               if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
92776               // fall back on creation order as consistent tie-breaker
92777
92778               if (a.id < b.id) return -1;
92779               if (a.id > b.id) return 1; // identical segment, ie a === b
92780
92781               return 0;
92782             }
92783             /* Warning: a reference to ringWindings input will be stored,
92784              *  and possibly will be later modified */
92785
92786           }]);
92787
92788           function Segment(leftSE, rightSE, rings, windings) {
92789             _classCallCheck$1(this, Segment);
92790
92791             this.id = ++segmentId;
92792             this.leftSE = leftSE;
92793             leftSE.segment = this;
92794             leftSE.otherSE = rightSE;
92795             this.rightSE = rightSE;
92796             rightSE.segment = this;
92797             rightSE.otherSE = leftSE;
92798             this.rings = rings;
92799             this.windings = windings; // left unset for performance, set later in algorithm
92800             // this.ringOut, this.consumedBy, this.prev
92801           }
92802
92803           _createClass$1(Segment, [{
92804             key: "replaceRightSE",
92805
92806             /* When a segment is split, the rightSE is replaced with a new sweep event */
92807             value: function replaceRightSE(newRightSE) {
92808               this.rightSE = newRightSE;
92809               this.rightSE.segment = this;
92810               this.rightSE.otherSE = this.leftSE;
92811               this.leftSE.otherSE = this.rightSE;
92812             }
92813           }, {
92814             key: "bbox",
92815             value: function bbox() {
92816               var y1 = this.leftSE.point.y;
92817               var y2 = this.rightSE.point.y;
92818               return {
92819                 ll: {
92820                   x: this.leftSE.point.x,
92821                   y: y1 < y2 ? y1 : y2
92822                 },
92823                 ur: {
92824                   x: this.rightSE.point.x,
92825                   y: y1 > y2 ? y1 : y2
92826                 }
92827               };
92828             }
92829             /* A vector from the left point to the right */
92830
92831           }, {
92832             key: "vector",
92833             value: function vector() {
92834               return {
92835                 x: this.rightSE.point.x - this.leftSE.point.x,
92836                 y: this.rightSE.point.y - this.leftSE.point.y
92837               };
92838             }
92839           }, {
92840             key: "isAnEndpoint",
92841             value: function isAnEndpoint(pt) {
92842               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;
92843             }
92844             /* Compare this segment with a point.
92845              *
92846              * A point P is considered to be colinear to a segment if there
92847              * exists a distance D such that if we travel along the segment
92848              * from one * endpoint towards the other a distance D, we find
92849              * ourselves at point P.
92850              *
92851              * Return value indicates:
92852              *
92853              *   1: point lies above the segment (to the left of vertical)
92854              *   0: point is colinear to segment
92855              *  -1: point lies below the segment (to the right of vertical)
92856              */
92857
92858           }, {
92859             key: "comparePoint",
92860             value: function comparePoint(point) {
92861               if (this.isAnEndpoint(point)) return 0;
92862               var lPt = this.leftSE.point;
92863               var rPt = this.rightSE.point;
92864               var v = this.vector(); // Exactly vertical segments.
92865
92866               if (lPt.x === rPt.x) {
92867                 if (point.x === lPt.x) return 0;
92868                 return point.x < lPt.x ? 1 : -1;
92869               } // Nearly vertical segments with an intersection.
92870               // Check to see where a point on the line with matching Y coordinate is.
92871
92872
92873               var yDist = (point.y - lPt.y) / v.y;
92874               var xFromYDist = lPt.x + yDist * v.x;
92875               if (point.x === xFromYDist) return 0; // General case.
92876               // Check to see where a point on the line with matching X coordinate is.
92877
92878               var xDist = (point.x - lPt.x) / v.x;
92879               var yFromXDist = lPt.y + xDist * v.y;
92880               if (point.y === yFromXDist) return 0;
92881               return point.y < yFromXDist ? -1 : 1;
92882             }
92883             /**
92884              * Given another segment, returns the first non-trivial intersection
92885              * between the two segments (in terms of sweep line ordering), if it exists.
92886              *
92887              * A 'non-trivial' intersection is one that will cause one or both of the
92888              * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
92889              *
92890              *   * endpoint of segA with endpoint of segB --> trivial
92891              *   * endpoint of segA with point along segB --> non-trivial
92892              *   * endpoint of segB with point along segA --> non-trivial
92893              *   * point along segA with point along segB --> non-trivial
92894              *
92895              * If no non-trivial intersection exists, return null
92896              * Else, return null.
92897              */
92898
92899           }, {
92900             key: "getIntersection",
92901             value: function getIntersection(other) {
92902               // If bboxes don't overlap, there can't be any intersections
92903               var tBbox = this.bbox();
92904               var oBbox = other.bbox();
92905               var bboxOverlap = getBboxOverlap(tBbox, oBbox);
92906               if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
92907               // This will 'snap' intersections to endpoints if possible, and will
92908               // handle cases of colinearity.
92909
92910               var tlp = this.leftSE.point;
92911               var trp = this.rightSE.point;
92912               var olp = other.leftSE.point;
92913               var orp = other.rightSE.point; // does each endpoint touch the other segment?
92914               // note that we restrict the 'touching' definition to only allow segments
92915               // to touch endpoints that lie forward from where we are in the sweep line pass
92916
92917               var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
92918               var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
92919               var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
92920               var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
92921
92922               if (touchesThisLSE && touchesOtherLSE) {
92923                 // these two cases are for colinear segments with matching left
92924                 // endpoints, and one segment being longer than the other
92925                 if (touchesThisRSE && !touchesOtherRSE) return trp;
92926                 if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
92927                 // or just on their left endpoint (one trivial intersection
92928
92929                 return null;
92930               } // does this left endpoint matches (other doesn't)
92931
92932
92933               if (touchesThisLSE) {
92934                 // check for segments that just intersect on opposing endpoints
92935                 if (touchesOtherRSE) {
92936                   if (tlp.x === orp.x && tlp.y === orp.y) return null;
92937                 } // t-intersection on left endpoint
92938
92939
92940                 return tlp;
92941               } // does other left endpoint matches (this doesn't)
92942
92943
92944               if (touchesOtherLSE) {
92945                 // check for segments that just intersect on opposing endpoints
92946                 if (touchesThisRSE) {
92947                   if (trp.x === olp.x && trp.y === olp.y) return null;
92948                 } // t-intersection on left endpoint
92949
92950
92951                 return olp;
92952               } // trivial intersection on right endpoints
92953
92954
92955               if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
92956
92957               if (touchesThisRSE) return trp;
92958               if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
92959               // infinite lines laid over the segments
92960
92961               var pt = intersection$1(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
92962               // they would have an endpoint intersection and that case was already handled above
92963
92964               if (pt === null) return null; // is the intersection found between the lines not on the segments?
92965
92966               if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
92967
92968               return rounder.round(pt.x, pt.y);
92969             }
92970             /**
92971              * Split the given segment into multiple segments on the given points.
92972              *  * Each existing segment will retain its leftSE and a new rightSE will be
92973              *    generated for it.
92974              *  * A new segment will be generated which will adopt the original segment's
92975              *    rightSE, and a new leftSE will be generated for it.
92976              *  * If there are more than two points given to split on, new segments
92977              *    in the middle will be generated with new leftSE and rightSE's.
92978              *  * An array of the newly generated SweepEvents will be returned.
92979              *
92980              * Warning: input array of points is modified
92981              */
92982
92983           }, {
92984             key: "split",
92985             value: function split(point) {
92986               var newEvents = [];
92987               var alreadyLinked = point.events !== undefined;
92988               var newLeftSE = new SweepEvent$1(point, true);
92989               var newRightSE = new SweepEvent$1(point, false);
92990               var oldRightSE = this.rightSE;
92991               this.replaceRightSE(newRightSE);
92992               newEvents.push(newRightSE);
92993               newEvents.push(newLeftSE);
92994               var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
92995               // sometimes one of the resulting new segments is vertical, in which
92996               // case its left and right events may need to be swapped
92997
92998               if (SweepEvent$1.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
92999                 newSeg.swapEvents();
93000               }
93001
93002               if (SweepEvent$1.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
93003                 this.swapEvents();
93004               } // in the point we just used to create new sweep events with was already
93005               // linked to other events, we need to check if either of the affected
93006               // segments should be consumed
93007
93008
93009               if (alreadyLinked) {
93010                 newLeftSE.checkForConsuming();
93011                 newRightSE.checkForConsuming();
93012               }
93013
93014               return newEvents;
93015             }
93016             /* Swap which event is left and right */
93017
93018           }, {
93019             key: "swapEvents",
93020             value: function swapEvents() {
93021               var tmpEvt = this.rightSE;
93022               this.rightSE = this.leftSE;
93023               this.leftSE = tmpEvt;
93024               this.leftSE.isLeft = true;
93025               this.rightSE.isLeft = false;
93026
93027               for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
93028                 this.windings[i] *= -1;
93029               }
93030             }
93031             /* Consume another segment. We take their rings under our wing
93032              * and mark them as consumed. Use for perfectly overlapping segments */
93033
93034           }, {
93035             key: "consume",
93036             value: function consume(other) {
93037               var consumer = this;
93038               var consumee = other;
93039
93040               while (consumer.consumedBy) {
93041                 consumer = consumer.consumedBy;
93042               }
93043
93044               while (consumee.consumedBy) {
93045                 consumee = consumee.consumedBy;
93046               }
93047
93048               var cmp = Segment.compare(consumer, consumee);
93049               if (cmp === 0) return; // already consumed
93050               // the winner of the consumption is the earlier segment
93051               // according to sweep line ordering
93052
93053               if (cmp > 0) {
93054                 var tmp = consumer;
93055                 consumer = consumee;
93056                 consumee = tmp;
93057               } // make sure a segment doesn't consume it's prev
93058
93059
93060               if (consumer.prev === consumee) {
93061                 var _tmp = consumer;
93062                 consumer = consumee;
93063                 consumee = _tmp;
93064               }
93065
93066               for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
93067                 var ring = consumee.rings[i];
93068                 var winding = consumee.windings[i];
93069                 var index = consumer.rings.indexOf(ring);
93070
93071                 if (index === -1) {
93072                   consumer.rings.push(ring);
93073                   consumer.windings.push(winding);
93074                 } else consumer.windings[index] += winding;
93075               }
93076
93077               consumee.rings = null;
93078               consumee.windings = null;
93079               consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
93080
93081               consumee.leftSE.consumedBy = consumer.leftSE;
93082               consumee.rightSE.consumedBy = consumer.rightSE;
93083             }
93084             /* The first segment previous segment chain that is in the result */
93085
93086           }, {
93087             key: "prevInResult",
93088             value: function prevInResult() {
93089               if (this._prevInResult !== undefined) return this._prevInResult;
93090               if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
93091               return this._prevInResult;
93092             }
93093           }, {
93094             key: "beforeState",
93095             value: function beforeState() {
93096               if (this._beforeState !== undefined) return this._beforeState;
93097               if (!this.prev) this._beforeState = {
93098                 rings: [],
93099                 windings: [],
93100                 multiPolys: []
93101               };else {
93102                 var seg = this.prev.consumedBy || this.prev;
93103                 this._beforeState = seg.afterState();
93104               }
93105               return this._beforeState;
93106             }
93107           }, {
93108             key: "afterState",
93109             value: function afterState() {
93110               if (this._afterState !== undefined) return this._afterState;
93111               var beforeState = this.beforeState();
93112               this._afterState = {
93113                 rings: beforeState.rings.slice(0),
93114                 windings: beforeState.windings.slice(0),
93115                 multiPolys: []
93116               };
93117               var ringsAfter = this._afterState.rings;
93118               var windingsAfter = this._afterState.windings;
93119               var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
93120
93121               for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
93122                 var ring = this.rings[i];
93123                 var winding = this.windings[i];
93124                 var index = ringsAfter.indexOf(ring);
93125
93126                 if (index === -1) {
93127                   ringsAfter.push(ring);
93128                   windingsAfter.push(winding);
93129                 } else windingsAfter[index] += winding;
93130               } // calcualte polysAfter
93131
93132
93133               var polysAfter = [];
93134               var polysExclude = [];
93135
93136               for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
93137                 if (windingsAfter[_i] === 0) continue; // non-zero rule
93138
93139                 var _ring = ringsAfter[_i];
93140                 var poly = _ring.poly;
93141                 if (polysExclude.indexOf(poly) !== -1) continue;
93142                 if (_ring.isExterior) polysAfter.push(poly);else {
93143                   if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
93144
93145                   var _index = polysAfter.indexOf(_ring.poly);
93146
93147                   if (_index !== -1) polysAfter.splice(_index, 1);
93148                 }
93149               } // calculate multiPolysAfter
93150
93151
93152               for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
93153                 var mp = polysAfter[_i2].multiPoly;
93154                 if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
93155               }
93156
93157               return this._afterState;
93158             }
93159             /* Is this segment part of the final result? */
93160
93161           }, {
93162             key: "isInResult",
93163             value: function isInResult() {
93164               // if we've been consumed, we're not in the result
93165               if (this.consumedBy) return false;
93166               if (this._isInResult !== undefined) return this._isInResult;
93167               var mpsBefore = this.beforeState().multiPolys;
93168               var mpsAfter = this.afterState().multiPolys;
93169
93170               switch (operation.type) {
93171                 case 'union':
93172                   {
93173                     // UNION - included iff:
93174                     //  * On one side of us there is 0 poly interiors AND
93175                     //  * On the other side there is 1 or more.
93176                     var noBefores = mpsBefore.length === 0;
93177                     var noAfters = mpsAfter.length === 0;
93178                     this._isInResult = noBefores !== noAfters;
93179                     break;
93180                   }
93181
93182                 case 'intersection':
93183                   {
93184                     // INTERSECTION - included iff:
93185                     //  * on one side of us all multipolys are rep. with poly interiors AND
93186                     //  * on the other side of us, not all multipolys are repsented
93187                     //    with poly interiors
93188                     var least;
93189                     var most;
93190
93191                     if (mpsBefore.length < mpsAfter.length) {
93192                       least = mpsBefore.length;
93193                       most = mpsAfter.length;
93194                     } else {
93195                       least = mpsAfter.length;
93196                       most = mpsBefore.length;
93197                     }
93198
93199                     this._isInResult = most === operation.numMultiPolys && least < most;
93200                     break;
93201                   }
93202
93203                 case 'xor':
93204                   {
93205                     // XOR - included iff:
93206                     //  * the difference between the number of multipolys represented
93207                     //    with poly interiors on our two sides is an odd number
93208                     var diff = Math.abs(mpsBefore.length - mpsAfter.length);
93209                     this._isInResult = diff % 2 === 1;
93210                     break;
93211                   }
93212
93213                 case 'difference':
93214                   {
93215                     // DIFFERENCE included iff:
93216                     //  * on exactly one side, we have just the subject
93217                     var isJustSubject = function isJustSubject(mps) {
93218                       return mps.length === 1 && mps[0].isSubject;
93219                     };
93220
93221                     this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
93222                     break;
93223                   }
93224
93225                 default:
93226                   throw new Error("Unrecognized operation type found ".concat(operation.type));
93227               }
93228
93229               return this._isInResult;
93230             }
93231           }], [{
93232             key: "fromRing",
93233             value: function fromRing(pt1, pt2, ring) {
93234               var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
93235
93236               var cmpPts = SweepEvent$1.comparePoints(pt1, pt2);
93237
93238               if (cmpPts < 0) {
93239                 leftPt = pt1;
93240                 rightPt = pt2;
93241                 winding = 1;
93242               } else if (cmpPts > 0) {
93243                 leftPt = pt2;
93244                 rightPt = pt1;
93245                 winding = -1;
93246               } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
93247
93248               var leftSE = new SweepEvent$1(leftPt, true);
93249               var rightSE = new SweepEvent$1(rightPt, false);
93250               return new Segment(leftSE, rightSE, [ring], [winding]);
93251             }
93252           }]);
93253
93254           return Segment;
93255         }();
93256
93257         var RingIn = /*#__PURE__*/function () {
93258           function RingIn(geomRing, poly, isExterior) {
93259             _classCallCheck$1(this, RingIn);
93260
93261             if (!Array.isArray(geomRing) || geomRing.length === 0) {
93262               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93263             }
93264
93265             this.poly = poly;
93266             this.isExterior = isExterior;
93267             this.segments = [];
93268
93269             if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
93270               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93271             }
93272
93273             var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
93274             this.bbox = {
93275               ll: {
93276                 x: firstPoint.x,
93277                 y: firstPoint.y
93278               },
93279               ur: {
93280                 x: firstPoint.x,
93281                 y: firstPoint.y
93282               }
93283             };
93284             var prevPoint = firstPoint;
93285
93286             for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
93287               if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
93288                 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93289               }
93290
93291               var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
93292
93293               if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
93294               this.segments.push(Segment.fromRing(prevPoint, point, this));
93295               if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
93296               if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
93297               if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
93298               if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
93299               prevPoint = point;
93300             } // add segment from last to first if last is not the same as first
93301
93302
93303             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
93304               this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
93305             }
93306           }
93307
93308           _createClass$1(RingIn, [{
93309             key: "getSweepEvents",
93310             value: function getSweepEvents() {
93311               var sweepEvents = [];
93312
93313               for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
93314                 var segment = this.segments[i];
93315                 sweepEvents.push(segment.leftSE);
93316                 sweepEvents.push(segment.rightSE);
93317               }
93318
93319               return sweepEvents;
93320             }
93321           }]);
93322
93323           return RingIn;
93324         }();
93325
93326         var PolyIn = /*#__PURE__*/function () {
93327           function PolyIn(geomPoly, multiPoly) {
93328             _classCallCheck$1(this, PolyIn);
93329
93330             if (!Array.isArray(geomPoly)) {
93331               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93332             }
93333
93334             this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
93335
93336             this.bbox = {
93337               ll: {
93338                 x: this.exteriorRing.bbox.ll.x,
93339                 y: this.exteriorRing.bbox.ll.y
93340               },
93341               ur: {
93342                 x: this.exteriorRing.bbox.ur.x,
93343                 y: this.exteriorRing.bbox.ur.y
93344               }
93345             };
93346             this.interiorRings = [];
93347
93348             for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
93349               var ring = new RingIn(geomPoly[i], this, false);
93350               if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
93351               if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
93352               if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
93353               if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
93354               this.interiorRings.push(ring);
93355             }
93356
93357             this.multiPoly = multiPoly;
93358           }
93359
93360           _createClass$1(PolyIn, [{
93361             key: "getSweepEvents",
93362             value: function getSweepEvents() {
93363               var sweepEvents = this.exteriorRing.getSweepEvents();
93364
93365               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
93366                 var ringSweepEvents = this.interiorRings[i].getSweepEvents();
93367
93368                 for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
93369                   sweepEvents.push(ringSweepEvents[j]);
93370                 }
93371               }
93372
93373               return sweepEvents;
93374             }
93375           }]);
93376
93377           return PolyIn;
93378         }();
93379
93380         var MultiPolyIn = /*#__PURE__*/function () {
93381           function MultiPolyIn(geom, isSubject) {
93382             _classCallCheck$1(this, MultiPolyIn);
93383
93384             if (!Array.isArray(geom)) {
93385               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93386             }
93387
93388             try {
93389               // if the input looks like a polygon, convert it to a multipolygon
93390               if (typeof geom[0][0][0] === 'number') geom = [geom];
93391             } catch (ex) {// The input is either malformed or has empty arrays.
93392               // In either case, it will be handled later on.
93393             }
93394
93395             this.polys = [];
93396             this.bbox = {
93397               ll: {
93398                 x: Number.POSITIVE_INFINITY,
93399                 y: Number.POSITIVE_INFINITY
93400               },
93401               ur: {
93402                 x: Number.NEGATIVE_INFINITY,
93403                 y: Number.NEGATIVE_INFINITY
93404               }
93405             };
93406
93407             for (var i = 0, iMax = geom.length; i < iMax; i++) {
93408               var poly = new PolyIn(geom[i], this);
93409               if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
93410               if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
93411               if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
93412               if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
93413               this.polys.push(poly);
93414             }
93415
93416             this.isSubject = isSubject;
93417           }
93418
93419           _createClass$1(MultiPolyIn, [{
93420             key: "getSweepEvents",
93421             value: function getSweepEvents() {
93422               var sweepEvents = [];
93423
93424               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
93425                 var polySweepEvents = this.polys[i].getSweepEvents();
93426
93427                 for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
93428                   sweepEvents.push(polySweepEvents[j]);
93429                 }
93430               }
93431
93432               return sweepEvents;
93433             }
93434           }]);
93435
93436           return MultiPolyIn;
93437         }();
93438
93439         var RingOut = /*#__PURE__*/function () {
93440           _createClass$1(RingOut, null, [{
93441             key: "factory",
93442
93443             /* Given the segments from the sweep line pass, compute & return a series
93444              * of closed rings from all the segments marked to be part of the result */
93445             value: function factory(allSegments) {
93446               var ringsOut = [];
93447
93448               for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
93449                 var segment = allSegments[i];
93450                 if (!segment.isInResult() || segment.ringOut) continue;
93451                 var prevEvent = null;
93452                 var event = segment.leftSE;
93453                 var nextEvent = segment.rightSE;
93454                 var events = [event];
93455                 var startingPoint = event.point;
93456                 var intersectionLEs = [];
93457                 /* Walk the chain of linked events to form a closed ring */
93458
93459                 while (true) {
93460                   prevEvent = event;
93461                   event = nextEvent;
93462                   events.push(event);
93463                   /* Is the ring complete? */
93464
93465                   if (event.point === startingPoint) break;
93466
93467                   while (true) {
93468                     var availableLEs = event.getAvailableLinkedEvents();
93469                     /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
93470                      * part of the algorithm malfunctioned... please file a bug report. */
93471
93472                     if (availableLEs.length === 0) {
93473                       var firstPt = events[0].point;
93474                       var lastPt = events[events.length - 1].point;
93475                       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, "]."));
93476                     }
93477                     /* Only one way to go, so cotinue on the path */
93478
93479
93480                     if (availableLEs.length === 1) {
93481                       nextEvent = availableLEs[0].otherSE;
93482                       break;
93483                     }
93484                     /* We must have an intersection. Check for a completed loop */
93485
93486
93487                     var indexLE = null;
93488
93489                     for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
93490                       if (intersectionLEs[j].point === event.point) {
93491                         indexLE = j;
93492                         break;
93493                       }
93494                     }
93495                     /* Found a completed loop. Cut that off and make a ring */
93496
93497
93498                     if (indexLE !== null) {
93499                       var intersectionLE = intersectionLEs.splice(indexLE)[0];
93500                       var ringEvents = events.splice(intersectionLE.index);
93501                       ringEvents.unshift(ringEvents[0].otherSE);
93502                       ringsOut.push(new RingOut(ringEvents.reverse()));
93503                       continue;
93504                     }
93505                     /* register the intersection */
93506
93507
93508                     intersectionLEs.push({
93509                       index: events.length,
93510                       point: event.point
93511                     });
93512                     /* Choose the left-most option to continue the walk */
93513
93514                     var comparator = event.getLeftmostComparator(prevEvent);
93515                     nextEvent = availableLEs.sort(comparator)[0].otherSE;
93516                     break;
93517                   }
93518                 }
93519
93520                 ringsOut.push(new RingOut(events));
93521               }
93522
93523               return ringsOut;
93524             }
93525           }]);
93526
93527           function RingOut(events) {
93528             _classCallCheck$1(this, RingOut);
93529
93530             this.events = events;
93531
93532             for (var i = 0, iMax = events.length; i < iMax; i++) {
93533               events[i].segment.ringOut = this;
93534             }
93535
93536             this.poly = null;
93537           }
93538
93539           _createClass$1(RingOut, [{
93540             key: "getGeom",
93541             value: function getGeom() {
93542               // Remove superfluous points (ie extra points along a straight line),
93543               var prevPt = this.events[0].point;
93544               var points = [prevPt];
93545
93546               for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
93547                 var _pt = this.events[i].point;
93548                 var _nextPt = this.events[i + 1].point;
93549                 if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
93550                 points.push(_pt);
93551                 prevPt = _pt;
93552               } // ring was all (within rounding error of angle calc) colinear points
93553
93554
93555               if (points.length === 1) return null; // check if the starting point is necessary
93556
93557               var pt = points[0];
93558               var nextPt = points[1];
93559               if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
93560               points.push(points[0]);
93561               var step = this.isExteriorRing() ? 1 : -1;
93562               var iStart = this.isExteriorRing() ? 0 : points.length - 1;
93563               var iEnd = this.isExteriorRing() ? points.length : -1;
93564               var orderedPoints = [];
93565
93566               for (var _i = iStart; _i != iEnd; _i += step) {
93567                 orderedPoints.push([points[_i].x, points[_i].y]);
93568               }
93569
93570               return orderedPoints;
93571             }
93572           }, {
93573             key: "isExteriorRing",
93574             value: function isExteriorRing() {
93575               if (this._isExteriorRing === undefined) {
93576                 var enclosing = this.enclosingRing();
93577                 this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
93578               }
93579
93580               return this._isExteriorRing;
93581             }
93582           }, {
93583             key: "enclosingRing",
93584             value: function enclosingRing() {
93585               if (this._enclosingRing === undefined) {
93586                 this._enclosingRing = this._calcEnclosingRing();
93587               }
93588
93589               return this._enclosingRing;
93590             }
93591             /* Returns the ring that encloses this one, if any */
93592
93593           }, {
93594             key: "_calcEnclosingRing",
93595             value: function _calcEnclosingRing() {
93596               // start with the ealier sweep line event so that the prevSeg
93597               // chain doesn't lead us inside of a loop of ours
93598               var leftMostEvt = this.events[0];
93599
93600               for (var i = 1, iMax = this.events.length; i < iMax; i++) {
93601                 var evt = this.events[i];
93602                 if (SweepEvent$1.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
93603               }
93604
93605               var prevSeg = leftMostEvt.segment.prevInResult();
93606               var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93607
93608               while (true) {
93609                 // no segment found, thus no ring can enclose us
93610                 if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
93611                 // segment must loop back around and enclose us
93612
93613                 if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
93614                 // segment must either loop around us or the ring of the prev prev
93615                 // seg, which would make us and the ring of the prev peers
93616
93617                 if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
93618                   if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
93619                     return prevSeg.ringOut;
93620                   } else return prevSeg.ringOut.enclosingRing();
93621                 } // two segments are from the same ring, so this was a penisula
93622                 // of that ring. iterate downward, keep searching
93623
93624
93625                 prevSeg = prevPrevSeg.prevInResult();
93626                 prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93627               }
93628             }
93629           }]);
93630
93631           return RingOut;
93632         }();
93633
93634         var PolyOut = /*#__PURE__*/function () {
93635           function PolyOut(exteriorRing) {
93636             _classCallCheck$1(this, PolyOut);
93637
93638             this.exteriorRing = exteriorRing;
93639             exteriorRing.poly = this;
93640             this.interiorRings = [];
93641           }
93642
93643           _createClass$1(PolyOut, [{
93644             key: "addInterior",
93645             value: function addInterior(ring) {
93646               this.interiorRings.push(ring);
93647               ring.poly = this;
93648             }
93649           }, {
93650             key: "getGeom",
93651             value: function getGeom() {
93652               var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
93653
93654               if (geom[0] === null) return null;
93655
93656               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
93657                 var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
93658
93659                 if (ringGeom === null) continue;
93660                 geom.push(ringGeom);
93661               }
93662
93663               return geom;
93664             }
93665           }]);
93666
93667           return PolyOut;
93668         }();
93669
93670         var MultiPolyOut = /*#__PURE__*/function () {
93671           function MultiPolyOut(rings) {
93672             _classCallCheck$1(this, MultiPolyOut);
93673
93674             this.rings = rings;
93675             this.polys = this._composePolys(rings);
93676           }
93677
93678           _createClass$1(MultiPolyOut, [{
93679             key: "getGeom",
93680             value: function getGeom() {
93681               var geom = [];
93682
93683               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
93684                 var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
93685
93686                 if (polyGeom === null) continue;
93687                 geom.push(polyGeom);
93688               }
93689
93690               return geom;
93691             }
93692           }, {
93693             key: "_composePolys",
93694             value: function _composePolys(rings) {
93695               var polys = [];
93696
93697               for (var i = 0, iMax = rings.length; i < iMax; i++) {
93698                 var ring = rings[i];
93699                 if (ring.poly) continue;
93700                 if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
93701                   var enclosingRing = ring.enclosingRing();
93702                   if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
93703                   enclosingRing.poly.addInterior(ring);
93704                 }
93705               }
93706
93707               return polys;
93708             }
93709           }]);
93710
93711           return MultiPolyOut;
93712         }();
93713         /**
93714          * NOTE:  We must be careful not to change any segments while
93715          *        they are in the SplayTree. AFAIK, there's no way to tell
93716          *        the tree to rebalance itself - thus before splitting
93717          *        a segment that's in the tree, we remove it from the tree,
93718          *        do the split, then re-insert it. (Even though splitting a
93719          *        segment *shouldn't* change its correct position in the
93720          *        sweep line tree, the reality is because of rounding errors,
93721          *        it sometimes does.)
93722          */
93723
93724
93725         var SweepLine = /*#__PURE__*/function () {
93726           function SweepLine(queue) {
93727             var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
93728
93729             _classCallCheck$1(this, SweepLine);
93730
93731             this.queue = queue;
93732             this.tree = new Tree(comparator);
93733             this.segments = [];
93734           }
93735
93736           _createClass$1(SweepLine, [{
93737             key: "process",
93738             value: function process(event) {
93739               var segment = event.segment;
93740               var newEvents = []; // if we've already been consumed by another segment,
93741               // clean up our body parts and get out
93742
93743               if (event.consumedBy) {
93744                 if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
93745                 return newEvents;
93746               }
93747
93748               var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
93749               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.');
93750               var prevNode = node;
93751               var nextNode = node;
93752               var prevSeg = undefined;
93753               var nextSeg = undefined; // skip consumed segments still in tree
93754
93755               while (prevSeg === undefined) {
93756                 prevNode = this.tree.prev(prevNode);
93757                 if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
93758               } // skip consumed segments still in tree
93759
93760
93761               while (nextSeg === undefined) {
93762                 nextNode = this.tree.next(nextNode);
93763                 if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
93764               }
93765
93766               if (event.isLeft) {
93767                 // Check for intersections against the previous segment in the sweep line
93768                 var prevMySplitter = null;
93769
93770                 if (prevSeg) {
93771                   var prevInter = prevSeg.getIntersection(segment);
93772
93773                   if (prevInter !== null) {
93774                     if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
93775
93776                     if (!prevSeg.isAnEndpoint(prevInter)) {
93777                       var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
93778
93779                       for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
93780                         newEvents.push(newEventsFromSplit[i]);
93781                       }
93782                     }
93783                   }
93784                 } // Check for intersections against the next segment in the sweep line
93785
93786
93787                 var nextMySplitter = null;
93788
93789                 if (nextSeg) {
93790                   var nextInter = nextSeg.getIntersection(segment);
93791
93792                   if (nextInter !== null) {
93793                     if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
93794
93795                     if (!nextSeg.isAnEndpoint(nextInter)) {
93796                       var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
93797
93798                       for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
93799                         newEvents.push(_newEventsFromSplit[_i]);
93800                       }
93801                     }
93802                   }
93803                 } // For simplicity, even if we find more than one intersection we only
93804                 // spilt on the 'earliest' (sweep-line style) of the intersections.
93805                 // The other intersection will be handled in a future process().
93806
93807
93808                 if (prevMySplitter !== null || nextMySplitter !== null) {
93809                   var mySplitter = null;
93810                   if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
93811                     var cmpSplitters = SweepEvent$1.comparePoints(prevMySplitter, nextMySplitter);
93812                     mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
93813                   } // Rounding errors can cause changes in ordering,
93814                   // so remove afected segments and right sweep events before splitting
93815
93816                   this.queue.remove(segment.rightSE);
93817                   newEvents.push(segment.rightSE);
93818
93819                   var _newEventsFromSplit2 = segment.split(mySplitter);
93820
93821                   for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
93822                     newEvents.push(_newEventsFromSplit2[_i2]);
93823                   }
93824                 }
93825
93826                 if (newEvents.length > 0) {
93827                   // We found some intersections, so re-do the current event to
93828                   // make sure sweep line ordering is totally consistent for later
93829                   // use with the segment 'prev' pointers
93830                   this.tree.remove(segment);
93831                   newEvents.push(event);
93832                 } else {
93833                   // done with left event
93834                   this.segments.push(segment);
93835                   segment.prev = prevSeg;
93836                 }
93837               } else {
93838                 // event.isRight
93839                 // since we're about to be removed from the sweep line, check for
93840                 // intersections between our previous and next segments
93841                 if (prevSeg && nextSeg) {
93842                   var inter = prevSeg.getIntersection(nextSeg);
93843
93844                   if (inter !== null) {
93845                     if (!prevSeg.isAnEndpoint(inter)) {
93846                       var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
93847
93848                       for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
93849                         newEvents.push(_newEventsFromSplit3[_i3]);
93850                       }
93851                     }
93852
93853                     if (!nextSeg.isAnEndpoint(inter)) {
93854                       var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
93855
93856                       for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
93857                         newEvents.push(_newEventsFromSplit4[_i4]);
93858                       }
93859                     }
93860                   }
93861                 }
93862
93863                 this.tree.remove(segment);
93864               }
93865
93866               return newEvents;
93867             }
93868             /* Safely split a segment that is currently in the datastructures
93869              * IE - a segment other than the one that is currently being processed. */
93870
93871           }, {
93872             key: "_splitSafely",
93873             value: function _splitSafely(seg, pt) {
93874               // Rounding errors can cause changes in ordering,
93875               // so remove afected segments and right sweep events before splitting
93876               // removeNode() doesn't work, so have re-find the seg
93877               // https://github.com/w8r/splay-tree/pull/5
93878               this.tree.remove(seg);
93879               var rightSE = seg.rightSE;
93880               this.queue.remove(rightSE);
93881               var newEvents = seg.split(pt);
93882               newEvents.push(rightSE); // splitting can trigger consumption
93883
93884               if (seg.consumedBy === undefined) this.tree.insert(seg);
93885               return newEvents;
93886             }
93887           }]);
93888
93889           return SweepLine;
93890         }();
93891
93892         var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
93893         var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
93894
93895         var Operation = /*#__PURE__*/function () {
93896           function Operation() {
93897             _classCallCheck$1(this, Operation);
93898           }
93899
93900           _createClass$1(Operation, [{
93901             key: "run",
93902             value: function run(type, geom, moreGeoms) {
93903               operation.type = type;
93904               rounder.reset();
93905               /* Convert inputs to MultiPoly objects */
93906
93907               var multipolys = [new MultiPolyIn(geom, true)];
93908
93909               for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
93910                 multipolys.push(new MultiPolyIn(moreGeoms[i], false));
93911               }
93912
93913               operation.numMultiPolys = multipolys.length;
93914               /* BBox optimization for difference operation
93915                * If the bbox of a multipolygon that's part of the clipping doesn't
93916                * intersect the bbox of the subject at all, we can just drop that
93917                * multiploygon. */
93918
93919               if (operation.type === 'difference') {
93920                 // in place removal
93921                 var subject = multipolys[0];
93922                 var _i = 1;
93923
93924                 while (_i < multipolys.length) {
93925                   if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
93926                 }
93927               }
93928               /* BBox optimization for intersection operation
93929                * If we can find any pair of multipolygons whose bbox does not overlap,
93930                * then the result will be empty. */
93931
93932
93933               if (operation.type === 'intersection') {
93934                 // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
93935                 //       it could be optimized to O(n * ln(n))
93936                 for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
93937                   var mpA = multipolys[_i2];
93938
93939                   for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
93940                     if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
93941                   }
93942                 }
93943               }
93944               /* Put segment endpoints in a priority queue */
93945
93946
93947               var queue = new Tree(SweepEvent$1.compare);
93948
93949               for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
93950                 var sweepEvents = multipolys[_i3].getSweepEvents();
93951
93952                 for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
93953                   queue.insert(sweepEvents[_j]);
93954
93955                   if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
93956                     // prevents an infinite loop, an otherwise common manifestation of bugs
93957                     throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
93958                   }
93959                 }
93960               }
93961               /* Pass the sweep line over those endpoints */
93962
93963
93964               var sweepLine = new SweepLine(queue);
93965               var prevQueueSize = queue.size;
93966               var node = queue.pop();
93967
93968               while (node) {
93969                 var evt = node.key;
93970
93971                 if (queue.size === prevQueueSize) {
93972                   // prevents an infinite loop, an otherwise common manifestation of bugs
93973                   var seg = evt.segment;
93974                   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.');
93975                 }
93976
93977                 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
93978                   // prevents an infinite loop, an otherwise common manifestation of bugs
93979                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
93980                 }
93981
93982                 if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
93983                   // prevents an infinite loop, an otherwise common manifestation of bugs
93984                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
93985                 }
93986
93987                 var newEvents = sweepLine.process(evt);
93988
93989                 for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
93990                   var _evt = newEvents[_i4];
93991                   if (_evt.consumedBy === undefined) queue.insert(_evt);
93992                 }
93993
93994                 prevQueueSize = queue.size;
93995                 node = queue.pop();
93996               } // free some memory we don't need anymore
93997
93998
93999               rounder.reset();
94000               /* Collect and compile segments we're keeping into a multipolygon */
94001
94002               var ringsOut = RingOut.factory(sweepLine.segments);
94003               var result = new MultiPolyOut(ringsOut);
94004               return result.getGeom();
94005             }
94006           }]);
94007
94008           return Operation;
94009         }(); // singleton available by import
94010
94011
94012         var operation = new Operation();
94013
94014         var union$1 = function union(geom) {
94015           for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
94016             moreGeoms[_key - 1] = arguments[_key];
94017           }
94018
94019           return operation.run('union', geom, moreGeoms);
94020         };
94021
94022         var intersection$1$1 = function intersection(geom) {
94023           for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
94024             moreGeoms[_key2 - 1] = arguments[_key2];
94025           }
94026
94027           return operation.run('intersection', geom, moreGeoms);
94028         };
94029
94030         var xor = function xor(geom) {
94031           for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
94032             moreGeoms[_key3 - 1] = arguments[_key3];
94033           }
94034
94035           return operation.run('xor', geom, moreGeoms);
94036         };
94037
94038         var difference = function difference(subjectGeom) {
94039           for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
94040             clippingGeoms[_key4 - 1] = arguments[_key4];
94041           }
94042
94043           return operation.run('difference', subjectGeom, clippingGeoms);
94044         };
94045
94046         var index$1 = {
94047           union: union$1,
94048           intersection: intersection$1$1,
94049           xor: xor,
94050           difference: difference
94051         };
94052
94053         var geojsonPrecision = createCommonjsModule(function (module) {
94054           (function () {
94055             function parse(t, coordinatePrecision, extrasPrecision) {
94056               function point(p) {
94057                 return p.map(function (e, index) {
94058                   if (index < 2) {
94059                     return 1 * e.toFixed(coordinatePrecision);
94060                   } else {
94061                     return 1 * e.toFixed(extrasPrecision);
94062                   }
94063                 });
94064               }
94065
94066               function multi(l) {
94067                 return l.map(point);
94068               }
94069
94070               function poly(p) {
94071                 return p.map(multi);
94072               }
94073
94074               function multiPoly(m) {
94075                 return m.map(poly);
94076               }
94077
94078               function geometry(obj) {
94079                 if (!obj) {
94080                   return {};
94081                 }
94082
94083                 switch (obj.type) {
94084                   case "Point":
94085                     obj.coordinates = point(obj.coordinates);
94086                     return obj;
94087
94088                   case "LineString":
94089                   case "MultiPoint":
94090                     obj.coordinates = multi(obj.coordinates);
94091                     return obj;
94092
94093                   case "Polygon":
94094                   case "MultiLineString":
94095                     obj.coordinates = poly(obj.coordinates);
94096                     return obj;
94097
94098                   case "MultiPolygon":
94099                     obj.coordinates = multiPoly(obj.coordinates);
94100                     return obj;
94101
94102                   case "GeometryCollection":
94103                     obj.geometries = obj.geometries.map(geometry);
94104                     return obj;
94105
94106                   default:
94107                     return {};
94108                 }
94109               }
94110
94111               function feature(obj) {
94112                 obj.geometry = geometry(obj.geometry);
94113                 return obj;
94114               }
94115
94116               function featureCollection(f) {
94117                 f.features = f.features.map(feature);
94118                 return f;
94119               }
94120
94121               function geometryCollection(g) {
94122                 g.geometries = g.geometries.map(geometry);
94123                 return g;
94124               }
94125
94126               if (!t) {
94127                 return t;
94128               }
94129
94130               switch (t.type) {
94131                 case "Feature":
94132                   return feature(t);
94133
94134                 case "GeometryCollection":
94135                   return geometryCollection(t);
94136
94137                 case "FeatureCollection":
94138                   return featureCollection(t);
94139
94140                 case "Point":
94141                 case "LineString":
94142                 case "Polygon":
94143                 case "MultiPoint":
94144                 case "MultiPolygon":
94145                 case "MultiLineString":
94146                   return geometry(t);
94147
94148                 default:
94149                   return t;
94150               }
94151             }
94152
94153             module.exports = parse;
94154             module.exports.parse = parse;
94155           })();
94156         });
94157
94158         function isObject$4(obj) {
94159           return _typeof(obj) === 'object' && obj !== null;
94160         }
94161
94162         function forEach(obj, cb) {
94163           if (Array.isArray(obj)) {
94164             obj.forEach(cb);
94165           } else if (isObject$4(obj)) {
94166             Object.keys(obj).forEach(function (key) {
94167               var val = obj[key];
94168               cb(val, key);
94169             });
94170           }
94171         }
94172
94173         function getTreeDepth(obj) {
94174           var depth = 0;
94175
94176           if (Array.isArray(obj) || isObject$4(obj)) {
94177             forEach(obj, function (val) {
94178               if (Array.isArray(val) || isObject$4(val)) {
94179                 var tmpDepth = getTreeDepth(val);
94180
94181                 if (tmpDepth > depth) {
94182                   depth = tmpDepth;
94183                 }
94184               }
94185             });
94186             return depth + 1;
94187           }
94188
94189           return depth;
94190         }
94191
94192         function stringify(obj, options) {
94193           options = options || {};
94194           var indent = JSON.stringify([1], null, get$5(options, 'indent', 2)).slice(2, -3);
94195           var addMargin = get$5(options, 'margins', false);
94196           var addArrayMargin = get$5(options, 'arrayMargins', false);
94197           var addObjectMargin = get$5(options, 'objectMargins', false);
94198           var maxLength = indent === '' ? Infinity : get$5(options, 'maxLength', 80);
94199           var maxNesting = get$5(options, 'maxNesting', Infinity);
94200           return function _stringify(obj, currentIndent, reserved) {
94201             if (obj && typeof obj.toJSON === 'function') {
94202               obj = obj.toJSON();
94203             }
94204
94205             var string = JSON.stringify(obj);
94206
94207             if (string === undefined) {
94208               return string;
94209             }
94210
94211             var length = maxLength - currentIndent.length - reserved;
94212             var treeDepth = getTreeDepth(obj);
94213
94214             if (treeDepth <= maxNesting && string.length <= length) {
94215               var prettified = prettify(string, {
94216                 addMargin: addMargin,
94217                 addArrayMargin: addArrayMargin,
94218                 addObjectMargin: addObjectMargin
94219               });
94220
94221               if (prettified.length <= length) {
94222                 return prettified;
94223               }
94224             }
94225
94226             if (isObject$4(obj)) {
94227               var nextIndent = currentIndent + indent;
94228               var items = [];
94229               var delimiters;
94230
94231               var comma = function comma(array, index) {
94232                 return index === array.length - 1 ? 0 : 1;
94233               };
94234
94235               if (Array.isArray(obj)) {
94236                 for (var index = 0; index < obj.length; index++) {
94237                   items.push(_stringify(obj[index], nextIndent, comma(obj, index)) || 'null');
94238                 }
94239
94240                 delimiters = '[]';
94241               } else {
94242                 Object.keys(obj).forEach(function (key, index, array) {
94243                   var keyPart = JSON.stringify(key) + ': ';
94244
94245                   var value = _stringify(obj[key], nextIndent, keyPart.length + comma(array, index));
94246
94247                   if (value !== undefined) {
94248                     items.push(keyPart + value);
94249                   }
94250                 });
94251                 delimiters = '{}';
94252               }
94253
94254               if (items.length > 0) {
94255                 return [delimiters[0], indent + items.join(',\n' + nextIndent), delimiters[1]].join('\n' + currentIndent);
94256               }
94257             }
94258
94259             return string;
94260           }(obj, '', 0);
94261         } // Note: This regex matches even invalid JSON strings, but since we’re
94262         // working on the output of `JSON.stringify` we know that only valid strings
94263         // are present (unless the user supplied a weird `options.indent` but in
94264         // that case we don’t care since the output would be invalid anyway).
94265
94266
94267         var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
94268
94269         function prettify(string, options) {
94270           options = options || {};
94271           var tokens = {
94272             '{': '{',
94273             '}': '}',
94274             '[': '[',
94275             ']': ']',
94276             ',': ', ',
94277             ':': ': '
94278           };
94279
94280           if (options.addMargin || options.addObjectMargin) {
94281             tokens['{'] = '{ ';
94282             tokens['}'] = ' }';
94283           }
94284
94285           if (options.addMargin || options.addArrayMargin) {
94286             tokens['['] = '[ ';
94287             tokens[']'] = ' ]';
94288           }
94289
94290           return string.replace(stringOrChar, function (match, string) {
94291             return string ? match : tokens[match];
94292           });
94293         }
94294
94295         function get$5(options, name, defaultValue) {
94296           return name in options ? options[name] : defaultValue;
94297         }
94298
94299         var jsonStringifyPrettyCompact = stringify;
94300
94301         var _default$3 = /*#__PURE__*/function () {
94302           // constructor
94303           //
94304           // `fc`  Optional FeatureCollection of known features
94305           //
94306           // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
94307           // Each feature must have a filename-like `id`, for example: `something.geojson`
94308           //
94309           // {
94310           //   "type": "FeatureCollection"
94311           //   "features": [
94312           //     {
94313           //       "type": "Feature",
94314           //       "id": "philly_metro.geojson",
94315           //       "properties": { … },
94316           //       "geometry": { … }
94317           //     }
94318           //   ]
94319           // }
94320           function _default(fc) {
94321             var _this = this;
94322
94323             _classCallCheck(this, _default);
94324
94325             // The _cache retains resolved features, so if you ask for the same thing multiple times
94326             // we don't repeat the expensive resolving/clipping operations.
94327             //
94328             // Each feature has a stable identifier that is used as the cache key.
94329             // The identifiers look like:
94330             // - for point locations, the stringified point:          e.g. '[8.67039,49.41882]'
94331             // - for geojson locations, the geojson id:               e.g. 'de-hamburg.geojson'
94332             // - for countrycoder locations, feature.id property:     e.g. 'Q2'  (countrycoder uses Wikidata identifiers)
94333             // - for aggregated locationSets, +[include]-[exclude]:   e.g '+[Q2]-[Q18,Q27611]'
94334             this._cache = {}; // When strict mode = true, throw on invalid locations or locationSets.
94335             // When strict mode = false, return `null` for invalid locations or locationSets.
94336
94337             this._strict = true; // process input FeatureCollection
94338
94339             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
94340               fc.features.forEach(function (feature) {
94341                 feature.properties = feature.properties || {};
94342                 var props = feature.properties; // get `id` from either `id` or `properties`
94343
94344                 var id = feature.id || props.id;
94345                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // ensure `id` exists and is lowercase
94346
94347                 id = id.toLowerCase();
94348                 feature.id = id;
94349                 props.id = id; // ensure `area` property exists
94350
94351                 if (!props.area) {
94352                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
94353
94354                   props.area = Number(area.toFixed(2));
94355                 }
94356
94357                 _this._cache[id] = feature;
94358               });
94359             } // Replace CountryCoder world geometry to be a polygon covering the world.
94360
94361
94362             var world = _cloneDeep(feature('Q2'));
94363
94364             world.geometry = {
94365               type: 'Polygon',
94366               coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
94367             };
94368             world.id = 'Q2';
94369             world.properties.id = 'Q2';
94370             world.properties.area = geojsonArea.geometry(world.geometry) / 1e6; // m² to km²
94371
94372             this._cache.Q2 = world;
94373           } // validateLocation
94374           // `location`  The location to validate
94375           //
94376           // Pass a `location` value to validate
94377           //
94378           // Returns a result like:
94379           //   {
94380           //     type:     'point', 'geojson', or 'countrycoder'
94381           //     location:  the queried location
94382           //     id:        the stable identifier for the feature
94383           //   }
94384           // or `null` if the location is invalid
94385           //
94386
94387
94388           _createClass(_default, [{
94389             key: "validateLocation",
94390             value: function validateLocation(location) {
94391               if (Array.isArray(location)) {
94392                 // a [lon,lat] coordinate pair?
94393                 if (location.length === 2 && Number.isFinite(location[0]) && Number.isFinite(location[1]) && location[0] >= -180 && location[0] <= 180 && location[1] >= -90 && location[1] <= 90) {
94394                   var id = '[' + location.toString() + ']';
94395                   return {
94396                     type: 'point',
94397                     location: location,
94398                     id: id
94399                   };
94400                 }
94401               } else if (typeof location === 'string' && /^\S+\.geojson$/i.test(location)) {
94402                 // a .geojson filename?
94403                 var _id = location.toLowerCase();
94404
94405                 if (this._cache[_id]) {
94406                   return {
94407                     type: 'geojson',
94408                     location: location,
94409                     id: _id
94410                   };
94411                 }
94412               } else if (typeof location === 'string' || typeof location === 'number') {
94413                 // a country-coder value?
94414                 var feature$1 = feature(location);
94415
94416                 if (feature$1) {
94417                   // Use wikidata QID as the identifier, since that seems to be the one
94418                   // property that everything in CountryCoder is guaranteed to have.
94419                   var _id2 = feature$1.properties.wikidata;
94420                   return {
94421                     type: 'countrycoder',
94422                     location: location,
94423                     id: _id2
94424                   };
94425                 }
94426               }
94427
94428               if (this._strict) {
94429                 throw new Error("validateLocation:  Invalid location: \"".concat(location, "\"."));
94430               } else {
94431                 return null;
94432               }
94433             } // resolveLocation
94434             // `location`  The location to resolve
94435             //
94436             // Pass a `location` value to resolve
94437             //
94438             // Returns a result like:
94439             //   {
94440             //     type:      'point', 'geojson', or 'countrycoder'
94441             //     location:  the queried location
94442             //     id:        a stable identifier for the feature
94443             //     feature:   the resolved GeoJSON feature
94444             //   }
94445             //  or `null` if the location is invalid
94446             //
94447
94448           }, {
94449             key: "resolveLocation",
94450             value: function resolveLocation(location) {
94451               var valid = this.validateLocation(location);
94452               if (!valid) return null;
94453               var id = valid.id; // return a result from cache if we can
94454
94455               if (this._cache[id]) {
94456                 return Object.assign(valid, {
94457                   feature: this._cache[id]
94458                 });
94459               } // a [lon,lat] coordinate pair?
94460
94461
94462               if (valid.type === 'point') {
94463                 var RADIUS = 25000; // meters
94464
94465                 var EDGES = 10;
94466                 var PRECISION = 3;
94467                 var area = Math.PI * RADIUS * RADIUS / 1e6; // m² to km²
94468
94469                 var feature$1 = this._cache[id] = geojsonPrecision({
94470                   type: 'Feature',
94471                   id: id,
94472                   properties: {
94473                     id: id,
94474                     area: Number(area.toFixed(2))
94475                   },
94476                   geometry: circleToPolygon(location, RADIUS, EDGES)
94477                 }, PRECISION);
94478                 return Object.assign(valid, {
94479                   feature: feature$1
94480                 }); // a .geojson filename?
94481               } else if (valid.type === 'geojson') ; else if (valid.type === 'countrycoder') {
94482                 var _feature = _cloneDeep(feature(id));
94483
94484                 var props = _feature.properties; // -> This block of code is weird and requires some explanation. <-
94485                 // CountryCoder includes higher level features which are made up of members.
94486                 // These features don't have their own geometry, but CountryCoder provides an
94487                 //   `aggregateFeature` method to combine these members into a MultiPolygon.
94488                 // BUT, when we try to actually work with these aggregated MultiPolygons,
94489                 //   Turf/JSTS gets crashy because of topography bugs.
94490                 // SO, we'll aggregate the features ourselves by unioning them together.
94491                 // This approach also has the benefit of removing all the internal boaders and
94492                 //   simplifying the regional polygons a lot.
94493
94494                 if (Array.isArray(props.members)) {
94495                   var seed = _feature.geometry ? _feature : null;
94496                   var aggregate = props.members.reduce(_locationReducer.bind(this), seed);
94497                   _feature.geometry = aggregate.geometry;
94498                 } // ensure `area` property exists
94499
94500
94501                 if (!props.area) {
94502                   var _area = geojsonArea.geometry(_feature.geometry) / 1e6; // m² to km²
94503
94504
94505                   props.area = Number(_area.toFixed(2));
94506                 } // ensure `id` property exists
94507
94508
94509                 _feature.id = id;
94510                 props.id = id;
94511                 this._cache[id] = _feature;
94512                 return Object.assign(valid, {
94513                   feature: _feature
94514                 });
94515               }
94516
94517               if (this._strict) {
94518                 throw new Error("resolveLocation:  Couldn't resolve location \"".concat(location, "\"."));
94519               } else {
94520                 return null;
94521               }
94522             } // validateLocationSet
94523             // `locationSet`  the locationSet to validate
94524             //
94525             // Pass a locationSet Object to validate like:
94526             //   {
94527             //     include: [ Array of locations ],
94528             //     exclude: [ Array of locations ]
94529             //   }
94530             //
94531             // Returns a result like:
94532             //   {
94533             //     type:         'locationset'
94534             //     locationSet:  the queried locationSet
94535             //     id:           the stable identifier for the feature
94536             //   }
94537             // or `null` if the locationSet is invalid
94538             //
94539
94540           }, {
94541             key: "validateLocationSet",
94542             value: function validateLocationSet(locationSet) {
94543               locationSet = locationSet || {};
94544               var validator = this.validateLocation.bind(this);
94545               var include = (locationSet.include || []).map(validator).filter(Boolean);
94546               var exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
94547
94548               if (!include.length) {
94549                 if (this._strict) {
94550                   throw new Error("validateLocationSet:  LocationSet includes nothing.");
94551                 } else {
94552                   // non-strict mode, replace an empty locationSet with one that includes "the world"
94553                   locationSet.include = ['Q2'];
94554                   include = [{
94555                     type: 'countrycoder',
94556                     location: 'Q2',
94557                     id: 'Q2'
94558                   }];
94559                 }
94560               } // generate stable identifier
94561
94562
94563               include.sort(_sortLocations);
94564               var id = '+[' + include.map(function (d) {
94565                 return d.id;
94566               }).join(',') + ']';
94567
94568               if (exclude.length) {
94569                 exclude.sort(_sortLocations);
94570                 id += '-[' + exclude.map(function (d) {
94571                   return d.id;
94572                 }).join(',') + ']';
94573               }
94574
94575               return {
94576                 type: 'locationset',
94577                 locationSet: locationSet,
94578                 id: id
94579               };
94580             } // resolveLocationSet
94581             // `locationSet`  the locationSet to resolve
94582             //
94583             // Pass a locationSet Object to validate like:
94584             //   {
94585             //     include: [ Array of locations ],
94586             //     exclude: [ Array of locations ]
94587             //   }
94588             //
94589             // Returns a result like:
94590             //   {
94591             //     type:         'locationset'
94592             //     locationSet:  the queried locationSet
94593             //     id:           the stable identifier for the feature
94594             //     feature:      the resolved GeoJSON feature
94595             //   }
94596             // or `null` if the locationSet is invalid
94597             //
94598
94599           }, {
94600             key: "resolveLocationSet",
94601             value: function resolveLocationSet(locationSet) {
94602               locationSet = locationSet || {};
94603               var valid = this.validateLocationSet(locationSet);
94604               if (!valid) return null;
94605               var id = valid.id; // return a result from cache if we can
94606
94607               if (this._cache[id]) {
94608                 return Object.assign(valid, {
94609                   feature: this._cache[id]
94610                 });
94611               }
94612
94613               var resolver = this.resolveLocation.bind(this);
94614               var include = (locationSet.include || []).map(resolver).filter(Boolean);
94615               var exclude = (locationSet.exclude || []).map(resolver).filter(Boolean); // return quickly if it's a single included location..
94616
94617               if (include.length === 1 && exclude.length === 0) {
94618                 return Object.assign(valid, {
94619                   feature: include[0].feature
94620                 });
94621               } // calculate unions
94622
94623
94624               var includeGeoJSON = include.map(function (d) {
94625                 return d.location;
94626               }).reduce(_locationReducer.bind(this), null);
94627               var excludeGeoJSON = exclude.map(function (d) {
94628                 return d.location;
94629               }).reduce(_locationReducer.bind(this), null); // calculate difference, update `area` and return result
94630
94631               var resultGeoJSON = excludeGeoJSON ? _clip(includeGeoJSON, excludeGeoJSON, 'DIFFERENCE') : includeGeoJSON;
94632               var area = geojsonArea.geometry(resultGeoJSON.geometry) / 1e6; // m² to km²
94633
94634               resultGeoJSON.id = id;
94635               resultGeoJSON.properties = {
94636                 id: id,
94637                 area: Number(area.toFixed(2))
94638               };
94639               this._cache[id] = resultGeoJSON;
94640               return Object.assign(valid, {
94641                 feature: resultGeoJSON
94642               });
94643             } // strict
94644             //
94645
94646           }, {
94647             key: "strict",
94648             value: function strict(val) {
94649               if (val === undefined) {
94650                 // get
94651                 return this._strict;
94652               } else {
94653                 // set
94654                 this._strict = val;
94655                 return this;
94656               }
94657             } // cache
94658             // convenience method to access the internal cache
94659
94660           }, {
94661             key: "cache",
94662             value: function cache() {
94663               return this._cache;
94664             } // stringify
94665             // convenience method to prettyStringify the given object
94666
94667           }, {
94668             key: "stringify",
94669             value: function stringify(obj, options) {
94670               return jsonStringifyPrettyCompact(obj, options);
94671             }
94672           }]);
94673
94674           return _default;
94675         }(); // Wrap the mfogel/polygon-clipping library and return a GeoJSON feature.
94676
94677         function _clip(a, b, which) {
94678           var fn = {
94679             UNION: index$1.union,
94680             DIFFERENCE: index$1.difference
94681           }[which];
94682           var coords = fn(a.geometry.coordinates, b.geometry.coordinates);
94683           return {
94684             type: 'Feature',
94685             properties: {},
94686             geometry: {
94687               type: whichType(coords),
94688               coordinates: coords
94689             }
94690           }; // is this a Polygon or a MultiPolygon?
94691
94692           function whichType(coords) {
94693             var a = Array.isArray(coords);
94694             var b = a && Array.isArray(coords[0]);
94695             var c = b && Array.isArray(coords[0][0]);
94696             var d = c && Array.isArray(coords[0][0][0]);
94697             return d ? 'MultiPolygon' : 'Polygon';
94698           }
94699         } // Reduce an array of locations into a single GeoJSON feature
94700
94701
94702         function _locationReducer(accumulator, location) {
94703           /* eslint-disable no-console, no-invalid-this */
94704           var result;
94705
94706           try {
94707             var resolved = this.resolveLocation(location);
94708
94709             if (!resolved || !resolved.feature) {
94710               console.warn("Warning:  Couldn't resolve location \"".concat(location, "\""));
94711               return accumulator;
94712             }
94713
94714             result = !accumulator ? resolved.feature : _clip(accumulator, resolved.feature, 'UNION');
94715           } catch (e) {
94716             console.warn("Warning:  Error resolving location \"".concat(location, "\""));
94717             console.warn(e);
94718             result = accumulator;
94719           }
94720
94721           return result;
94722           /* eslint-enable no-console, no-invalid-this */
94723         }
94724
94725         function _cloneDeep(obj) {
94726           return JSON.parse(JSON.stringify(obj));
94727         } // Sorting the location lists is ok because they end up unioned together.
94728         // This sorting makes it possible to generate a deterministic id.
94729
94730
94731         function _sortLocations(a, b) {
94732           var rank = {
94733             countrycoder: 1,
94734             geojson: 2,
94735             point: 3
94736           };
94737           var aRank = rank[a.type];
94738           var bRank = rank[b.type];
94739           return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
94740         }
94741
94742         var _oci = null;
94743         function uiSuccess(context) {
94744           var MAXEVENTS = 2;
94745           var dispatch$1 = dispatch('cancel');
94746
94747           var _changeset;
94748
94749           var _location;
94750
94751           ensureOSMCommunityIndex(); // start fetching the data
94752
94753           function ensureOSMCommunityIndex() {
94754             var data = _mainFileFetcher;
94755             return Promise.all([data.get('oci_resources'), data.get('oci_features')]).then(function (vals) {
94756               if (_oci) return _oci;
94757               var ociResources = vals[0].resources;
94758               var loco = new _default$3(vals[1]);
94759               var ociFeatures = {};
94760               Object.values(ociResources).forEach(function (resource) {
94761                 var feature = loco.resolveLocationSet(resource.locationSet).feature;
94762                 var ociFeature = ociFeatures[feature.id];
94763
94764                 if (!ociFeature) {
94765                   ociFeature = JSON.parse(JSON.stringify(feature)); // deep clone
94766
94767                   ociFeature.properties.resourceIDs = new Set();
94768                   ociFeatures[feature.id] = ociFeature;
94769                 }
94770
94771                 ociFeature.properties.resourceIDs.add(resource.id);
94772               });
94773               return _oci = {
94774                 features: ociFeatures,
94775                 resources: ociResources,
94776                 query: whichPolygon_1({
94777                   type: 'FeatureCollection',
94778                   features: Object.values(ociFeatures)
94779                 })
94780               };
94781             });
94782           } // string-to-date parsing in JavaScript is weird
94783
94784
94785           function parseEventDate(when) {
94786             if (!when) return;
94787             var raw = when.trim();
94788             if (!raw) return;
94789
94790             if (!/Z$/.test(raw)) {
94791               // if no trailing 'Z', add one
94792               raw += 'Z'; // this forces date to be parsed as a UTC date
94793             }
94794
94795             var parsed = new Date(raw);
94796             return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone
94797           }
94798
94799           function success(selection) {
94800             var header = selection.append('div').attr('class', 'header fillL');
94801             header.append('h3').html(_t.html('success.just_edited'));
94802             header.append('button').attr('class', 'close').on('click', function () {
94803               return dispatch$1.call('cancel');
94804             }).call(svgIcon('#iD-icon-close'));
94805             var body = selection.append('div').attr('class', 'body save-success fillL');
94806             var summary = body.append('div').attr('class', 'save-summary');
94807             summary.append('h3').html(_t.html('success.thank_you' + (_location ? '_location' : ''), {
94808               where: _location
94809             }));
94810             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'));
94811             var osm = context.connection();
94812             if (!osm) return;
94813             var changesetURL = osm.changesetURL(_changeset.id);
94814             var table = summary.append('table').attr('class', 'summary-table');
94815             var row = table.append('tr').attr('class', 'summary-row');
94816             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');
94817             var summaryDetail = row.append('td').attr('class', 'cell-detail summary-detail');
94818             summaryDetail.append('a').attr('class', 'cell-detail summary-view-on-osm').attr('target', '_blank').attr('href', changesetURL).html(_t.html('success.view_on_osm'));
94819             summaryDetail.append('div').html(_t.html('success.changeset_id', {
94820               changeset_id: "<a href=\"".concat(changesetURL, "\" target=\"_blank\">").concat(_changeset.id, "</a>")
94821             })); // Get OSM community index features intersecting the map..
94822
94823             ensureOSMCommunityIndex().then(function (oci) {
94824               var communities = [];
94825               var properties = oci.query(context.map().center(), true) || []; // Gather the communities from the result
94826
94827               properties.forEach(function (props) {
94828                 var resourceIDs = Array.from(props.resourceIDs);
94829                 resourceIDs.forEach(function (resourceID) {
94830                   var resource = oci.resources[resourceID];
94831                   communities.push({
94832                     area: props.area || Infinity,
94833                     order: resource.order || 0,
94834                     resource: resource
94835                   });
94836                 });
94837               }); // sort communities by feature area ascending, community order descending
94838
94839               communities.sort(function (a, b) {
94840                 return a.area - b.area || b.order - a.order;
94841               });
94842               body.call(showCommunityLinks, communities.map(function (c) {
94843                 return c.resource;
94844               }));
94845             });
94846           }
94847
94848           function showCommunityLinks(selection, resources) {
94849             var communityLinks = selection.append('div').attr('class', 'save-communityLinks');
94850             communityLinks.append('h3').html(_t.html('success.like_osm'));
94851             var table = communityLinks.append('table').attr('class', 'community-table');
94852             var row = table.selectAll('.community-row').data(resources);
94853             var rowEnter = row.enter().append('tr').attr('class', 'community-row');
94854             rowEnter.append('td').attr('class', 'cell-icon community-icon').append('a').attr('target', '_blank').attr('href', function (d) {
94855               return d.url;
94856             }).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', function (d) {
94857               return "#community-".concat(d.type);
94858             });
94859             var communityDetail = rowEnter.append('td').attr('class', 'cell-detail community-detail');
94860             communityDetail.each(showCommunityDetails);
94861             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'));
94862           }
94863
94864           function showCommunityDetails(d) {
94865             var selection = select(this);
94866             var communityID = d.id;
94867             var replacements = {
94868               url: linkify(d.url),
94869               signupUrl: linkify(d.signupUrl || d.url)
94870             };
94871             selection.append('div').attr('class', 'community-name').append('a').attr('target', '_blank').attr('href', d.url).html(_t.html("community.".concat(d.id, ".name")));
94872             var descriptionHTML = _t.html("community.".concat(d.id, ".description"), replacements);
94873
94874             if (d.type === 'reddit') {
94875               // linkify subreddits  #4997
94876               descriptionHTML = descriptionHTML.replace(/(\/r\/\w*\/*)/i, function (match) {
94877                 return linkify(d.url, match);
94878               });
94879             }
94880
94881             selection.append('div').attr('class', 'community-description').html(descriptionHTML);
94882
94883             if (d.extendedDescription || d.languageCodes && d.languageCodes.length) {
94884               selection.append('div').call(uiDisclosure(context, "community-more-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.more')).content(showMore));
94885             }
94886
94887             var nextEvents = (d.events || []).map(function (event) {
94888               event.date = parseEventDate(event.when);
94889               return event;
94890             }).filter(function (event) {
94891               // date is valid and future (or today)
94892               var t = event.date.getTime();
94893               var now = new Date().setHours(0, 0, 0, 0);
94894               return !isNaN(t) && t >= now;
94895             }).sort(function (a, b) {
94896               // sort by date ascending
94897               return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
94898             }).slice(0, MAXEVENTS); // limit number of events shown
94899
94900             if (nextEvents.length) {
94901               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);
94902             }
94903
94904             function showMore(selection) {
94905               var more = selection.selectAll('.community-more').data([0]);
94906               var moreEnter = more.enter().append('div').attr('class', 'community-more');
94907
94908               if (d.extendedDescription) {
94909                 moreEnter.append('div').attr('class', 'community-extended-description').html(_t.html("community.".concat(d.id, ".extendedDescription"), replacements));
94910               }
94911
94912               if (d.languageCodes && d.languageCodes.length) {
94913                 var languageList = d.languageCodes.map(function (code) {
94914                   return _mainLocalizer.languageName(code);
94915                 }).join(', ');
94916                 moreEnter.append('div').attr('class', 'community-languages').html(_t.html('success.languages', {
94917                   languages: languageList
94918                 }));
94919               }
94920             }
94921
94922             function showNextEvents(selection) {
94923               var events = selection.append('div').attr('class', 'community-events');
94924               var item = events.selectAll('.community-event').data(nextEvents);
94925               var itemEnter = item.enter().append('div').attr('class', 'community-event');
94926               itemEnter.append('div').attr('class', 'community-event-name').append('a').attr('target', '_blank').attr('href', function (d) {
94927                 return d.url;
94928               }).html(function (d) {
94929                 var name = d.name;
94930
94931                 if (d.i18n && d.id) {
94932                   name = _t("community.".concat(communityID, ".events.").concat(d.id, ".name"), {
94933                     "default": name
94934                   });
94935                 }
94936
94937                 return name;
94938               });
94939               itemEnter.append('div').attr('class', 'community-event-when').html(function (d) {
94940                 var options = {
94941                   weekday: 'short',
94942                   day: 'numeric',
94943                   month: 'short',
94944                   year: 'numeric'
94945                 };
94946
94947                 if (d.date.getHours() || d.date.getMinutes()) {
94948                   // include time if it has one
94949                   options.hour = 'numeric';
94950                   options.minute = 'numeric';
94951                 }
94952
94953                 return d.date.toLocaleString(_mainLocalizer.localeCode(), options);
94954               });
94955               itemEnter.append('div').attr('class', 'community-event-where').html(function (d) {
94956                 var where = d.where;
94957
94958                 if (d.i18n && d.id) {
94959                   where = _t("community.".concat(communityID, ".events.").concat(d.id, ".where"), {
94960                     "default": where
94961                   });
94962                 }
94963
94964                 return where;
94965               });
94966               itemEnter.append('div').attr('class', 'community-event-description').html(function (d) {
94967                 var description = d.description;
94968
94969                 if (d.i18n && d.id) {
94970                   description = _t("community.".concat(communityID, ".events.").concat(d.id, ".description"), {
94971                     "default": description
94972                   });
94973                 }
94974
94975                 return description;
94976               });
94977             }
94978
94979             function linkify(url, text) {
94980               text = text || url;
94981               return "<a target=\"_blank\" href=\"".concat(url, "\">").concat(text, "</a>");
94982             }
94983           }
94984
94985           success.changeset = function (val) {
94986             if (!arguments.length) return _changeset;
94987             _changeset = val;
94988             return success;
94989           };
94990
94991           success.location = function (val) {
94992             if (!arguments.length) return _location;
94993             _location = val;
94994             return success;
94995           };
94996
94997           return utilRebind(success, dispatch$1, 'on');
94998         }
94999
95000         function modeSave(context) {
95001           var mode = {
95002             id: 'save'
95003           };
95004           var keybinding = utilKeybinding('modeSave');
95005           var commit = uiCommit(context).on('cancel', cancel);
95006
95007           var _conflictsUi; // uiConflicts
95008
95009
95010           var _location;
95011
95012           var _success;
95013
95014           var uploader = context.uploader().on('saveStarted.modeSave', function () {
95015             keybindingOff();
95016           }) // fire off some async work that we want to be ready later
95017           .on('willAttemptUpload.modeSave', prepareForSuccess).on('progressChanged.modeSave', showProgress).on('resultNoChanges.modeSave', function () {
95018             cancel();
95019           }).on('resultErrors.modeSave', showErrors).on('resultConflicts.modeSave', showConflicts).on('resultSuccess.modeSave', showSuccess);
95020
95021           function cancel() {
95022             context.enter(modeBrowse(context));
95023           }
95024
95025           function showProgress(num, total) {
95026             var modal = context.container().select('.loading-modal .modal-section');
95027             var progress = modal.selectAll('.progress').data([0]); // enter/update
95028
95029             progress.enter().append('div').attr('class', 'progress').merge(progress).text(_t('save.conflict_progress', {
95030               num: num,
95031               total: total
95032             }));
95033           }
95034
95035           function showConflicts(changeset, conflicts, origChanges) {
95036             var selection = context.container().select('.sidebar').append('div').attr('class', 'sidebar-component');
95037             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
95038             _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on('cancel', function () {
95039               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95040               selection.remove();
95041               keybindingOn();
95042               uploader.cancelConflictResolution();
95043             }).on('save', function () {
95044               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95045               selection.remove();
95046               uploader.processResolvedConflicts(changeset);
95047             });
95048             selection.call(_conflictsUi);
95049           }
95050
95051           function showErrors(errors) {
95052             keybindingOn();
95053             var selection = uiConfirm(context.container());
95054             selection.select('.modal-section.header').append('h3').text(_t('save.error'));
95055             addErrors(selection, errors);
95056             selection.okButton();
95057           }
95058
95059           function addErrors(selection, data) {
95060             var message = selection.select('.modal-section.message-text');
95061             var items = message.selectAll('.error-container').data(data);
95062             var enter = items.enter().append('div').attr('class', 'error-container');
95063             enter.append('a').attr('class', 'error-description').attr('href', '#').classed('hide-toggle', true).text(function (d) {
95064               return d.msg || _t('save.unknown_error_details');
95065             }).on('click', function (d3_event) {
95066               d3_event.preventDefault();
95067               var error = select(this);
95068               var detail = select(this.nextElementSibling);
95069               var exp = error.classed('expanded');
95070               detail.style('display', exp ? 'none' : 'block');
95071               error.classed('expanded', !exp);
95072             });
95073             var details = enter.append('div').attr('class', 'error-detail-container').style('display', 'none');
95074             details.append('ul').attr('class', 'error-detail-list').selectAll('li').data(function (d) {
95075               return d.details || [];
95076             }).enter().append('li').attr('class', 'error-detail-item').text(function (d) {
95077               return d;
95078             });
95079             items.exit().remove();
95080           }
95081
95082           function showSuccess(changeset) {
95083             commit.reset();
95084
95085             var ui = _success.changeset(changeset).location(_location).on('cancel', function () {
95086               context.ui().sidebar.hide();
95087             });
95088
95089             context.enter(modeBrowse(context).sidebar(ui));
95090           }
95091
95092           function keybindingOn() {
95093             select(document).call(keybinding.on('⎋', cancel, true));
95094           }
95095
95096           function keybindingOff() {
95097             select(document).call(keybinding.unbind);
95098           } // Reverse geocode current map location so we can display a message on
95099           // the success screen like "Thank you for editing around place, region."
95100
95101
95102           function prepareForSuccess() {
95103             _success = uiSuccess(context);
95104             _location = null;
95105             if (!services.geocoder) return;
95106             services.geocoder.reverse(context.map().center(), function (err, result) {
95107               if (err || !result || !result.address) return;
95108               var addr = result.address;
95109               var place = addr && (addr.town || addr.city || addr.county) || '';
95110               var region = addr && (addr.state || addr.country) || '';
95111               var separator = place && region ? _t('success.thank_you_where.separator') : '';
95112               _location = _t('success.thank_you_where.format', {
95113                 place: place,
95114                 separator: separator,
95115                 region: region
95116               });
95117             });
95118           }
95119
95120           mode.selectedIDs = function () {
95121             return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
95122           };
95123
95124           mode.enter = function () {
95125             // Show sidebar
95126             context.ui().sidebar.expand();
95127
95128             function done() {
95129               context.ui().sidebar.show(commit);
95130             }
95131
95132             keybindingOn();
95133             context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95134             var osm = context.connection();
95135
95136             if (!osm) {
95137               cancel();
95138               return;
95139             }
95140
95141             if (osm.authenticated()) {
95142               done();
95143             } else {
95144               osm.authenticate(function (err) {
95145                 if (err) {
95146                   cancel();
95147                 } else {
95148                   done();
95149                 }
95150               });
95151             }
95152           };
95153
95154           mode.exit = function () {
95155             keybindingOff();
95156             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
95157             context.ui().sidebar.hide();
95158           };
95159
95160           return mode;
95161         }
95162
95163         function uiToolOldDrawModes(context) {
95164           var tool = {
95165             id: 'old_modes',
95166             label: _t.html('toolbar.add_feature')
95167           };
95168           var modes = [modeAddPoint(context, {
95169             title: _t.html('modes.add_point.title'),
95170             button: 'point',
95171             description: _t.html('modes.add_point.description'),
95172             preset: _mainPresetIndex.item('point'),
95173             key: '1'
95174           }), modeAddLine(context, {
95175             title: _t.html('modes.add_line.title'),
95176             button: 'line',
95177             description: _t.html('modes.add_line.description'),
95178             preset: _mainPresetIndex.item('line'),
95179             key: '2'
95180           }), modeAddArea(context, {
95181             title: _t.html('modes.add_area.title'),
95182             button: 'area',
95183             description: _t.html('modes.add_area.description'),
95184             preset: _mainPresetIndex.item('area'),
95185             key: '3'
95186           })];
95187
95188           function enabled() {
95189             return osmEditable();
95190           }
95191
95192           function osmEditable() {
95193             return context.editable();
95194           }
95195
95196           modes.forEach(function (mode) {
95197             context.keybinding().on(mode.key, function () {
95198               if (!enabled()) return;
95199
95200               if (mode.id === context.mode().id) {
95201                 context.enter(modeBrowse(context));
95202               } else {
95203                 context.enter(mode);
95204               }
95205             });
95206           });
95207
95208           tool.render = function (selection) {
95209             var wrap = selection.append('div').attr('class', 'joined').style('display', 'flex');
95210
95211             var debouncedUpdate = debounce(update, 500, {
95212               leading: true,
95213               trailing: true
95214             });
95215
95216             context.map().on('move.modes', debouncedUpdate).on('drawn.modes', debouncedUpdate);
95217             context.on('enter.modes', update);
95218             update();
95219
95220             function update() {
95221               var buttons = wrap.selectAll('button.add-button').data(modes, function (d) {
95222                 return d.id;
95223               }); // exit
95224
95225               buttons.exit().remove(); // enter
95226
95227               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
95228                 return d.id + ' add-button bar-button';
95229               }).on('click.mode-buttons', function (d3_event, d) {
95230                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
95231
95232                 var currMode = context.mode().id;
95233                 if (/^draw/.test(currMode)) return;
95234
95235                 if (d.id === currMode) {
95236                   context.enter(modeBrowse(context));
95237                 } else {
95238                   context.enter(d);
95239                 }
95240               }).call(uiTooltip().placement('bottom').title(function (d) {
95241                 return d.description;
95242               }).keys(function (d) {
95243                 return [d.key];
95244               }).scrollContainer(context.container().select('.top-toolbar')));
95245               buttonsEnter.each(function (d) {
95246                 select(this).call(svgIcon('#iD-icon-' + d.button));
95247               });
95248               buttonsEnter.append('span').attr('class', 'label').html(function (mode) {
95249                 return mode.title;
95250               }); // if we are adding/removing the buttons, check if toolbar has overflowed
95251
95252               if (buttons.enter().size() || buttons.exit().size()) {
95253                 context.ui().checkOverflow('.top-toolbar', true);
95254               } // update
95255
95256
95257               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
95258                 return !enabled();
95259               }).classed('active', function (d) {
95260                 return context.mode() && context.mode().button === d.button;
95261               });
95262             }
95263           };
95264
95265           return tool;
95266         }
95267
95268         function uiToolNotes(context) {
95269           var tool = {
95270             id: 'notes',
95271             label: _t.html('modes.add_note.label')
95272           };
95273           var mode = modeAddNote(context);
95274
95275           function enabled() {
95276             return notesEnabled() && notesEditable();
95277           }
95278
95279           function notesEnabled() {
95280             var noteLayer = context.layers().layer('notes');
95281             return noteLayer && noteLayer.enabled();
95282           }
95283
95284           function notesEditable() {
95285             var mode = context.mode();
95286             return context.map().notesEditable() && mode && mode.id !== 'save';
95287           }
95288
95289           context.keybinding().on(mode.key, function () {
95290             if (!enabled()) return;
95291
95292             if (mode.id === context.mode().id) {
95293               context.enter(modeBrowse(context));
95294             } else {
95295               context.enter(mode);
95296             }
95297           });
95298
95299           tool.render = function (selection) {
95300             var debouncedUpdate = debounce(update, 500, {
95301               leading: true,
95302               trailing: true
95303             });
95304
95305             context.map().on('move.notes', debouncedUpdate).on('drawn.notes', debouncedUpdate);
95306             context.on('enter.notes', update);
95307             update();
95308
95309             function update() {
95310               var showNotes = notesEnabled();
95311               var data = showNotes ? [mode] : [];
95312               var buttons = selection.selectAll('button.add-button').data(data, function (d) {
95313                 return d.id;
95314               }); // exit
95315
95316               buttons.exit().remove(); // enter
95317
95318               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
95319                 return d.id + ' add-button bar-button';
95320               }).on('click.notes', function (d3_event, d) {
95321                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
95322
95323                 var currMode = context.mode().id;
95324                 if (/^draw/.test(currMode)) return;
95325
95326                 if (d.id === currMode) {
95327                   context.enter(modeBrowse(context));
95328                 } else {
95329                   context.enter(d);
95330                 }
95331               }).call(uiTooltip().placement('bottom').title(function (d) {
95332                 return d.description;
95333               }).keys(function (d) {
95334                 return [d.key];
95335               }).scrollContainer(context.container().select('.top-toolbar')));
95336               buttonsEnter.each(function (d) {
95337                 select(this).call(svgIcon(d.icon || '#iD-icon-' + d.button));
95338               }); // if we are adding/removing the buttons, check if toolbar has overflowed
95339
95340               if (buttons.enter().size() || buttons.exit().size()) {
95341                 context.ui().checkOverflow('.top-toolbar', true);
95342               } // update
95343
95344
95345               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
95346                 return !enabled();
95347               }).classed('active', function (d) {
95348                 return context.mode() && context.mode().button === d.button;
95349               });
95350             }
95351           };
95352
95353           tool.uninstall = function () {
95354             context.on('enter.editor.notes', null).on('exit.editor.notes', null).on('enter.notes', null);
95355             context.map().on('move.notes', null).on('drawn.notes', null);
95356           };
95357
95358           return tool;
95359         }
95360
95361         function uiToolSave(context) {
95362           var tool = {
95363             id: 'save',
95364             label: _t.html('save.title')
95365           };
95366           var button = null;
95367           var tooltipBehavior = null;
95368           var history = context.history();
95369           var key = uiCmd('⌘S');
95370           var _numChanges = 0;
95371
95372           function isSaving() {
95373             var mode = context.mode();
95374             return mode && mode.id === 'save';
95375           }
95376
95377           function isDisabled() {
95378             return _numChanges === 0 || isSaving();
95379           }
95380
95381           function save(d3_event) {
95382             d3_event.preventDefault();
95383
95384             if (!context.inIntro() && !isSaving() && history.hasChanges()) {
95385               context.enter(modeSave(context));
95386             }
95387           }
95388
95389           function bgColor() {
95390             var step;
95391
95392             if (_numChanges === 0) {
95393               return null;
95394             } else if (_numChanges <= 50) {
95395               step = _numChanges / 50;
95396               return d3_interpolateRgb('#fff', '#ff8')(step); // white -> yellow
95397             } else {
95398               step = Math.min((_numChanges - 50) / 50, 1.0);
95399               return d3_interpolateRgb('#ff8', '#f88')(step); // yellow -> red
95400             }
95401           }
95402
95403           function updateCount() {
95404             var val = history.difference().summary().length;
95405             if (val === _numChanges) return;
95406             _numChanges = val;
95407
95408             if (tooltipBehavior) {
95409               tooltipBehavior.title(_t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')).keys([key]);
95410             }
95411
95412             if (button) {
95413               button.classed('disabled', isDisabled()).style('background', bgColor());
95414               button.select('span.count').html(_numChanges);
95415             }
95416           }
95417
95418           tool.render = function (selection) {
95419             tooltipBehavior = uiTooltip().placement('bottom').title(_t.html('save.no_changes')).keys([key]).scrollContainer(context.container().select('.top-toolbar'));
95420             var lastPointerUpType;
95421             button = selection.append('button').attr('class', 'save disabled bar-button').on('pointerup', function (d3_event) {
95422               lastPointerUpType = d3_event.pointerType;
95423             }).on('click', function (d3_event) {
95424               save(d3_event);
95425
95426               if (_numChanges === 0 && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
95427                 // there are no tooltips for touch interactions so flash feedback instead
95428                 context.ui().flash.duration(2000).iconName('#iD-icon-save').iconClass('disabled').label(_t.html('save.no_changes'))();
95429               }
95430
95431               lastPointerUpType = null;
95432             }).call(tooltipBehavior);
95433             button.call(svgIcon('#iD-icon-save'));
95434             button.append('span').attr('class', 'count').attr('aria-hidden', 'true').html('0');
95435             updateCount();
95436             context.keybinding().on(key, save, true);
95437             context.history().on('change.save', updateCount);
95438             context.on('enter.save', function () {
95439               if (button) {
95440                 button.classed('disabled', isDisabled());
95441
95442                 if (isSaving()) {
95443                   button.call(tooltipBehavior.hide);
95444                 }
95445               }
95446             });
95447           };
95448
95449           tool.uninstall = function () {
95450             context.keybinding().off(key, true);
95451             context.history().on('change.save', null);
95452             context.on('enter.save', null);
95453             button = null;
95454             tooltipBehavior = null;
95455           };
95456
95457           return tool;
95458         }
95459
95460         function uiToolSidebarToggle(context) {
95461           var tool = {
95462             id: 'sidebar_toggle',
95463             label: _t.html('toolbar.inspect')
95464           };
95465
95466           tool.render = function (selection) {
95467             selection.append('button').attr('class', 'bar-button').on('click', function () {
95468               context.ui().sidebar.toggle();
95469             }).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')));
95470           };
95471
95472           return tool;
95473         }
95474
95475         function uiToolUndoRedo(context) {
95476           var tool = {
95477             id: 'undo_redo',
95478             label: _t.html('toolbar.undo_redo')
95479           };
95480           var commands = [{
95481             id: 'undo',
95482             cmd: uiCmd('⌘Z'),
95483             action: function action() {
95484               context.undo();
95485             },
95486             annotation: function annotation() {
95487               return context.history().undoAnnotation();
95488             },
95489             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')
95490           }, {
95491             id: 'redo',
95492             cmd: uiCmd('⌘⇧Z'),
95493             action: function action() {
95494               context.redo();
95495             },
95496             annotation: function annotation() {
95497               return context.history().redoAnnotation();
95498             },
95499             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'undo' : 'redo')
95500           }];
95501
95502           function editable() {
95503             return context.mode() && context.mode().id !== 'save' && context.map().editableDataEnabled(true
95504             /* ignore min zoom */
95505             );
95506           }
95507
95508           tool.render = function (selection) {
95509             var tooltipBehavior = uiTooltip().placement('bottom').title(function (d) {
95510               return d.annotation() ? _t.html(d.id + '.tooltip', {
95511                 action: d.annotation()
95512               }) : _t.html(d.id + '.nothing');
95513             }).keys(function (d) {
95514               return [d.cmd];
95515             }).scrollContainer(context.container().select('.top-toolbar'));
95516             var lastPointerUpType;
95517             var buttons = selection.selectAll('button').data(commands).enter().append('button').attr('class', function (d) {
95518               return 'disabled ' + d.id + '-button bar-button';
95519             }).on('pointerup', function (d3_event) {
95520               // `pointerup` is always called before `click`
95521               lastPointerUpType = d3_event.pointerType;
95522             }).on('click', function (d3_event, d) {
95523               d3_event.preventDefault();
95524               var annotation = d.annotation();
95525
95526               if (editable() && annotation) {
95527                 d.action();
95528               }
95529
95530               if (editable() && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
95531                 // there are no tooltips for touch interactions so flash feedback instead
95532                 var text = annotation ? _t(d.id + '.tooltip', {
95533                   action: annotation
95534                 }) : _t(d.id + '.nothing');
95535                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass(annotation ? '' : 'disabled').label(text)();
95536               }
95537
95538               lastPointerUpType = null;
95539             }).call(tooltipBehavior);
95540             buttons.each(function (d) {
95541               select(this).call(svgIcon('#' + d.icon));
95542             });
95543             context.keybinding().on(commands[0].cmd, function (d3_event) {
95544               d3_event.preventDefault();
95545               if (editable()) commands[0].action();
95546             }).on(commands[1].cmd, function (d3_event) {
95547               d3_event.preventDefault();
95548               if (editable()) commands[1].action();
95549             });
95550
95551             var debouncedUpdate = debounce(update, 500, {
95552               leading: true,
95553               trailing: true
95554             });
95555
95556             context.map().on('move.undo_redo', debouncedUpdate).on('drawn.undo_redo', debouncedUpdate);
95557             context.history().on('change.undo_redo', function (difference) {
95558               if (difference) update();
95559             });
95560             context.on('enter.undo_redo', update);
95561
95562             function update() {
95563               buttons.classed('disabled', function (d) {
95564                 return !editable() || !d.annotation();
95565               }).each(function () {
95566                 var selection = select(this);
95567
95568                 if (!selection.select('.tooltip.in').empty()) {
95569                   selection.call(tooltipBehavior.updateContent);
95570                 }
95571               });
95572             }
95573           };
95574
95575           tool.uninstall = function () {
95576             context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
95577             context.map().on('move.undo_redo', null).on('drawn.undo_redo', null);
95578             context.history().on('change.undo_redo', null);
95579             context.on('enter.undo_redo', null);
95580           };
95581
95582           return tool;
95583         }
95584
95585         function uiTopToolbar(context) {
95586           var sidebarToggle = uiToolSidebarToggle(context),
95587               modes = uiToolOldDrawModes(context),
95588               notes = uiToolNotes(context),
95589               undoRedo = uiToolUndoRedo(context),
95590               save = uiToolSave(context);
95591
95592           function notesEnabled() {
95593             var noteLayer = context.layers().layer('notes');
95594             return noteLayer && noteLayer.enabled();
95595           }
95596
95597           function topToolbar(bar) {
95598             bar.on('wheel.topToolbar', function (d3_event) {
95599               if (!d3_event.deltaX) {
95600                 // translate vertical scrolling into horizontal scrolling in case
95601                 // the user doesn't have an input device that can scroll horizontally
95602                 bar.node().scrollLeft += d3_event.deltaY;
95603               }
95604             });
95605
95606             var debouncedUpdate = debounce(update, 500, {
95607               leading: true,
95608               trailing: true
95609             });
95610
95611             context.layers().on('change.topToolbar', debouncedUpdate);
95612             update();
95613
95614             function update() {
95615               var tools = [sidebarToggle, 'spacer', modes];
95616               tools.push('spacer');
95617
95618               if (notesEnabled()) {
95619                 tools = tools.concat([notes, 'spacer']);
95620               }
95621
95622               tools = tools.concat([undoRedo, save]);
95623               var toolbarItems = bar.selectAll('.toolbar-item').data(tools, function (d) {
95624                 return d.id || d;
95625               });
95626               toolbarItems.exit().each(function (d) {
95627                 if (d.uninstall) {
95628                   d.uninstall();
95629                 }
95630               }).remove();
95631               var itemsEnter = toolbarItems.enter().append('div').attr('class', function (d) {
95632                 var classes = 'toolbar-item ' + (d.id || d).replace('_', '-');
95633                 if (d.klass) classes += ' ' + d.klass;
95634                 return classes;
95635               });
95636               var actionableItems = itemsEnter.filter(function (d) {
95637                 return d !== 'spacer';
95638               });
95639               actionableItems.append('div').attr('class', 'item-content').each(function (d) {
95640                 select(this).call(d.render, bar);
95641               });
95642               actionableItems.append('div').attr('class', 'item-label').html(function (d) {
95643                 return d.label;
95644               });
95645             }
95646           }
95647
95648           return topToolbar;
95649         }
95650
95651         var sawVersion = null;
95652         var isNewVersion = false;
95653         var isNewUser = false;
95654         function uiVersion(context) {
95655           var currVersion = context.version;
95656           var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
95657
95658           if (sawVersion === null && matchedVersion !== null) {
95659             if (corePreferences('sawVersion')) {
95660               isNewUser = false;
95661               isNewVersion = corePreferences('sawVersion') !== currVersion && currVersion.indexOf('-') === -1;
95662             } else {
95663               isNewUser = true;
95664               isNewVersion = true;
95665             }
95666
95667             corePreferences('sawVersion', currVersion);
95668             sawVersion = currVersion;
95669           }
95670
95671           return function (selection) {
95672             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
95673
95674             if (isNewVersion && !isNewUser) {
95675               selection.append('div').attr('class', 'badge').append('a').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', {
95676                 version: currVersion
95677               })).placement('top'));
95678             }
95679           };
95680         }
95681
95682         function uiZoom(context) {
95683           var zooms = [{
95684             id: 'zoom-in',
95685             icon: 'iD-icon-plus',
95686             title: _t.html('zoom.in'),
95687             action: zoomIn,
95688             disabled: function disabled() {
95689               return !context.map().canZoomIn();
95690             },
95691             disabledTitle: _t.html('zoom.disabled.in'),
95692             key: '+'
95693           }, {
95694             id: 'zoom-out',
95695             icon: 'iD-icon-minus',
95696             title: _t.html('zoom.out'),
95697             action: zoomOut,
95698             disabled: function disabled() {
95699               return !context.map().canZoomOut();
95700             },
95701             disabledTitle: _t.html('zoom.disabled.out'),
95702             key: '-'
95703           }];
95704
95705           function zoomIn(d3_event) {
95706             if (d3_event.shiftKey) return;
95707             d3_event.preventDefault();
95708             context.map().zoomIn();
95709           }
95710
95711           function zoomOut(d3_event) {
95712             if (d3_event.shiftKey) return;
95713             d3_event.preventDefault();
95714             context.map().zoomOut();
95715           }
95716
95717           function zoomInFurther(d3_event) {
95718             if (d3_event.shiftKey) return;
95719             d3_event.preventDefault();
95720             context.map().zoomInFurther();
95721           }
95722
95723           function zoomOutFurther(d3_event) {
95724             if (d3_event.shiftKey) return;
95725             d3_event.preventDefault();
95726             context.map().zoomOutFurther();
95727           }
95728
95729           return function (selection) {
95730             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function (d) {
95731               if (d.disabled()) {
95732                 return d.disabledTitle;
95733               }
95734
95735               return d.title;
95736             }).keys(function (d) {
95737               return [d.key];
95738             });
95739             var lastPointerUpType;
95740             var buttons = selection.selectAll('button').data(zooms).enter().append('button').attr('class', function (d) {
95741               return d.id;
95742             }).on('pointerup.editor', function (d3_event) {
95743               lastPointerUpType = d3_event.pointerType;
95744             }).on('click.editor', function (d3_event, d) {
95745               if (!d.disabled()) {
95746                 d.action(d3_event);
95747               } else if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
95748                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass('disabled').label(d.disabledTitle)();
95749               }
95750
95751               lastPointerUpType = null;
95752             }).call(tooltipBehavior);
95753             buttons.each(function (d) {
95754               select(this).call(svgIcon('#' + d.icon, 'light'));
95755             });
95756             utilKeybinding.plusKeys.forEach(function (key) {
95757               context.keybinding().on([key], zoomIn);
95758               context.keybinding().on([uiCmd('⌥' + key)], zoomInFurther);
95759             });
95760             utilKeybinding.minusKeys.forEach(function (key) {
95761               context.keybinding().on([key], zoomOut);
95762               context.keybinding().on([uiCmd('⌥' + key)], zoomOutFurther);
95763             });
95764
95765             function updateButtonStates() {
95766               buttons.classed('disabled', function (d) {
95767                 return d.disabled();
95768               }).each(function () {
95769                 var selection = select(this);
95770
95771                 if (!selection.select('.tooltip.in').empty()) {
95772                   selection.call(tooltipBehavior.updateContent);
95773                 }
95774               });
95775             }
95776
95777             updateButtonStates();
95778             context.map().on('move.uiZoom', updateButtonStates);
95779           };
95780         }
95781
95782         function uiZoomToSelection(context) {
95783           function isDisabled() {
95784             var mode = context.mode();
95785             return !mode || !mode.zoomToSelected;
95786           }
95787
95788           var _lastPointerUpType;
95789
95790           function pointerup(d3_event) {
95791             _lastPointerUpType = d3_event.pointerType;
95792           }
95793
95794           function click(d3_event) {
95795             d3_event.preventDefault();
95796
95797             if (isDisabled()) {
95798               if (_lastPointerUpType === 'touch' || _lastPointerUpType === 'pen') {
95799                 context.ui().flash.duration(2000).iconName('#iD-icon-framed-dot').iconClass('disabled').label(_t.html('inspector.zoom_to.no_selection'))();
95800               }
95801             } else {
95802               var mode = context.mode();
95803
95804               if (mode && mode.zoomToSelected) {
95805                 mode.zoomToSelected();
95806               }
95807             }
95808
95809             _lastPointerUpType = null;
95810           }
95811
95812           return function (selection) {
95813             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function () {
95814               if (isDisabled()) {
95815                 return _t.html('inspector.zoom_to.no_selection');
95816               }
95817
95818               return _t.html('inspector.zoom_to.title');
95819             }).keys([_t('inspector.zoom_to.key')]);
95820             var button = selection.append('button').on('pointerup', pointerup).on('click', click).call(svgIcon('#iD-icon-framed-dot', 'light')).call(tooltipBehavior);
95821
95822             function setEnabledState() {
95823               button.classed('disabled', isDisabled());
95824
95825               if (!button.select('.tooltip.in').empty()) {
95826                 button.call(tooltipBehavior.updateContent);
95827               }
95828             }
95829
95830             context.on('enter.uiZoomToSelection', setEnabledState);
95831             setEnabledState();
95832           };
95833         }
95834
95835         function uiPane(id, context) {
95836           var _key;
95837
95838           var _label = '';
95839           var _description = '';
95840           var _iconName = '';
95841
95842           var _sections; // array of uiSection objects
95843
95844
95845           var _paneSelection = select(null);
95846
95847           var _paneTooltip;
95848
95849           var pane = {
95850             id: id
95851           };
95852
95853           pane.label = function (val) {
95854             if (!arguments.length) return _label;
95855             _label = val;
95856             return pane;
95857           };
95858
95859           pane.key = function (val) {
95860             if (!arguments.length) return _key;
95861             _key = val;
95862             return pane;
95863           };
95864
95865           pane.description = function (val) {
95866             if (!arguments.length) return _description;
95867             _description = val;
95868             return pane;
95869           };
95870
95871           pane.iconName = function (val) {
95872             if (!arguments.length) return _iconName;
95873             _iconName = val;
95874             return pane;
95875           };
95876
95877           pane.sections = function (val) {
95878             if (!arguments.length) return _sections;
95879             _sections = val;
95880             return pane;
95881           };
95882
95883           pane.selection = function () {
95884             return _paneSelection;
95885           };
95886
95887           function hidePane() {
95888             context.ui().togglePanes();
95889           }
95890
95891           pane.togglePane = function (d3_event) {
95892             if (d3_event) d3_event.preventDefault();
95893
95894             _paneTooltip.hide();
95895
95896             context.ui().togglePanes(!_paneSelection.classed('shown') ? _paneSelection : undefined);
95897           };
95898
95899           pane.renderToggleButton = function (selection) {
95900             if (!_paneTooltip) {
95901               _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_description).keys([_key]);
95902             }
95903
95904             selection.append('button').on('click', pane.togglePane).call(svgIcon('#' + _iconName, 'light')).call(_paneTooltip);
95905           };
95906
95907           pane.renderContent = function (selection) {
95908             // override to fully customize content
95909             if (_sections) {
95910               _sections.forEach(function (section) {
95911                 selection.call(section.render);
95912               });
95913             }
95914           };
95915
95916           pane.renderPane = function (selection) {
95917             _paneSelection = selection.append('div').attr('class', 'fillL map-pane hide ' + id + '-pane').attr('pane', id);
95918
95919             var heading = _paneSelection.append('div').attr('class', 'pane-heading');
95920
95921             heading.append('h2').html(_label);
95922             heading.append('button').on('click', hidePane).call(svgIcon('#iD-icon-close'));
95923
95924             _paneSelection.append('div').attr('class', 'pane-content').call(pane.renderContent);
95925
95926             if (_key) {
95927               context.keybinding().on(_key, pane.togglePane);
95928             }
95929           };
95930
95931           return pane;
95932         }
95933
95934         function uiSectionBackgroundDisplayOptions(context) {
95935           var section = uiSection('background-display-options', context).label(_t.html('background.display_options')).disclosureContent(renderDisclosureContent);
95936
95937           var _detected = utilDetect();
95938
95939           var _storedOpacity = corePreferences('background-opacity');
95940
95941           var _minVal = 0;
95942
95943           var _maxVal = _detected.cssfilters ? 3 : 1;
95944
95945           var _sliders = _detected.cssfilters ? ['brightness', 'contrast', 'saturation', 'sharpness'] : ['brightness'];
95946
95947           var _options = {
95948             brightness: _storedOpacity !== null ? +_storedOpacity : 1,
95949             contrast: 1,
95950             saturation: 1,
95951             sharpness: 1
95952           };
95953
95954           function clamp(x, min, max) {
95955             return Math.max(min, Math.min(x, max));
95956           }
95957
95958           function updateValue(d, val) {
95959             val = clamp(val, _minVal, _maxVal);
95960             _options[d] = val;
95961             context.background()[d](val);
95962
95963             if (d === 'brightness') {
95964               corePreferences('background-opacity', val);
95965             }
95966
95967             section.reRender();
95968           }
95969
95970           function renderDisclosureContent(selection) {
95971             var container = selection.selectAll('.display-options-container').data([0]);
95972             var containerEnter = container.enter().append('div').attr('class', 'display-options-container controls-list'); // add slider controls
95973
95974             var slidersEnter = containerEnter.selectAll('.display-control').data(_sliders).enter().append('div').attr('class', function (d) {
95975               return 'display-control display-control-' + d;
95976             });
95977             slidersEnter.append('h5').html(function (d) {
95978               return _t.html('background.' + d);
95979             }).append('span').attr('class', function (d) {
95980               return 'display-option-value display-option-value-' + d;
95981             });
95982             var sildersControlEnter = slidersEnter.append('div').attr('class', 'control-wrap');
95983             sildersControlEnter.append('input').attr('class', function (d) {
95984               return 'display-option-input display-option-input-' + d;
95985             }).attr('type', 'range').attr('min', _minVal).attr('max', _maxVal).attr('step', '0.05').on('input', function (d3_event, d) {
95986               var val = select(this).property('value');
95987
95988               if (!val && d3_event && d3_event.target) {
95989                 val = d3_event.target.value;
95990               }
95991
95992               updateValue(d, val);
95993             });
95994             sildersControlEnter.append('button').attr('title', _t('background.reset')).attr('class', function (d) {
95995               return 'display-option-reset display-option-reset-' + d;
95996             }).on('click', function (d3_event, d) {
95997               if (d3_event.button !== 0) return;
95998               updateValue(d, 1);
95999             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo'))); // reset all button
96000
96001             containerEnter.append('a').attr('class', 'display-option-resetlink').attr('href', '#').html(_t.html('background.reset_all')).on('click', function (d3_event) {
96002               d3_event.preventDefault();
96003
96004               for (var i = 0; i < _sliders.length; i++) {
96005                 updateValue(_sliders[i], 1);
96006               }
96007             }); // update
96008
96009             container = containerEnter.merge(container);
96010             container.selectAll('.display-option-input').property('value', function (d) {
96011               return _options[d];
96012             });
96013             container.selectAll('.display-option-value').html(function (d) {
96014               return Math.floor(_options[d] * 100) + '%';
96015             });
96016             container.selectAll('.display-option-reset').classed('disabled', function (d) {
96017               return _options[d] === 1;
96018             }); // first time only, set brightness if needed
96019
96020             if (containerEnter.size() && _options.brightness !== 1) {
96021               context.background().brightness(_options.brightness);
96022             }
96023           }
96024
96025           return section;
96026         }
96027
96028         function uiSettingsCustomBackground() {
96029           var dispatch$1 = dispatch('change');
96030
96031           function render(selection) {
96032             // keep separate copies of original and current settings
96033             var _origSettings = {
96034               template: corePreferences('background-custom-template')
96035             };
96036             var _currSettings = {
96037               template: corePreferences('background-custom-template')
96038             };
96039             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
96040             var modal = uiConfirm(selection).okButton();
96041             modal.classed('settings-modal settings-custom-background', true);
96042             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_background.header'));
96043             var textSection = modal.select('.modal-section.message-text');
96044             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, "`");
96045             textSection.append('div').attr('class', 'instructions-template').html(marked_1(instructions));
96046             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
96047
96048             var buttonSection = modal.select('.modal-section.buttons');
96049             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
96050             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
96051             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
96052
96053             function isSaveDisabled() {
96054               return null;
96055             } // restore the original template
96056
96057
96058             function clickCancel() {
96059               textSection.select('.field-template').property('value', _origSettings.template);
96060               corePreferences('background-custom-template', _origSettings.template);
96061               this.blur();
96062               modal.close();
96063             } // accept the current template
96064
96065
96066             function clickSave() {
96067               _currSettings.template = textSection.select('.field-template').property('value');
96068               corePreferences('background-custom-template', _currSettings.template);
96069               this.blur();
96070               modal.close();
96071               dispatch$1.call('change', this, _currSettings);
96072             }
96073           }
96074
96075           return utilRebind(render, dispatch$1, 'on');
96076         }
96077
96078         function uiSectionBackgroundList(context) {
96079           var _backgroundList = select(null);
96080
96081           var _customSource = context.background().findSource('custom');
96082
96083           var _settingsCustomBackground = uiSettingsCustomBackground().on('change', customChanged);
96084
96085           var section = uiSection('background-list', context).label(_t.html('background.backgrounds')).disclosureContent(renderDisclosureContent);
96086
96087           function previousBackgroundID() {
96088             return corePreferences('background-last-used-toggle');
96089           }
96090
96091           function renderDisclosureContent(selection) {
96092             // the background list
96093             var container = selection.selectAll('.layer-background-list').data([0]);
96094             _backgroundList = container.enter().append('ul').attr('class', 'layer-list layer-background-list').attr('dir', 'auto').merge(container); // add minimap toggle below list
96095
96096             var bgExtrasListEnter = selection.selectAll('.bg-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list bg-extras-list');
96097             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'));
96098             minimapLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96099               d3_event.preventDefault();
96100               uiMapInMap.toggle();
96101             });
96102             minimapLabelEnter.append('span').html(_t.html('background.minimap.description'));
96103             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'));
96104             panelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96105               d3_event.preventDefault();
96106               context.ui().info.toggle('background');
96107             });
96108             panelLabelEnter.append('span').html(_t.html('background.panel.description'));
96109             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'));
96110             locPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96111               d3_event.preventDefault();
96112               context.ui().info.toggle('location');
96113             });
96114             locPanelLabelEnter.append('span').html(_t.html('background.location_panel.description')); // "Info / Report a Problem" link
96115
96116             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'));
96117
96118             _backgroundList.call(drawListItems, 'radio', function (d3_event, d) {
96119               chooseBackground(d);
96120             }, function (d) {
96121               return !d.isHidden() && !d.overlay;
96122             });
96123           }
96124
96125           function setTooltips(selection) {
96126             selection.each(function (d, i, nodes) {
96127               var item = select(this).select('label');
96128               var span = item.select('span');
96129               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
96130               var description = d.description();
96131               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
96132               item.call(uiTooltip().destroyAny);
96133
96134               if (d.id === previousBackgroundID()) {
96135                 item.call(uiTooltip().placement(placement).title('<div>' + _t.html('background.switch') + '</div>').keys([uiCmd('⌘' + _t('background.key'))]));
96136               } else if (description || isOverflowing) {
96137                 item.call(uiTooltip().placement(placement).title(description || d.label()));
96138               }
96139             });
96140           }
96141
96142           function drawListItems(layerList, type, change, filter) {
96143             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter).sort(function (a, b) {
96144               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
96145             });
96146             var layerLinks = layerList.selectAll('li') // We have to be a bit inefficient about reordering the list since
96147             // arrow key navigation of radio values likes to work in the order
96148             // they were added, not the display document order.
96149             .data(sources, function (d, i) {
96150               return d.id + '---' + i;
96151             });
96152             layerLinks.exit().remove();
96153             var enter = layerLinks.enter().append('li').classed('layer-custom', function (d) {
96154               return d.id === 'custom';
96155             }).classed('best', function (d) {
96156               return d.best();
96157             });
96158             var label = enter.append('label');
96159             label.append('input').attr('type', type).attr('name', 'background-layer').attr('value', function (d) {
96160               return d.id;
96161             }).on('change', change);
96162             label.append('span').html(function (d) {
96163               return d.label();
96164             });
96165             enter.filter(function (d) {
96166               return d.id === 'custom';
96167             }).append('button').attr('class', 'layer-browse').call(uiTooltip().title(_t.html('settings.custom_background.tooltip')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', editCustom).call(svgIcon('#iD-icon-more'));
96168             enter.filter(function (d) {
96169               return d.best();
96170             }).append('div').attr('class', 'best').call(uiTooltip().title(_t.html('background.best_imagery')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).append('span').html('&#9733;');
96171             layerList.call(updateLayerSelections);
96172           }
96173
96174           function updateLayerSelections(selection) {
96175             function active(d) {
96176               return context.background().showsLayer(d);
96177             }
96178
96179             selection.selectAll('li').classed('active', active).classed('switch', function (d) {
96180               return d.id === previousBackgroundID();
96181             }).call(setTooltips).selectAll('input').property('checked', active);
96182           }
96183
96184           function chooseBackground(d) {
96185             if (d.id === 'custom' && !d.template()) {
96186               return editCustom();
96187             }
96188
96189             var previousBackground = context.background().baseLayerSource();
96190             corePreferences('background-last-used-toggle', previousBackground.id);
96191             corePreferences('background-last-used', d.id);
96192             context.background().baseLayerSource(d);
96193           }
96194
96195           function customChanged(d) {
96196             if (d && d.template) {
96197               _customSource.template(d.template);
96198
96199               chooseBackground(_customSource);
96200             } else {
96201               _customSource.template('');
96202
96203               chooseBackground(context.background().findSource('none'));
96204             }
96205           }
96206
96207           function editCustom(d3_event) {
96208             d3_event.preventDefault();
96209             context.container().call(_settingsCustomBackground);
96210           }
96211
96212           context.background().on('change.background_list', function () {
96213             _backgroundList.call(updateLayerSelections);
96214           });
96215           context.map().on('move.background_list', debounce(function () {
96216             // layers in-view may have changed due to map move
96217             window.requestIdleCallback(section.reRender);
96218           }, 1000));
96219           return section;
96220         }
96221
96222         function uiSectionBackgroundOffset(context) {
96223           var section = uiSection('background-offset', context).label(_t.html('background.fix_misalignment')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
96224
96225           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
96226
96227           var _directions = [['top', [0, -0.5]], ['left', [-0.5, 0]], ['right', [0.5, 0]], ['bottom', [0, 0.5]]];
96228
96229           function updateValue() {
96230             var meters = geoOffsetToMeters(context.background().offset());
96231             var x = +meters[0].toFixed(2);
96232             var y = +meters[1].toFixed(2);
96233             context.container().selectAll('.nudge-inner-rect').select('input').classed('error', false).property('value', x + ', ' + y);
96234             context.container().selectAll('.nudge-reset').classed('disabled', function () {
96235               return x === 0 && y === 0;
96236             });
96237           }
96238
96239           function resetOffset() {
96240             context.background().offset([0, 0]);
96241             updateValue();
96242           }
96243
96244           function nudge(d) {
96245             context.background().nudge(d, context.map().zoom());
96246             updateValue();
96247           }
96248
96249           function inputOffset() {
96250             var input = select(this);
96251             var d = input.node().value;
96252             if (d === '') return resetOffset();
96253             d = d.replace(/;/g, ',').split(',').map(function (n) {
96254               // if n is NaN, it will always get mapped to false.
96255               return !isNaN(n) && n;
96256             });
96257
96258             if (d.length !== 2 || !d[0] || !d[1]) {
96259               input.classed('error', true);
96260               return;
96261             }
96262
96263             context.background().offset(geoMetersToOffset(d));
96264             updateValue();
96265           }
96266
96267           function dragOffset(d3_event) {
96268             if (d3_event.button !== 0) return;
96269             var origin = [d3_event.clientX, d3_event.clientY];
96270             var pointerId = d3_event.pointerId || 'mouse';
96271             context.container().append('div').attr('class', 'nudge-surface');
96272             select(window).on(_pointerPrefix + 'move.drag-bg-offset', pointermove).on(_pointerPrefix + 'up.drag-bg-offset', pointerup);
96273
96274             if (_pointerPrefix === 'pointer') {
96275               select(window).on('pointercancel.drag-bg-offset', pointerup);
96276             }
96277
96278             function pointermove(d3_event) {
96279               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
96280               var latest = [d3_event.clientX, d3_event.clientY];
96281               var d = [-(origin[0] - latest[0]) / 4, -(origin[1] - latest[1]) / 4];
96282               origin = latest;
96283               nudge(d);
96284             }
96285
96286             function pointerup(d3_event) {
96287               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
96288               if (d3_event.button !== 0) return;
96289               context.container().selectAll('.nudge-surface').remove();
96290               select(window).on('.drag-bg-offset', null);
96291             }
96292           }
96293
96294           function renderDisclosureContent(selection) {
96295             var container = selection.selectAll('.nudge-container').data([0]);
96296             var containerEnter = container.enter().append('div').attr('class', 'nudge-container');
96297             containerEnter.append('div').attr('class', 'nudge-instructions').html(_t.html('background.offset'));
96298             var nudgeWrapEnter = containerEnter.append('div').attr('class', 'nudge-controls-wrap');
96299             var nudgeEnter = nudgeWrapEnter.append('div').attr('class', 'nudge-outer-rect').on(_pointerPrefix + 'down', dragOffset);
96300             nudgeEnter.append('div').attr('class', 'nudge-inner-rect').append('input').attr('type', 'text').on('change', inputOffset);
96301             nudgeWrapEnter.append('div').selectAll('button').data(_directions).enter().append('button').attr('class', function (d) {
96302               return d[0] + ' nudge';
96303             }).on('click', function (d3_event, d) {
96304               nudge(d[1]);
96305             });
96306             nudgeWrapEnter.append('button').attr('title', _t('background.reset')).attr('class', 'nudge-reset disabled').on('click', function (d3_event) {
96307               d3_event.preventDefault();
96308               resetOffset();
96309             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')));
96310             updateValue();
96311           }
96312
96313           context.background().on('change.backgroundOffset-update', updateValue);
96314           return section;
96315         }
96316
96317         function uiSectionOverlayList(context) {
96318           var section = uiSection('overlay-list', context).label(_t.html('background.overlays')).disclosureContent(renderDisclosureContent);
96319
96320           var _overlayList = select(null);
96321
96322           function setTooltips(selection) {
96323             selection.each(function (d, i, nodes) {
96324               var item = select(this).select('label');
96325               var span = item.select('span');
96326               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
96327               var description = d.description();
96328               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
96329               item.call(uiTooltip().destroyAny);
96330
96331               if (description || isOverflowing) {
96332                 item.call(uiTooltip().placement(placement).title(description || d.name()));
96333               }
96334             });
96335           }
96336
96337           function updateLayerSelections(selection) {
96338             function active(d) {
96339               return context.background().showsLayer(d);
96340             }
96341
96342             selection.selectAll('li').classed('active', active).call(setTooltips).selectAll('input').property('checked', active);
96343           }
96344
96345           function chooseOverlay(d3_event, d) {
96346             d3_event.preventDefault();
96347             context.background().toggleOverlayLayer(d);
96348
96349             _overlayList.call(updateLayerSelections);
96350
96351             document.activeElement.blur();
96352           }
96353
96354           function drawListItems(layerList, type, change, filter) {
96355             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter);
96356             var layerLinks = layerList.selectAll('li').data(sources, function (d) {
96357               return d.name();
96358             });
96359             layerLinks.exit().remove();
96360             var enter = layerLinks.enter().append('li');
96361             var label = enter.append('label');
96362             label.append('input').attr('type', type).attr('name', 'layers').on('change', change);
96363             label.append('span').html(function (d) {
96364               return d.label();
96365             });
96366             layerList.selectAll('li').sort(sortSources);
96367             layerList.call(updateLayerSelections);
96368
96369             function sortSources(a, b) {
96370               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
96371             }
96372           }
96373
96374           function renderDisclosureContent(selection) {
96375             var container = selection.selectAll('.layer-overlay-list').data([0]);
96376             _overlayList = container.enter().append('ul').attr('class', 'layer-list layer-overlay-list').attr('dir', 'auto').merge(container);
96377
96378             _overlayList.call(drawListItems, 'checkbox', chooseOverlay, function (d) {
96379               return !d.isHidden() && d.overlay;
96380             });
96381           }
96382
96383           context.map().on('move.overlay_list', debounce(function () {
96384             // layers in-view may have changed due to map move
96385             window.requestIdleCallback(section.reRender);
96386           }, 1000));
96387           return section;
96388         }
96389
96390         function uiPaneBackground(context) {
96391           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)]);
96392           return backgroundPane;
96393         }
96394
96395         function uiPaneHelp(context) {
96396           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']]];
96397           var headings = {
96398             'help.help.open_data_h': 3,
96399             'help.help.before_start_h': 3,
96400             'help.help.open_source_h': 3,
96401             'help.overview.navigation_h': 3,
96402             'help.overview.features_h': 3,
96403             'help.editing.select_h': 3,
96404             'help.editing.multiselect_h': 3,
96405             'help.editing.undo_redo_h': 3,
96406             'help.editing.save_h': 3,
96407             'help.editing.upload_h': 3,
96408             'help.editing.backups_h': 3,
96409             'help.editing.keyboard_h': 3,
96410             'help.feature_editor.type_h': 3,
96411             'help.feature_editor.fields_h': 3,
96412             'help.feature_editor.tags_h': 3,
96413             'help.points.add_point_h': 3,
96414             'help.points.move_point_h': 3,
96415             'help.points.delete_point_h': 3,
96416             'help.lines.add_line_h': 3,
96417             'help.lines.modify_line_h': 3,
96418             'help.lines.connect_line_h': 3,
96419             'help.lines.disconnect_line_h': 3,
96420             'help.lines.move_line_h': 3,
96421             'help.lines.delete_line_h': 3,
96422             'help.areas.point_or_area_h': 3,
96423             'help.areas.add_area_h': 3,
96424             'help.areas.square_area_h': 3,
96425             'help.areas.modify_area_h': 3,
96426             'help.areas.delete_area_h': 3,
96427             'help.relations.edit_relation_h': 3,
96428             'help.relations.maintain_relation_h': 3,
96429             'help.relations.relation_types_h': 2,
96430             'help.relations.multipolygon_h': 3,
96431             'help.relations.turn_restriction_h': 3,
96432             'help.relations.route_h': 3,
96433             'help.relations.boundary_h': 3,
96434             'help.notes.add_note_h': 3,
96435             'help.notes.update_note_h': 3,
96436             'help.notes.save_note_h': 3,
96437             'help.imagery.sources_h': 3,
96438             'help.imagery.offsets_h': 3,
96439             'help.streetlevel.using_h': 3,
96440             'help.gps.using_h': 3,
96441             'help.qa.tools_h': 3,
96442             'help.qa.issues_h': 3
96443           }; // For each section, squash all the texts into a single markdown document
96444
96445           var docs = docKeys.map(function (key) {
96446             var helpkey = 'help.' + key[0];
96447             var helpPaneReplacements = {
96448               version: context.version
96449             };
96450             var text = key[1].reduce(function (all, part) {
96451               var subkey = helpkey + '.' + part;
96452               var depth = headings[subkey]; // is this subkey a heading?
96453
96454               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
96455
96456               return all + hhh + helpHtml(subkey, helpPaneReplacements) + '\n\n';
96457             }, '');
96458             return {
96459               title: _t.html(helpkey + '.title'),
96460               content: marked_1(text.trim()) // use keyboard key styling for shortcuts
96461               .replace(/<code>/g, '<kbd>').replace(/<\/code>/g, '<\/kbd>')
96462             };
96463           });
96464           var helpPane = uiPane('help', context).key(_t('help.key')).label(_t.html('help.title')).description(_t.html('help.title')).iconName('iD-icon-help');
96465
96466           helpPane.renderContent = function (content) {
96467             function clickHelp(d, i) {
96468               var rtl = _mainLocalizer.textDirection() === 'rtl';
96469               content.property('scrollTop', 0);
96470               helpPane.selection().select('.pane-heading h2').html(d.title);
96471               body.html(d.content);
96472               body.selectAll('a').attr('target', '_blank');
96473               menuItems.classed('selected', function (m) {
96474                 return m.title === d.title;
96475               });
96476               nav.html('');
96477
96478               if (rtl) {
96479                 nav.call(drawNext).call(drawPrevious);
96480               } else {
96481                 nav.call(drawPrevious).call(drawNext);
96482               }
96483
96484               function drawNext(selection) {
96485                 if (i < docs.length - 1) {
96486                   var nextLink = selection.append('a').attr('href', '#').attr('class', 'next').on('click', function (d3_event) {
96487                     d3_event.preventDefault();
96488                     clickHelp(docs[i + 1], i + 1);
96489                   });
96490                   nextLink.append('span').html(docs[i + 1].title).call(svgIcon(rtl ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
96491                 }
96492               }
96493
96494               function drawPrevious(selection) {
96495                 if (i > 0) {
96496                   var prevLink = selection.append('a').attr('href', '#').attr('class', 'previous').on('click', function (d3_event) {
96497                     d3_event.preventDefault();
96498                     clickHelp(docs[i - 1], i - 1);
96499                   });
96500                   prevLink.call(svgIcon(rtl ? '#iD-icon-forward' : '#iD-icon-backward', 'inline')).append('span').html(docs[i - 1].title);
96501                 }
96502               }
96503             }
96504
96505             function clickWalkthrough(d3_event) {
96506               d3_event.preventDefault();
96507               if (context.inIntro()) return;
96508               context.container().call(uiIntro(context));
96509               context.ui().togglePanes();
96510             }
96511
96512             function clickShortcuts(d3_event) {
96513               d3_event.preventDefault();
96514               context.container().call(context.ui().shortcuts, true);
96515             }
96516
96517             var toc = content.append('ul').attr('class', 'toc');
96518             var menuItems = toc.selectAll('li').data(docs).enter().append('li').append('a').attr('href', '#').html(function (d) {
96519               return d.title;
96520             }).on('click', function (d3_event, d) {
96521               d3_event.preventDefault();
96522               clickHelp(d, docs.indexOf(d));
96523             });
96524             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);
96525             shortcuts.append('div').html(_t.html('shortcuts.title'));
96526             var walkthrough = toc.append('li').attr('class', 'walkthrough').append('a').attr('href', '#').on('click', clickWalkthrough);
96527             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
96528             walkthrough.append('div').html(_t.html('splash.walkthrough'));
96529             var helpContent = content.append('div').attr('class', 'left-content');
96530             var body = helpContent.append('div').attr('class', 'body');
96531             var nav = helpContent.append('div').attr('class', 'nav');
96532             clickHelp(docs[0], 0);
96533           };
96534
96535           return helpPane;
96536         }
96537
96538         function uiSectionValidationIssues(id, severity, context) {
96539           var _issues = [];
96540           var section = uiSection(id, context).label(function () {
96541             if (!_issues) return '';
96542             var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
96543             return _t('inspector.title_count', {
96544               title: _t.html('issues.' + severity + 's.list_title'),
96545               count: issueCountText
96546             });
96547           }).disclosureContent(renderDisclosureContent).shouldDisplay(function () {
96548             return _issues && _issues.length;
96549           });
96550
96551           function getOptions() {
96552             return {
96553               what: corePreferences('validate-what') || 'edited',
96554               where: corePreferences('validate-where') || 'all'
96555             };
96556           } // get and cache the issues to display, unordered
96557
96558
96559           function reloadIssues() {
96560             _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
96561           }
96562
96563           function renderDisclosureContent(selection) {
96564             var center = context.map().center();
96565             var graph = context.graph(); // sort issues by distance away from the center of the map
96566
96567             var issues = _issues.map(function withDistance(issue) {
96568               var extent = issue.extent(graph);
96569               var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
96570               return Object.assign(issue, {
96571                 dist: dist
96572               });
96573             }).sort(function byDistance(a, b) {
96574               return a.dist - b.dist;
96575             }); // cut off at 1000
96576
96577
96578             issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection);
96579
96580             selection.call(drawIssuesList, issues);
96581           }
96582
96583           function drawIssuesList(selection, issues) {
96584             var list = selection.selectAll('.issues-list').data([0]);
96585             list = list.enter().append('ul').attr('class', 'layer-list issues-list ' + severity + 's-list').merge(list);
96586             var items = list.selectAll('li').data(issues, function (d) {
96587               return d.id;
96588             }); // Exit
96589
96590             items.exit().remove(); // Enter
96591
96592             var itemsEnter = items.enter().append('li').attr('class', function (d) {
96593               return 'issue severity-' + d.severity;
96594             }).on('click', function (d3_event, d) {
96595               context.validator().focusIssue(d);
96596             }).on('mouseover', function (d3_event, d) {
96597               utilHighlightEntities(d.entityIds, true, context);
96598             }).on('mouseout', function (d3_event, d) {
96599               utilHighlightEntities(d.entityIds, false, context);
96600             });
96601             var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
96602             var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
96603             textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
96604               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
96605               select(this).call(svgIcon(iconName));
96606             });
96607             textEnter.append('span').attr('class', 'issue-message');
96608             /*
96609             labelsEnter
96610                 .append('span')
96611                 .attr('class', 'issue-autofix')
96612                 .each(function(d) {
96613                     if (!d.autoFix) return;
96614                      d3_select(this)
96615                         .append('button')
96616                         .attr('title', t('issues.fix_one.title'))
96617                         .datum(d.autoFix)  // set button datum to the autofix
96618                         .attr('class', 'autofix action')
96619                         .on('click', function(d3_event, d) {
96620                             d3_event.preventDefault();
96621                             d3_event.stopPropagation();
96622                              var issuesEntityIDs = d.issue.entityIds;
96623                             utilHighlightEntities(issuesEntityIDs.concat(d.entityIds), false, context);
96624                              context.perform.apply(context, d.autoArgs);
96625                             context.validator().validate();
96626                         })
96627                         .call(svgIcon('#iD-icon-wrench'));
96628                 });
96629             */
96630             // Update
96631
96632             items = items.merge(itemsEnter).order();
96633             items.selectAll('.issue-message').html(function (d) {
96634               return d.message(context);
96635             });
96636             /*
96637             // autofix
96638             var canAutoFix = issues.filter(function(issue) { return issue.autoFix; });
96639              var autoFixAll = selection.selectAll('.autofix-all')
96640                 .data(canAutoFix.length ? [0] : []);
96641              // exit
96642             autoFixAll.exit()
96643                 .remove();
96644              // enter
96645             var autoFixAllEnter = autoFixAll.enter()
96646                 .insert('div', '.issues-list')
96647                 .attr('class', 'autofix-all');
96648              var linkEnter = autoFixAllEnter
96649                 .append('a')
96650                 .attr('class', 'autofix-all-link')
96651                 .attr('href', '#');
96652              linkEnter
96653                 .append('span')
96654                 .attr('class', 'autofix-all-link-text')
96655                 .html(t.html('issues.fix_all.title'));
96656              linkEnter
96657                 .append('span')
96658                 .attr('class', 'autofix-all-link-icon')
96659                 .call(svgIcon('#iD-icon-wrench'));
96660              if (severity === 'warning') {
96661                 renderIgnoredIssuesReset(selection);
96662             }
96663              // update
96664             autoFixAll = autoFixAll
96665                 .merge(autoFixAllEnter);
96666              autoFixAll.selectAll('.autofix-all-link')
96667                 .on('click', function() {
96668                     context.pauseChangeDispatch();
96669                     context.perform(actionNoop());
96670                     canAutoFix.forEach(function(issue) {
96671                         var args = issue.autoFix.autoArgs.slice();  // copy
96672                         if (typeof args[args.length - 1] !== 'function') {
96673                             args.pop();
96674                         }
96675                         args.push(t('issues.fix_all.annotation'));
96676                         context.replace.apply(context, args);
96677                     });
96678                     context.resumeChangeDispatch();
96679                     context.validator().validate();
96680                 });
96681             */
96682           }
96683
96684           context.validator().on('validated.uiSectionValidationIssues' + id, function () {
96685             window.requestIdleCallback(function () {
96686               reloadIssues();
96687               section.reRender();
96688             });
96689           });
96690           context.map().on('move.uiSectionValidationIssues' + id, debounce(function () {
96691             window.requestIdleCallback(function () {
96692               if (getOptions().where === 'visible') {
96693                 // must refetch issues if they are viewport-dependent
96694                 reloadIssues();
96695               } // always reload list to re-sort-by-distance
96696
96697
96698               section.reRender();
96699             });
96700           }, 1000));
96701           return section;
96702         }
96703
96704         function uiSectionValidationOptions(context) {
96705           var section = uiSection('issues-options', context).content(renderContent);
96706
96707           function renderContent(selection) {
96708             var container = selection.selectAll('.issues-options-container').data([0]);
96709             container = container.enter().append('div').attr('class', 'issues-options-container').merge(container);
96710             var data = [{
96711               key: 'what',
96712               values: ['edited', 'all']
96713             }, {
96714               key: 'where',
96715               values: ['visible', 'all']
96716             }];
96717             var options = container.selectAll('.issues-option').data(data, function (d) {
96718               return d.key;
96719             });
96720             var optionsEnter = options.enter().append('div').attr('class', function (d) {
96721               return 'issues-option issues-option-' + d.key;
96722             });
96723             optionsEnter.append('div').attr('class', 'issues-option-title').html(function (d) {
96724               return _t.html('issues.options.' + d.key + '.title');
96725             });
96726             var valuesEnter = optionsEnter.selectAll('label').data(function (d) {
96727               return d.values.map(function (val) {
96728                 return {
96729                   value: val,
96730                   key: d.key
96731                 };
96732               });
96733             }).enter().append('label');
96734             valuesEnter.append('input').attr('type', 'radio').attr('name', function (d) {
96735               return 'issues-option-' + d.key;
96736             }).attr('value', function (d) {
96737               return d.value;
96738             }).property('checked', function (d) {
96739               return getOptions()[d.key] === d.value;
96740             }).on('change', function (d3_event, d) {
96741               updateOptionValue(d3_event, d.key, d.value);
96742             });
96743             valuesEnter.append('span').html(function (d) {
96744               return _t.html('issues.options.' + d.key + '.' + d.value);
96745             });
96746           }
96747
96748           function getOptions() {
96749             return {
96750               what: corePreferences('validate-what') || 'edited',
96751               // 'all', 'edited'
96752               where: corePreferences('validate-where') || 'all' // 'all', 'visible'
96753
96754             };
96755           }
96756
96757           function updateOptionValue(d3_event, d, val) {
96758             if (!val && d3_event && d3_event.target) {
96759               val = d3_event.target.value;
96760             }
96761
96762             corePreferences('validate-' + d, val);
96763             context.validator().validate();
96764           }
96765
96766           return section;
96767         }
96768
96769         function uiSectionValidationRules(context) {
96770           var MINSQUARE = 0;
96771           var MAXSQUARE = 20;
96772           var DEFAULTSQUARE = 5; // see also unsquare_way.js
96773
96774           var section = uiSection('issues-rules', context).disclosureContent(renderDisclosureContent).label(_t.html('issues.rules.title'));
96775
96776           var _ruleKeys = context.validator().getRuleKeys().filter(function (key) {
96777             return key !== 'maprules';
96778           }).sort(function (key1, key2) {
96779             // alphabetize by localized title
96780             return _t('issues.' + key1 + '.title') < _t('issues.' + key2 + '.title') ? -1 : 1;
96781           });
96782
96783           function renderDisclosureContent(selection) {
96784             var container = selection.selectAll('.issues-rulelist-container').data([0]);
96785             var containerEnter = container.enter().append('div').attr('class', 'issues-rulelist-container');
96786             containerEnter.append('ul').attr('class', 'layer-list issue-rules-list');
96787             var ruleLinks = containerEnter.append('div').attr('class', 'issue-rules-links section-footer');
96788             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
96789               d3_event.preventDefault();
96790               context.validator().disableRules(_ruleKeys);
96791             });
96792             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
96793               d3_event.preventDefault();
96794               context.validator().disableRules([]);
96795             }); // Update
96796
96797             container = container.merge(containerEnter);
96798             container.selectAll('.issue-rules-list').call(drawListItems, _ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
96799           }
96800
96801           function drawListItems(selection, data, type, name, change, active) {
96802             var items = selection.selectAll('li').data(data); // Exit
96803
96804             items.exit().remove(); // Enter
96805
96806             var enter = items.enter().append('li');
96807
96808             if (name === 'rule') {
96809               enter.call(uiTooltip().title(function (d) {
96810                 return _t.html('issues.' + d + '.tip');
96811               }).placement('top'));
96812             }
96813
96814             var label = enter.append('label');
96815             label.append('input').attr('type', type).attr('name', name).on('change', change);
96816             label.append('span').html(function (d) {
96817               var params = {};
96818
96819               if (d === 'unsquare_way') {
96820                 params.val = '<span class="square-degrees"></span>';
96821               }
96822
96823               return _t.html('issues.' + d + '.title', params);
96824             }); // Update
96825
96826             items = items.merge(enter);
96827             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false); // user-configurable square threshold
96828
96829             var degStr = corePreferences('validate-square-degrees');
96830
96831             if (degStr === null) {
96832               degStr = DEFAULTSQUARE.toString();
96833             }
96834
96835             var span = items.selectAll('.square-degrees');
96836             var input = span.selectAll('.square-degrees-input').data([0]); // enter / update
96837
96838             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) {
96839               d3_event.preventDefault();
96840               d3_event.stopPropagation();
96841               this.select();
96842             }).on('keyup', function (d3_event) {
96843               if (d3_event.keyCode === 13) {
96844                 // ↩ Return
96845                 this.blur();
96846                 this.select();
96847               }
96848             }).on('blur', changeSquare).merge(input).property('value', degStr);
96849           }
96850
96851           function changeSquare() {
96852             var input = select(this);
96853             var degStr = utilGetSetValue(input).trim();
96854             var degNum = parseFloat(degStr, 10);
96855
96856             if (!isFinite(degNum)) {
96857               degNum = DEFAULTSQUARE;
96858             } else if (degNum > MAXSQUARE) {
96859               degNum = MAXSQUARE;
96860             } else if (degNum < MINSQUARE) {
96861               degNum = MINSQUARE;
96862             }
96863
96864             degNum = Math.round(degNum * 10) / 10; // round to 1 decimal
96865
96866             degStr = degNum.toString();
96867             input.property('value', degStr);
96868             corePreferences('validate-square-degrees', degStr);
96869             context.validator().reloadUnsquareIssues();
96870           }
96871
96872           function isRuleEnabled(d) {
96873             return context.validator().isRuleEnabled(d);
96874           }
96875
96876           function toggleRule(d3_event, d) {
96877             context.validator().toggleRule(d);
96878           }
96879
96880           context.validator().on('validated.uiSectionValidationRules', function () {
96881             window.requestIdleCallback(section.reRender);
96882           });
96883           return section;
96884         }
96885
96886         function uiSectionValidationStatus(context) {
96887           var section = uiSection('issues-status', context).content(renderContent).shouldDisplay(function () {
96888             var issues = context.validator().getIssues(getOptions());
96889             return issues.length === 0;
96890           });
96891
96892           function getOptions() {
96893             return {
96894               what: corePreferences('validate-what') || 'edited',
96895               where: corePreferences('validate-where') || 'all'
96896             };
96897           }
96898
96899           function renderContent(selection) {
96900             var box = selection.selectAll('.box').data([0]);
96901             var boxEnter = box.enter().append('div').attr('class', 'box');
96902             boxEnter.append('div').call(svgIcon('#iD-icon-apply', 'pre-text'));
96903             var noIssuesMessage = boxEnter.append('span');
96904             noIssuesMessage.append('strong').attr('class', 'message');
96905             noIssuesMessage.append('br');
96906             noIssuesMessage.append('span').attr('class', 'details');
96907             renderIgnoredIssuesReset(selection);
96908             setNoIssuesText(selection);
96909           }
96910
96911           function renderIgnoredIssuesReset(selection) {
96912             var ignoredIssues = context.validator().getIssues({
96913               what: 'all',
96914               where: 'all',
96915               includeDisabledRules: true,
96916               includeIgnored: 'only'
96917             });
96918             var resetIgnored = selection.selectAll('.reset-ignored').data(ignoredIssues.length ? [0] : []); // exit
96919
96920             resetIgnored.exit().remove(); // enter
96921
96922             var resetIgnoredEnter = resetIgnored.enter().append('div').attr('class', 'reset-ignored section-footer');
96923             resetIgnoredEnter.append('a').attr('href', '#'); // update
96924
96925             resetIgnored = resetIgnored.merge(resetIgnoredEnter);
96926             resetIgnored.select('a').html(_t('inspector.title_count', {
96927               title: _t.html('issues.reset_ignored'),
96928               count: ignoredIssues.length
96929             }));
96930             resetIgnored.on('click', function (d3_event) {
96931               d3_event.preventDefault();
96932               context.validator().resetIgnoredIssues();
96933             });
96934           }
96935
96936           function setNoIssuesText(selection) {
96937             var opts = getOptions();
96938
96939             function checkForHiddenIssues(cases) {
96940               for (var type in cases) {
96941                 var hiddenOpts = cases[type];
96942                 var hiddenIssues = context.validator().getIssues(hiddenOpts);
96943
96944                 if (hiddenIssues.length) {
96945                   selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.' + type, {
96946                     count: hiddenIssues.length.toString()
96947                   }));
96948                   return;
96949                 }
96950               }
96951
96952               selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.none'));
96953             }
96954
96955             var messageType;
96956
96957             if (opts.what === 'edited' && opts.where === 'visible') {
96958               messageType = 'edits_in_view';
96959               checkForHiddenIssues({
96960                 elsewhere: {
96961                   what: 'edited',
96962                   where: 'all'
96963                 },
96964                 everything_else: {
96965                   what: 'all',
96966                   where: 'visible'
96967                 },
96968                 disabled_rules: {
96969                   what: 'edited',
96970                   where: 'visible',
96971                   includeDisabledRules: 'only'
96972                 },
96973                 everything_else_elsewhere: {
96974                   what: 'all',
96975                   where: 'all'
96976                 },
96977                 disabled_rules_elsewhere: {
96978                   what: 'edited',
96979                   where: 'all',
96980                   includeDisabledRules: 'only'
96981                 },
96982                 ignored_issues: {
96983                   what: 'edited',
96984                   where: 'visible',
96985                   includeIgnored: 'only'
96986                 },
96987                 ignored_issues_elsewhere: {
96988                   what: 'edited',
96989                   where: 'all',
96990                   includeIgnored: 'only'
96991                 }
96992               });
96993             } else if (opts.what === 'edited' && opts.where === 'all') {
96994               messageType = 'edits';
96995               checkForHiddenIssues({
96996                 everything_else: {
96997                   what: 'all',
96998                   where: 'all'
96999                 },
97000                 disabled_rules: {
97001                   what: 'edited',
97002                   where: 'all',
97003                   includeDisabledRules: 'only'
97004                 },
97005                 ignored_issues: {
97006                   what: 'edited',
97007                   where: 'all',
97008                   includeIgnored: 'only'
97009                 }
97010               });
97011             } else if (opts.what === 'all' && opts.where === 'visible') {
97012               messageType = 'everything_in_view';
97013               checkForHiddenIssues({
97014                 elsewhere: {
97015                   what: 'all',
97016                   where: 'all'
97017                 },
97018                 disabled_rules: {
97019                   what: 'all',
97020                   where: 'visible',
97021                   includeDisabledRules: 'only'
97022                 },
97023                 disabled_rules_elsewhere: {
97024                   what: 'all',
97025                   where: 'all',
97026                   includeDisabledRules: 'only'
97027                 },
97028                 ignored_issues: {
97029                   what: 'all',
97030                   where: 'visible',
97031                   includeIgnored: 'only'
97032                 },
97033                 ignored_issues_elsewhere: {
97034                   what: 'all',
97035                   where: 'all',
97036                   includeIgnored: 'only'
97037                 }
97038               });
97039             } else if (opts.what === 'all' && opts.where === 'all') {
97040               messageType = 'everything';
97041               checkForHiddenIssues({
97042                 disabled_rules: {
97043                   what: 'all',
97044                   where: 'all',
97045                   includeDisabledRules: 'only'
97046                 },
97047                 ignored_issues: {
97048                   what: 'all',
97049                   where: 'all',
97050                   includeIgnored: 'only'
97051                 }
97052               });
97053             }
97054
97055             if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
97056               messageType = 'no_edits';
97057             }
97058
97059             selection.select('.box .message').html(_t.html('issues.no_issues.message.' + messageType));
97060           }
97061
97062           context.validator().on('validated.uiSectionValidationStatus', function () {
97063             window.requestIdleCallback(section.reRender);
97064           });
97065           context.map().on('move.uiSectionValidationStatus', debounce(function () {
97066             window.requestIdleCallback(section.reRender);
97067           }, 1000));
97068           return section;
97069         }
97070
97071         function uiPaneIssues(context) {
97072           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)]);
97073           return issuesPane;
97074         }
97075
97076         function uiSettingsCustomData(context) {
97077           var dispatch$1 = dispatch('change');
97078
97079           function render(selection) {
97080             var dataLayer = context.layers().layer('data'); // keep separate copies of original and current settings
97081
97082             var _origSettings = {
97083               fileList: dataLayer && dataLayer.fileList() || null,
97084               url: corePreferences('settings-custom-data-url')
97085             };
97086             var _currSettings = {
97087               fileList: dataLayer && dataLayer.fileList() || null,
97088               url: corePreferences('settings-custom-data-url')
97089             }; // var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
97090
97091             var modal = uiConfirm(selection).okButton();
97092             modal.classed('settings-modal settings-custom-data', true);
97093             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_data.header'));
97094             var textSection = modal.select('.modal-section.message-text');
97095             textSection.append('pre').attr('class', 'instructions-file').html(_t.html('settings.custom_data.file.instructions'));
97096             textSection.append('input').attr('class', 'field-file').attr('type', 'file').property('files', _currSettings.fileList) // works for all except IE11
97097             .on('change', function (d3_event) {
97098               var files = d3_event.target.files;
97099
97100               if (files && files.length) {
97101                 _currSettings.url = '';
97102                 textSection.select('.field-url').property('value', '');
97103                 _currSettings.fileList = files;
97104               } else {
97105                 _currSettings.fileList = null;
97106               }
97107             });
97108             textSection.append('h4').html(_t.html('settings.custom_data.or'));
97109             textSection.append('pre').attr('class', 'instructions-url').html(_t.html('settings.custom_data.url.instructions'));
97110             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
97111
97112             var buttonSection = modal.select('.modal-section.buttons');
97113             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
97114             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
97115             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
97116
97117             function isSaveDisabled() {
97118               return null;
97119             } // restore the original url
97120
97121
97122             function clickCancel() {
97123               textSection.select('.field-url').property('value', _origSettings.url);
97124               corePreferences('settings-custom-data-url', _origSettings.url);
97125               this.blur();
97126               modal.close();
97127             } // accept the current url
97128
97129
97130             function clickSave() {
97131               _currSettings.url = textSection.select('.field-url').property('value').trim(); // one or the other but not both
97132
97133               if (_currSettings.url) {
97134                 _currSettings.fileList = null;
97135               }
97136
97137               if (_currSettings.fileList) {
97138                 _currSettings.url = '';
97139               }
97140
97141               corePreferences('settings-custom-data-url', _currSettings.url);
97142               this.blur();
97143               modal.close();
97144               dispatch$1.call('change', this, _currSettings);
97145             }
97146           }
97147
97148           return utilRebind(render, dispatch$1, 'on');
97149         }
97150
97151         function uiSectionDataLayers(context) {
97152           var settingsCustomData = uiSettingsCustomData(context).on('change', customChanged);
97153           var layers = context.layers();
97154           var section = uiSection('data-layers', context).label(_t.html('map_data.data_layers')).disclosureContent(renderDisclosureContent);
97155
97156           function renderDisclosureContent(selection) {
97157             var container = selection.selectAll('.data-layer-container').data([0]);
97158             container.enter().append('div').attr('class', 'data-layer-container').merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems) // Beta - Detroit mapping challenge
97159             .call(drawPanelItems);
97160           }
97161
97162           function showsLayer(which) {
97163             var layer = layers.layer(which);
97164
97165             if (layer) {
97166               return layer.enabled();
97167             }
97168
97169             return false;
97170           }
97171
97172           function setLayer(which, enabled) {
97173             // Don't allow layer changes while drawing - #6584
97174             var mode = context.mode();
97175             if (mode && /^draw/.test(mode.id)) return;
97176             var layer = layers.layer(which);
97177
97178             if (layer) {
97179               layer.enabled(enabled);
97180
97181               if (!enabled && (which === 'osm' || which === 'notes')) {
97182                 context.enter(modeBrowse(context));
97183               }
97184             }
97185           }
97186
97187           function toggleLayer(which) {
97188             setLayer(which, !showsLayer(which));
97189           }
97190
97191           function drawOsmItems(selection) {
97192             var osmKeys = ['osm', 'notes'];
97193             var osmLayers = layers.all().filter(function (obj) {
97194               return osmKeys.indexOf(obj.id) !== -1;
97195             });
97196             var ul = selection.selectAll('.layer-list-osm').data([0]);
97197             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-osm').merge(ul);
97198             var li = ul.selectAll('.list-item').data(osmLayers);
97199             li.exit().remove();
97200             var liEnter = li.enter().append('li').attr('class', function (d) {
97201               return 'list-item list-item-' + d.id;
97202             });
97203             var labelEnter = liEnter.append('label').each(function (d) {
97204               if (d.id === 'osm') {
97205                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).keys([uiCmd('⌥' + _t('area_fill.wireframe.key'))]).placement('bottom'));
97206               } else {
97207                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
97208               }
97209             });
97210             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97211               toggleLayer(d.id);
97212             });
97213             labelEnter.append('span').html(function (d) {
97214               return _t.html('map_data.layers.' + d.id + '.title');
97215             }); // Update
97216
97217             li.merge(liEnter).classed('active', function (d) {
97218               return d.layer.enabled();
97219             }).selectAll('input').property('checked', function (d) {
97220               return d.layer.enabled();
97221             });
97222           }
97223
97224           function drawQAItems(selection) {
97225             var qaKeys = ['keepRight', 'improveOSM', 'osmose'];
97226             var qaLayers = layers.all().filter(function (obj) {
97227               return qaKeys.indexOf(obj.id) !== -1;
97228             });
97229             var ul = selection.selectAll('.layer-list-qa').data([0]);
97230             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-qa').merge(ul);
97231             var li = ul.selectAll('.list-item').data(qaLayers);
97232             li.exit().remove();
97233             var liEnter = li.enter().append('li').attr('class', function (d) {
97234               return 'list-item list-item-' + d.id;
97235             });
97236             var labelEnter = liEnter.append('label').each(function (d) {
97237               select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
97238             });
97239             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97240               toggleLayer(d.id);
97241             });
97242             labelEnter.append('span').html(function (d) {
97243               return _t.html('map_data.layers.' + d.id + '.title');
97244             }); // Update
97245
97246             li.merge(liEnter).classed('active', function (d) {
97247               return d.layer.enabled();
97248             }).selectAll('input').property('checked', function (d) {
97249               return d.layer.enabled();
97250             });
97251           } // Beta feature - sample vector layers to support Detroit Mapping Challenge
97252           // https://github.com/osmus/detroit-mapping-challenge
97253
97254
97255           function drawVectorItems(selection) {
97256             var dataLayer = layers.layer('data');
97257             var vtData = [{
97258               name: 'Detroit Neighborhoods/Parks',
97259               src: 'neighborhoods-parks',
97260               tooltip: 'Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.',
97261               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'
97262             }, {
97263               name: 'Detroit Composite POIs',
97264               src: 'composite-poi',
97265               tooltip: 'Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.',
97266               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'
97267             }, {
97268               name: 'Detroit All-The-Places POIs',
97269               src: 'alltheplaces-poi',
97270               tooltip: 'Public domain business location data created by web scrapers.',
97271               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'
97272             }]; // Only show this if the map is around Detroit..
97273
97274             var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
97275             var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
97276             var container = selection.selectAll('.vectortile-container').data(showVectorItems ? [0] : []);
97277             container.exit().remove();
97278             var containerEnter = container.enter().append('div').attr('class', 'vectortile-container');
97279             containerEnter.append('h4').attr('class', 'vectortile-header').html('Detroit Vector Tiles (Beta)');
97280             containerEnter.append('ul').attr('class', 'layer-list layer-list-vectortile');
97281             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');
97282             container = container.merge(containerEnter);
97283             var ul = container.selectAll('.layer-list-vectortile');
97284             var li = ul.selectAll('.list-item').data(vtData);
97285             li.exit().remove();
97286             var liEnter = li.enter().append('li').attr('class', function (d) {
97287               return 'list-item list-item-' + d.src;
97288             });
97289             var labelEnter = liEnter.append('label').each(function (d) {
97290               select(this).call(uiTooltip().title(d.tooltip).placement('top'));
97291             });
97292             labelEnter.append('input').attr('type', 'radio').attr('name', 'vectortile').on('change', selectVTLayer);
97293             labelEnter.append('span').html(function (d) {
97294               return d.name;
97295             }); // Update
97296
97297             li.merge(liEnter).classed('active', isVTLayerSelected).selectAll('input').property('checked', isVTLayerSelected);
97298
97299             function isVTLayerSelected(d) {
97300               return dataLayer && dataLayer.template() === d.template;
97301             }
97302
97303             function selectVTLayer(d3_event, d) {
97304               corePreferences('settings-custom-data-url', d.template);
97305
97306               if (dataLayer) {
97307                 dataLayer.template(d.template, d.src);
97308                 dataLayer.enabled(true);
97309               }
97310             }
97311           }
97312
97313           function drawCustomDataItems(selection) {
97314             var dataLayer = layers.layer('data');
97315             var hasData = dataLayer && dataLayer.hasData();
97316             var showsData = hasData && dataLayer.enabled();
97317             var ul = selection.selectAll('.layer-list-data').data(dataLayer ? [0] : []); // Exit
97318
97319             ul.exit().remove(); // Enter
97320
97321             var ulEnter = ul.enter().append('ul').attr('class', 'layer-list layer-list-data');
97322             var liEnter = ulEnter.append('li').attr('class', 'list-item-data');
97323             var labelEnter = liEnter.append('label').call(uiTooltip().title(_t.html('map_data.layers.custom.tooltip')).placement('top'));
97324             labelEnter.append('input').attr('type', 'checkbox').on('change', function () {
97325               toggleLayer('data');
97326             });
97327             labelEnter.append('span').html(_t.html('map_data.layers.custom.title'));
97328             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', editCustom).call(svgIcon('#iD-icon-more'));
97329             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) {
97330               if (select(this).classed('disabled')) return;
97331               d3_event.preventDefault();
97332               d3_event.stopPropagation();
97333               dataLayer.fitZoom();
97334             }).call(svgIcon('#iD-icon-framed-dot', 'monochrome')); // Update
97335
97336             ul = ul.merge(ulEnter);
97337             ul.selectAll('.list-item-data').classed('active', showsData).selectAll('label').classed('deemphasize', !hasData).selectAll('input').property('disabled', !hasData).property('checked', showsData);
97338             ul.selectAll('button.zoom-to-data').classed('disabled', !hasData);
97339           }
97340
97341           function editCustom(d3_event) {
97342             d3_event.preventDefault();
97343             context.container().call(settingsCustomData);
97344           }
97345
97346           function customChanged(d) {
97347             var dataLayer = layers.layer('data');
97348
97349             if (d && d.url) {
97350               dataLayer.url(d.url);
97351             } else if (d && d.fileList) {
97352               dataLayer.fileList(d.fileList);
97353             }
97354           }
97355
97356           function drawPanelItems(selection) {
97357             var panelsListEnter = selection.selectAll('.md-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list md-extras-list');
97358             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'));
97359             historyPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97360               d3_event.preventDefault();
97361               context.ui().info.toggle('history');
97362             });
97363             historyPanelLabelEnter.append('span').html(_t.html('map_data.history_panel.title'));
97364             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'));
97365             measurementPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97366               d3_event.preventDefault();
97367               context.ui().info.toggle('measurement');
97368             });
97369             measurementPanelLabelEnter.append('span').html(_t.html('map_data.measurement_panel.title'));
97370           }
97371
97372           context.layers().on('change.uiSectionDataLayers', section.reRender);
97373           context.map().on('move.uiSectionDataLayers', debounce(function () {
97374             // Detroit layers may have moved in or out of view
97375             window.requestIdleCallback(section.reRender);
97376           }, 1000));
97377           return section;
97378         }
97379
97380         function uiSectionMapFeatures(context) {
97381           var _features = context.features().keys();
97382
97383           var section = uiSection('map-features', context).label(_t.html('map_data.map_features')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97384
97385           function renderDisclosureContent(selection) {
97386             var container = selection.selectAll('.layer-feature-list-container').data([0]);
97387             var containerEnter = container.enter().append('div').attr('class', 'layer-feature-list-container');
97388             containerEnter.append('ul').attr('class', 'layer-list layer-feature-list');
97389             var footer = containerEnter.append('div').attr('class', 'feature-list-links section-footer');
97390             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
97391               d3_event.preventDefault();
97392               context.features().disableAll();
97393             });
97394             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
97395               d3_event.preventDefault();
97396               context.features().enableAll();
97397             }); // Update
97398
97399             container = container.merge(containerEnter);
97400             container.selectAll('.layer-feature-list').call(drawListItems, _features, 'checkbox', 'feature', clickFeature, showsFeature);
97401           }
97402
97403           function drawListItems(selection, data, type, name, change, active) {
97404             var items = selection.selectAll('li').data(data); // Exit
97405
97406             items.exit().remove(); // Enter
97407
97408             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
97409               var tip = _t.html(name + '.' + d + '.tooltip');
97410
97411               if (autoHiddenFeature(d)) {
97412                 var msg = showsLayer('osm') ? _t.html('map_data.autohidden') : _t.html('map_data.osmhidden');
97413                 tip += '<div>' + msg + '</div>';
97414               }
97415
97416               return tip;
97417             }).placement('top'));
97418             var label = enter.append('label');
97419             label.append('input').attr('type', type).attr('name', name).on('change', change);
97420             label.append('span').html(function (d) {
97421               return _t.html(name + '.' + d + '.description');
97422             }); // Update
97423
97424             items = items.merge(enter);
97425             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', autoHiddenFeature);
97426           }
97427
97428           function autoHiddenFeature(d) {
97429             return context.features().autoHidden(d);
97430           }
97431
97432           function showsFeature(d) {
97433             return context.features().enabled(d);
97434           }
97435
97436           function clickFeature(d3_event, d) {
97437             context.features().toggle(d);
97438           }
97439
97440           function showsLayer(id) {
97441             var layer = context.layers().layer(id);
97442             return layer && layer.enabled();
97443           } // add listeners
97444
97445
97446           context.features().on('change.map_features', section.reRender);
97447           return section;
97448         }
97449
97450         function uiSectionMapStyleOptions(context) {
97451           var section = uiSection('fill-area', context).label(_t.html('map_data.style_options')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97452
97453           function renderDisclosureContent(selection) {
97454             var container = selection.selectAll('.layer-fill-list').data([0]);
97455             container.enter().append('ul').attr('class', 'layer-list layer-fill-list').merge(container).call(drawListItems, context.map().areaFillOptions, 'radio', 'area_fill', setFill, isActiveFill);
97456             var container2 = selection.selectAll('.layer-visual-diff-list').data([0]);
97457             container2.enter().append('ul').attr('class', 'layer-list layer-visual-diff-list').merge(container2).call(drawListItems, ['highlight_edits'], 'checkbox', 'visual_diff', toggleHighlightEdited, function () {
97458               return context.surface().classed('highlight-edited');
97459             });
97460           }
97461
97462           function drawListItems(selection, data, type, name, change, active) {
97463             var items = selection.selectAll('li').data(data); // Exit
97464
97465             items.exit().remove(); // Enter
97466
97467             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
97468               return _t.html(name + '.' + d + '.tooltip');
97469             }).keys(function (d) {
97470               var key = d === 'wireframe' ? _t('area_fill.wireframe.key') : null;
97471               if (d === 'highlight_edits') key = _t('map_data.highlight_edits.key');
97472               return key ? [key] : null;
97473             }).placement('top'));
97474             var label = enter.append('label');
97475             label.append('input').attr('type', type).attr('name', name).on('change', change);
97476             label.append('span').html(function (d) {
97477               return _t.html(name + '.' + d + '.description');
97478             }); // Update
97479
97480             items = items.merge(enter);
97481             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false);
97482           }
97483
97484           function isActiveFill(d) {
97485             return context.map().activeAreaFill() === d;
97486           }
97487
97488           function toggleHighlightEdited(d3_event) {
97489             d3_event.preventDefault();
97490             context.map().toggleHighlightEdited();
97491           }
97492
97493           function setFill(d3_event, d) {
97494             context.map().activeAreaFill(d);
97495           }
97496
97497           context.map().on('changeHighlighting.ui_style, changeAreaFill.ui_style', section.reRender);
97498           return section;
97499         }
97500
97501         function uiSectionPhotoOverlays(context) {
97502           var layers = context.layers();
97503           var section = uiSection('photo-overlays', context).label(_t.html('photo_overlays.title')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97504
97505           function renderDisclosureContent(selection) {
97506             var container = selection.selectAll('.photo-overlay-container').data([0]);
97507             container.enter().append('div').attr('class', 'photo-overlay-container').merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter);
97508           }
97509
97510           function drawPhotoItems(selection) {
97511             var photoKeys = context.photos().overlayLayerIDs();
97512             var photoLayers = layers.all().filter(function (obj) {
97513               return photoKeys.indexOf(obj.id) !== -1;
97514             });
97515             var data = photoLayers.filter(function (obj) {
97516               return obj.layer.supported();
97517             });
97518
97519             function layerSupported(d) {
97520               return d.layer && d.layer.supported();
97521             }
97522
97523             function layerEnabled(d) {
97524               return layerSupported(d) && d.layer.enabled();
97525             }
97526
97527             var ul = selection.selectAll('.layer-list-photos').data([0]);
97528             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photos').merge(ul);
97529             var li = ul.selectAll('.list-item-photos').data(data);
97530             li.exit().remove();
97531             var liEnter = li.enter().append('li').attr('class', function (d) {
97532               var classes = 'list-item-photos list-item-' + d.id;
97533
97534               if (d.id === 'mapillary-signs' || d.id === 'mapillary-map-features') {
97535                 classes += ' indented';
97536               }
97537
97538               return classes;
97539             });
97540             var labelEnter = liEnter.append('label').each(function (d) {
97541               var titleID;
97542               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';
97543               select(this).call(uiTooltip().title(_t.html(titleID)).placement('top'));
97544             });
97545             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97546               toggleLayer(d.id);
97547             });
97548             labelEnter.append('span').html(function (d) {
97549               var id = d.id;
97550               if (id === 'mapillary-signs') id = 'photo_overlays.traffic_signs';
97551               return _t.html(id.replace(/-/g, '_') + '.title');
97552             }); // Update
97553
97554             li.merge(liEnter).classed('active', layerEnabled).selectAll('input').property('checked', layerEnabled);
97555           }
97556
97557           function drawPhotoTypeItems(selection) {
97558             var data = context.photos().allPhotoTypes();
97559
97560             function typeEnabled(d) {
97561               return context.photos().showsPhotoType(d);
97562             }
97563
97564             var ul = selection.selectAll('.layer-list-photo-types').data([0]);
97565             ul.exit().remove();
97566             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photo-types').merge(ul);
97567             var li = ul.selectAll('.list-item-photo-types').data(context.photos().shouldFilterByPhotoType() ? data : []);
97568             li.exit().remove();
97569             var liEnter = li.enter().append('li').attr('class', function (d) {
97570               return 'list-item-photo-types list-item-' + d;
97571             });
97572             var labelEnter = liEnter.append('label').each(function (d) {
97573               select(this).call(uiTooltip().title(_t.html('photo_overlays.photo_type.' + d + '.tooltip')).placement('top'));
97574             });
97575             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97576               context.photos().togglePhotoType(d);
97577             });
97578             labelEnter.append('span').html(function (d) {
97579               return _t.html('photo_overlays.photo_type.' + d + '.title');
97580             }); // Update
97581
97582             li.merge(liEnter).classed('active', typeEnabled).selectAll('input').property('checked', typeEnabled);
97583           }
97584
97585           function drawDateFilter(selection) {
97586             var data = context.photos().dateFilters();
97587
97588             function filterEnabled(d) {
97589               return context.photos().dateFilterValue(d);
97590             }
97591
97592             var ul = selection.selectAll('.layer-list-date-filter').data([0]);
97593             ul.exit().remove();
97594             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-date-filter').merge(ul);
97595             var li = ul.selectAll('.list-item-date-filter').data(context.photos().shouldFilterByDate() ? data : []);
97596             li.exit().remove();
97597             var liEnter = li.enter().append('li').attr('class', 'list-item-date-filter');
97598             var labelEnter = liEnter.append('label').each(function (d) {
97599               select(this).call(uiTooltip().title(_t.html('photo_overlays.date_filter.' + d + '.tooltip')).placement('top'));
97600             });
97601             labelEnter.append('span').html(function (d) {
97602               return _t.html('photo_overlays.date_filter.' + d + '.title');
97603             });
97604             labelEnter.append('input').attr('type', 'date').attr('class', 'list-item-input').attr('placeholder', _t('units.year_month_day')).call(utilNoAuto).each(function (d) {
97605               utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97606             }).on('change', function (d3_event, d) {
97607               var value = utilGetSetValue(select(this)).trim();
97608               context.photos().setDateFilter(d, value, true); // reload the displayed dates
97609
97610               li.selectAll('input').each(function (d) {
97611                 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97612               });
97613             });
97614             li = li.merge(liEnter).classed('active', filterEnabled);
97615           }
97616
97617           function drawUsernameFilter(selection) {
97618             function filterEnabled() {
97619               return context.photos().usernames();
97620             }
97621
97622             var ul = selection.selectAll('.layer-list-username-filter').data([0]);
97623             ul.exit().remove();
97624             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-username-filter').merge(ul);
97625             var li = ul.selectAll('.list-item-username-filter').data(context.photos().shouldFilterByUsername() ? ['username-filter'] : []);
97626             li.exit().remove();
97627             var liEnter = li.enter().append('li').attr('class', 'list-item-username-filter');
97628             var labelEnter = liEnter.append('label').each(function () {
97629               select(this).call(uiTooltip().title(_t.html('photo_overlays.username_filter.tooltip')).placement('top'));
97630             });
97631             labelEnter.append('span').html(_t.html('photo_overlays.username_filter.title'));
97632             labelEnter.append('input').attr('type', 'text').attr('class', 'list-item-input').call(utilNoAuto).property('value', usernameValue).on('change', function () {
97633               var value = select(this).property('value');
97634               context.photos().setUsernameFilter(value, true);
97635               select(this).property('value', usernameValue);
97636             });
97637             li.merge(liEnter).classed('active', filterEnabled);
97638
97639             function usernameValue() {
97640               var usernames = context.photos().usernames();
97641               if (usernames) return usernames.join('; ');
97642               return usernames;
97643             }
97644           }
97645
97646           function toggleLayer(which) {
97647             setLayer(which, !showsLayer(which));
97648           }
97649
97650           function showsLayer(which) {
97651             var layer = layers.layer(which);
97652
97653             if (layer) {
97654               return layer.enabled();
97655             }
97656
97657             return false;
97658           }
97659
97660           function setLayer(which, enabled) {
97661             var layer = layers.layer(which);
97662
97663             if (layer) {
97664               layer.enabled(enabled);
97665             }
97666           }
97667
97668           context.layers().on('change.uiSectionPhotoOverlays', section.reRender);
97669           context.photos().on('change.uiSectionPhotoOverlays', section.reRender);
97670           return section;
97671         }
97672
97673         function uiPaneMapData(context) {
97674           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)]);
97675           return mapDataPane;
97676         }
97677
97678         function uiSectionPrivacy(context) {
97679           var section = uiSection('preferences-third-party', context).label(_t.html('preferences.privacy.title')).disclosureContent(renderDisclosureContent);
97680
97681           var _showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
97682
97683           function renderDisclosureContent(selection) {
97684             // enter
97685             var privacyOptionsListEnter = selection.selectAll('.privacy-options-list').data([0]).enter().append('ul').attr('class', 'layer-list privacy-options-list');
97686             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'));
97687             thirdPartyIconsEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97688               d3_event.preventDefault();
97689               _showThirdPartyIcons = _showThirdPartyIcons === 'true' ? 'false' : 'true';
97690               corePreferences('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
97691               update();
97692             });
97693             thirdPartyIconsEnter.append('span').html(_t.html('preferences.privacy.third_party_icons.description')); // Privacy Policy link
97694
97695             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'));
97696             update();
97697
97698             function update() {
97699               selection.selectAll('.privacy-third-party-icons-item').classed('active', _showThirdPartyIcons === 'true').select('input').property('checked', _showThirdPartyIcons === 'true');
97700             }
97701           }
97702
97703           return section;
97704         }
97705
97706         function uiPanePreferences(context) {
97707           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)]);
97708           return preferencesPane;
97709         }
97710
97711         function uiInit(context) {
97712           var _initCounter = 0;
97713           var _needWidth = {};
97714
97715           var _lastPointerType;
97716
97717           function render(container) {
97718             container.on('click.ui', function (d3_event) {
97719               // we're only concerned with the primary mouse button
97720               if (d3_event.button !== 0) return;
97721               if (!d3_event.composedPath) return; // some targets have default click events we don't want to override
97722
97723               var isOkayTarget = d3_event.composedPath().some(function (node) {
97724                 // we only care about element nodes
97725                 return node.nodeType === 1 && ( // clicking <input> focuses it and/or changes a value
97726                 node.nodeName === 'INPUT' || // clicking <label> affects its <input> by default
97727                 node.nodeName === 'LABEL' || // clicking <a> opens a hyperlink by default
97728                 node.nodeName === 'A');
97729               });
97730               if (isOkayTarget) return; // disable double-tap-to-zoom on touchscreens
97731
97732               d3_event.preventDefault();
97733             });
97734             var detected = utilDetect(); // only WebKit supports gesture events
97735
97736             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
97737             // but we only need to do this on desktop Safari anyway. – #7694
97738             !detected.isMobileWebKit) {
97739               // On iOS we disable pinch-to-zoom of the UI via the `touch-action`
97740               // CSS property, but on desktop Safari we need to manually cancel the
97741               // default gesture events.
97742               container.on('gesturestart.ui gesturechange.ui gestureend.ui', function (d3_event) {
97743                 // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari
97744                 d3_event.preventDefault();
97745               });
97746             }
97747
97748             if ('PointerEvent' in window) {
97749               select(window).on('pointerdown.ui pointerup.ui', function (d3_event) {
97750                 var pointerType = d3_event.pointerType || 'mouse';
97751
97752                 if (_lastPointerType !== pointerType) {
97753                   _lastPointerType = pointerType;
97754                   container.attr('pointer', pointerType);
97755                 }
97756               }, true);
97757             } else {
97758               _lastPointerType = 'mouse';
97759               container.attr('pointer', 'mouse');
97760             }
97761
97762             container.attr('lang', _mainLocalizer.localeCode()).attr('dir', _mainLocalizer.textDirection()); // setup fullscreen keybindings (no button shown at this time)
97763
97764             container.call(uiFullScreen(context));
97765             var map = context.map();
97766             map.redrawEnable(false); // don't draw until we've set zoom/lat/long
97767
97768             map.on('hitMinZoom.ui', function () {
97769               ui.flash.iconName('#iD-icon-no').label(_t.html('cannot_zoom'))();
97770             });
97771             container.append('svg').attr('id', 'ideditor-defs').call(ui.svgDefs);
97772             container.append('div').attr('class', 'sidebar').call(ui.sidebar);
97773             var content = container.append('div').attr('class', 'main-content active'); // Top toolbar
97774
97775             content.append('div').attr('class', 'top-toolbar-wrap').append('div').attr('class', 'top-toolbar fillD').call(uiTopToolbar(context));
97776             content.append('div').attr('class', 'main-map').attr('dir', 'ltr').call(map);
97777             var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
97778             // pressing, even if it's not targeted. This conflicts with long-pressing
97779             // to show the edit menu. We add a selectable offscreen element as the first
97780             // child to trick Safari into not showing the selection UI.
97781
97782             overMap.append('div').attr('class', 'select-trap').text('t');
97783             overMap.append('div').attr('class', 'spinner').call(uiSpinner(context));
97784             overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Map controls
97785
97786             var controls = overMap.append('div').attr('class', 'map-controls');
97787             controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
97788             controls.append('div').attr('class', 'map-control zoom-to-selection-control').call(uiZoomToSelection(context));
97789             controls.append('div').attr('class', 'map-control geolocate-control').call(uiGeolocate(context)); // Add panes
97790             // This should happen after map is initialized, as some require surface()
97791
97792             var panes = overMap.append('div').attr('class', 'map-panes');
97793             var uiPanes = [uiPaneBackground(context), uiPaneMapData(context), uiPaneIssues(context), uiPanePreferences(context), uiPaneHelp(context)];
97794             uiPanes.forEach(function (pane) {
97795               controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
97796               panes.call(pane.renderPane);
97797             });
97798             ui.info = uiInfo(context); // Add absolutely-positioned elements that sit on top of the map
97799             // This should happen after the map is ready (center/zoom)
97800
97801             overMap.call(uiMapInMap(context)).call(ui.info).call(uiNotice(context));
97802             overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left,  'ar'=right
97803             .classed('hide', true).call(ui.photoviewer); // Add footer
97804
97805             var about = content.append('div').attr('class', 'map-footer');
97806             about.append('div').attr('class', 'api-status').call(uiStatus(context));
97807             var footer = about.append('div').attr('class', 'map-footer-bar fillD');
97808             footer.append('div').attr('class', 'flash-wrap footer-hide');
97809             var footerWrap = footer.append('div').attr('class', 'main-footer-wrap footer-show');
97810             footerWrap.append('div').attr('class', 'scale-block').call(uiScale(context));
97811             var aboutList = footerWrap.append('div').attr('class', 'info-block').append('ul').attr('class', 'map-footer-list');
97812             aboutList.append('li').attr('class', 'user-list').call(uiContributors(context));
97813             var apiConnections = context.apiConnections();
97814
97815             if (apiConnections && apiConnections.length > 1) {
97816               aboutList.append('li').attr('class', 'source-switch').call(uiSourceSwitch(context).keys(apiConnections));
97817             }
97818
97819             aboutList.append('li').attr('class', 'issues-info').call(uiIssuesInfo(context));
97820             aboutList.append('li').attr('class', 'feature-warning').call(uiFeatureInfo(context));
97821             var issueLinks = aboutList.append('li');
97822             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'));
97823             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'));
97824             aboutList.append('li').attr('class', 'version').call(uiVersion(context));
97825
97826             if (!context.embed()) {
97827               aboutList.call(uiAccount(context));
97828             } // Setup map dimensions and move map to initial center/zoom.
97829             // This should happen after .main-content and toolbars exist.
97830
97831
97832             ui.onResize();
97833             map.redrawEnable(true);
97834             ui.hash = behaviorHash(context);
97835             ui.hash();
97836
97837             if (!ui.hash.hadHash) {
97838               map.centerZoom([0, 0], 2);
97839             } // Bind events
97840
97841
97842             window.onbeforeunload = function () {
97843               return context.save();
97844             };
97845
97846             window.onunload = function () {
97847               context.history().unlock();
97848             };
97849
97850             select(window).on('resize.editor', function () {
97851               ui.onResize();
97852             });
97853             var panPixels = 80;
97854             context.keybinding().on('⌫', function (d3_event) {
97855               d3_event.preventDefault();
97856             }).on([_t('sidebar.key'), '`', '²', '@'], ui.sidebar.toggle) // #5663, #6864 - common QWERTY, AZERTY
97857             .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) {
97858               if (d3_event) {
97859                 d3_event.stopImmediatePropagation();
97860                 d3_event.preventDefault();
97861               }
97862
97863               var previousBackground = context.background().findSource(corePreferences('background-last-used-toggle'));
97864
97865               if (previousBackground) {
97866                 var currentBackground = context.background().baseLayerSource();
97867                 corePreferences('background-last-used-toggle', currentBackground.id);
97868                 corePreferences('background-last-used', previousBackground.id);
97869                 context.background().baseLayerSource(previousBackground);
97870               }
97871             }).on(_t('area_fill.wireframe.key'), function toggleWireframe(d3_event) {
97872               d3_event.preventDefault();
97873               d3_event.stopPropagation();
97874               context.map().toggleWireframe();
97875             }).on(uiCmd('⌥' + _t('area_fill.wireframe.key')), function toggleOsmData(d3_event) {
97876               d3_event.preventDefault();
97877               d3_event.stopPropagation(); // Don't allow layer changes while drawing - #6584
97878
97879               var mode = context.mode();
97880               if (mode && /^draw/.test(mode.id)) return;
97881               var layer = context.layers().layer('osm');
97882
97883               if (layer) {
97884                 layer.enabled(!layer.enabled());
97885
97886                 if (!layer.enabled()) {
97887                   context.enter(modeBrowse(context));
97888                 }
97889               }
97890             }).on(_t('map_data.highlight_edits.key'), function toggleHighlightEdited(d3_event) {
97891               d3_event.preventDefault();
97892               context.map().toggleHighlightEdited();
97893             });
97894             context.on('enter.editor', function (entered) {
97895               container.classed('mode-' + entered.id, true);
97896             }).on('exit.editor', function (exited) {
97897               container.classed('mode-' + exited.id, false);
97898             });
97899             context.enter(modeBrowse(context));
97900
97901             if (!_initCounter++) {
97902               if (!ui.hash.startWalkthrough) {
97903                 context.container().call(uiSplash(context)).call(uiRestore(context));
97904               }
97905
97906               context.container().call(ui.shortcuts);
97907             }
97908
97909             var osm = context.connection();
97910             var auth = uiLoading(context).message(_t.html('loading_auth')).blocking(true);
97911
97912             if (osm && auth) {
97913               osm.on('authLoading.ui', function () {
97914                 context.container().call(auth);
97915               }).on('authDone.ui', function () {
97916                 auth.close();
97917               });
97918             }
97919
97920             _initCounter++;
97921
97922             if (ui.hash.startWalkthrough) {
97923               ui.hash.startWalkthrough = false;
97924               context.container().call(uiIntro(context));
97925             }
97926
97927             function pan(d) {
97928               return function (d3_event) {
97929                 if (d3_event.shiftKey) return;
97930                 if (context.container().select('.combobox').size()) return;
97931                 d3_event.preventDefault();
97932                 context.map().pan(d, 100);
97933               };
97934             }
97935           }
97936
97937           var ui = {};
97938
97939           var _loadPromise; // renders the iD interface into the container node
97940
97941
97942           ui.ensureLoaded = function () {
97943             if (_loadPromise) return _loadPromise;
97944             return _loadPromise = Promise.all([// must have strings and presets before loading the UI
97945             _mainLocalizer.ensureLoaded(), _mainPresetIndex.ensureLoaded()]).then(function () {
97946               if (!context.container().empty()) render(context.container());
97947             })["catch"](function (err) {
97948               return console.error(err);
97949             }); // eslint-disable-line
97950           }; // `ui.restart()` will destroy and rebuild the entire iD interface,
97951           // for example to switch the locale while iD is running.
97952
97953
97954           ui.restart = function () {
97955             context.keybinding().clear();
97956             _loadPromise = null;
97957             context.container().selectAll('*').remove();
97958             ui.ensureLoaded();
97959           };
97960
97961           ui.lastPointerType = function () {
97962             return _lastPointerType;
97963           };
97964
97965           ui.svgDefs = svgDefs(context);
97966           ui.flash = uiFlash(context);
97967           ui.sidebar = uiSidebar(context);
97968           ui.photoviewer = uiPhotoviewer(context);
97969           ui.shortcuts = uiShortcuts(context);
97970
97971           ui.onResize = function (withPan) {
97972             var map = context.map(); // Recalc dimensions of map and sidebar.. (`true` = force recalc)
97973             // This will call `getBoundingClientRect` and trigger reflow,
97974             //  but the values will be cached for later use.
97975
97976             var mapDimensions = utilGetDimensions(context.container().select('.main-content'), true);
97977             utilGetDimensions(context.container().select('.sidebar'), true);
97978
97979             if (withPan !== undefined) {
97980               map.redrawEnable(false);
97981               map.pan(withPan);
97982               map.redrawEnable(true);
97983             }
97984
97985             map.dimensions(mapDimensions);
97986             ui.photoviewer.onMapResize(); // check if header or footer have overflowed
97987
97988             ui.checkOverflow('.top-toolbar');
97989             ui.checkOverflow('.map-footer-bar'); // Use outdated code so it works on Explorer
97990
97991             var resizeWindowEvent = document.createEvent('Event');
97992             resizeWindowEvent.initEvent('resizeWindow', true, true);
97993             document.dispatchEvent(resizeWindowEvent);
97994           }; // Call checkOverflow when resizing or whenever the contents change.
97995
97996
97997           ui.checkOverflow = function (selector, reset) {
97998             if (reset) {
97999               delete _needWidth[selector];
98000             }
98001
98002             var element = select(selector);
98003             var scrollWidth = element.property('scrollWidth');
98004             var clientWidth = element.property('clientWidth');
98005             var needed = _needWidth[selector] || scrollWidth;
98006
98007             if (scrollWidth > clientWidth) {
98008               // overflow happening
98009               element.classed('narrow', true);
98010
98011               if (!_needWidth[selector]) {
98012                 _needWidth[selector] = scrollWidth;
98013               }
98014             } else if (scrollWidth >= needed) {
98015               element.classed('narrow', false);
98016             }
98017           };
98018
98019           ui.togglePanes = function (showPane) {
98020             var hidePanes = context.container().selectAll('.map-pane.shown');
98021             var side = _mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left';
98022             hidePanes.classed('shown', false).classed('hide', true);
98023             context.container().selectAll('.map-pane-control button').classed('active', false);
98024
98025             if (showPane) {
98026               hidePanes.classed('shown', false).classed('hide', true).style(side, '-500px');
98027               context.container().selectAll('.' + showPane.attr('pane') + '-control button').classed('active', true);
98028               showPane.classed('shown', true).classed('hide', false);
98029
98030               if (hidePanes.empty()) {
98031                 showPane.style(side, '-500px').transition().duration(200).style(side, '0px');
98032               } else {
98033                 showPane.style(side, '0px');
98034               }
98035             } else {
98036               hidePanes.classed('shown', true).classed('hide', false).style(side, '0px').transition().duration(200).style(side, '-500px').on('end', function () {
98037                 select(this).classed('shown', false).classed('hide', true);
98038               });
98039             }
98040           };
98041
98042           var _editMenu = uiEditMenu(context);
98043
98044           ui.editMenu = function () {
98045             return _editMenu;
98046           };
98047
98048           ui.showEditMenu = function (anchorPoint, triggerType, operations) {
98049             // remove any displayed menu
98050             ui.closeEditMenu();
98051             if (!operations && context.mode().operations) operations = context.mode().operations();
98052             if (!operations || !operations.length) return; // disable menu if in wide selection, for example
98053
98054             if (!context.map().editableDataEnabled()) return;
98055             var surfaceNode = context.surface().node();
98056
98057             if (surfaceNode.focus) {
98058               // FF doesn't support it
98059               // focus the surface or else clicking off the menu may not trigger modeBrowse
98060               surfaceNode.focus();
98061             }
98062
98063             operations.forEach(function (operation) {
98064               if (operation.point) operation.point(anchorPoint);
98065             });
98066
98067             _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations); // render the menu
98068
98069
98070             context.map().supersurface.call(_editMenu);
98071           };
98072
98073           ui.closeEditMenu = function () {
98074             // remove any existing menu no matter how it was added
98075             context.map().supersurface.select('.edit-menu').remove();
98076           };
98077
98078           var _saveLoading = select(null);
98079
98080           context.uploader().on('saveStarted.ui', function () {
98081             _saveLoading = uiLoading(context).message(_t.html('save.uploading')).blocking(true);
98082             context.container().call(_saveLoading); // block input during upload
98083           }).on('saveEnded.ui', function () {
98084             _saveLoading.close();
98085
98086             _saveLoading = select(null);
98087           });
98088           return ui;
98089         }
98090
98091         function coreContext() {
98092           var _this = this;
98093
98094           var dispatch$1 = dispatch('enter', 'exit', 'change');
98095           var context = utilRebind({}, dispatch$1, 'on');
98096
98097           var _deferred = new Set();
98098
98099           context.version = '2.19.2';
98100           context.privacyVersion = '20200407'; // iD will alter the hash so cache the parameters intended to setup the session
98101
98102           context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
98103           context.isFirstSession = !corePreferences('sawSplash') && !corePreferences('sawPrivacyVersion');
98104           /* Changeset */
98105           // An osmChangeset object. Not loaded until needed.
98106
98107           context.changeset = null;
98108           var _defaultChangesetComment = context.initialHashParams.comment;
98109           var _defaultChangesetSource = context.initialHashParams.source;
98110           var _defaultChangesetHashtags = context.initialHashParams.hashtags;
98111
98112           context.defaultChangesetComment = function (val) {
98113             if (!arguments.length) return _defaultChangesetComment;
98114             _defaultChangesetComment = val;
98115             return context;
98116           };
98117
98118           context.defaultChangesetSource = function (val) {
98119             if (!arguments.length) return _defaultChangesetSource;
98120             _defaultChangesetSource = val;
98121             return context;
98122           };
98123
98124           context.defaultChangesetHashtags = function (val) {
98125             if (!arguments.length) return _defaultChangesetHashtags;
98126             _defaultChangesetHashtags = val;
98127             return context;
98128           };
98129           /* Document title */
98130
98131           /* (typically shown as the label for the browser window/tab) */
98132           // If true, iD will update the title based on what the user is doing
98133
98134
98135           var _setsDocumentTitle = true;
98136
98137           context.setsDocumentTitle = function (val) {
98138             if (!arguments.length) return _setsDocumentTitle;
98139             _setsDocumentTitle = val;
98140             return context;
98141           }; // The part of the title that is always the same
98142
98143
98144           var _documentTitleBase = document.title;
98145
98146           context.documentTitleBase = function (val) {
98147             if (!arguments.length) return _documentTitleBase;
98148             _documentTitleBase = val;
98149             return context;
98150           };
98151           /* User interface and keybinding */
98152
98153
98154           var _ui;
98155
98156           context.ui = function () {
98157             return _ui;
98158           };
98159
98160           context.lastPointerType = function () {
98161             return _ui.lastPointerType();
98162           };
98163
98164           var _keybinding = utilKeybinding('context');
98165
98166           context.keybinding = function () {
98167             return _keybinding;
98168           };
98169
98170           select(document).call(_keybinding);
98171           /* Straight accessors. Avoid using these if you can. */
98172           // Instantiate the connection here because it doesn't require passing in
98173           // `context` and it's needed for pre-init calls like `preauth`
98174
98175           var _connection = services.osm;
98176
98177           var _history;
98178
98179           var _validator;
98180
98181           var _uploader;
98182
98183           context.connection = function () {
98184             return _connection;
98185           };
98186
98187           context.history = function () {
98188             return _history;
98189           };
98190
98191           context.validator = function () {
98192             return _validator;
98193           };
98194
98195           context.uploader = function () {
98196             return _uploader;
98197           };
98198           /* Connection */
98199
98200
98201           context.preauth = function (options) {
98202             if (_connection) {
98203               _connection["switch"](options);
98204             }
98205
98206             return context;
98207           };
98208           /* connection options for source switcher (optional) */
98209
98210
98211           var _apiConnections;
98212
98213           context.apiConnections = function (val) {
98214             if (!arguments.length) return _apiConnections;
98215             _apiConnections = val;
98216             return context;
98217           }; // A string or array or locale codes to prefer over the browser's settings
98218
98219
98220           context.locale = function (locale) {
98221             if (!arguments.length) return _mainLocalizer.localeCode();
98222             _mainLocalizer.preferredLocaleCodes(locale);
98223             return context;
98224           };
98225
98226           function afterLoad(cid, callback) {
98227             return function (err, result) {
98228               if (err) {
98229                 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
98230                 if (err.status === 400 || err.status === 401 || err.status === 403) {
98231                   if (_connection) {
98232                     _connection.logout();
98233                   }
98234                 }
98235
98236                 if (typeof callback === 'function') {
98237                   callback(err);
98238                 }
98239
98240                 return;
98241               } else if (_connection && _connection.getConnectionId() !== cid) {
98242                 if (typeof callback === 'function') {
98243                   callback({
98244                     message: 'Connection Switched',
98245                     status: -1
98246                   });
98247                 }
98248
98249                 return;
98250               } else {
98251                 _history.merge(result.data, result.extent);
98252
98253                 if (typeof callback === 'function') {
98254                   callback(err, result);
98255                 }
98256
98257                 return;
98258               }
98259             };
98260           }
98261
98262           context.loadTiles = function (projection, callback) {
98263             var handle = window.requestIdleCallback(function () {
98264               _deferred["delete"](handle);
98265
98266               if (_connection && context.editableDataEnabled()) {
98267                 var cid = _connection.getConnectionId();
98268
98269                 _connection.loadTiles(projection, afterLoad(cid, callback));
98270               }
98271             });
98272
98273             _deferred.add(handle);
98274           };
98275
98276           context.loadTileAtLoc = function (loc, callback) {
98277             var handle = window.requestIdleCallback(function () {
98278               _deferred["delete"](handle);
98279
98280               if (_connection && context.editableDataEnabled()) {
98281                 var cid = _connection.getConnectionId();
98282
98283                 _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
98284               }
98285             });
98286
98287             _deferred.add(handle);
98288           };
98289
98290           context.loadEntity = function (entityID, callback) {
98291             if (_connection) {
98292               var cid = _connection.getConnectionId();
98293
98294               _connection.loadEntity(entityID, afterLoad(cid, callback));
98295             }
98296           };
98297
98298           context.zoomToEntity = function (entityID, zoomTo) {
98299             if (zoomTo !== false) {
98300               context.loadEntity(entityID, function (err, result) {
98301                 if (err) return;
98302                 var entity = result.data.find(function (e) {
98303                   return e.id === entityID;
98304                 });
98305
98306                 if (entity) {
98307                   _map.zoomTo(entity);
98308                 }
98309               });
98310             }
98311
98312             _map.on('drawn.zoomToEntity', function () {
98313               if (!context.hasEntity(entityID)) return;
98314
98315               _map.on('drawn.zoomToEntity', null);
98316
98317               context.on('enter.zoomToEntity', null);
98318               context.enter(modeSelect(context, [entityID]));
98319             });
98320
98321             context.on('enter.zoomToEntity', function () {
98322               if (_mode.id !== 'browse') {
98323                 _map.on('drawn.zoomToEntity', null);
98324
98325                 context.on('enter.zoomToEntity', null);
98326               }
98327             });
98328           };
98329
98330           var _minEditableZoom = 16;
98331
98332           context.minEditableZoom = function (val) {
98333             if (!arguments.length) return _minEditableZoom;
98334             _minEditableZoom = val;
98335
98336             if (_connection) {
98337               _connection.tileZoom(val);
98338             }
98339
98340             return context;
98341           }; // String length limits in Unicode characters, not JavaScript UTF-16 code units
98342
98343
98344           context.maxCharsForTagKey = function () {
98345             return 255;
98346           };
98347
98348           context.maxCharsForTagValue = function () {
98349             return 255;
98350           };
98351
98352           context.maxCharsForRelationRole = function () {
98353             return 255;
98354           };
98355
98356           function cleanOsmString(val, maxChars) {
98357             // be lenient with input
98358             if (val === undefined || val === null) {
98359               val = '';
98360             } else {
98361               val = val.toString();
98362             } // remove whitespace
98363
98364
98365             val = val.trim(); // use the canonical form of the string
98366
98367             if (val.normalize) val = val.normalize('NFC'); // trim to the number of allowed characters
98368
98369             return utilUnicodeCharsTruncated(val, maxChars);
98370           }
98371
98372           context.cleanTagKey = function (val) {
98373             return cleanOsmString(val, context.maxCharsForTagKey());
98374           };
98375
98376           context.cleanTagValue = function (val) {
98377             return cleanOsmString(val, context.maxCharsForTagValue());
98378           };
98379
98380           context.cleanRelationRole = function (val) {
98381             return cleanOsmString(val, context.maxCharsForRelationRole());
98382           };
98383           /* History */
98384
98385
98386           var _inIntro = false;
98387
98388           context.inIntro = function (val) {
98389             if (!arguments.length) return _inIntro;
98390             _inIntro = val;
98391             return context;
98392           }; // Immediately save the user's history to localstorage, if possible
98393           // This is called someteimes, but also on the `window.onbeforeunload` handler
98394
98395
98396           context.save = function () {
98397             // no history save, no message onbeforeunload
98398             if (_inIntro || context.container().select('.modal').size()) return;
98399             var canSave;
98400
98401             if (_mode && _mode.id === 'save') {
98402               canSave = false; // Attempt to prevent user from creating duplicate changes - see #5200
98403
98404               if (services.osm && services.osm.isChangesetInflight()) {
98405                 _history.clearSaved();
98406
98407                 return;
98408               }
98409             } else {
98410               canSave = context.selectedIDs().every(function (id) {
98411                 var entity = context.hasEntity(id);
98412                 return entity && !entity.isDegenerate();
98413               });
98414             }
98415
98416             if (canSave) {
98417               _history.save();
98418             }
98419
98420             if (_history.hasChanges()) {
98421               return _t('save.unsaved_changes');
98422             }
98423           }; // Debounce save, since it's a synchronous localStorage write,
98424           // and history changes can happen frequently (e.g. when dragging).
98425
98426
98427           context.debouncedSave = debounce(context.save, 350);
98428
98429           function withDebouncedSave(fn) {
98430             return function () {
98431               var result = fn.apply(_history, arguments);
98432               context.debouncedSave();
98433               return result;
98434             };
98435           }
98436           /* Graph */
98437
98438
98439           context.hasEntity = function (id) {
98440             return _history.graph().hasEntity(id);
98441           };
98442
98443           context.entity = function (id) {
98444             return _history.graph().entity(id);
98445           };
98446           /* Modes */
98447
98448
98449           var _mode;
98450
98451           context.mode = function () {
98452             return _mode;
98453           };
98454
98455           context.enter = function (newMode) {
98456             if (_mode) {
98457               _mode.exit();
98458
98459               dispatch$1.call('exit', _this, _mode);
98460             }
98461
98462             _mode = newMode;
98463
98464             _mode.enter();
98465
98466             dispatch$1.call('enter', _this, _mode);
98467           };
98468
98469           context.selectedIDs = function () {
98470             return _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
98471           };
98472
98473           context.activeID = function () {
98474             return _mode && _mode.activeID && _mode.activeID();
98475           };
98476
98477           var _selectedNoteID;
98478
98479           context.selectedNoteID = function (noteID) {
98480             if (!arguments.length) return _selectedNoteID;
98481             _selectedNoteID = noteID;
98482             return context;
98483           }; // NOTE: Don't change the name of this until UI v3 is merged
98484
98485
98486           var _selectedErrorID;
98487
98488           context.selectedErrorID = function (errorID) {
98489             if (!arguments.length) return _selectedErrorID;
98490             _selectedErrorID = errorID;
98491             return context;
98492           };
98493           /* Behaviors */
98494
98495
98496           context.install = function (behavior) {
98497             return context.surface().call(behavior);
98498           };
98499
98500           context.uninstall = function (behavior) {
98501             return context.surface().call(behavior.off);
98502           };
98503           /* Copy/Paste */
98504
98505
98506           var _copyGraph;
98507
98508           context.copyGraph = function () {
98509             return _copyGraph;
98510           };
98511
98512           var _copyIDs = [];
98513
98514           context.copyIDs = function (val) {
98515             if (!arguments.length) return _copyIDs;
98516             _copyIDs = val;
98517             _copyGraph = _history.graph();
98518             return context;
98519           };
98520
98521           var _copyLonLat;
98522
98523           context.copyLonLat = function (val) {
98524             if (!arguments.length) return _copyLonLat;
98525             _copyLonLat = val;
98526             return context;
98527           };
98528           /* Background */
98529
98530
98531           var _background;
98532
98533           context.background = function () {
98534             return _background;
98535           };
98536           /* Features */
98537
98538
98539           var _features;
98540
98541           context.features = function () {
98542             return _features;
98543           };
98544
98545           context.hasHiddenConnections = function (id) {
98546             var graph = _history.graph();
98547
98548             var entity = graph.entity(id);
98549             return _features.hasHiddenConnections(entity, graph);
98550           };
98551           /* Photos */
98552
98553
98554           var _photos;
98555
98556           context.photos = function () {
98557             return _photos;
98558           };
98559           /* Map */
98560
98561
98562           var _map;
98563
98564           context.map = function () {
98565             return _map;
98566           };
98567
98568           context.layers = function () {
98569             return _map.layers();
98570           };
98571
98572           context.surface = function () {
98573             return _map.surface;
98574           };
98575
98576           context.editableDataEnabled = function () {
98577             return _map.editableDataEnabled();
98578           };
98579
98580           context.surfaceRect = function () {
98581             return _map.surface.node().getBoundingClientRect();
98582           };
98583
98584           context.editable = function () {
98585             // don't allow editing during save
98586             var mode = context.mode();
98587             if (!mode || mode.id === 'save') return false;
98588             return _map.editableDataEnabled();
98589           };
98590           /* Debug */
98591
98592
98593           var _debugFlags = {
98594             tile: false,
98595             // tile boundaries
98596             collision: false,
98597             // label collision bounding boxes
98598             imagery: false,
98599             // imagery bounding polygons
98600             target: false,
98601             // touch targets
98602             downloaded: false // downloaded data from osm
98603
98604           };
98605
98606           context.debugFlags = function () {
98607             return _debugFlags;
98608           };
98609
98610           context.getDebug = function (flag) {
98611             return flag && _debugFlags[flag];
98612           };
98613
98614           context.setDebug = function (flag, val) {
98615             if (arguments.length === 1) val = true;
98616             _debugFlags[flag] = val;
98617             dispatch$1.call('change');
98618             return context;
98619           };
98620           /* Container */
98621
98622
98623           var _container = select(null);
98624
98625           context.container = function (val) {
98626             if (!arguments.length) return _container;
98627             _container = val;
98628
98629             _container.classed('ideditor', true);
98630
98631             return context;
98632           };
98633
98634           context.containerNode = function (val) {
98635             if (!arguments.length) return context.container().node();
98636             context.container(select(val));
98637             return context;
98638           };
98639
98640           var _embed;
98641
98642           context.embed = function (val) {
98643             if (!arguments.length) return _embed;
98644             _embed = val;
98645             return context;
98646           };
98647           /* Assets */
98648
98649
98650           var _assetPath = '';
98651
98652           context.assetPath = function (val) {
98653             if (!arguments.length) return _assetPath;
98654             _assetPath = val;
98655             _mainFileFetcher.assetPath(val);
98656             return context;
98657           };
98658
98659           var _assetMap = {};
98660
98661           context.assetMap = function (val) {
98662             if (!arguments.length) return _assetMap;
98663             _assetMap = val;
98664             _mainFileFetcher.assetMap(val);
98665             return context;
98666           };
98667
98668           context.asset = function (val) {
98669             if (/^http(s)?:\/\//i.test(val)) return val;
98670             var filename = _assetPath + val;
98671             return _assetMap[filename] || filename;
98672           };
98673
98674           context.imagePath = function (val) {
98675             return context.asset("img/".concat(val));
98676           };
98677           /* reset (aka flush) */
98678
98679
98680           context.reset = context.flush = function () {
98681             context.debouncedSave.cancel();
98682             Array.from(_deferred).forEach(function (handle) {
98683               window.cancelIdleCallback(handle);
98684
98685               _deferred["delete"](handle);
98686             });
98687             Object.values(services).forEach(function (service) {
98688               if (service && typeof service.reset === 'function') {
98689                 service.reset(context);
98690               }
98691             });
98692             context.changeset = null;
98693
98694             _validator.reset();
98695
98696             _features.reset();
98697
98698             _history.reset();
98699
98700             _uploader.reset(); // don't leave stale state in the inspector
98701
98702
98703             context.container().select('.inspector-wrap *').remove();
98704             return context;
98705           };
98706           /* Projections */
98707
98708
98709           context.projection = geoRawMercator();
98710           context.curtainProjection = geoRawMercator();
98711           /* Init */
98712
98713           context.init = function () {
98714             instantiateInternal();
98715             initializeDependents();
98716             return context; // Load variables and properties. No property of `context` should be accessed
98717             // until this is complete since load statuses are indeterminate. The order
98718             // of instantiation shouldn't matter.
98719
98720             function instantiateInternal() {
98721               _history = coreHistory(context);
98722               context.graph = _history.graph;
98723               context.pauseChangeDispatch = _history.pauseChangeDispatch;
98724               context.resumeChangeDispatch = _history.resumeChangeDispatch;
98725               context.perform = withDebouncedSave(_history.perform);
98726               context.replace = withDebouncedSave(_history.replace);
98727               context.pop = withDebouncedSave(_history.pop);
98728               context.overwrite = withDebouncedSave(_history.overwrite);
98729               context.undo = withDebouncedSave(_history.undo);
98730               context.redo = withDebouncedSave(_history.redo);
98731               _validator = coreValidator(context);
98732               _uploader = coreUploader(context);
98733               _background = rendererBackground(context);
98734               _features = rendererFeatures(context);
98735               _map = rendererMap(context);
98736               _photos = rendererPhotos(context);
98737               _ui = uiInit(context);
98738             } // Set up objects that might need to access properties of `context`. The order
98739             // might matter if dependents make calls to each other. Be wary of async calls.
98740
98741
98742             function initializeDependents() {
98743               if (context.initialHashParams.presets) {
98744                 _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(',')));
98745               }
98746
98747               if (context.initialHashParams.locale) {
98748                 _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
98749               } // kick off some async work
98750
98751
98752               _mainLocalizer.ensureLoaded();
98753
98754               _background.ensureLoaded();
98755
98756               _mainPresetIndex.ensureLoaded();
98757               Object.values(services).forEach(function (service) {
98758                 if (service && typeof service.init === 'function') {
98759                   service.init();
98760                 }
98761               });
98762
98763               _map.init();
98764
98765               _validator.init();
98766
98767               _features.init();
98768
98769               if (services.maprules && context.initialHashParams.maprules) {
98770                 d3_json(context.initialHashParams.maprules).then(function (mapcss) {
98771                   services.maprules.init();
98772                   mapcss.forEach(function (mapcssSelector) {
98773                     return services.maprules.addRule(mapcssSelector);
98774                   });
98775                 })["catch"](function () {
98776                   /* ignore */
98777                 });
98778               } // if the container isn't available, e.g. when testing, don't load the UI
98779
98780
98781               if (!context.container().empty()) {
98782                 _ui.ensureLoaded().then(function () {
98783                   _photos.init();
98784                 });
98785               }
98786             }
98787           };
98788
98789           return context;
98790         }
98791
98792         // This is only done in testing because of the performance penalty.
98793
98794         var debug = false; // Reexport just what our tests use, see #4379
98795         var d3 = {
98796           dispatch: dispatch,
98797           geoMercator: mercator,
98798           geoProjection: projection,
98799           polygonArea: d3_polygonArea,
98800           polygonCentroid: d3_polygonCentroid,
98801           select: select,
98802           selectAll: selectAll,
98803           timerFlush: timerFlush
98804         };
98805
98806         var iD = /*#__PURE__*/Object.freeze({
98807                 __proto__: null,
98808                 debug: debug,
98809                 d3: d3,
98810                 actionAddEntity: actionAddEntity,
98811                 actionAddMember: actionAddMember,
98812                 actionAddMidpoint: actionAddMidpoint,
98813                 actionAddVertex: actionAddVertex,
98814                 actionChangeMember: actionChangeMember,
98815                 actionChangePreset: actionChangePreset,
98816                 actionChangeTags: actionChangeTags,
98817                 actionCircularize: actionCircularize,
98818                 actionConnect: actionConnect,
98819                 actionCopyEntities: actionCopyEntities,
98820                 actionDeleteMember: actionDeleteMember,
98821                 actionDeleteMultiple: actionDeleteMultiple,
98822                 actionDeleteNode: actionDeleteNode,
98823                 actionDeleteRelation: actionDeleteRelation,
98824                 actionDeleteWay: actionDeleteWay,
98825                 actionDiscardTags: actionDiscardTags,
98826                 actionDisconnect: actionDisconnect,
98827                 actionExtract: actionExtract,
98828                 actionJoin: actionJoin,
98829                 actionMerge: actionMerge,
98830                 actionMergeNodes: actionMergeNodes,
98831                 actionMergePolygon: actionMergePolygon,
98832                 actionMergeRemoteChanges: actionMergeRemoteChanges,
98833                 actionMove: actionMove,
98834                 actionMoveMember: actionMoveMember,
98835                 actionMoveNode: actionMoveNode,
98836                 actionNoop: actionNoop,
98837                 actionOrthogonalize: actionOrthogonalize,
98838                 actionRestrictTurn: actionRestrictTurn,
98839                 actionReverse: actionReverse,
98840                 actionRevert: actionRevert,
98841                 actionRotate: actionRotate,
98842                 actionScale: actionScale,
98843                 actionSplit: actionSplit,
98844                 actionStraightenNodes: actionStraightenNodes,
98845                 actionStraightenWay: actionStraightenWay,
98846                 actionUnrestrictTurn: actionUnrestrictTurn,
98847                 actionReflect: actionReflect,
98848                 actionUpgradeTags: actionUpgradeTags,
98849                 behaviorAddWay: behaviorAddWay,
98850                 behaviorBreathe: behaviorBreathe,
98851                 behaviorDrag: behaviorDrag,
98852                 behaviorDrawWay: behaviorDrawWay,
98853                 behaviorDraw: behaviorDraw,
98854                 behaviorEdit: behaviorEdit,
98855                 behaviorHash: behaviorHash,
98856                 behaviorHover: behaviorHover,
98857                 behaviorLasso: behaviorLasso,
98858                 behaviorOperation: behaviorOperation,
98859                 behaviorPaste: behaviorPaste,
98860                 behaviorSelect: behaviorSelect,
98861                 coreContext: coreContext,
98862                 coreFileFetcher: coreFileFetcher,
98863                 fileFetcher: _mainFileFetcher,
98864                 coreDifference: coreDifference,
98865                 coreGraph: coreGraph,
98866                 coreHistory: coreHistory,
98867                 coreLocalizer: coreLocalizer,
98868                 t: _t,
98869                 localizer: _mainLocalizer,
98870                 prefs: corePreferences,
98871                 coreTree: coreTree,
98872                 coreUploader: coreUploader,
98873                 coreValidator: coreValidator,
98874                 geoExtent: geoExtent,
98875                 geoLatToMeters: geoLatToMeters,
98876                 geoLonToMeters: geoLonToMeters,
98877                 geoMetersToLat: geoMetersToLat,
98878                 geoMetersToLon: geoMetersToLon,
98879                 geoMetersToOffset: geoMetersToOffset,
98880                 geoOffsetToMeters: geoOffsetToMeters,
98881                 geoScaleToZoom: geoScaleToZoom,
98882                 geoSphericalClosestNode: geoSphericalClosestNode,
98883                 geoSphericalDistance: geoSphericalDistance,
98884                 geoZoomToScale: geoZoomToScale,
98885                 geoAngle: geoAngle,
98886                 geoChooseEdge: geoChooseEdge,
98887                 geoEdgeEqual: geoEdgeEqual,
98888                 geoGetSmallestSurroundingRectangle: geoGetSmallestSurroundingRectangle,
98889                 geoHasLineIntersections: geoHasLineIntersections,
98890                 geoHasSelfIntersections: geoHasSelfIntersections,
98891                 geoRotate: geoRotate,
98892                 geoLineIntersection: geoLineIntersection,
98893                 geoPathHasIntersections: geoPathHasIntersections,
98894                 geoPathIntersections: geoPathIntersections,
98895                 geoPathLength: geoPathLength,
98896                 geoPointInPolygon: geoPointInPolygon,
98897                 geoPolygonContainsPolygon: geoPolygonContainsPolygon,
98898                 geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
98899                 geoViewportEdge: geoViewportEdge,
98900                 geoRawMercator: geoRawMercator,
98901                 geoVecAdd: geoVecAdd,
98902                 geoVecAngle: geoVecAngle,
98903                 geoVecCross: geoVecCross,
98904                 geoVecDot: geoVecDot,
98905                 geoVecEqual: geoVecEqual,
98906                 geoVecFloor: geoVecFloor,
98907                 geoVecInterp: geoVecInterp,
98908                 geoVecLength: geoVecLength,
98909                 geoVecLengthSquare: geoVecLengthSquare,
98910                 geoVecNormalize: geoVecNormalize,
98911                 geoVecNormalizedDot: geoVecNormalizedDot,
98912                 geoVecProject: geoVecProject,
98913                 geoVecSubtract: geoVecSubtract,
98914                 geoVecScale: geoVecScale,
98915                 geoOrthoNormalizedDotProduct: geoOrthoNormalizedDotProduct,
98916                 geoOrthoCalcScore: geoOrthoCalcScore,
98917                 geoOrthoMaxOffsetAngle: geoOrthoMaxOffsetAngle,
98918                 geoOrthoCanOrthogonalize: geoOrthoCanOrthogonalize,
98919                 modeAddArea: modeAddArea,
98920                 modeAddLine: modeAddLine,
98921                 modeAddPoint: modeAddPoint,
98922                 modeAddNote: modeAddNote,
98923                 modeBrowse: modeBrowse,
98924                 modeDragNode: modeDragNode,
98925                 modeDragNote: modeDragNote,
98926                 modeDrawArea: modeDrawArea,
98927                 modeDrawLine: modeDrawLine,
98928                 modeMove: modeMove,
98929                 modeRotate: modeRotate,
98930                 modeSave: modeSave,
98931                 modeSelect: modeSelect,
98932                 modeSelectData: modeSelectData,
98933                 modeSelectError: modeSelectError,
98934                 modeSelectNote: modeSelectNote,
98935                 operationCircularize: operationCircularize,
98936                 operationContinue: operationContinue,
98937                 operationCopy: operationCopy,
98938                 operationDelete: operationDelete,
98939                 operationDisconnect: operationDisconnect,
98940                 operationDowngrade: operationDowngrade,
98941                 operationExtract: operationExtract,
98942                 operationMerge: operationMerge,
98943                 operationMove: operationMove,
98944                 operationOrthogonalize: operationOrthogonalize,
98945                 operationPaste: operationPaste,
98946                 operationReflectShort: operationReflectShort,
98947                 operationReflectLong: operationReflectLong,
98948                 operationReverse: operationReverse,
98949                 operationRotate: operationRotate,
98950                 operationSplit: operationSplit,
98951                 operationStraighten: operationStraighten,
98952                 osmChangeset: osmChangeset,
98953                 osmEntity: osmEntity,
98954                 osmNode: osmNode,
98955                 osmNote: osmNote,
98956                 osmRelation: osmRelation,
98957                 osmWay: osmWay,
98958                 QAItem: QAItem,
98959                 osmIntersection: osmIntersection,
98960                 osmTurn: osmTurn,
98961                 osmInferRestriction: osmInferRestriction,
98962                 osmLanes: osmLanes,
98963                 osmOldMultipolygonOuterMemberOfRelation: osmOldMultipolygonOuterMemberOfRelation,
98964                 osmIsOldMultipolygonOuterMember: osmIsOldMultipolygonOuterMember,
98965                 osmOldMultipolygonOuterMember: osmOldMultipolygonOuterMember,
98966                 osmJoinWays: osmJoinWays,
98967                 get osmAreaKeys () { return osmAreaKeys; },
98968                 osmSetAreaKeys: osmSetAreaKeys,
98969                 osmTagSuggestingArea: osmTagSuggestingArea,
98970                 get osmPointTags () { return osmPointTags; },
98971                 osmSetPointTags: osmSetPointTags,
98972                 get osmVertexTags () { return osmVertexTags; },
98973                 osmSetVertexTags: osmSetVertexTags,
98974                 osmNodeGeometriesForTags: osmNodeGeometriesForTags,
98975                 osmOneWayTags: osmOneWayTags,
98976                 osmPavedTags: osmPavedTags,
98977                 osmIsInterestingTag: osmIsInterestingTag,
98978                 osmRoutableHighwayTagValues: osmRoutableHighwayTagValues,
98979                 osmFlowingWaterwayTagValues: osmFlowingWaterwayTagValues,
98980                 osmRailwayTrackTagValues: osmRailwayTrackTagValues,
98981                 presetCategory: presetCategory,
98982                 presetCollection: presetCollection,
98983                 presetField: presetField,
98984                 presetPreset: presetPreset,
98985                 presetManager: _mainPresetIndex,
98986                 presetIndex: presetIndex,
98987                 rendererBackgroundSource: rendererBackgroundSource,
98988                 rendererBackground: rendererBackground,
98989                 rendererFeatures: rendererFeatures,
98990                 rendererMap: rendererMap,
98991                 rendererPhotos: rendererPhotos,
98992                 rendererTileLayer: rendererTileLayer,
98993                 services: services,
98994                 serviceKeepRight: serviceKeepRight,
98995                 serviceImproveOSM: serviceImproveOSM,
98996                 serviceOsmose: serviceOsmose,
98997                 serviceMapillary: serviceMapillary,
98998                 serviceMapRules: serviceMapRules,
98999                 serviceNominatim: serviceNominatim,
99000                 serviceOpenstreetcam: serviceOpenstreetcam,
99001                 serviceOsm: serviceOsm,
99002                 serviceOsmWikibase: serviceOsmWikibase,
99003                 serviceStreetside: serviceStreetside,
99004                 serviceTaginfo: serviceTaginfo,
99005                 serviceVectorTile: serviceVectorTile,
99006                 serviceWikidata: serviceWikidata,
99007                 serviceWikipedia: serviceWikipedia,
99008                 svgAreas: svgAreas,
99009                 svgData: svgData,
99010                 svgDebug: svgDebug,
99011                 svgDefs: svgDefs,
99012                 svgKeepRight: svgKeepRight,
99013                 svgIcon: svgIcon,
99014                 svgGeolocate: svgGeolocate,
99015                 svgLabels: svgLabels,
99016                 svgLayers: svgLayers,
99017                 svgLines: svgLines,
99018                 svgMapillaryImages: svgMapillaryImages,
99019                 svgMapillarySigns: svgMapillarySigns,
99020                 svgMidpoints: svgMidpoints,
99021                 svgNotes: svgNotes,
99022                 svgMarkerSegments: svgMarkerSegments,
99023                 svgOpenstreetcamImages: svgOpenstreetcamImages,
99024                 svgOsm: svgOsm,
99025                 svgPassiveVertex: svgPassiveVertex,
99026                 svgPath: svgPath,
99027                 svgPointTransform: svgPointTransform,
99028                 svgPoints: svgPoints,
99029                 svgRelationMemberTags: svgRelationMemberTags,
99030                 svgSegmentWay: svgSegmentWay,
99031                 svgStreetside: svgStreetside,
99032                 svgTagClasses: svgTagClasses,
99033                 svgTagPattern: svgTagPattern,
99034                 svgTouch: svgTouch,
99035                 svgTurns: svgTurns,
99036                 svgVertices: svgVertices,
99037                 uiFieldDefaultCheck: uiFieldCheck,
99038                 uiFieldOnewayCheck: uiFieldCheck,
99039                 uiFieldCheck: uiFieldCheck,
99040                 uiFieldManyCombo: uiFieldCombo,
99041                 uiFieldMultiCombo: uiFieldCombo,
99042                 uiFieldNetworkCombo: uiFieldCombo,
99043                 uiFieldSemiCombo: uiFieldCombo,
99044                 uiFieldTypeCombo: uiFieldCombo,
99045                 uiFieldCombo: uiFieldCombo,
99046                 uiFieldUrl: uiFieldText,
99047                 uiFieldIdentifier: uiFieldText,
99048                 uiFieldNumber: uiFieldText,
99049                 uiFieldTel: uiFieldText,
99050                 uiFieldEmail: uiFieldText,
99051                 uiFieldText: uiFieldText,
99052                 uiFieldAccess: uiFieldAccess,
99053                 uiFieldAddress: uiFieldAddress,
99054                 uiFieldCycleway: uiFieldCycleway,
99055                 uiFieldLanes: uiFieldLanes,
99056                 uiFieldLocalized: uiFieldLocalized,
99057                 uiFieldMaxspeed: uiFieldMaxspeed,
99058                 uiFieldStructureRadio: uiFieldRadio,
99059                 uiFieldRadio: uiFieldRadio,
99060                 uiFieldRestrictions: uiFieldRestrictions,
99061                 uiFieldTextarea: uiFieldTextarea,
99062                 uiFieldWikidata: uiFieldWikidata,
99063                 uiFieldWikipedia: uiFieldWikipedia,
99064                 uiFields: uiFields,
99065                 uiIntro: uiIntro,
99066                 uiPanelBackground: uiPanelBackground,
99067                 uiPanelHistory: uiPanelHistory,
99068                 uiPanelLocation: uiPanelLocation,
99069                 uiPanelMeasurement: uiPanelMeasurement,
99070                 uiInfoPanels: uiInfoPanels,
99071                 uiPaneBackground: uiPaneBackground,
99072                 uiPaneHelp: uiPaneHelp,
99073                 uiPaneIssues: uiPaneIssues,
99074                 uiPaneMapData: uiPaneMapData,
99075                 uiPanePreferences: uiPanePreferences,
99076                 uiSectionBackgroundDisplayOptions: uiSectionBackgroundDisplayOptions,
99077                 uiSectionBackgroundList: uiSectionBackgroundList,
99078                 uiSectionBackgroundOffset: uiSectionBackgroundOffset,
99079                 uiSectionChanges: uiSectionChanges,
99080                 uiSectionDataLayers: uiSectionDataLayers,
99081                 uiSectionEntityIssues: uiSectionEntityIssues,
99082                 uiSectionFeatureType: uiSectionFeatureType,
99083                 uiSectionMapFeatures: uiSectionMapFeatures,
99084                 uiSectionMapStyleOptions: uiSectionMapStyleOptions,
99085                 uiSectionOverlayList: uiSectionOverlayList,
99086                 uiSectionPhotoOverlays: uiSectionPhotoOverlays,
99087                 uiSectionPresetFields: uiSectionPresetFields,
99088                 uiSectionPrivacy: uiSectionPrivacy,
99089                 uiSectionRawMemberEditor: uiSectionRawMemberEditor,
99090                 uiSectionRawMembershipEditor: uiSectionRawMembershipEditor,
99091                 uiSectionRawTagEditor: uiSectionRawTagEditor,
99092                 uiSectionSelectionList: uiSectionSelectionList,
99093                 uiSectionValidationIssues: uiSectionValidationIssues,
99094                 uiSectionValidationOptions: uiSectionValidationOptions,
99095                 uiSectionValidationRules: uiSectionValidationRules,
99096                 uiSectionValidationStatus: uiSectionValidationStatus,
99097                 uiSettingsCustomBackground: uiSettingsCustomBackground,
99098                 uiSettingsCustomData: uiSettingsCustomData,
99099                 uiInit: uiInit,
99100                 uiAccount: uiAccount,
99101                 uiAttribution: uiAttribution,
99102                 uiChangesetEditor: uiChangesetEditor,
99103                 uiCmd: uiCmd,
99104                 uiCombobox: uiCombobox,
99105                 uiCommit: uiCommit,
99106                 uiCommitWarnings: uiCommitWarnings,
99107                 uiConfirm: uiConfirm,
99108                 uiConflicts: uiConflicts,
99109                 uiContributors: uiContributors,
99110                 uiCurtain: uiCurtain,
99111                 uiDataEditor: uiDataEditor,
99112                 uiDataHeader: uiDataHeader,
99113                 uiDisclosure: uiDisclosure,
99114                 uiEditMenu: uiEditMenu,
99115                 uiEntityEditor: uiEntityEditor,
99116                 uiFeatureInfo: uiFeatureInfo,
99117                 uiFeatureList: uiFeatureList,
99118                 uiField: uiField,
99119                 uiFieldHelp: uiFieldHelp,
99120                 uiFlash: uiFlash,
99121                 uiFormFields: uiFormFields,
99122                 uiFullScreen: uiFullScreen,
99123                 uiGeolocate: uiGeolocate,
99124                 uiImproveOsmComments: uiImproveOsmComments,
99125                 uiImproveOsmDetails: uiImproveOsmDetails,
99126                 uiImproveOsmEditor: uiImproveOsmEditor,
99127                 uiImproveOsmHeader: uiImproveOsmHeader,
99128                 uiInfo: uiInfo,
99129                 uiInspector: uiInspector,
99130                 uiIssuesInfo: uiIssuesInfo,
99131                 uiKeepRightDetails: uiKeepRightDetails,
99132                 uiKeepRightEditor: uiKeepRightEditor,
99133                 uiKeepRightHeader: uiKeepRightHeader,
99134                 uiLasso: uiLasso,
99135                 uiLoading: uiLoading,
99136                 uiMapInMap: uiMapInMap,
99137                 uiModal: uiModal,
99138                 uiNotice: uiNotice,
99139                 uiNoteComments: uiNoteComments,
99140                 uiNoteEditor: uiNoteEditor,
99141                 uiNoteHeader: uiNoteHeader,
99142                 uiNoteReport: uiNoteReport,
99143                 uiPopover: uiPopover,
99144                 uiPresetIcon: uiPresetIcon,
99145                 uiPresetList: uiPresetList,
99146                 uiRestore: uiRestore,
99147                 uiScale: uiScale,
99148                 uiSidebar: uiSidebar,
99149                 uiSourceSwitch: uiSourceSwitch,
99150                 uiSpinner: uiSpinner,
99151                 uiSplash: uiSplash,
99152                 uiStatus: uiStatus,
99153                 uiSuccess: uiSuccess,
99154                 uiTagReference: uiTagReference,
99155                 uiToggle: uiToggle,
99156                 uiTooltip: uiTooltip,
99157                 uiVersion: uiVersion,
99158                 uiViewOnOSM: uiViewOnOSM,
99159                 uiViewOnKeepRight: uiViewOnKeepRight,
99160                 uiZoom: uiZoom,
99161                 utilAesEncrypt: utilAesEncrypt,
99162                 utilAesDecrypt: utilAesDecrypt,
99163                 utilArrayChunk: utilArrayChunk,
99164                 utilArrayDifference: utilArrayDifference,
99165                 utilArrayFlatten: utilArrayFlatten,
99166                 utilArrayGroupBy: utilArrayGroupBy,
99167                 utilArrayIdentical: utilArrayIdentical,
99168                 utilArrayIntersection: utilArrayIntersection,
99169                 utilArrayUnion: utilArrayUnion,
99170                 utilArrayUniq: utilArrayUniq,
99171                 utilArrayUniqBy: utilArrayUniqBy,
99172                 utilAsyncMap: utilAsyncMap,
99173                 utilCleanTags: utilCleanTags,
99174                 utilCombinedTags: utilCombinedTags,
99175                 utilDeepMemberSelector: utilDeepMemberSelector,
99176                 utilDetect: utilDetect,
99177                 utilDisplayName: utilDisplayName,
99178                 utilDisplayNameForPath: utilDisplayNameForPath,
99179                 utilDisplayType: utilDisplayType,
99180                 utilDisplayLabel: utilDisplayLabel,
99181                 utilEntityRoot: utilEntityRoot,
99182                 utilEditDistance: utilEditDistance,
99183                 utilEntitySelector: utilEntitySelector,
99184                 utilEntityOrMemberSelector: utilEntityOrMemberSelector,
99185                 utilEntityOrDeepMemberSelector: utilEntityOrDeepMemberSelector,
99186                 utilFastMouse: utilFastMouse,
99187                 utilFunctor: utilFunctor,
99188                 utilGetAllNodes: utilGetAllNodes,
99189                 utilGetSetValue: utilGetSetValue,
99190                 utilHashcode: utilHashcode,
99191                 utilHighlightEntities: utilHighlightEntities,
99192                 utilKeybinding: utilKeybinding,
99193                 utilNoAuto: utilNoAuto,
99194                 utilObjectOmit: utilObjectOmit,
99195                 utilPrefixCSSProperty: utilPrefixCSSProperty,
99196                 utilPrefixDOMProperty: utilPrefixDOMProperty,
99197                 utilQsString: utilQsString,
99198                 utilRebind: utilRebind,
99199                 utilSafeClassName: utilSafeClassName,
99200                 utilSetTransform: utilSetTransform,
99201                 utilSessionMutex: utilSessionMutex,
99202                 utilStringQs: utilStringQs,
99203                 utilTagDiff: utilTagDiff,
99204                 utilTagText: utilTagText,
99205                 utilTiler: utilTiler,
99206                 utilTotalExtent: utilTotalExtent,
99207                 utilTriggerEvent: utilTriggerEvent,
99208                 utilUnicodeCharsCount: utilUnicodeCharsCount,
99209                 utilUnicodeCharsTruncated: utilUnicodeCharsTruncated,
99210                 utilUniqueDomId: utilUniqueDomId,
99211                 utilWrap: utilWrap,
99212                 validationAlmostJunction: validationAlmostJunction,
99213                 validationCloseNodes: validationCloseNodes,
99214                 validationCrossingWays: validationCrossingWays,
99215                 validationDisconnectedWay: validationDisconnectedWay,
99216                 validationFormatting: validationFormatting,
99217                 validationHelpRequest: validationHelpRequest,
99218                 validationImpossibleOneway: validationImpossibleOneway,
99219                 validationIncompatibleSource: validationIncompatibleSource,
99220                 validationMaprules: validationMaprules,
99221                 validationMismatchedGeometry: validationMismatchedGeometry,
99222                 validationMissingRole: validationMissingRole,
99223                 validationMissingTag: validationMissingTag,
99224                 validationOutdatedTags: validationOutdatedTags,
99225                 validationPrivateData: validationPrivateData,
99226                 validationSuspiciousName: validationSuspiciousName,
99227                 validationUnsquareWay: validationUnsquareWay
99228         });
99229
99230         window.requestIdleCallback = window.requestIdleCallback || function (cb) {
99231           var start = Date.now();
99232           return window.requestAnimationFrame(function () {
99233             cb({
99234               didTimeout: false,
99235               timeRemaining: function timeRemaining() {
99236                 return Math.max(0, 50 - (Date.now() - start));
99237               }
99238             });
99239           });
99240         };
99241
99242         window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
99243           window.cancelAnimationFrame(id);
99244         };
99245         window.iD = iD;
99246
99247 }());